162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <net/mac80211.h> 862306a36Sopenharmony_ci#include <linux/etherdevice.h> 962306a36Sopenharmony_ci#include "mac.h" 1062306a36Sopenharmony_ci#include "core.h" 1162306a36Sopenharmony_ci#include "debug.h" 1262306a36Sopenharmony_ci#include "wmi.h" 1362306a36Sopenharmony_ci#include "hw.h" 1462306a36Sopenharmony_ci#include "dp_tx.h" 1562306a36Sopenharmony_ci#include "dp_rx.h" 1662306a36Sopenharmony_ci#include "peer.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define CHAN2G(_channel, _freq, _flags) { \ 1962306a36Sopenharmony_ci .band = NL80211_BAND_2GHZ, \ 2062306a36Sopenharmony_ci .hw_value = (_channel), \ 2162306a36Sopenharmony_ci .center_freq = (_freq), \ 2262306a36Sopenharmony_ci .flags = (_flags), \ 2362306a36Sopenharmony_ci .max_antenna_gain = 0, \ 2462306a36Sopenharmony_ci .max_power = 30, \ 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define CHAN5G(_channel, _freq, _flags) { \ 2862306a36Sopenharmony_ci .band = NL80211_BAND_5GHZ, \ 2962306a36Sopenharmony_ci .hw_value = (_channel), \ 3062306a36Sopenharmony_ci .center_freq = (_freq), \ 3162306a36Sopenharmony_ci .flags = (_flags), \ 3262306a36Sopenharmony_ci .max_antenna_gain = 0, \ 3362306a36Sopenharmony_ci .max_power = 30, \ 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define CHAN6G(_channel, _freq, _flags) { \ 3762306a36Sopenharmony_ci .band = NL80211_BAND_6GHZ, \ 3862306a36Sopenharmony_ci .hw_value = (_channel), \ 3962306a36Sopenharmony_ci .center_freq = (_freq), \ 4062306a36Sopenharmony_ci .flags = (_flags), \ 4162306a36Sopenharmony_ci .max_antenna_gain = 0, \ 4262306a36Sopenharmony_ci .max_power = 30, \ 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const struct ieee80211_channel ath12k_2ghz_channels[] = { 4662306a36Sopenharmony_ci CHAN2G(1, 2412, 0), 4762306a36Sopenharmony_ci CHAN2G(2, 2417, 0), 4862306a36Sopenharmony_ci CHAN2G(3, 2422, 0), 4962306a36Sopenharmony_ci CHAN2G(4, 2427, 0), 5062306a36Sopenharmony_ci CHAN2G(5, 2432, 0), 5162306a36Sopenharmony_ci CHAN2G(6, 2437, 0), 5262306a36Sopenharmony_ci CHAN2G(7, 2442, 0), 5362306a36Sopenharmony_ci CHAN2G(8, 2447, 0), 5462306a36Sopenharmony_ci CHAN2G(9, 2452, 0), 5562306a36Sopenharmony_ci CHAN2G(10, 2457, 0), 5662306a36Sopenharmony_ci CHAN2G(11, 2462, 0), 5762306a36Sopenharmony_ci CHAN2G(12, 2467, 0), 5862306a36Sopenharmony_ci CHAN2G(13, 2472, 0), 5962306a36Sopenharmony_ci CHAN2G(14, 2484, 0), 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct ieee80211_channel ath12k_5ghz_channels[] = { 6362306a36Sopenharmony_ci CHAN5G(36, 5180, 0), 6462306a36Sopenharmony_ci CHAN5G(40, 5200, 0), 6562306a36Sopenharmony_ci CHAN5G(44, 5220, 0), 6662306a36Sopenharmony_ci CHAN5G(48, 5240, 0), 6762306a36Sopenharmony_ci CHAN5G(52, 5260, 0), 6862306a36Sopenharmony_ci CHAN5G(56, 5280, 0), 6962306a36Sopenharmony_ci CHAN5G(60, 5300, 0), 7062306a36Sopenharmony_ci CHAN5G(64, 5320, 0), 7162306a36Sopenharmony_ci CHAN5G(100, 5500, 0), 7262306a36Sopenharmony_ci CHAN5G(104, 5520, 0), 7362306a36Sopenharmony_ci CHAN5G(108, 5540, 0), 7462306a36Sopenharmony_ci CHAN5G(112, 5560, 0), 7562306a36Sopenharmony_ci CHAN5G(116, 5580, 0), 7662306a36Sopenharmony_ci CHAN5G(120, 5600, 0), 7762306a36Sopenharmony_ci CHAN5G(124, 5620, 0), 7862306a36Sopenharmony_ci CHAN5G(128, 5640, 0), 7962306a36Sopenharmony_ci CHAN5G(132, 5660, 0), 8062306a36Sopenharmony_ci CHAN5G(136, 5680, 0), 8162306a36Sopenharmony_ci CHAN5G(140, 5700, 0), 8262306a36Sopenharmony_ci CHAN5G(144, 5720, 0), 8362306a36Sopenharmony_ci CHAN5G(149, 5745, 0), 8462306a36Sopenharmony_ci CHAN5G(153, 5765, 0), 8562306a36Sopenharmony_ci CHAN5G(157, 5785, 0), 8662306a36Sopenharmony_ci CHAN5G(161, 5805, 0), 8762306a36Sopenharmony_ci CHAN5G(165, 5825, 0), 8862306a36Sopenharmony_ci CHAN5G(169, 5845, 0), 8962306a36Sopenharmony_ci CHAN5G(173, 5865, 0), 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct ieee80211_channel ath12k_6ghz_channels[] = { 9362306a36Sopenharmony_ci CHAN6G(1, 5955, 0), 9462306a36Sopenharmony_ci CHAN6G(5, 5975, 0), 9562306a36Sopenharmony_ci CHAN6G(9, 5995, 0), 9662306a36Sopenharmony_ci CHAN6G(13, 6015, 0), 9762306a36Sopenharmony_ci CHAN6G(17, 6035, 0), 9862306a36Sopenharmony_ci CHAN6G(21, 6055, 0), 9962306a36Sopenharmony_ci CHAN6G(25, 6075, 0), 10062306a36Sopenharmony_ci CHAN6G(29, 6095, 0), 10162306a36Sopenharmony_ci CHAN6G(33, 6115, 0), 10262306a36Sopenharmony_ci CHAN6G(37, 6135, 0), 10362306a36Sopenharmony_ci CHAN6G(41, 6155, 0), 10462306a36Sopenharmony_ci CHAN6G(45, 6175, 0), 10562306a36Sopenharmony_ci CHAN6G(49, 6195, 0), 10662306a36Sopenharmony_ci CHAN6G(53, 6215, 0), 10762306a36Sopenharmony_ci CHAN6G(57, 6235, 0), 10862306a36Sopenharmony_ci CHAN6G(61, 6255, 0), 10962306a36Sopenharmony_ci CHAN6G(65, 6275, 0), 11062306a36Sopenharmony_ci CHAN6G(69, 6295, 0), 11162306a36Sopenharmony_ci CHAN6G(73, 6315, 0), 11262306a36Sopenharmony_ci CHAN6G(77, 6335, 0), 11362306a36Sopenharmony_ci CHAN6G(81, 6355, 0), 11462306a36Sopenharmony_ci CHAN6G(85, 6375, 0), 11562306a36Sopenharmony_ci CHAN6G(89, 6395, 0), 11662306a36Sopenharmony_ci CHAN6G(93, 6415, 0), 11762306a36Sopenharmony_ci CHAN6G(97, 6435, 0), 11862306a36Sopenharmony_ci CHAN6G(101, 6455, 0), 11962306a36Sopenharmony_ci CHAN6G(105, 6475, 0), 12062306a36Sopenharmony_ci CHAN6G(109, 6495, 0), 12162306a36Sopenharmony_ci CHAN6G(113, 6515, 0), 12262306a36Sopenharmony_ci CHAN6G(117, 6535, 0), 12362306a36Sopenharmony_ci CHAN6G(121, 6555, 0), 12462306a36Sopenharmony_ci CHAN6G(125, 6575, 0), 12562306a36Sopenharmony_ci CHAN6G(129, 6595, 0), 12662306a36Sopenharmony_ci CHAN6G(133, 6615, 0), 12762306a36Sopenharmony_ci CHAN6G(137, 6635, 0), 12862306a36Sopenharmony_ci CHAN6G(141, 6655, 0), 12962306a36Sopenharmony_ci CHAN6G(145, 6675, 0), 13062306a36Sopenharmony_ci CHAN6G(149, 6695, 0), 13162306a36Sopenharmony_ci CHAN6G(153, 6715, 0), 13262306a36Sopenharmony_ci CHAN6G(157, 6735, 0), 13362306a36Sopenharmony_ci CHAN6G(161, 6755, 0), 13462306a36Sopenharmony_ci CHAN6G(165, 6775, 0), 13562306a36Sopenharmony_ci CHAN6G(169, 6795, 0), 13662306a36Sopenharmony_ci CHAN6G(173, 6815, 0), 13762306a36Sopenharmony_ci CHAN6G(177, 6835, 0), 13862306a36Sopenharmony_ci CHAN6G(181, 6855, 0), 13962306a36Sopenharmony_ci CHAN6G(185, 6875, 0), 14062306a36Sopenharmony_ci CHAN6G(189, 6895, 0), 14162306a36Sopenharmony_ci CHAN6G(193, 6915, 0), 14262306a36Sopenharmony_ci CHAN6G(197, 6935, 0), 14362306a36Sopenharmony_ci CHAN6G(201, 6955, 0), 14462306a36Sopenharmony_ci CHAN6G(205, 6975, 0), 14562306a36Sopenharmony_ci CHAN6G(209, 6995, 0), 14662306a36Sopenharmony_ci CHAN6G(213, 7015, 0), 14762306a36Sopenharmony_ci CHAN6G(217, 7035, 0), 14862306a36Sopenharmony_ci CHAN6G(221, 7055, 0), 14962306a36Sopenharmony_ci CHAN6G(225, 7075, 0), 15062306a36Sopenharmony_ci CHAN6G(229, 7095, 0), 15162306a36Sopenharmony_ci CHAN6G(233, 7115, 0), 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic struct ieee80211_rate ath12k_legacy_rates[] = { 15562306a36Sopenharmony_ci { .bitrate = 10, 15662306a36Sopenharmony_ci .hw_value = ATH12K_HW_RATE_CCK_LP_1M }, 15762306a36Sopenharmony_ci { .bitrate = 20, 15862306a36Sopenharmony_ci .hw_value = ATH12K_HW_RATE_CCK_LP_2M, 15962306a36Sopenharmony_ci .hw_value_short = ATH12K_HW_RATE_CCK_SP_2M, 16062306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 16162306a36Sopenharmony_ci { .bitrate = 55, 16262306a36Sopenharmony_ci .hw_value = ATH12K_HW_RATE_CCK_LP_5_5M, 16362306a36Sopenharmony_ci .hw_value_short = ATH12K_HW_RATE_CCK_SP_5_5M, 16462306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 16562306a36Sopenharmony_ci { .bitrate = 110, 16662306a36Sopenharmony_ci .hw_value = ATH12K_HW_RATE_CCK_LP_11M, 16762306a36Sopenharmony_ci .hw_value_short = ATH12K_HW_RATE_CCK_SP_11M, 16862306a36Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE }, 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci { .bitrate = 60, .hw_value = ATH12K_HW_RATE_OFDM_6M }, 17162306a36Sopenharmony_ci { .bitrate = 90, .hw_value = ATH12K_HW_RATE_OFDM_9M }, 17262306a36Sopenharmony_ci { .bitrate = 120, .hw_value = ATH12K_HW_RATE_OFDM_12M }, 17362306a36Sopenharmony_ci { .bitrate = 180, .hw_value = ATH12K_HW_RATE_OFDM_18M }, 17462306a36Sopenharmony_ci { .bitrate = 240, .hw_value = ATH12K_HW_RATE_OFDM_24M }, 17562306a36Sopenharmony_ci { .bitrate = 360, .hw_value = ATH12K_HW_RATE_OFDM_36M }, 17662306a36Sopenharmony_ci { .bitrate = 480, .hw_value = ATH12K_HW_RATE_OFDM_48M }, 17762306a36Sopenharmony_ci { .bitrate = 540, .hw_value = ATH12K_HW_RATE_OFDM_54M }, 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic const int 18162306a36Sopenharmony_ciath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = { 18262306a36Sopenharmony_ci [NL80211_BAND_2GHZ] = { 18362306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, 18462306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, 18562306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20_2G, 18662306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20_2G, 18762306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40_2G, 18862306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80] = MODE_UNKNOWN, 18962306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN, 19062306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN, 19162306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_320] = MODE_UNKNOWN, 19262306a36Sopenharmony_ci }, 19362306a36Sopenharmony_ci [NL80211_BAND_5GHZ] = { 19462306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, 19562306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, 19662306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20, 19762306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20, 19862306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, 19962306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, 20062306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, 20162306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, 20262306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, 20362306a36Sopenharmony_ci }, 20462306a36Sopenharmony_ci [NL80211_BAND_6GHZ] = { 20562306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, 20662306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, 20762306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11BE_EHT20, 20862306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_20] = MODE_11BE_EHT20, 20962306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, 21062306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, 21162306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, 21262306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, 21362306a36Sopenharmony_ci [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, 21462306a36Sopenharmony_ci }, 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciconst struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default = { 21962306a36Sopenharmony_ci .rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START | 22062306a36Sopenharmony_ci HTT_RX_FILTER_TLV_FLAGS_PPDU_END | 22162306a36Sopenharmony_ci HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE, 22262306a36Sopenharmony_ci .pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0, 22362306a36Sopenharmony_ci .pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1, 22462306a36Sopenharmony_ci .pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2, 22562306a36Sopenharmony_ci .pkt_filter_flags3 = HTT_RX_FP_DATA_FILTER_FLASG3 | 22662306a36Sopenharmony_ci HTT_RX_FP_CTRL_FILTER_FLASG3 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define ATH12K_MAC_FIRST_OFDM_RATE_IDX 4 23062306a36Sopenharmony_ci#define ath12k_g_rates ath12k_legacy_rates 23162306a36Sopenharmony_ci#define ath12k_g_rates_size (ARRAY_SIZE(ath12k_legacy_rates)) 23262306a36Sopenharmony_ci#define ath12k_a_rates (ath12k_legacy_rates + 4) 23362306a36Sopenharmony_ci#define ath12k_a_rates_size (ARRAY_SIZE(ath12k_legacy_rates) - 4) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define ATH12K_MAC_SCAN_TIMEOUT_MSECS 200 /* in msecs */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic const u32 ath12k_smps_map[] = { 23862306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC, 23962306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC, 24062306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE, 24162306a36Sopenharmony_ci [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int ath12k_start_vdev_delay(struct ieee80211_hw *hw, 24562306a36Sopenharmony_ci struct ieee80211_vif *vif); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci switch (mode) { 25062306a36Sopenharmony_ci case MODE_11A: 25162306a36Sopenharmony_ci return "11a"; 25262306a36Sopenharmony_ci case MODE_11G: 25362306a36Sopenharmony_ci return "11g"; 25462306a36Sopenharmony_ci case MODE_11B: 25562306a36Sopenharmony_ci return "11b"; 25662306a36Sopenharmony_ci case MODE_11GONLY: 25762306a36Sopenharmony_ci return "11gonly"; 25862306a36Sopenharmony_ci case MODE_11NA_HT20: 25962306a36Sopenharmony_ci return "11na-ht20"; 26062306a36Sopenharmony_ci case MODE_11NG_HT20: 26162306a36Sopenharmony_ci return "11ng-ht20"; 26262306a36Sopenharmony_ci case MODE_11NA_HT40: 26362306a36Sopenharmony_ci return "11na-ht40"; 26462306a36Sopenharmony_ci case MODE_11NG_HT40: 26562306a36Sopenharmony_ci return "11ng-ht40"; 26662306a36Sopenharmony_ci case MODE_11AC_VHT20: 26762306a36Sopenharmony_ci return "11ac-vht20"; 26862306a36Sopenharmony_ci case MODE_11AC_VHT40: 26962306a36Sopenharmony_ci return "11ac-vht40"; 27062306a36Sopenharmony_ci case MODE_11AC_VHT80: 27162306a36Sopenharmony_ci return "11ac-vht80"; 27262306a36Sopenharmony_ci case MODE_11AC_VHT160: 27362306a36Sopenharmony_ci return "11ac-vht160"; 27462306a36Sopenharmony_ci case MODE_11AC_VHT80_80: 27562306a36Sopenharmony_ci return "11ac-vht80+80"; 27662306a36Sopenharmony_ci case MODE_11AC_VHT20_2G: 27762306a36Sopenharmony_ci return "11ac-vht20-2g"; 27862306a36Sopenharmony_ci case MODE_11AC_VHT40_2G: 27962306a36Sopenharmony_ci return "11ac-vht40-2g"; 28062306a36Sopenharmony_ci case MODE_11AC_VHT80_2G: 28162306a36Sopenharmony_ci return "11ac-vht80-2g"; 28262306a36Sopenharmony_ci case MODE_11AX_HE20: 28362306a36Sopenharmony_ci return "11ax-he20"; 28462306a36Sopenharmony_ci case MODE_11AX_HE40: 28562306a36Sopenharmony_ci return "11ax-he40"; 28662306a36Sopenharmony_ci case MODE_11AX_HE80: 28762306a36Sopenharmony_ci return "11ax-he80"; 28862306a36Sopenharmony_ci case MODE_11AX_HE80_80: 28962306a36Sopenharmony_ci return "11ax-he80+80"; 29062306a36Sopenharmony_ci case MODE_11AX_HE160: 29162306a36Sopenharmony_ci return "11ax-he160"; 29262306a36Sopenharmony_ci case MODE_11AX_HE20_2G: 29362306a36Sopenharmony_ci return "11ax-he20-2g"; 29462306a36Sopenharmony_ci case MODE_11AX_HE40_2G: 29562306a36Sopenharmony_ci return "11ax-he40-2g"; 29662306a36Sopenharmony_ci case MODE_11AX_HE80_2G: 29762306a36Sopenharmony_ci return "11ax-he80-2g"; 29862306a36Sopenharmony_ci case MODE_11BE_EHT20: 29962306a36Sopenharmony_ci return "11be-eht20"; 30062306a36Sopenharmony_ci case MODE_11BE_EHT40: 30162306a36Sopenharmony_ci return "11be-eht40"; 30262306a36Sopenharmony_ci case MODE_11BE_EHT80: 30362306a36Sopenharmony_ci return "11be-eht80"; 30462306a36Sopenharmony_ci case MODE_11BE_EHT80_80: 30562306a36Sopenharmony_ci return "11be-eht80+80"; 30662306a36Sopenharmony_ci case MODE_11BE_EHT160: 30762306a36Sopenharmony_ci return "11be-eht160"; 30862306a36Sopenharmony_ci case MODE_11BE_EHT160_160: 30962306a36Sopenharmony_ci return "11be-eht160+160"; 31062306a36Sopenharmony_ci case MODE_11BE_EHT320: 31162306a36Sopenharmony_ci return "11be-eht320"; 31262306a36Sopenharmony_ci case MODE_11BE_EHT20_2G: 31362306a36Sopenharmony_ci return "11be-eht20-2g"; 31462306a36Sopenharmony_ci case MODE_11BE_EHT40_2G: 31562306a36Sopenharmony_ci return "11be-eht40-2g"; 31662306a36Sopenharmony_ci case MODE_UNKNOWN: 31762306a36Sopenharmony_ci /* skip */ 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* no default handler to allow compiler to check that the 32162306a36Sopenharmony_ci * enum is fully handled 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return "<unknown>"; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cienum rate_info_bw 32962306a36Sopenharmony_ciath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci u8 ret = RATE_INFO_BW_20; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci switch (bw) { 33462306a36Sopenharmony_ci case ATH12K_BW_20: 33562306a36Sopenharmony_ci ret = RATE_INFO_BW_20; 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci case ATH12K_BW_40: 33862306a36Sopenharmony_ci ret = RATE_INFO_BW_40; 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci case ATH12K_BW_80: 34162306a36Sopenharmony_ci ret = RATE_INFO_BW_80; 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci case ATH12K_BW_160: 34462306a36Sopenharmony_ci ret = RATE_INFO_BW_160; 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return ret; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cienum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci switch (bw) { 35462306a36Sopenharmony_ci case RATE_INFO_BW_20: 35562306a36Sopenharmony_ci return ATH12K_BW_20; 35662306a36Sopenharmony_ci case RATE_INFO_BW_40: 35762306a36Sopenharmony_ci return ATH12K_BW_40; 35862306a36Sopenharmony_ci case RATE_INFO_BW_80: 35962306a36Sopenharmony_ci return ATH12K_BW_80; 36062306a36Sopenharmony_ci case RATE_INFO_BW_160: 36162306a36Sopenharmony_ci return ATH12K_BW_160; 36262306a36Sopenharmony_ci default: 36362306a36Sopenharmony_ci return ATH12K_BW_20; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciint ath12k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx, 36862306a36Sopenharmony_ci u16 *rate) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci /* As default, it is OFDM rates */ 37162306a36Sopenharmony_ci int i = ATH12K_MAC_FIRST_OFDM_RATE_IDX; 37262306a36Sopenharmony_ci int max_rates_idx = ath12k_g_rates_size; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (preamble == WMI_RATE_PREAMBLE_CCK) { 37562306a36Sopenharmony_ci hw_rc &= ~ATH12K_HW_RATECODE_CCK_SHORT_PREAM_MASK; 37662306a36Sopenharmony_ci i = 0; 37762306a36Sopenharmony_ci max_rates_idx = ATH12K_MAC_FIRST_OFDM_RATE_IDX; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci while (i < max_rates_idx) { 38162306a36Sopenharmony_ci if (hw_rc == ath12k_legacy_rates[i].hw_value) { 38262306a36Sopenharmony_ci *rateidx = i; 38362306a36Sopenharmony_ci *rate = ath12k_legacy_rates[i].bitrate; 38462306a36Sopenharmony_ci return 0; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci i++; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ciu8 ath12k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband, 39362306a36Sopenharmony_ci u32 bitrate) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci int i; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) 39862306a36Sopenharmony_ci if (sband->bitrates[i].bitrate == bitrate) 39962306a36Sopenharmony_ci return i; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic u32 40562306a36Sopenharmony_ciath12k_mac_max_ht_nss(const u8 *ht_mcs_mask) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci int nss; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for (nss = IEEE80211_HT_MCS_MASK_LEN - 1; nss >= 0; nss--) 41062306a36Sopenharmony_ci if (ht_mcs_mask[nss]) 41162306a36Sopenharmony_ci return nss + 1; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 1; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic u32 41762306a36Sopenharmony_ciath12k_mac_max_vht_nss(const u16 *vht_mcs_mask) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci int nss; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci for (nss = NL80211_VHT_NSS_MAX - 1; nss >= 0; nss--) 42262306a36Sopenharmony_ci if (vht_mcs_mask[nss]) 42362306a36Sopenharmony_ci return nss + 1; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 1; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic u8 ath12k_parse_mpdudensity(u8 mpdudensity) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci/* From IEEE Std 802.11-2020 defined values for "Minimum MPDU Start Spacing": 43162306a36Sopenharmony_ci * 0 for no restriction 43262306a36Sopenharmony_ci * 1 for 1/4 us 43362306a36Sopenharmony_ci * 2 for 1/2 us 43462306a36Sopenharmony_ci * 3 for 1 us 43562306a36Sopenharmony_ci * 4 for 2 us 43662306a36Sopenharmony_ci * 5 for 4 us 43762306a36Sopenharmony_ci * 6 for 8 us 43862306a36Sopenharmony_ci * 7 for 16 us 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci switch (mpdudensity) { 44162306a36Sopenharmony_ci case 0: 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci case 1: 44462306a36Sopenharmony_ci case 2: 44562306a36Sopenharmony_ci case 3: 44662306a36Sopenharmony_ci /* Our lower layer calculations limit our precision to 44762306a36Sopenharmony_ci * 1 microsecond 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci return 1; 45062306a36Sopenharmony_ci case 4: 45162306a36Sopenharmony_ci return 2; 45262306a36Sopenharmony_ci case 5: 45362306a36Sopenharmony_ci return 4; 45462306a36Sopenharmony_ci case 6: 45562306a36Sopenharmony_ci return 8; 45662306a36Sopenharmony_ci case 7: 45762306a36Sopenharmony_ci return 16; 45862306a36Sopenharmony_ci default: 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int ath12k_mac_vif_chan(struct ieee80211_vif *vif, 46462306a36Sopenharmony_ci struct cfg80211_chan_def *def) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci rcu_read_lock(); 46962306a36Sopenharmony_ci conf = rcu_dereference(vif->bss_conf.chanctx_conf); 47062306a36Sopenharmony_ci if (!conf) { 47162306a36Sopenharmony_ci rcu_read_unlock(); 47262306a36Sopenharmony_ci return -ENOENT; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci *def = conf->def; 47662306a36Sopenharmony_ci rcu_read_unlock(); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic bool ath12k_mac_bitrate_is_cck(int bitrate) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci switch (bitrate) { 48462306a36Sopenharmony_ci case 10: 48562306a36Sopenharmony_ci case 20: 48662306a36Sopenharmony_ci case 55: 48762306a36Sopenharmony_ci case 110: 48862306a36Sopenharmony_ci return true; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return false; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciu8 ath12k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, 49562306a36Sopenharmony_ci u8 hw_rate, bool cck) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci const struct ieee80211_rate *rate; 49862306a36Sopenharmony_ci int i; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci for (i = 0; i < sband->n_bitrates; i++) { 50162306a36Sopenharmony_ci rate = &sband->bitrates[i]; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (ath12k_mac_bitrate_is_cck(rate->bitrate) != cck) 50462306a36Sopenharmony_ci continue; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (rate->hw_value == hw_rate) 50762306a36Sopenharmony_ci return i; 50862306a36Sopenharmony_ci else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE && 50962306a36Sopenharmony_ci rate->hw_value_short == hw_rate) 51062306a36Sopenharmony_ci return i; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic u8 ath12k_mac_bitrate_to_rate(int bitrate) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci return DIV_ROUND_UP(bitrate, 5) | 51962306a36Sopenharmony_ci (ath12k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void ath12k_get_arvif_iter(void *data, u8 *mac, 52362306a36Sopenharmony_ci struct ieee80211_vif *vif) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct ath12k_vif_iter *arvif_iter = data; 52662306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (arvif->vdev_id == arvif_iter->vdev_id) 52962306a36Sopenharmony_ci arvif_iter->arvif = arvif; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistruct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct ath12k_vif_iter arvif_iter = {}; 53562306a36Sopenharmony_ci u32 flags; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci arvif_iter.vdev_id = vdev_id; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci flags = IEEE80211_IFACE_ITER_RESUME_ALL; 54062306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 54162306a36Sopenharmony_ci flags, 54262306a36Sopenharmony_ci ath12k_get_arvif_iter, 54362306a36Sopenharmony_ci &arvif_iter); 54462306a36Sopenharmony_ci if (!arvif_iter.arvif) { 54562306a36Sopenharmony_ci ath12k_warn(ar->ab, "No VIF found for vdev %d\n", vdev_id); 54662306a36Sopenharmony_ci return NULL; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return arvif_iter.arvif; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistruct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, 55362306a36Sopenharmony_ci u32 vdev_id) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci int i; 55662306a36Sopenharmony_ci struct ath12k_pdev *pdev; 55762306a36Sopenharmony_ci struct ath12k_vif *arvif; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 56062306a36Sopenharmony_ci pdev = rcu_dereference(ab->pdevs_active[i]); 56162306a36Sopenharmony_ci if (pdev && pdev->ar) { 56262306a36Sopenharmony_ci arvif = ath12k_mac_get_arvif(pdev->ar, vdev_id); 56362306a36Sopenharmony_ci if (arvif) 56462306a36Sopenharmony_ci return arvif; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return NULL; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistruct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci int i; 57462306a36Sopenharmony_ci struct ath12k_pdev *pdev; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 57762306a36Sopenharmony_ci pdev = rcu_dereference(ab->pdevs_active[i]); 57862306a36Sopenharmony_ci if (pdev && pdev->ar) { 57962306a36Sopenharmony_ci if (pdev->ar->allocated_vdev_map & (1LL << vdev_id)) 58062306a36Sopenharmony_ci return pdev->ar; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return NULL; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistruct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci int i; 59062306a36Sopenharmony_ci struct ath12k_pdev *pdev; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (ab->hw_params->single_pdev_only) { 59362306a36Sopenharmony_ci pdev = rcu_dereference(ab->pdevs_active[0]); 59462306a36Sopenharmony_ci return pdev ? pdev->ar : NULL; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (WARN_ON(pdev_id > ab->num_radios)) 59862306a36Sopenharmony_ci return NULL; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 60162306a36Sopenharmony_ci pdev = rcu_dereference(ab->pdevs_active[i]); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (pdev && pdev->pdev_id == pdev_id) 60462306a36Sopenharmony_ci return (pdev->ar ? pdev->ar : NULL); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return NULL; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void ath12k_pdev_caps_update(struct ath12k *ar) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ar->max_tx_power = ab->target_caps.hw_max_tx_power; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* FIXME: Set min_tx_power to ab->target_caps.hw_min_tx_power. 61762306a36Sopenharmony_ci * But since the received value in svcrdy is same as hw_max_tx_power, 61862306a36Sopenharmony_ci * we can set ar->min_tx_power to 0 currently until 61962306a36Sopenharmony_ci * this is fixed in firmware 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci ar->min_tx_power = 0; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci ar->txpower_limit_2g = ar->max_tx_power; 62462306a36Sopenharmony_ci ar->txpower_limit_5g = ar->max_tx_power; 62562306a36Sopenharmony_ci ar->txpower_scale = WMI_HOST_TP_SCALE_MAX; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic int ath12k_mac_txpower_recalc(struct ath12k *ar) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct ath12k_pdev *pdev = ar->pdev; 63162306a36Sopenharmony_ci struct ath12k_vif *arvif; 63262306a36Sopenharmony_ci int ret, txpower = -1; 63362306a36Sopenharmony_ci u32 param; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 63862306a36Sopenharmony_ci if (arvif->txpower <= 0) 63962306a36Sopenharmony_ci continue; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (txpower == -1) 64262306a36Sopenharmony_ci txpower = arvif->txpower; 64362306a36Sopenharmony_ci else 64462306a36Sopenharmony_ci txpower = min(txpower, arvif->txpower); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (txpower == -1) 64862306a36Sopenharmony_ci return 0; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* txpwr is set as 2 units per dBm in FW*/ 65162306a36Sopenharmony_ci txpower = min_t(u32, max_t(u32, ar->min_tx_power, txpower), 65262306a36Sopenharmony_ci ar->max_tx_power) * 2; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "txpower to set in hw %d\n", 65562306a36Sopenharmony_ci txpower / 2); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if ((pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) && 65862306a36Sopenharmony_ci ar->txpower_limit_2g != txpower) { 65962306a36Sopenharmony_ci param = WMI_PDEV_PARAM_TXPOWER_LIMIT2G; 66062306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, param, 66162306a36Sopenharmony_ci txpower, ar->pdev->pdev_id); 66262306a36Sopenharmony_ci if (ret) 66362306a36Sopenharmony_ci goto fail; 66462306a36Sopenharmony_ci ar->txpower_limit_2g = txpower; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if ((pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) && 66862306a36Sopenharmony_ci ar->txpower_limit_5g != txpower) { 66962306a36Sopenharmony_ci param = WMI_PDEV_PARAM_TXPOWER_LIMIT5G; 67062306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, param, 67162306a36Sopenharmony_ci txpower, ar->pdev->pdev_id); 67262306a36Sopenharmony_ci if (ret) 67362306a36Sopenharmony_ci goto fail; 67462306a36Sopenharmony_ci ar->txpower_limit_5g = txpower; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cifail: 68062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to recalc txpower limit %d using pdev param %d: %d\n", 68162306a36Sopenharmony_ci txpower / 2, param, ret); 68262306a36Sopenharmony_ci return ret; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int ath12k_recalc_rtscts_prot(struct ath12k_vif *arvif) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 68862306a36Sopenharmony_ci u32 vdev_param, rts_cts; 68962306a36Sopenharmony_ci int ret; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_ENABLE_RTSCTS; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Enable RTS/CTS protection for sw retries (when legacy stations 69662306a36Sopenharmony_ci * are in BSS) or by default only for second rate series. 69762306a36Sopenharmony_ci * TODO: Check if we need to enable CTS 2 Self in any case 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci rts_cts = WMI_USE_RTS_CTS; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (arvif->num_legacy_stations > 0) 70262306a36Sopenharmony_ci rts_cts |= WMI_RTSCTS_ACROSS_SW_RETRIES << 4; 70362306a36Sopenharmony_ci else 70462306a36Sopenharmony_ci rts_cts |= WMI_RTSCTS_FOR_SECOND_RATESERIES << 4; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* Need not send duplicate param value to firmware */ 70762306a36Sopenharmony_ci if (arvif->rtscts_prot_mode == rts_cts) 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci arvif->rtscts_prot_mode = rts_cts; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d recalc rts/cts prot %d\n", 71362306a36Sopenharmony_ci arvif->vdev_id, rts_cts); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 71662306a36Sopenharmony_ci vdev_param, rts_cts); 71762306a36Sopenharmony_ci if (ret) 71862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to recalculate rts/cts prot for vdev %d: %d\n", 71962306a36Sopenharmony_ci arvif->vdev_id, ret); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return ret; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int ath12k_mac_set_kickout(struct ath12k_vif *arvif) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 72762306a36Sopenharmony_ci u32 param; 72862306a36Sopenharmony_ci int ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_STA_KICKOUT_TH, 73162306a36Sopenharmony_ci ATH12K_KICKOUT_THRESHOLD, 73262306a36Sopenharmony_ci ar->pdev->pdev_id); 73362306a36Sopenharmony_ci if (ret) { 73462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set kickout threshold on vdev %i: %d\n", 73562306a36Sopenharmony_ci arvif->vdev_id, ret); 73662306a36Sopenharmony_ci return ret; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci param = WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS; 74062306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, 74162306a36Sopenharmony_ci ATH12K_KEEPALIVE_MIN_IDLE); 74262306a36Sopenharmony_ci if (ret) { 74362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set keepalive minimum idle time on vdev %i: %d\n", 74462306a36Sopenharmony_ci arvif->vdev_id, ret); 74562306a36Sopenharmony_ci return ret; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci param = WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS; 74962306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, 75062306a36Sopenharmony_ci ATH12K_KEEPALIVE_MAX_IDLE); 75162306a36Sopenharmony_ci if (ret) { 75262306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set keepalive maximum idle time on vdev %i: %d\n", 75362306a36Sopenharmony_ci arvif->vdev_id, ret); 75462306a36Sopenharmony_ci return ret; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci param = WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS; 75862306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, 75962306a36Sopenharmony_ci ATH12K_KEEPALIVE_MAX_UNRESPONSIVE); 76062306a36Sopenharmony_ci if (ret) { 76162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n", 76262306a36Sopenharmony_ci arvif->vdev_id, ret); 76362306a36Sopenharmony_ci return ret; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_civoid ath12k_mac_peer_cleanup_all(struct ath12k *ar) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct ath12k_peer *peer, *tmp; 77262306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 77762306a36Sopenharmony_ci list_for_each_entry_safe(peer, tmp, &ab->peers, list) { 77862306a36Sopenharmony_ci ath12k_dp_rx_peer_tid_cleanup(ar, peer); 77962306a36Sopenharmony_ci list_del(&peer->list); 78062306a36Sopenharmony_ci kfree(peer); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci ar->num_peers = 0; 78562306a36Sopenharmony_ci ar->num_stations = 0; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int ath12k_mac_vdev_setup_sync(struct ath12k *ar) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) 79362306a36Sopenharmony_ci return -ESHUTDOWN; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev setup timeout %d\n", 79662306a36Sopenharmony_ci ATH12K_VDEV_SETUP_TIMEOUT_HZ); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ar->vdev_setup_done, 79962306a36Sopenharmony_ci ATH12K_VDEV_SETUP_TIMEOUT_HZ)) 80062306a36Sopenharmony_ci return -ETIMEDOUT; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return ar->last_wmi_vdev_start_status ? -EINVAL : 0; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic int ath12k_monitor_vdev_up(struct ath12k *ar, int vdev_id) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci int ret; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci ret = ath12k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); 81062306a36Sopenharmony_ci if (ret) { 81162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", 81262306a36Sopenharmony_ci vdev_id, ret); 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor vdev %i started\n", 81762306a36Sopenharmony_ci vdev_id); 81862306a36Sopenharmony_ci return 0; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic int ath12k_mac_monitor_vdev_start(struct ath12k *ar, int vdev_id, 82262306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct ieee80211_channel *channel; 82562306a36Sopenharmony_ci struct wmi_vdev_start_req_arg arg = {}; 82662306a36Sopenharmony_ci int ret; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci channel = chandef->chan; 83162306a36Sopenharmony_ci arg.vdev_id = vdev_id; 83262306a36Sopenharmony_ci arg.freq = channel->center_freq; 83362306a36Sopenharmony_ci arg.band_center_freq1 = chandef->center_freq1; 83462306a36Sopenharmony_ci arg.band_center_freq2 = chandef->center_freq2; 83562306a36Sopenharmony_ci arg.mode = ath12k_phymodes[chandef->chan->band][chandef->width]; 83662306a36Sopenharmony_ci arg.chan_radar = !!(channel->flags & IEEE80211_CHAN_RADAR); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci arg.min_power = 0; 83962306a36Sopenharmony_ci arg.max_power = channel->max_power; 84062306a36Sopenharmony_ci arg.max_reg_power = channel->max_reg_power; 84162306a36Sopenharmony_ci arg.max_antenna_gain = channel->max_antenna_gain; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci arg.pref_tx_streams = ar->num_tx_chains; 84462306a36Sopenharmony_ci arg.pref_rx_streams = ar->num_rx_chains; 84562306a36Sopenharmony_ci arg.punct_bitmap = 0xFFFFFFFF; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 85062306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci ret = ath12k_wmi_vdev_start(ar, &arg, false); 85362306a36Sopenharmony_ci if (ret) { 85462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to request monitor vdev %i start: %d\n", 85562306a36Sopenharmony_ci vdev_id, ret); 85662306a36Sopenharmony_ci return ret; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci ret = ath12k_mac_vdev_setup_sync(ar); 86062306a36Sopenharmony_ci if (ret) { 86162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to synchronize setup for monitor vdev %i start: %d\n", 86262306a36Sopenharmony_ci vdev_id, ret); 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ret = ath12k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr); 86762306a36Sopenharmony_ci if (ret) { 86862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n", 86962306a36Sopenharmony_ci vdev_id, ret); 87062306a36Sopenharmony_ci goto vdev_stop; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor vdev %i started\n", 87462306a36Sopenharmony_ci vdev_id); 87562306a36Sopenharmony_ci return 0; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_civdev_stop: 87862306a36Sopenharmony_ci ret = ath12k_wmi_vdev_stop(ar, vdev_id); 87962306a36Sopenharmony_ci if (ret) 88062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to stop monitor vdev %i after start failure: %d\n", 88162306a36Sopenharmony_ci vdev_id, ret); 88262306a36Sopenharmony_ci return ret; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int ath12k_mac_monitor_vdev_stop(struct ath12k *ar) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci int ret; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci ret = ath12k_wmi_vdev_stop(ar, ar->monitor_vdev_id); 89462306a36Sopenharmony_ci if (ret) 89562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to request monitor vdev %i stop: %d\n", 89662306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci ret = ath12k_mac_vdev_setup_sync(ar); 89962306a36Sopenharmony_ci if (ret) 90062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to synchronize monitor vdev %i stop: %d\n", 90162306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci ret = ath12k_wmi_vdev_down(ar, ar->monitor_vdev_id); 90462306a36Sopenharmony_ci if (ret) 90562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to put down monitor vdev %i: %d\n", 90662306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor vdev %i stopped\n", 90962306a36Sopenharmony_ci ar->monitor_vdev_id); 91062306a36Sopenharmony_ci return ret; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic int ath12k_mac_monitor_vdev_create(struct ath12k *ar) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct ath12k_pdev *pdev = ar->pdev; 91662306a36Sopenharmony_ci struct ath12k_wmi_vdev_create_arg arg = {}; 91762306a36Sopenharmony_ci int bit, ret; 91862306a36Sopenharmony_ci u8 tmp_addr[6]; 91962306a36Sopenharmony_ci u16 nss; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (ar->monitor_vdev_created) 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (ar->ab->free_vdev_map == 0) { 92762306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to find free vdev id for monitor vdev\n"); 92862306a36Sopenharmony_ci return -ENOMEM; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci bit = __ffs64(ar->ab->free_vdev_map); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci ar->monitor_vdev_id = bit; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci arg.if_id = ar->monitor_vdev_id; 93662306a36Sopenharmony_ci arg.type = WMI_VDEV_TYPE_MONITOR; 93762306a36Sopenharmony_ci arg.subtype = WMI_VDEV_SUBTYPE_NONE; 93862306a36Sopenharmony_ci arg.pdev_id = pdev->pdev_id; 93962306a36Sopenharmony_ci arg.if_stats_id = ATH12K_INVAL_VDEV_STATS_ID; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) { 94262306a36Sopenharmony_ci arg.chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains; 94362306a36Sopenharmony_ci arg.chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) { 94762306a36Sopenharmony_ci arg.chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains; 94862306a36Sopenharmony_ci arg.chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_create(ar, tmp_addr, &arg); 95262306a36Sopenharmony_ci if (ret) { 95362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to request monitor vdev %i creation: %d\n", 95462306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 95562306a36Sopenharmony_ci ar->monitor_vdev_id = -1; 95662306a36Sopenharmony_ci return ret; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci nss = hweight32(ar->cfg_tx_chainmask) ? : 1; 96062306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, ar->monitor_vdev_id, 96162306a36Sopenharmony_ci WMI_VDEV_PARAM_NSS, nss); 96262306a36Sopenharmony_ci if (ret) { 96362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n", 96462306a36Sopenharmony_ci ar->monitor_vdev_id, ar->cfg_tx_chainmask, nss, ret); 96562306a36Sopenharmony_ci return ret; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci ret = ath12k_mac_txpower_recalc(ar); 96962306a36Sopenharmony_ci if (ret) 97062306a36Sopenharmony_ci return ret; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci ar->allocated_vdev_map |= 1LL << ar->monitor_vdev_id; 97362306a36Sopenharmony_ci ar->ab->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); 97462306a36Sopenharmony_ci ar->num_created_vdevs++; 97562306a36Sopenharmony_ci ar->monitor_vdev_created = true; 97662306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor vdev %d created\n", 97762306a36Sopenharmony_ci ar->monitor_vdev_id); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci return 0; 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int ath12k_mac_monitor_vdev_delete(struct ath12k *ar) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci int ret; 98562306a36Sopenharmony_ci unsigned long time_left; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (!ar->monitor_vdev_created) 99062306a36Sopenharmony_ci return 0; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci ret = ath12k_wmi_vdev_delete(ar, ar->monitor_vdev_id); 99562306a36Sopenharmony_ci if (ret) { 99662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to request wmi monitor vdev %i removal: %d\n", 99762306a36Sopenharmony_ci ar->monitor_vdev_id, ret); 99862306a36Sopenharmony_ci return ret; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->vdev_delete_done, 100262306a36Sopenharmony_ci ATH12K_VDEV_DELETE_TIMEOUT_HZ); 100362306a36Sopenharmony_ci if (time_left == 0) { 100462306a36Sopenharmony_ci ath12k_warn(ar->ab, "Timeout in receiving vdev delete response\n"); 100562306a36Sopenharmony_ci } else { 100662306a36Sopenharmony_ci ar->allocated_vdev_map &= ~(1LL << ar->monitor_vdev_id); 100762306a36Sopenharmony_ci ar->ab->free_vdev_map |= 1LL << (ar->monitor_vdev_id); 100862306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor vdev %d deleted\n", 100962306a36Sopenharmony_ci ar->monitor_vdev_id); 101062306a36Sopenharmony_ci ar->num_created_vdevs--; 101162306a36Sopenharmony_ci ar->monitor_vdev_id = -1; 101262306a36Sopenharmony_ci ar->monitor_vdev_created = false; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci return ret; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic void 101962306a36Sopenharmony_ciath12k_mac_get_any_chandef_iter(struct ieee80211_hw *hw, 102062306a36Sopenharmony_ci struct ieee80211_chanctx_conf *conf, 102162306a36Sopenharmony_ci void *data) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct cfg80211_chan_def **def = data; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci *def = &conf->def; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int ath12k_mac_monitor_start(struct ath12k *ar) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = NULL; 103162306a36Sopenharmony_ci int ret; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (ar->monitor_started) 103662306a36Sopenharmony_ci return 0; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci ieee80211_iter_chan_contexts_atomic(ar->hw, 103962306a36Sopenharmony_ci ath12k_mac_get_any_chandef_iter, 104062306a36Sopenharmony_ci &chandef); 104162306a36Sopenharmony_ci if (!chandef) 104262306a36Sopenharmony_ci return 0; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ret = ath12k_mac_monitor_vdev_start(ar, ar->monitor_vdev_id, chandef); 104562306a36Sopenharmony_ci if (ret) { 104662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to start monitor vdev: %d\n", ret); 104762306a36Sopenharmony_ci ath12k_mac_monitor_vdev_delete(ar); 104862306a36Sopenharmony_ci return ret; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci ar->monitor_started = true; 105262306a36Sopenharmony_ci ar->num_started_vdevs++; 105362306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_monitor_mode_ring_config(ar, false); 105462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor started ret %d\n", ret); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci return ret; 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic int ath12k_mac_monitor_stop(struct ath12k *ar) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci int ret; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (!ar->monitor_started) 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci ret = ath12k_mac_monitor_vdev_stop(ar); 106962306a36Sopenharmony_ci if (ret) { 107062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to stop monitor vdev: %d\n", ret); 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci ar->monitor_started = false; 107562306a36Sopenharmony_ci ar->num_started_vdevs--; 107662306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_monitor_mode_ring_config(ar, true); 107762306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac monitor stopped ret %d\n", ret); 107862306a36Sopenharmony_ci return ret; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_cistatic int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 108462306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 108562306a36Sopenharmony_ci int ret = 0; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 109062306a36Sopenharmony_ci ar->monitor_conf_enabled = conf->flags & IEEE80211_CONF_MONITOR; 109162306a36Sopenharmony_ci if (ar->monitor_conf_enabled) { 109262306a36Sopenharmony_ci if (ar->monitor_vdev_created) 109362306a36Sopenharmony_ci goto exit; 109462306a36Sopenharmony_ci ret = ath12k_mac_monitor_vdev_create(ar); 109562306a36Sopenharmony_ci if (ret) 109662306a36Sopenharmony_ci goto exit; 109762306a36Sopenharmony_ci ret = ath12k_mac_monitor_start(ar); 109862306a36Sopenharmony_ci if (ret) 109962306a36Sopenharmony_ci goto err_mon_del; 110062306a36Sopenharmony_ci } else { 110162306a36Sopenharmony_ci if (!ar->monitor_vdev_created) 110262306a36Sopenharmony_ci goto exit; 110362306a36Sopenharmony_ci ret = ath12k_mac_monitor_stop(ar); 110462306a36Sopenharmony_ci if (ret) 110562306a36Sopenharmony_ci goto exit; 110662306a36Sopenharmony_ci ath12k_mac_monitor_vdev_delete(ar); 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ciexit: 111162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 111262306a36Sopenharmony_ci return ret; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cierr_mon_del: 111562306a36Sopenharmony_ci ath12k_mac_monitor_vdev_delete(ar); 111662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 111762306a36Sopenharmony_ci return ret; 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 112362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 112462306a36Sopenharmony_ci struct ieee80211_hw *hw = ar->hw; 112562306a36Sopenharmony_ci struct ieee80211_vif *vif = arvif->vif; 112662306a36Sopenharmony_ci struct ieee80211_mutable_offsets offs = {}; 112762306a36Sopenharmony_ci struct sk_buff *bcn; 112862306a36Sopenharmony_ci struct ieee80211_mgmt *mgmt; 112962306a36Sopenharmony_ci u8 *ies; 113062306a36Sopenharmony_ci int ret; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_AP) 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci bcn = ieee80211_beacon_get_template(hw, vif, &offs, 0); 113662306a36Sopenharmony_ci if (!bcn) { 113762306a36Sopenharmony_ci ath12k_warn(ab, "failed to get beacon template from mac80211\n"); 113862306a36Sopenharmony_ci return -EPERM; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); 114262306a36Sopenharmony_ci ies += sizeof(mgmt->u.beacon); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies))) 114562306a36Sopenharmony_ci arvif->rsnie_present = true; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, 114862306a36Sopenharmony_ci WLAN_OUI_TYPE_MICROSOFT_WPA, 114962306a36Sopenharmony_ci ies, (skb_tail_pointer(bcn) - ies))) 115062306a36Sopenharmony_ci arvif->wpaie_present = true; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci kfree_skb(bcn); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (ret) 115762306a36Sopenharmony_ci ath12k_warn(ab, "failed to submit beacon template command: %d\n", 115862306a36Sopenharmony_ci ret); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return ret; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic void ath12k_control_beaconing(struct ath12k_vif *arvif, 116462306a36Sopenharmony_ci struct ieee80211_bss_conf *info) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 116762306a36Sopenharmony_ci int ret; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (!info->enable_beacon) { 117262306a36Sopenharmony_ci ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id); 117362306a36Sopenharmony_ci if (ret) 117462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to down vdev_id %i: %d\n", 117562306a36Sopenharmony_ci arvif->vdev_id, ret); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci arvif->is_up = false; 117862306a36Sopenharmony_ci return; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Install the beacon template to the FW */ 118262306a36Sopenharmony_ci ret = ath12k_mac_setup_bcn_tmpl(arvif); 118362306a36Sopenharmony_ci if (ret) { 118462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update bcn tmpl during vdev up: %d\n", 118562306a36Sopenharmony_ci ret); 118662306a36Sopenharmony_ci return; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci arvif->aid = 0; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci ether_addr_copy(arvif->bssid, info->bssid); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci ret = ath12k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, 119462306a36Sopenharmony_ci arvif->bssid); 119562306a36Sopenharmony_ci if (ret) { 119662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to bring up vdev %d: %i\n", 119762306a36Sopenharmony_ci arvif->vdev_id, ret); 119862306a36Sopenharmony_ci return; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci arvif->is_up = true; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_basic(struct ath12k *ar, 120762306a36Sopenharmony_ci struct ieee80211_vif *vif, 120862306a36Sopenharmony_ci struct ieee80211_sta *sta, 120962306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 121262306a36Sopenharmony_ci u32 aid; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION) 121762306a36Sopenharmony_ci aid = vif->cfg.aid; 121862306a36Sopenharmony_ci else 121962306a36Sopenharmony_ci aid = sta->aid; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci ether_addr_copy(arg->peer_mac, sta->addr); 122262306a36Sopenharmony_ci arg->vdev_id = arvif->vdev_id; 122362306a36Sopenharmony_ci arg->peer_associd = aid; 122462306a36Sopenharmony_ci arg->auth_flag = true; 122562306a36Sopenharmony_ci /* TODO: STA WAR in ath10k for listen interval required? */ 122662306a36Sopenharmony_ci arg->peer_listen_intval = ar->hw->conf.listen_interval; 122762306a36Sopenharmony_ci arg->peer_nss = 1; 122862306a36Sopenharmony_ci arg->peer_caps = vif->bss_conf.assoc_capability; 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_crypto(struct ath12k *ar, 123262306a36Sopenharmony_ci struct ieee80211_vif *vif, 123362306a36Sopenharmony_ci struct ieee80211_sta *sta, 123462306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci struct ieee80211_bss_conf *info = &vif->bss_conf; 123762306a36Sopenharmony_ci struct cfg80211_chan_def def; 123862306a36Sopenharmony_ci struct cfg80211_bss *bss; 123962306a36Sopenharmony_ci struct ath12k_vif *arvif = (struct ath12k_vif *)vif->drv_priv; 124062306a36Sopenharmony_ci const u8 *rsnie = NULL; 124162306a36Sopenharmony_ci const u8 *wpaie = NULL; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) 124662306a36Sopenharmony_ci return; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0, 124962306a36Sopenharmony_ci IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (arvif->rsnie_present || arvif->wpaie_present) { 125262306a36Sopenharmony_ci arg->need_ptk_4_way = true; 125362306a36Sopenharmony_ci if (arvif->wpaie_present) 125462306a36Sopenharmony_ci arg->need_gtk_2_way = true; 125562306a36Sopenharmony_ci } else if (bss) { 125662306a36Sopenharmony_ci const struct cfg80211_bss_ies *ies; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci rcu_read_lock(); 125962306a36Sopenharmony_ci rsnie = ieee80211_bss_get_ie(bss, WLAN_EID_RSN); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci ies = rcu_dereference(bss->ies); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, 126462306a36Sopenharmony_ci WLAN_OUI_TYPE_MICROSOFT_WPA, 126562306a36Sopenharmony_ci ies->data, 126662306a36Sopenharmony_ci ies->len); 126762306a36Sopenharmony_ci rcu_read_unlock(); 126862306a36Sopenharmony_ci cfg80211_put_bss(ar->hw->wiphy, bss); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci /* FIXME: base on RSN IE/WPA IE is a correct idea? */ 127262306a36Sopenharmony_ci if (rsnie || wpaie) { 127362306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_WMI, 127462306a36Sopenharmony_ci "%s: rsn ie found\n", __func__); 127562306a36Sopenharmony_ci arg->need_ptk_4_way = true; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (wpaie) { 127962306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_WMI, 128062306a36Sopenharmony_ci "%s: wpa ie found\n", __func__); 128162306a36Sopenharmony_ci arg->need_gtk_2_way = true; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (sta->mfp) { 128562306a36Sopenharmony_ci /* TODO: Need to check if FW supports PMF? */ 128662306a36Sopenharmony_ci arg->is_pmf_enabled = true; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* TODO: safe_mode_enabled (bypass 4-way handshake) flag req? */ 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_rates(struct ath12k *ar, 129362306a36Sopenharmony_ci struct ieee80211_vif *vif, 129462306a36Sopenharmony_ci struct ieee80211_sta *sta, 129562306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 129662306a36Sopenharmony_ci{ 129762306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 129862306a36Sopenharmony_ci struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates; 129962306a36Sopenharmony_ci struct cfg80211_chan_def def; 130062306a36Sopenharmony_ci const struct ieee80211_supported_band *sband; 130162306a36Sopenharmony_ci const struct ieee80211_rate *rates; 130262306a36Sopenharmony_ci enum nl80211_band band; 130362306a36Sopenharmony_ci u32 ratemask; 130462306a36Sopenharmony_ci u8 rate; 130562306a36Sopenharmony_ci int i; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) 131062306a36Sopenharmony_ci return; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci band = def.chan->band; 131362306a36Sopenharmony_ci sband = ar->hw->wiphy->bands[band]; 131462306a36Sopenharmony_ci ratemask = sta->deflink.supp_rates[band]; 131562306a36Sopenharmony_ci ratemask &= arvif->bitrate_mask.control[band].legacy; 131662306a36Sopenharmony_ci rates = sband->bitrates; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci rateset->num_rates = 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci for (i = 0; i < 32; i++, ratemask >>= 1, rates++) { 132162306a36Sopenharmony_ci if (!(ratemask & 1)) 132262306a36Sopenharmony_ci continue; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci rate = ath12k_mac_bitrate_to_rate(rates->bitrate); 132562306a36Sopenharmony_ci rateset->rates[rateset->num_rates] = rate; 132662306a36Sopenharmony_ci rateset->num_rates++; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic bool 133162306a36Sopenharmony_ciath12k_peer_assoc_h_ht_masked(const u8 *ht_mcs_mask) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci int nss; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci for (nss = 0; nss < IEEE80211_HT_MCS_MASK_LEN; nss++) 133662306a36Sopenharmony_ci if (ht_mcs_mask[nss]) 133762306a36Sopenharmony_ci return false; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci return true; 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic bool 134362306a36Sopenharmony_ciath12k_peer_assoc_h_vht_masked(const u16 *vht_mcs_mask) 134462306a36Sopenharmony_ci{ 134562306a36Sopenharmony_ci int nss; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) 134862306a36Sopenharmony_ci if (vht_mcs_mask[nss]) 134962306a36Sopenharmony_ci return false; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return true; 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_ht(struct ath12k *ar, 135562306a36Sopenharmony_ci struct ieee80211_vif *vif, 135662306a36Sopenharmony_ci struct ieee80211_sta *sta, 135762306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; 136062306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 136162306a36Sopenharmony_ci struct cfg80211_chan_def def; 136262306a36Sopenharmony_ci enum nl80211_band band; 136362306a36Sopenharmony_ci const u8 *ht_mcs_mask; 136462306a36Sopenharmony_ci int i, n; 136562306a36Sopenharmony_ci u8 max_nss; 136662306a36Sopenharmony_ci u32 stbc; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) 137162306a36Sopenharmony_ci return; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (!ht_cap->ht_supported) 137462306a36Sopenharmony_ci return; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci band = def.chan->band; 137762306a36Sopenharmony_ci ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (ath12k_peer_assoc_h_ht_masked(ht_mcs_mask)) 138062306a36Sopenharmony_ci return; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci arg->ht_flag = true; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + 138562306a36Sopenharmony_ci ht_cap->ampdu_factor)) - 1; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci arg->peer_mpdu_density = 138862306a36Sopenharmony_ci ath12k_parse_mpdudensity(ht_cap->ampdu_density); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci arg->peer_ht_caps = ht_cap->cap; 139162306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_HT_FLAG; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) 139462306a36Sopenharmony_ci arg->ldpc_flag = true; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) { 139762306a36Sopenharmony_ci arg->bw_40 = true; 139862306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { 140262306a36Sopenharmony_ci if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | 140362306a36Sopenharmony_ci IEEE80211_HT_CAP_SGI_40)) 140462306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) { 140862306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_TX_STBC_FLAG; 140962306a36Sopenharmony_ci arg->stbc_flag = true; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) { 141362306a36Sopenharmony_ci stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC; 141462306a36Sopenharmony_ci stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT; 141562306a36Sopenharmony_ci stbc = stbc << WMI_HOST_RC_RX_STBC_FLAG_S; 141662306a36Sopenharmony_ci arg->peer_rate_caps |= stbc; 141762306a36Sopenharmony_ci arg->stbc_flag = true; 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2]) 142162306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_TS_FLAG; 142262306a36Sopenharmony_ci else if (ht_cap->mcs.rx_mask[1]) 142362306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_DS_FLAG; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci for (i = 0, n = 0, max_nss = 0; i < IEEE80211_HT_MCS_MASK_LEN * 8; i++) 142662306a36Sopenharmony_ci if ((ht_cap->mcs.rx_mask[i / 8] & BIT(i % 8)) && 142762306a36Sopenharmony_ci (ht_mcs_mask[i / 8] & BIT(i % 8))) { 142862306a36Sopenharmony_ci max_nss = (i / 8) + 1; 142962306a36Sopenharmony_ci arg->peer_ht_rates.rates[n++] = i; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* This is a workaround for HT-enabled STAs which break the spec 143362306a36Sopenharmony_ci * and have no HT capabilities RX mask (no HT RX MCS map). 143462306a36Sopenharmony_ci * 143562306a36Sopenharmony_ci * As per spec, in section 20.3.5 Modulation and coding scheme (MCS), 143662306a36Sopenharmony_ci * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs. 143762306a36Sopenharmony_ci * 143862306a36Sopenharmony_ci * Firmware asserts if such situation occurs. 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_ci if (n == 0) { 144162306a36Sopenharmony_ci arg->peer_ht_rates.num_rates = 8; 144262306a36Sopenharmony_ci for (i = 0; i < arg->peer_ht_rates.num_rates; i++) 144362306a36Sopenharmony_ci arg->peer_ht_rates.rates[i] = i; 144462306a36Sopenharmony_ci } else { 144562306a36Sopenharmony_ci arg->peer_ht_rates.num_rates = n; 144662306a36Sopenharmony_ci arg->peer_nss = min(sta->deflink.rx_nss, max_nss); 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n", 145062306a36Sopenharmony_ci arg->peer_mac, 145162306a36Sopenharmony_ci arg->peer_ht_rates.num_rates, 145262306a36Sopenharmony_ci arg->peer_nss); 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic int ath12k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci switch ((mcs_map >> (2 * nss)) & 0x3) { 145862306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1; 145962306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1; 146062306a36Sopenharmony_ci case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci return 0; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic u16 146662306a36Sopenharmony_ciath12k_peer_assoc_h_vht_limit(u16 tx_mcs_set, 146762306a36Sopenharmony_ci const u16 vht_mcs_limit[NL80211_VHT_NSS_MAX]) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci int idx_limit; 147062306a36Sopenharmony_ci int nss; 147162306a36Sopenharmony_ci u16 mcs_map; 147262306a36Sopenharmony_ci u16 mcs; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) { 147562306a36Sopenharmony_ci mcs_map = ath12k_mac_get_max_vht_mcs_map(tx_mcs_set, nss) & 147662306a36Sopenharmony_ci vht_mcs_limit[nss]; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci if (mcs_map) 147962306a36Sopenharmony_ci idx_limit = fls(mcs_map) - 1; 148062306a36Sopenharmony_ci else 148162306a36Sopenharmony_ci idx_limit = -1; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci switch (idx_limit) { 148462306a36Sopenharmony_ci case 0: 148562306a36Sopenharmony_ci case 1: 148662306a36Sopenharmony_ci case 2: 148762306a36Sopenharmony_ci case 3: 148862306a36Sopenharmony_ci case 4: 148962306a36Sopenharmony_ci case 5: 149062306a36Sopenharmony_ci case 6: 149162306a36Sopenharmony_ci case 7: 149262306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_SUPPORT_0_7; 149362306a36Sopenharmony_ci break; 149462306a36Sopenharmony_ci case 8: 149562306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_SUPPORT_0_8; 149662306a36Sopenharmony_ci break; 149762306a36Sopenharmony_ci case 9: 149862306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_SUPPORT_0_9; 149962306a36Sopenharmony_ci break; 150062306a36Sopenharmony_ci default: 150162306a36Sopenharmony_ci WARN_ON(1); 150262306a36Sopenharmony_ci fallthrough; 150362306a36Sopenharmony_ci case -1: 150462306a36Sopenharmony_ci mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED; 150562306a36Sopenharmony_ci break; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci tx_mcs_set &= ~(0x3 << (nss * 2)); 150962306a36Sopenharmony_ci tx_mcs_set |= mcs << (nss * 2); 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci return tx_mcs_set; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_vht(struct ath12k *ar, 151662306a36Sopenharmony_ci struct ieee80211_vif *vif, 151762306a36Sopenharmony_ci struct ieee80211_sta *sta, 151862306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap; 152162306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 152262306a36Sopenharmony_ci struct cfg80211_chan_def def; 152362306a36Sopenharmony_ci enum nl80211_band band; 152462306a36Sopenharmony_ci const u16 *vht_mcs_mask; 152562306a36Sopenharmony_ci u16 tx_mcs_map; 152662306a36Sopenharmony_ci u8 ampdu_factor; 152762306a36Sopenharmony_ci u8 max_nss, vht_mcs; 152862306a36Sopenharmony_ci int i; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) 153162306a36Sopenharmony_ci return; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (!vht_cap->vht_supported) 153462306a36Sopenharmony_ci return; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci band = def.chan->band; 153762306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci if (ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) 154062306a36Sopenharmony_ci return; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci arg->vht_flag = true; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci /* TODO: similar flags required? */ 154562306a36Sopenharmony_ci arg->vht_capable = true; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci if (def.chan->band == NL80211_BAND_2GHZ) 154862306a36Sopenharmony_ci arg->vht_ng_flag = true; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci arg->peer_vht_caps = vht_cap->cap; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci ampdu_factor = (vht_cap->cap & 155362306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >> 155462306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci /* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to 155762306a36Sopenharmony_ci * zero in VHT IE. Using it would result in degraded throughput. 155862306a36Sopenharmony_ci * arg->peer_max_mpdu at this point contains HT max_mpdu so keep 155962306a36Sopenharmony_ci * it if VHT max_mpdu is smaller. 156062306a36Sopenharmony_ci */ 156162306a36Sopenharmony_ci arg->peer_max_mpdu = max(arg->peer_max_mpdu, 156262306a36Sopenharmony_ci (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR + 156362306a36Sopenharmony_ci ampdu_factor)) - 1); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 156662306a36Sopenharmony_ci arg->bw_80 = true; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) 156962306a36Sopenharmony_ci arg->bw_160 = true; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci /* Calculate peer NSS capability from VHT capabilities if STA 157262306a36Sopenharmony_ci * supports VHT. 157362306a36Sopenharmony_ci */ 157462306a36Sopenharmony_ci for (i = 0, max_nss = 0, vht_mcs = 0; i < NL80211_VHT_NSS_MAX; i++) { 157562306a36Sopenharmony_ci vht_mcs = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) >> 157662306a36Sopenharmony_ci (2 * i) & 3; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci if (vht_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED && 157962306a36Sopenharmony_ci vht_mcs_mask[i]) 158062306a36Sopenharmony_ci max_nss = i + 1; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci arg->peer_nss = min(sta->deflink.rx_nss, max_nss); 158362306a36Sopenharmony_ci arg->rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest); 158462306a36Sopenharmony_ci arg->rx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); 158562306a36Sopenharmony_ci arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci tx_mcs_map = __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); 158862306a36Sopenharmony_ci arg->tx_mcs_set = ath12k_peer_assoc_h_vht_limit(tx_mcs_map, vht_mcs_mask); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci /* In QCN9274 platform, VHT MCS rate 10 and 11 is enabled by default. 159162306a36Sopenharmony_ci * VHT MCS rate 10 and 11 is not supported in 11ac standard. 159262306a36Sopenharmony_ci * so explicitly disable the VHT MCS rate 10 and 11 in 11ac mode. 159362306a36Sopenharmony_ci */ 159462306a36Sopenharmony_ci arg->tx_mcs_set &= ~IEEE80211_VHT_MCS_SUPPORT_0_11_MASK; 159562306a36Sopenharmony_ci arg->tx_mcs_set |= IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if ((arg->tx_mcs_set & IEEE80211_VHT_MCS_NOT_SUPPORTED) == 159862306a36Sopenharmony_ci IEEE80211_VHT_MCS_NOT_SUPPORTED) 159962306a36Sopenharmony_ci arg->peer_vht_caps &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* TODO: Check */ 160262306a36Sopenharmony_ci arg->tx_max_mcs_nss = 0xFF; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", 160562306a36Sopenharmony_ci sta->addr, arg->peer_max_mpdu, arg->peer_flags); 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci /* TODO: rxnss_override */ 160862306a36Sopenharmony_ci} 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_he(struct ath12k *ar, 161162306a36Sopenharmony_ci struct ieee80211_vif *vif, 161262306a36Sopenharmony_ci struct ieee80211_sta *sta, 161362306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; 161662306a36Sopenharmony_ci int i; 161762306a36Sopenharmony_ci u8 ampdu_factor, rx_mcs_80, rx_mcs_160, max_nss; 161862306a36Sopenharmony_ci u16 mcs_160_map, mcs_80_map; 161962306a36Sopenharmony_ci bool support_160; 162062306a36Sopenharmony_ci u16 v; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (!he_cap->has_he) 162362306a36Sopenharmony_ci return; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci arg->he_flag = true; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] & 162862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G); 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci /* Supported HE-MCS and NSS Set of peer he_cap is intersection with self he_cp */ 163162306a36Sopenharmony_ci mcs_160_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); 163262306a36Sopenharmony_ci mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci if (support_160) { 163562306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 163662306a36Sopenharmony_ci u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (mcs_160 != IEEE80211_HE_MCS_NOT_SUPPORTED) { 163962306a36Sopenharmony_ci rx_mcs_160 = i + 1; 164062306a36Sopenharmony_ci break; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 164662306a36Sopenharmony_ci u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci if (mcs_80 != IEEE80211_HE_MCS_NOT_SUPPORTED) { 164962306a36Sopenharmony_ci rx_mcs_80 = i + 1; 165062306a36Sopenharmony_ci break; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci if (support_160) 165562306a36Sopenharmony_ci max_nss = min(rx_mcs_80, rx_mcs_160); 165662306a36Sopenharmony_ci else 165762306a36Sopenharmony_ci max_nss = rx_mcs_80; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci arg->peer_nss = min(sta->deflink.rx_nss, max_nss); 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info, 166262306a36Sopenharmony_ci sizeof(he_cap->he_cap_elem.mac_cap_info)); 166362306a36Sopenharmony_ci memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info, 166462306a36Sopenharmony_ci sizeof(he_cap->he_cap_elem.phy_cap_info)); 166562306a36Sopenharmony_ci arg->peer_he_ops = vif->bss_conf.he_oper.params; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci /* the top most byte is used to indicate BSS color info */ 166862306a36Sopenharmony_ci arg->peer_he_ops &= 0xffffff; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* As per section 26.6.1 IEEE Std 802.11ax‐2022, if the Max AMPDU 167162306a36Sopenharmony_ci * Exponent Extension in HE cap is zero, use the arg->peer_max_mpdu 167262306a36Sopenharmony_ci * as calculated while parsing VHT caps(if VHT caps is present) 167362306a36Sopenharmony_ci * or HT caps (if VHT caps is not present). 167462306a36Sopenharmony_ci * 167562306a36Sopenharmony_ci * For non-zero value of Max AMPDU Exponent Extension in HE MAC caps, 167662306a36Sopenharmony_ci * if a HE STA sends VHT cap and HE cap IE in assoc request then, use 167762306a36Sopenharmony_ci * MAX_AMPDU_LEN_FACTOR as 20 to calculate max_ampdu length. 167862306a36Sopenharmony_ci * If a HE STA that does not send VHT cap, but HE and HT cap in assoc 167962306a36Sopenharmony_ci * request, then use MAX_AMPDU_LEN_FACTOR as 16 to calculate max_ampdu 168062306a36Sopenharmony_ci * length. 168162306a36Sopenharmony_ci */ 168262306a36Sopenharmony_ci ampdu_factor = (he_cap->he_cap_elem.mac_cap_info[3] & 168362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >> 168462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (ampdu_factor) { 168762306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported) 168862306a36Sopenharmony_ci arg->peer_max_mpdu = (1 << (IEEE80211_HE_VHT_MAX_AMPDU_FACTOR + 168962306a36Sopenharmony_ci ampdu_factor)) - 1; 169062306a36Sopenharmony_ci else if (sta->deflink.ht_cap.ht_supported) 169162306a36Sopenharmony_ci arg->peer_max_mpdu = (1 << (IEEE80211_HE_HT_MAX_AMPDU_FACTOR + 169262306a36Sopenharmony_ci ampdu_factor)) - 1; 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci if (he_cap->he_cap_elem.phy_cap_info[6] & 169662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) { 169762306a36Sopenharmony_ci int bit = 7; 169862306a36Sopenharmony_ci int nss, ru; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci arg->peer_ppet.numss_m1 = he_cap->ppe_thres[0] & 170162306a36Sopenharmony_ci IEEE80211_PPE_THRES_NSS_MASK; 170262306a36Sopenharmony_ci arg->peer_ppet.ru_bit_mask = 170362306a36Sopenharmony_ci (he_cap->ppe_thres[0] & 170462306a36Sopenharmony_ci IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK) >> 170562306a36Sopenharmony_ci IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci for (nss = 0; nss <= arg->peer_ppet.numss_m1; nss++) { 170862306a36Sopenharmony_ci for (ru = 0; ru < 4; ru++) { 170962306a36Sopenharmony_ci u32 val = 0; 171062306a36Sopenharmony_ci int i; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci if ((arg->peer_ppet.ru_bit_mask & BIT(ru)) == 0) 171362306a36Sopenharmony_ci continue; 171462306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 171562306a36Sopenharmony_ci val >>= 1; 171662306a36Sopenharmony_ci val |= ((he_cap->ppe_thres[bit / 8] >> 171762306a36Sopenharmony_ci (bit % 8)) & 0x1) << 5; 171862306a36Sopenharmony_ci bit++; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci arg->peer_ppet.ppet16_ppet8_ru3_ru0[nss] |= 172162306a36Sopenharmony_ci val << (ru * 6); 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_RES) 172762306a36Sopenharmony_ci arg->twt_responder = true; 172862306a36Sopenharmony_ci if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ) 172962306a36Sopenharmony_ci arg->twt_requester = true; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci switch (sta->deflink.bandwidth) { 173262306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 173362306a36Sopenharmony_ci if (he_cap->he_cap_elem.phy_cap_info[0] & 173462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { 173562306a36Sopenharmony_ci v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80); 173662306a36Sopenharmony_ci arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); 173962306a36Sopenharmony_ci arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci arg->peer_he_mcs_count++; 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); 174462306a36Sopenharmony_ci arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); 174762306a36Sopenharmony_ci arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci arg->peer_he_mcs_count++; 175062306a36Sopenharmony_ci fallthrough; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci default: 175362306a36Sopenharmony_ci v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); 175462306a36Sopenharmony_ci arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); 175762306a36Sopenharmony_ci arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci arg->peer_he_mcs_count++; 176062306a36Sopenharmony_ci break; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_smps(struct ieee80211_sta *sta, 176562306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap; 176862306a36Sopenharmony_ci int smps; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (!ht_cap->ht_supported) 177162306a36Sopenharmony_ci return; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; 177462306a36Sopenharmony_ci smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci switch (smps) { 177762306a36Sopenharmony_ci case WLAN_HT_CAP_SM_PS_STATIC: 177862306a36Sopenharmony_ci arg->static_mimops_flag = true; 177962306a36Sopenharmony_ci break; 178062306a36Sopenharmony_ci case WLAN_HT_CAP_SM_PS_DYNAMIC: 178162306a36Sopenharmony_ci arg->dynamic_mimops_flag = true; 178262306a36Sopenharmony_ci break; 178362306a36Sopenharmony_ci case WLAN_HT_CAP_SM_PS_DISABLED: 178462306a36Sopenharmony_ci arg->spatial_mux_flag = true; 178562306a36Sopenharmony_ci break; 178662306a36Sopenharmony_ci default: 178762306a36Sopenharmony_ci break; 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci} 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_qos(struct ath12k *ar, 179262306a36Sopenharmony_ci struct ieee80211_vif *vif, 179362306a36Sopenharmony_ci struct ieee80211_sta *sta, 179462306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 179562306a36Sopenharmony_ci{ 179662306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci switch (arvif->vdev_type) { 179962306a36Sopenharmony_ci case WMI_VDEV_TYPE_AP: 180062306a36Sopenharmony_ci if (sta->wme) { 180162306a36Sopenharmony_ci /* TODO: Check WME vs QoS */ 180262306a36Sopenharmony_ci arg->is_wme_set = true; 180362306a36Sopenharmony_ci arg->qos_flag = true; 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (sta->wme && sta->uapsd_queues) { 180762306a36Sopenharmony_ci /* TODO: Check WME vs QoS */ 180862306a36Sopenharmony_ci arg->is_wme_set = true; 180962306a36Sopenharmony_ci arg->apsd_flag = true; 181062306a36Sopenharmony_ci arg->peer_rate_caps |= WMI_HOST_RC_UAPSD_FLAG; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci break; 181362306a36Sopenharmony_ci case WMI_VDEV_TYPE_STA: 181462306a36Sopenharmony_ci if (sta->wme) { 181562306a36Sopenharmony_ci arg->is_wme_set = true; 181662306a36Sopenharmony_ci arg->qos_flag = true; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci break; 181962306a36Sopenharmony_ci default: 182062306a36Sopenharmony_ci break; 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac peer %pM qos %d\n", 182462306a36Sopenharmony_ci sta->addr, arg->qos_flag); 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic int ath12k_peer_assoc_qos_ap(struct ath12k *ar, 182862306a36Sopenharmony_ci struct ath12k_vif *arvif, 182962306a36Sopenharmony_ci struct ieee80211_sta *sta) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct ath12k_wmi_ap_ps_arg arg; 183262306a36Sopenharmony_ci u32 max_sp; 183362306a36Sopenharmony_ci u32 uapsd; 183462306a36Sopenharmony_ci int ret; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n", 184162306a36Sopenharmony_ci sta->uapsd_queues, sta->max_sp); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci uapsd = 0; 184462306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) 184562306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | 184662306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; 184762306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) 184862306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN | 184962306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC2_TRIGGER_EN; 185062306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) 185162306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN | 185262306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC1_TRIGGER_EN; 185362306a36Sopenharmony_ci if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) 185462306a36Sopenharmony_ci uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN | 185562306a36Sopenharmony_ci WMI_AP_PS_UAPSD_AC0_TRIGGER_EN; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci max_sp = 0; 185862306a36Sopenharmony_ci if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP) 185962306a36Sopenharmony_ci max_sp = sta->max_sp; 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci arg.param = WMI_AP_PS_PEER_PARAM_UAPSD; 186262306a36Sopenharmony_ci arg.value = uapsd; 186362306a36Sopenharmony_ci ret = ath12k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &arg); 186462306a36Sopenharmony_ci if (ret) 186562306a36Sopenharmony_ci goto err; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci arg.param = WMI_AP_PS_PEER_PARAM_MAX_SP; 186862306a36Sopenharmony_ci arg.value = max_sp; 186962306a36Sopenharmony_ci ret = ath12k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &arg); 187062306a36Sopenharmony_ci if (ret) 187162306a36Sopenharmony_ci goto err; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci /* TODO: revisit during testing */ 187462306a36Sopenharmony_ci arg.param = WMI_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE; 187562306a36Sopenharmony_ci arg.value = DISABLE_SIFS_RESPONSE_TRIGGER; 187662306a36Sopenharmony_ci ret = ath12k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &arg); 187762306a36Sopenharmony_ci if (ret) 187862306a36Sopenharmony_ci goto err; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci arg.param = WMI_AP_PS_PEER_PARAM_SIFS_RESP_UAPSD; 188162306a36Sopenharmony_ci arg.value = DISABLE_SIFS_RESPONSE_TRIGGER; 188262306a36Sopenharmony_ci ret = ath12k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &arg); 188362306a36Sopenharmony_ci if (ret) 188462306a36Sopenharmony_ci goto err; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci return 0; 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_cierr: 188962306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set ap ps peer param %d for vdev %i: %d\n", 189062306a36Sopenharmony_ci arg.param, arvif->vdev_id, ret); 189162306a36Sopenharmony_ci return ret; 189262306a36Sopenharmony_ci} 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_cistatic bool ath12k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta) 189562306a36Sopenharmony_ci{ 189662306a36Sopenharmony_ci return sta->deflink.supp_rates[NL80211_BAND_2GHZ] >> 189762306a36Sopenharmony_ci ATH12K_MAC_FIRST_OFDM_RATE_IDX; 189862306a36Sopenharmony_ci} 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_cistatic enum wmi_phy_mode ath12k_mac_get_phymode_vht(struct ath12k *ar, 190162306a36Sopenharmony_ci struct ieee80211_sta *sta) 190262306a36Sopenharmony_ci{ 190362306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) { 190462306a36Sopenharmony_ci switch (sta->deflink.vht_cap.cap & 190562306a36Sopenharmony_ci IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { 190662306a36Sopenharmony_ci case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: 190762306a36Sopenharmony_ci return MODE_11AC_VHT160; 190862306a36Sopenharmony_ci case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: 190962306a36Sopenharmony_ci return MODE_11AC_VHT80_80; 191062306a36Sopenharmony_ci default: 191162306a36Sopenharmony_ci /* not sure if this is a valid case? */ 191262306a36Sopenharmony_ci return MODE_11AC_VHT160; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 191762306a36Sopenharmony_ci return MODE_11AC_VHT80; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 192062306a36Sopenharmony_ci return MODE_11AC_VHT40; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) 192362306a36Sopenharmony_ci return MODE_11AC_VHT20; 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci return MODE_UNKNOWN; 192662306a36Sopenharmony_ci} 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_cistatic enum wmi_phy_mode ath12k_mac_get_phymode_he(struct ath12k *ar, 192962306a36Sopenharmony_ci struct ieee80211_sta *sta) 193062306a36Sopenharmony_ci{ 193162306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) { 193262306a36Sopenharmony_ci if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & 193362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) 193462306a36Sopenharmony_ci return MODE_11AX_HE160; 193562306a36Sopenharmony_ci else if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & 193662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) 193762306a36Sopenharmony_ci return MODE_11AX_HE80_80; 193862306a36Sopenharmony_ci /* not sure if this is a valid case? */ 193962306a36Sopenharmony_ci return MODE_11AX_HE160; 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 194362306a36Sopenharmony_ci return MODE_11AX_HE80; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 194662306a36Sopenharmony_ci return MODE_11AX_HE40; 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) 194962306a36Sopenharmony_ci return MODE_11AX_HE20; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci return MODE_UNKNOWN; 195262306a36Sopenharmony_ci} 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cistatic enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar, 195562306a36Sopenharmony_ci struct ieee80211_sta *sta) 195662306a36Sopenharmony_ci{ 195762306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) 195862306a36Sopenharmony_ci if (sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[0] & 195962306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) 196062306a36Sopenharmony_ci return MODE_11BE_EHT320; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160) { 196362306a36Sopenharmony_ci if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & 196462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) 196562306a36Sopenharmony_ci return MODE_11BE_EHT160; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] & 196862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) 196962306a36Sopenharmony_ci return MODE_11BE_EHT80_80; 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci ath12k_warn(ar->ab, "invalid EHT PHY capability info for 160 Mhz: %d\n", 197262306a36Sopenharmony_ci sta->deflink.he_cap.he_cap_elem.phy_cap_info[0]); 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci return MODE_11BE_EHT160; 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 197862306a36Sopenharmony_ci return MODE_11BE_EHT80; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 198162306a36Sopenharmony_ci return MODE_11BE_EHT40; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20) 198462306a36Sopenharmony_ci return MODE_11BE_EHT20; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci return MODE_UNKNOWN; 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_phymode(struct ath12k *ar, 199062306a36Sopenharmony_ci struct ieee80211_vif *vif, 199162306a36Sopenharmony_ci struct ieee80211_sta *sta, 199262306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 199362306a36Sopenharmony_ci{ 199462306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 199562306a36Sopenharmony_ci struct cfg80211_chan_def def; 199662306a36Sopenharmony_ci enum nl80211_band band; 199762306a36Sopenharmony_ci const u8 *ht_mcs_mask; 199862306a36Sopenharmony_ci const u16 *vht_mcs_mask; 199962306a36Sopenharmony_ci enum wmi_phy_mode phymode = MODE_UNKNOWN; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) 200262306a36Sopenharmony_ci return; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci band = def.chan->band; 200562306a36Sopenharmony_ci ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; 200662306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci switch (band) { 200962306a36Sopenharmony_ci case NL80211_BAND_2GHZ: 201062306a36Sopenharmony_ci if (sta->deflink.eht_cap.has_eht) { 201162306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 201262306a36Sopenharmony_ci phymode = MODE_11BE_EHT40_2G; 201362306a36Sopenharmony_ci else 201462306a36Sopenharmony_ci phymode = MODE_11BE_EHT20_2G; 201562306a36Sopenharmony_ci } else if (sta->deflink.he_cap.has_he) { 201662306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_80) 201762306a36Sopenharmony_ci phymode = MODE_11AX_HE80_2G; 201862306a36Sopenharmony_ci else if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 201962306a36Sopenharmony_ci phymode = MODE_11AX_HE40_2G; 202062306a36Sopenharmony_ci else 202162306a36Sopenharmony_ci phymode = MODE_11AX_HE20_2G; 202262306a36Sopenharmony_ci } else if (sta->deflink.vht_cap.vht_supported && 202362306a36Sopenharmony_ci !ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) { 202462306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 202562306a36Sopenharmony_ci phymode = MODE_11AC_VHT40; 202662306a36Sopenharmony_ci else 202762306a36Sopenharmony_ci phymode = MODE_11AC_VHT20; 202862306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported && 202962306a36Sopenharmony_ci !ath12k_peer_assoc_h_ht_masked(ht_mcs_mask)) { 203062306a36Sopenharmony_ci if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_40) 203162306a36Sopenharmony_ci phymode = MODE_11NG_HT40; 203262306a36Sopenharmony_ci else 203362306a36Sopenharmony_ci phymode = MODE_11NG_HT20; 203462306a36Sopenharmony_ci } else if (ath12k_mac_sta_has_ofdm_only(sta)) { 203562306a36Sopenharmony_ci phymode = MODE_11G; 203662306a36Sopenharmony_ci } else { 203762306a36Sopenharmony_ci phymode = MODE_11B; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci break; 204062306a36Sopenharmony_ci case NL80211_BAND_5GHZ: 204162306a36Sopenharmony_ci case NL80211_BAND_6GHZ: 204262306a36Sopenharmony_ci /* Check EHT first */ 204362306a36Sopenharmony_ci if (sta->deflink.eht_cap.has_eht) { 204462306a36Sopenharmony_ci phymode = ath12k_mac_get_phymode_eht(ar, sta); 204562306a36Sopenharmony_ci } else if (sta->deflink.he_cap.has_he) { 204662306a36Sopenharmony_ci phymode = ath12k_mac_get_phymode_he(ar, sta); 204762306a36Sopenharmony_ci } else if (sta->deflink.vht_cap.vht_supported && 204862306a36Sopenharmony_ci !ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) { 204962306a36Sopenharmony_ci phymode = ath12k_mac_get_phymode_vht(ar, sta); 205062306a36Sopenharmony_ci } else if (sta->deflink.ht_cap.ht_supported && 205162306a36Sopenharmony_ci !ath12k_peer_assoc_h_ht_masked(ht_mcs_mask)) { 205262306a36Sopenharmony_ci if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) 205362306a36Sopenharmony_ci phymode = MODE_11NA_HT40; 205462306a36Sopenharmony_ci else 205562306a36Sopenharmony_ci phymode = MODE_11NA_HT20; 205662306a36Sopenharmony_ci } else { 205762306a36Sopenharmony_ci phymode = MODE_11A; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci break; 206062306a36Sopenharmony_ci default: 206162306a36Sopenharmony_ci break; 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac peer %pM phymode %s\n", 206562306a36Sopenharmony_ci sta->addr, ath12k_mac_phymode_str(phymode)); 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci arg->peer_phymode = phymode; 206862306a36Sopenharmony_ci WARN_ON(phymode == MODE_UNKNOWN); 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_cistatic void ath12k_mac_set_eht_mcs(u8 rx_tx_mcs7, u8 rx_tx_mcs9, 207262306a36Sopenharmony_ci u8 rx_tx_mcs11, u8 rx_tx_mcs13, 207362306a36Sopenharmony_ci u32 *rx_mcs, u32 *tx_mcs) 207462306a36Sopenharmony_ci{ 207562306a36Sopenharmony_ci *rx_mcs = 0; 207662306a36Sopenharmony_ci u32p_replace_bits(rx_mcs, 207762306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_RX), 207862306a36Sopenharmony_ci WMI_EHT_MCS_NSS_0_7); 207962306a36Sopenharmony_ci u32p_replace_bits(rx_mcs, 208062306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_RX), 208162306a36Sopenharmony_ci WMI_EHT_MCS_NSS_8_9); 208262306a36Sopenharmony_ci u32p_replace_bits(rx_mcs, 208362306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_RX), 208462306a36Sopenharmony_ci WMI_EHT_MCS_NSS_10_11); 208562306a36Sopenharmony_ci u32p_replace_bits(rx_mcs, 208662306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_RX), 208762306a36Sopenharmony_ci WMI_EHT_MCS_NSS_12_13); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci *tx_mcs = 0; 209062306a36Sopenharmony_ci u32p_replace_bits(tx_mcs, 209162306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs7, IEEE80211_EHT_MCS_NSS_TX), 209262306a36Sopenharmony_ci WMI_EHT_MCS_NSS_0_7); 209362306a36Sopenharmony_ci u32p_replace_bits(tx_mcs, 209462306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs9, IEEE80211_EHT_MCS_NSS_TX), 209562306a36Sopenharmony_ci WMI_EHT_MCS_NSS_8_9); 209662306a36Sopenharmony_ci u32p_replace_bits(tx_mcs, 209762306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs11, IEEE80211_EHT_MCS_NSS_TX), 209862306a36Sopenharmony_ci WMI_EHT_MCS_NSS_10_11); 209962306a36Sopenharmony_ci u32p_replace_bits(tx_mcs, 210062306a36Sopenharmony_ci u8_get_bits(rx_tx_mcs13, IEEE80211_EHT_MCS_NSS_TX), 210162306a36Sopenharmony_ci WMI_EHT_MCS_NSS_12_13); 210262306a36Sopenharmony_ci} 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_cistatic void ath12k_mac_set_eht_ppe_threshold(const u8 *ppe_thres, 210562306a36Sopenharmony_ci struct ath12k_wmi_ppe_threshold_arg *ppet) 210662306a36Sopenharmony_ci{ 210762306a36Sopenharmony_ci u32 bit_pos = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE, val; 210862306a36Sopenharmony_ci u8 nss, ru, i; 210962306a36Sopenharmony_ci u8 ppet_bit_len_per_ru = IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci ppet->numss_m1 = u8_get_bits(ppe_thres[0], IEEE80211_EHT_PPE_THRES_NSS_MASK); 211262306a36Sopenharmony_ci ppet->ru_bit_mask = u16_get_bits(get_unaligned_le16(ppe_thres), 211362306a36Sopenharmony_ci IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci for (nss = 0; nss <= ppet->numss_m1; nss++) { 211662306a36Sopenharmony_ci for (ru = 0; 211762306a36Sopenharmony_ci ru < hweight16(IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); 211862306a36Sopenharmony_ci ru++) { 211962306a36Sopenharmony_ci if ((ppet->ru_bit_mask & BIT(ru)) == 0) 212062306a36Sopenharmony_ci continue; 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci val = 0; 212362306a36Sopenharmony_ci for (i = 0; i < ppet_bit_len_per_ru; i++) { 212462306a36Sopenharmony_ci val |= (((ppe_thres[bit_pos / 8] >> 212562306a36Sopenharmony_ci (bit_pos % 8)) & 0x1) << i); 212662306a36Sopenharmony_ci bit_pos++; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci ppet->ppet16_ppet8_ru3_ru0[nss] |= 212962306a36Sopenharmony_ci (val << (ru * ppet_bit_len_per_ru)); 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci} 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_cistatic void ath12k_peer_assoc_h_eht(struct ath12k *ar, 213562306a36Sopenharmony_ci struct ieee80211_vif *vif, 213662306a36Sopenharmony_ci struct ieee80211_sta *sta, 213762306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg) 213862306a36Sopenharmony_ci{ 213962306a36Sopenharmony_ci const struct ieee80211_sta_eht_cap *eht_cap = &sta->deflink.eht_cap; 214062306a36Sopenharmony_ci const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap; 214162306a36Sopenharmony_ci const struct ieee80211_eht_mcs_nss_supp_20mhz_only *bw_20; 214262306a36Sopenharmony_ci const struct ieee80211_eht_mcs_nss_supp_bw *bw; 214362306a36Sopenharmony_ci struct ath12k_vif *arvif = (struct ath12k_vif *)vif->drv_priv; 214462306a36Sopenharmony_ci u32 *rx_mcs, *tx_mcs; 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci if (!sta->deflink.he_cap.has_he || !eht_cap->has_eht) 214762306a36Sopenharmony_ci return; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci arg->eht_flag = true; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci if ((eht_cap->eht_cap_elem.phy_cap_info[5] & 215262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) && 215362306a36Sopenharmony_ci eht_cap->eht_ppe_thres[0] != 0) 215462306a36Sopenharmony_ci ath12k_mac_set_eht_ppe_threshold(eht_cap->eht_ppe_thres, 215562306a36Sopenharmony_ci &arg->peer_eht_ppet); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci memcpy(arg->peer_eht_cap_mac, eht_cap->eht_cap_elem.mac_cap_info, 215862306a36Sopenharmony_ci sizeof(eht_cap->eht_cap_elem.mac_cap_info)); 215962306a36Sopenharmony_ci memcpy(arg->peer_eht_cap_phy, eht_cap->eht_cap_elem.phy_cap_info, 216062306a36Sopenharmony_ci sizeof(eht_cap->eht_cap_elem.phy_cap_info)); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci rx_mcs = arg->peer_eht_rx_mcs_set; 216362306a36Sopenharmony_ci tx_mcs = arg->peer_eht_tx_mcs_set; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci switch (sta->deflink.bandwidth) { 216662306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_320: 216762306a36Sopenharmony_ci bw = &eht_cap->eht_mcs_nss_supp.bw._320; 216862306a36Sopenharmony_ci ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss, 216962306a36Sopenharmony_ci bw->rx_tx_mcs9_max_nss, 217062306a36Sopenharmony_ci bw->rx_tx_mcs11_max_nss, 217162306a36Sopenharmony_ci bw->rx_tx_mcs13_max_nss, 217262306a36Sopenharmony_ci &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320], 217362306a36Sopenharmony_ci &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_320]); 217462306a36Sopenharmony_ci arg->peer_eht_mcs_count++; 217562306a36Sopenharmony_ci fallthrough; 217662306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 217762306a36Sopenharmony_ci bw = &eht_cap->eht_mcs_nss_supp.bw._160; 217862306a36Sopenharmony_ci ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss, 217962306a36Sopenharmony_ci bw->rx_tx_mcs9_max_nss, 218062306a36Sopenharmony_ci bw->rx_tx_mcs11_max_nss, 218162306a36Sopenharmony_ci bw->rx_tx_mcs13_max_nss, 218262306a36Sopenharmony_ci &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160], 218362306a36Sopenharmony_ci &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_160]); 218462306a36Sopenharmony_ci arg->peer_eht_mcs_count++; 218562306a36Sopenharmony_ci fallthrough; 218662306a36Sopenharmony_ci default: 218762306a36Sopenharmony_ci if ((he_cap->he_cap_elem.phy_cap_info[0] & 218862306a36Sopenharmony_ci (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | 218962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 219062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 219162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) { 219262306a36Sopenharmony_ci bw_20 = &eht_cap->eht_mcs_nss_supp.only_20mhz; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci ath12k_mac_set_eht_mcs(bw_20->rx_tx_mcs7_max_nss, 219562306a36Sopenharmony_ci bw_20->rx_tx_mcs9_max_nss, 219662306a36Sopenharmony_ci bw_20->rx_tx_mcs11_max_nss, 219762306a36Sopenharmony_ci bw_20->rx_tx_mcs13_max_nss, 219862306a36Sopenharmony_ci &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80], 219962306a36Sopenharmony_ci &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]); 220062306a36Sopenharmony_ci } else { 220162306a36Sopenharmony_ci bw = &eht_cap->eht_mcs_nss_supp.bw._80; 220262306a36Sopenharmony_ci ath12k_mac_set_eht_mcs(bw->rx_tx_mcs9_max_nss, 220362306a36Sopenharmony_ci bw->rx_tx_mcs9_max_nss, 220462306a36Sopenharmony_ci bw->rx_tx_mcs11_max_nss, 220562306a36Sopenharmony_ci bw->rx_tx_mcs13_max_nss, 220662306a36Sopenharmony_ci &rx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80], 220762306a36Sopenharmony_ci &tx_mcs[WMI_EHTCAP_TXRX_MCS_NSS_IDX_80]); 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci arg->peer_eht_mcs_count++; 221162306a36Sopenharmony_ci break; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci arg->punct_bitmap = ~arvif->punct_bitmap; 221562306a36Sopenharmony_ci} 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_cistatic void ath12k_peer_assoc_prepare(struct ath12k *ar, 221862306a36Sopenharmony_ci struct ieee80211_vif *vif, 221962306a36Sopenharmony_ci struct ieee80211_sta *sta, 222062306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg *arg, 222162306a36Sopenharmony_ci bool reassoc) 222262306a36Sopenharmony_ci{ 222362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci reinit_completion(&ar->peer_assoc_done); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci arg->peer_new_assoc = !reassoc; 223062306a36Sopenharmony_ci ath12k_peer_assoc_h_basic(ar, vif, sta, arg); 223162306a36Sopenharmony_ci ath12k_peer_assoc_h_crypto(ar, vif, sta, arg); 223262306a36Sopenharmony_ci ath12k_peer_assoc_h_rates(ar, vif, sta, arg); 223362306a36Sopenharmony_ci ath12k_peer_assoc_h_ht(ar, vif, sta, arg); 223462306a36Sopenharmony_ci ath12k_peer_assoc_h_vht(ar, vif, sta, arg); 223562306a36Sopenharmony_ci ath12k_peer_assoc_h_he(ar, vif, sta, arg); 223662306a36Sopenharmony_ci ath12k_peer_assoc_h_eht(ar, vif, sta, arg); 223762306a36Sopenharmony_ci ath12k_peer_assoc_h_qos(ar, vif, sta, arg); 223862306a36Sopenharmony_ci ath12k_peer_assoc_h_phymode(ar, vif, sta, arg); 223962306a36Sopenharmony_ci ath12k_peer_assoc_h_smps(sta, arg); 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci /* TODO: amsdu_disable req? */ 224262306a36Sopenharmony_ci} 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_cistatic int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, 224562306a36Sopenharmony_ci const u8 *addr, 224662306a36Sopenharmony_ci const struct ieee80211_sta_ht_cap *ht_cap) 224762306a36Sopenharmony_ci{ 224862306a36Sopenharmony_ci int smps; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci if (!ht_cap->ht_supported) 225162306a36Sopenharmony_ci return 0; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS; 225462306a36Sopenharmony_ci smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci if (smps >= ARRAY_SIZE(ath12k_smps_map)) 225762306a36Sopenharmony_ci return -EINVAL; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci return ath12k_wmi_set_peer_param(ar, addr, arvif->vdev_id, 226062306a36Sopenharmony_ci WMI_PEER_MIMO_PS_STATE, 226162306a36Sopenharmony_ci ath12k_smps_map[smps]); 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic void ath12k_bss_assoc(struct ieee80211_hw *hw, 226562306a36Sopenharmony_ci struct ieee80211_vif *vif, 226662306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf) 226762306a36Sopenharmony_ci{ 226862306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 226962306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 227062306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg peer_arg; 227162306a36Sopenharmony_ci struct ieee80211_sta *ap_sta; 227262306a36Sopenharmony_ci struct ath12k_peer *peer; 227362306a36Sopenharmony_ci bool is_auth = false; 227462306a36Sopenharmony_ci int ret; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", 227962306a36Sopenharmony_ci arvif->vdev_id, arvif->bssid, arvif->aid); 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci rcu_read_lock(); 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); 228462306a36Sopenharmony_ci if (!ap_sta) { 228562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to find station entry for bss %pM vdev %i\n", 228662306a36Sopenharmony_ci bss_conf->bssid, arvif->vdev_id); 228762306a36Sopenharmony_ci rcu_read_unlock(); 228862306a36Sopenharmony_ci return; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci ath12k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false); 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci rcu_read_unlock(); 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci ret = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); 229662306a36Sopenharmony_ci if (ret) { 229762306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", 229862306a36Sopenharmony_ci bss_conf->bssid, arvif->vdev_id, ret); 229962306a36Sopenharmony_ci return; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { 230362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", 230462306a36Sopenharmony_ci bss_conf->bssid, arvif->vdev_id); 230562306a36Sopenharmony_ci return; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci ret = ath12k_setup_peer_smps(ar, arvif, bss_conf->bssid, 230962306a36Sopenharmony_ci &ap_sta->deflink.ht_cap); 231062306a36Sopenharmony_ci if (ret) { 231162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", 231262306a36Sopenharmony_ci arvif->vdev_id, ret); 231362306a36Sopenharmony_ci return; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci WARN_ON(arvif->is_up); 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci arvif->aid = vif->cfg.aid; 231962306a36Sopenharmony_ci ether_addr_copy(arvif->bssid, bss_conf->bssid); 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid); 232262306a36Sopenharmony_ci if (ret) { 232362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %d up: %d\n", 232462306a36Sopenharmony_ci arvif->vdev_id, ret); 232562306a36Sopenharmony_ci return; 232662306a36Sopenharmony_ci } 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci arvif->is_up = true; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 233162306a36Sopenharmony_ci "mac vdev %d up (associated) bssid %pM aid %d\n", 233262306a36Sopenharmony_ci arvif->vdev_id, bss_conf->bssid, vif->cfg.aid); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci peer = ath12k_peer_find(ar->ab, arvif->vdev_id, arvif->bssid); 233762306a36Sopenharmony_ci if (peer && peer->is_authorized) 233862306a36Sopenharmony_ci is_auth = true; 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci /* Authorize BSS Peer */ 234362306a36Sopenharmony_ci if (is_auth) { 234462306a36Sopenharmony_ci ret = ath12k_wmi_set_peer_param(ar, arvif->bssid, 234562306a36Sopenharmony_ci arvif->vdev_id, 234662306a36Sopenharmony_ci WMI_PEER_AUTHORIZE, 234762306a36Sopenharmony_ci 1); 234862306a36Sopenharmony_ci if (ret) 234962306a36Sopenharmony_ci ath12k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret); 235062306a36Sopenharmony_ci } 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci ret = ath12k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id, 235362306a36Sopenharmony_ci &bss_conf->he_obss_pd); 235462306a36Sopenharmony_ci if (ret) 235562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n", 235662306a36Sopenharmony_ci arvif->vdev_id, ret); 235762306a36Sopenharmony_ci} 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_cistatic void ath12k_bss_disassoc(struct ieee80211_hw *hw, 236062306a36Sopenharmony_ci struct ieee80211_vif *vif) 236162306a36Sopenharmony_ci{ 236262306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 236362306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 236462306a36Sopenharmony_ci int ret; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", 236962306a36Sopenharmony_ci arvif->vdev_id, arvif->bssid); 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id); 237262306a36Sopenharmony_ci if (ret) 237362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to down vdev %i: %d\n", 237462306a36Sopenharmony_ci arvif->vdev_id, ret); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci arvif->is_up = false; 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci /* TODO: cancel connection_loss_work */ 237962306a36Sopenharmony_ci} 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_cistatic u32 ath12k_mac_get_rate_hw_value(int bitrate) 238262306a36Sopenharmony_ci{ 238362306a36Sopenharmony_ci u32 preamble; 238462306a36Sopenharmony_ci u16 hw_value; 238562306a36Sopenharmony_ci int rate; 238662306a36Sopenharmony_ci size_t i; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci if (ath12k_mac_bitrate_is_cck(bitrate)) 238962306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_CCK; 239062306a36Sopenharmony_ci else 239162306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_OFDM; 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ath12k_legacy_rates); i++) { 239462306a36Sopenharmony_ci if (ath12k_legacy_rates[i].bitrate != bitrate) 239562306a36Sopenharmony_ci continue; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci hw_value = ath12k_legacy_rates[i].hw_value; 239862306a36Sopenharmony_ci rate = ATH12K_HW_RATE_CODE(hw_value, 0, preamble); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci return rate; 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci return -EINVAL; 240462306a36Sopenharmony_ci} 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_cistatic void ath12k_recalculate_mgmt_rate(struct ath12k *ar, 240762306a36Sopenharmony_ci struct ieee80211_vif *vif, 240862306a36Sopenharmony_ci struct cfg80211_chan_def *def) 240962306a36Sopenharmony_ci{ 241062306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 241162306a36Sopenharmony_ci const struct ieee80211_supported_band *sband; 241262306a36Sopenharmony_ci u8 basic_rate_idx; 241362306a36Sopenharmony_ci int hw_rate_code; 241462306a36Sopenharmony_ci u32 vdev_param; 241562306a36Sopenharmony_ci u16 bitrate; 241662306a36Sopenharmony_ci int ret; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci sband = ar->hw->wiphy->bands[def->chan->band]; 242162306a36Sopenharmony_ci basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; 242262306a36Sopenharmony_ci bitrate = sband->bitrates[basic_rate_idx].bitrate; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci hw_rate_code = ath12k_mac_get_rate_hw_value(bitrate); 242562306a36Sopenharmony_ci if (hw_rate_code < 0) { 242662306a36Sopenharmony_ci ath12k_warn(ar->ab, "bitrate not supported %d\n", bitrate); 242762306a36Sopenharmony_ci return; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_MGMT_RATE; 243162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, 243262306a36Sopenharmony_ci hw_rate_code); 243362306a36Sopenharmony_ci if (ret) 243462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret); 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_BEACON_RATE; 243762306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param, 243862306a36Sopenharmony_ci hw_rate_code); 243962306a36Sopenharmony_ci if (ret) 244062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret); 244162306a36Sopenharmony_ci} 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_cistatic int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, 244462306a36Sopenharmony_ci struct ieee80211_bss_conf *info) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 244762306a36Sopenharmony_ci struct sk_buff *tmpl; 244862306a36Sopenharmony_ci int ret; 244962306a36Sopenharmony_ci u32 interval; 245062306a36Sopenharmony_ci bool unsol_bcast_probe_resp_enabled = false; 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci if (info->fils_discovery.max_interval) { 245362306a36Sopenharmony_ci interval = info->fils_discovery.max_interval; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci tmpl = ieee80211_get_fils_discovery_tmpl(ar->hw, arvif->vif); 245662306a36Sopenharmony_ci if (tmpl) 245762306a36Sopenharmony_ci ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id, 245862306a36Sopenharmony_ci tmpl); 245962306a36Sopenharmony_ci } else if (info->unsol_bcast_probe_resp_interval) { 246062306a36Sopenharmony_ci unsol_bcast_probe_resp_enabled = 1; 246162306a36Sopenharmony_ci interval = info->unsol_bcast_probe_resp_interval; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(ar->hw, 246462306a36Sopenharmony_ci arvif->vif); 246562306a36Sopenharmony_ci if (tmpl) 246662306a36Sopenharmony_ci ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id, 246762306a36Sopenharmony_ci tmpl); 246862306a36Sopenharmony_ci } else { /* Disable */ 246962306a36Sopenharmony_ci return ath12k_wmi_fils_discovery(ar, arvif->vdev_id, 0, false); 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci if (!tmpl) { 247362306a36Sopenharmony_ci ath12k_warn(ar->ab, 247462306a36Sopenharmony_ci "mac vdev %i failed to retrieve %s template\n", 247562306a36Sopenharmony_ci arvif->vdev_id, (unsol_bcast_probe_resp_enabled ? 247662306a36Sopenharmony_ci "unsolicited broadcast probe response" : 247762306a36Sopenharmony_ci "FILS discovery")); 247862306a36Sopenharmony_ci return -EPERM; 247962306a36Sopenharmony_ci } 248062306a36Sopenharmony_ci kfree_skb(tmpl); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (!ret) 248362306a36Sopenharmony_ci ret = ath12k_wmi_fils_discovery(ar, arvif->vdev_id, interval, 248462306a36Sopenharmony_ci unsol_bcast_probe_resp_enabled); 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci return ret; 248762306a36Sopenharmony_ci} 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_cistatic void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, 249062306a36Sopenharmony_ci struct ieee80211_vif *vif, 249162306a36Sopenharmony_ci struct ieee80211_bss_conf *info, 249262306a36Sopenharmony_ci u64 changed) 249362306a36Sopenharmony_ci{ 249462306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 249562306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 249662306a36Sopenharmony_ci struct cfg80211_chan_def def; 249762306a36Sopenharmony_ci u32 param_id, param_value; 249862306a36Sopenharmony_ci enum nl80211_band band; 249962306a36Sopenharmony_ci u32 vdev_param; 250062306a36Sopenharmony_ci int mcast_rate; 250162306a36Sopenharmony_ci u32 preamble; 250262306a36Sopenharmony_ci u16 hw_value; 250362306a36Sopenharmony_ci u16 bitrate; 250462306a36Sopenharmony_ci int ret; 250562306a36Sopenharmony_ci u8 rateidx; 250662306a36Sopenharmony_ci u32 rate; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_INT) { 251162306a36Sopenharmony_ci arvif->beacon_interval = info->beacon_int; 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_BEACON_INTERVAL; 251462306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 251562306a36Sopenharmony_ci param_id, 251662306a36Sopenharmony_ci arvif->beacon_interval); 251762306a36Sopenharmony_ci if (ret) 251862306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set beacon interval for VDEV: %d\n", 251962306a36Sopenharmony_ci arvif->vdev_id); 252062306a36Sopenharmony_ci else 252162306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 252262306a36Sopenharmony_ci "Beacon interval: %d set for VDEV: %d\n", 252362306a36Sopenharmony_ci arvif->beacon_interval, arvif->vdev_id); 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON) { 252762306a36Sopenharmony_ci param_id = WMI_PDEV_PARAM_BEACON_TX_MODE; 252862306a36Sopenharmony_ci param_value = WMI_BEACON_STAGGERED_MODE; 252962306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, param_id, 253062306a36Sopenharmony_ci param_value, ar->pdev->pdev_id); 253162306a36Sopenharmony_ci if (ret) 253262306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set beacon mode for VDEV: %d\n", 253362306a36Sopenharmony_ci arvif->vdev_id); 253462306a36Sopenharmony_ci else 253562306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 253662306a36Sopenharmony_ci "Set staggered beacon mode for VDEV: %d\n", 253762306a36Sopenharmony_ci arvif->vdev_id); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci ret = ath12k_mac_setup_bcn_tmpl(arvif); 254062306a36Sopenharmony_ci if (ret) 254162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update bcn template: %d\n", 254262306a36Sopenharmony_ci ret); 254362306a36Sopenharmony_ci } 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { 254662306a36Sopenharmony_ci arvif->dtim_period = info->dtim_period; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_DTIM_PERIOD; 254962306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 255062306a36Sopenharmony_ci param_id, 255162306a36Sopenharmony_ci arvif->dtim_period); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci if (ret) 255462306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set dtim period for VDEV %d: %i\n", 255562306a36Sopenharmony_ci arvif->vdev_id, ret); 255662306a36Sopenharmony_ci else 255762306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 255862306a36Sopenharmony_ci "DTIM period: %d set for VDEV: %d\n", 255962306a36Sopenharmony_ci arvif->dtim_period, arvif->vdev_id); 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci if (changed & BSS_CHANGED_SSID && 256362306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_AP) { 256462306a36Sopenharmony_ci arvif->u.ap.ssid_len = vif->cfg.ssid_len; 256562306a36Sopenharmony_ci if (vif->cfg.ssid_len) 256662306a36Sopenharmony_ci memcpy(arvif->u.ap.ssid, vif->cfg.ssid, vif->cfg.ssid_len); 256762306a36Sopenharmony_ci arvif->u.ap.hidden_ssid = info->hidden_ssid; 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) 257162306a36Sopenharmony_ci ether_addr_copy(arvif->bssid, info->bssid); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED) { 257462306a36Sopenharmony_ci ath12k_control_beaconing(arvif, info); 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci if (arvif->is_up && vif->bss_conf.he_support && 257762306a36Sopenharmony_ci vif->bss_conf.he_oper.params) { 257862306a36Sopenharmony_ci /* TODO: Extend to support 1024 BA Bitmap size */ 257962306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 258062306a36Sopenharmony_ci WMI_VDEV_PARAM_BA_MODE, 258162306a36Sopenharmony_ci WMI_BA_MODE_BUFFER_SIZE_256); 258262306a36Sopenharmony_ci if (ret) 258362306a36Sopenharmony_ci ath12k_warn(ar->ab, 258462306a36Sopenharmony_ci "failed to set BA BUFFER SIZE 256 for vdev: %d\n", 258562306a36Sopenharmony_ci arvif->vdev_id); 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_HEOPS_0_31; 258862306a36Sopenharmony_ci param_value = vif->bss_conf.he_oper.params; 258962306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 259062306a36Sopenharmony_ci param_id, param_value); 259162306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 259262306a36Sopenharmony_ci "he oper param: %x set for VDEV: %d\n", 259362306a36Sopenharmony_ci param_value, arvif->vdev_id); 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci if (ret) 259662306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set he oper params %x for VDEV %d: %i\n", 259762306a36Sopenharmony_ci param_value, arvif->vdev_id, ret); 259862306a36Sopenharmony_ci } 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_CTS_PROT) { 260262306a36Sopenharmony_ci u32 cts_prot; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci cts_prot = !!(info->use_cts_prot); 260562306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_PROTECTION_MODE; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci if (arvif->is_started) { 260862306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 260962306a36Sopenharmony_ci param_id, cts_prot); 261062306a36Sopenharmony_ci if (ret) 261162306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set CTS prot for VDEV: %d\n", 261262306a36Sopenharmony_ci arvif->vdev_id); 261362306a36Sopenharmony_ci else 261462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "Set CTS prot: %d for VDEV: %d\n", 261562306a36Sopenharmony_ci cts_prot, arvif->vdev_id); 261662306a36Sopenharmony_ci } else { 261762306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "defer protection mode setup, vdev is not ready yet\n"); 261862306a36Sopenharmony_ci } 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 262262306a36Sopenharmony_ci u32 slottime; 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci if (info->use_short_slot) 262562306a36Sopenharmony_ci slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */ 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci else 262862306a36Sopenharmony_ci slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */ 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_SLOT_TIME; 263162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 263262306a36Sopenharmony_ci param_id, slottime); 263362306a36Sopenharmony_ci if (ret) 263462306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set erp slot for VDEV: %d\n", 263562306a36Sopenharmony_ci arvif->vdev_id); 263662306a36Sopenharmony_ci else 263762306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 263862306a36Sopenharmony_ci "Set slottime: %d for VDEV: %d\n", 263962306a36Sopenharmony_ci slottime, arvif->vdev_id); 264062306a36Sopenharmony_ci } 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_PREAMBLE) { 264362306a36Sopenharmony_ci u32 preamble; 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci if (info->use_short_preamble) 264662306a36Sopenharmony_ci preamble = WMI_VDEV_PREAMBLE_SHORT; 264762306a36Sopenharmony_ci else 264862306a36Sopenharmony_ci preamble = WMI_VDEV_PREAMBLE_LONG; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_PREAMBLE; 265162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 265262306a36Sopenharmony_ci param_id, preamble); 265362306a36Sopenharmony_ci if (ret) 265462306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to set preamble for VDEV: %d\n", 265562306a36Sopenharmony_ci arvif->vdev_id); 265662306a36Sopenharmony_ci else 265762306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 265862306a36Sopenharmony_ci "Set preamble: %d for VDEV: %d\n", 265962306a36Sopenharmony_ci preamble, arvif->vdev_id); 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 266362306a36Sopenharmony_ci if (vif->cfg.assoc) 266462306a36Sopenharmony_ci ath12k_bss_assoc(hw, vif, info); 266562306a36Sopenharmony_ci else 266662306a36Sopenharmony_ci ath12k_bss_disassoc(hw, vif); 266762306a36Sopenharmony_ci } 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci if (changed & BSS_CHANGED_TXPOWER) { 267062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev_id %i txpower %d\n", 267162306a36Sopenharmony_ci arvif->vdev_id, info->txpower); 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci arvif->txpower = info->txpower; 267462306a36Sopenharmony_ci ath12k_mac_txpower_recalc(ar); 267562306a36Sopenharmony_ci } 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci if (changed & BSS_CHANGED_MCAST_RATE && 267862306a36Sopenharmony_ci !ath12k_mac_vif_chan(arvif->vif, &def)) { 267962306a36Sopenharmony_ci band = def.chan->band; 268062306a36Sopenharmony_ci mcast_rate = vif->bss_conf.mcast_rate[band]; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci if (mcast_rate > 0) 268362306a36Sopenharmony_ci rateidx = mcast_rate - 1; 268462306a36Sopenharmony_ci else 268562306a36Sopenharmony_ci rateidx = ffs(vif->bss_conf.basic_rates) - 1; 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci if (ar->pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) 268862306a36Sopenharmony_ci rateidx += ATH12K_MAC_FIRST_OFDM_RATE_IDX; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci bitrate = ath12k_legacy_rates[rateidx].bitrate; 269162306a36Sopenharmony_ci hw_value = ath12k_legacy_rates[rateidx].hw_value; 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci if (ath12k_mac_bitrate_is_cck(bitrate)) 269462306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_CCK; 269562306a36Sopenharmony_ci else 269662306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_OFDM; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci rate = ATH12K_HW_RATE_CODE(hw_value, 0, preamble); 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 270162306a36Sopenharmony_ci "mac vdev %d mcast_rate %x\n", 270262306a36Sopenharmony_ci arvif->vdev_id, rate); 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_MCAST_DATA_RATE; 270562306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 270662306a36Sopenharmony_ci vdev_param, rate); 270762306a36Sopenharmony_ci if (ret) 270862306a36Sopenharmony_ci ath12k_warn(ar->ab, 270962306a36Sopenharmony_ci "failed to set mcast rate on vdev %i: %d\n", 271062306a36Sopenharmony_ci arvif->vdev_id, ret); 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_BCAST_DATA_RATE; 271362306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 271462306a36Sopenharmony_ci vdev_param, rate); 271562306a36Sopenharmony_ci if (ret) 271662306a36Sopenharmony_ci ath12k_warn(ar->ab, 271762306a36Sopenharmony_ci "failed to set bcast rate on vdev %i: %d\n", 271862306a36Sopenharmony_ci arvif->vdev_id, ret); 271962306a36Sopenharmony_ci } 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES && 272262306a36Sopenharmony_ci !ath12k_mac_vif_chan(arvif->vif, &def)) 272362306a36Sopenharmony_ci ath12k_recalculate_mgmt_rate(ar, vif, &def); 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci if (changed & BSS_CHANGED_TWT) { 272662306a36Sopenharmony_ci if (info->twt_requester || info->twt_responder) 272762306a36Sopenharmony_ci ath12k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id); 272862306a36Sopenharmony_ci else 272962306a36Sopenharmony_ci ath12k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id); 273062306a36Sopenharmony_ci } 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_OBSS_PD) 273362306a36Sopenharmony_ci ath12k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id, 273462306a36Sopenharmony_ci &info->he_obss_pd); 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_BSS_COLOR) { 273762306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP) { 273862306a36Sopenharmony_ci ret = ath12k_wmi_obss_color_cfg_cmd(ar, 273962306a36Sopenharmony_ci arvif->vdev_id, 274062306a36Sopenharmony_ci info->he_bss_color.color, 274162306a36Sopenharmony_ci ATH12K_BSS_COLOR_AP_PERIODS, 274262306a36Sopenharmony_ci info->he_bss_color.enabled); 274362306a36Sopenharmony_ci if (ret) 274462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", 274562306a36Sopenharmony_ci arvif->vdev_id, ret); 274662306a36Sopenharmony_ci } else if (vif->type == NL80211_IFTYPE_STATION) { 274762306a36Sopenharmony_ci ret = ath12k_wmi_send_bss_color_change_enable_cmd(ar, 274862306a36Sopenharmony_ci arvif->vdev_id, 274962306a36Sopenharmony_ci 1); 275062306a36Sopenharmony_ci if (ret) 275162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to enable bss color change on vdev %i: %d\n", 275262306a36Sopenharmony_ci arvif->vdev_id, ret); 275362306a36Sopenharmony_ci ret = ath12k_wmi_obss_color_cfg_cmd(ar, 275462306a36Sopenharmony_ci arvif->vdev_id, 275562306a36Sopenharmony_ci 0, 275662306a36Sopenharmony_ci ATH12K_BSS_COLOR_STA_PERIODS, 275762306a36Sopenharmony_ci 1); 275862306a36Sopenharmony_ci if (ret) 275962306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", 276062306a36Sopenharmony_ci arvif->vdev_id, ret); 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci } 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci if (changed & BSS_CHANGED_FILS_DISCOVERY || 276562306a36Sopenharmony_ci changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP) 276662306a36Sopenharmony_ci ath12k_mac_fils_discovery(arvif, info); 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci if (changed & BSS_CHANGED_EHT_PUNCTURING) 276962306a36Sopenharmony_ci arvif->punct_bitmap = info->eht_puncturing; 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 277262306a36Sopenharmony_ci} 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_civoid __ath12k_mac_scan_finish(struct ath12k *ar) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci lockdep_assert_held(&ar->data_lock); 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci switch (ar->scan.state) { 277962306a36Sopenharmony_ci case ATH12K_SCAN_IDLE: 278062306a36Sopenharmony_ci break; 278162306a36Sopenharmony_ci case ATH12K_SCAN_RUNNING: 278262306a36Sopenharmony_ci case ATH12K_SCAN_ABORTING: 278362306a36Sopenharmony_ci if (!ar->scan.is_roc) { 278462306a36Sopenharmony_ci struct cfg80211_scan_info info = { 278562306a36Sopenharmony_ci .aborted = (ar->scan.state == 278662306a36Sopenharmony_ci ATH12K_SCAN_ABORTING), 278762306a36Sopenharmony_ci }; 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci ieee80211_scan_completed(ar->hw, &info); 279062306a36Sopenharmony_ci } else if (ar->scan.roc_notify) { 279162306a36Sopenharmony_ci ieee80211_remain_on_channel_expired(ar->hw); 279262306a36Sopenharmony_ci } 279362306a36Sopenharmony_ci fallthrough; 279462306a36Sopenharmony_ci case ATH12K_SCAN_STARTING: 279562306a36Sopenharmony_ci ar->scan.state = ATH12K_SCAN_IDLE; 279662306a36Sopenharmony_ci ar->scan_channel = NULL; 279762306a36Sopenharmony_ci ar->scan.roc_freq = 0; 279862306a36Sopenharmony_ci cancel_delayed_work(&ar->scan.timeout); 279962306a36Sopenharmony_ci complete(&ar->scan.completed); 280062306a36Sopenharmony_ci break; 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci} 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_civoid ath12k_mac_scan_finish(struct ath12k *ar) 280562306a36Sopenharmony_ci{ 280662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 280762306a36Sopenharmony_ci __ath12k_mac_scan_finish(ar); 280862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 280962306a36Sopenharmony_ci} 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_cistatic int ath12k_scan_stop(struct ath12k *ar) 281262306a36Sopenharmony_ci{ 281362306a36Sopenharmony_ci struct ath12k_wmi_scan_cancel_arg arg = { 281462306a36Sopenharmony_ci .req_type = WLAN_SCAN_CANCEL_SINGLE, 281562306a36Sopenharmony_ci .scan_id = ATH12K_SCAN_ID, 281662306a36Sopenharmony_ci }; 281762306a36Sopenharmony_ci int ret; 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci /* TODO: Fill other STOP Params */ 282262306a36Sopenharmony_ci arg.pdev_id = ar->pdev->pdev_id; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci ret = ath12k_wmi_send_scan_stop_cmd(ar, &arg); 282562306a36Sopenharmony_ci if (ret) { 282662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to stop wmi scan: %d\n", ret); 282762306a36Sopenharmony_ci goto out; 282862306a36Sopenharmony_ci } 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->scan.completed, 3 * HZ); 283162306a36Sopenharmony_ci if (ret == 0) { 283262306a36Sopenharmony_ci ath12k_warn(ar->ab, 283362306a36Sopenharmony_ci "failed to receive scan abort comple: timed out\n"); 283462306a36Sopenharmony_ci ret = -ETIMEDOUT; 283562306a36Sopenharmony_ci } else if (ret > 0) { 283662306a36Sopenharmony_ci ret = 0; 283762306a36Sopenharmony_ci } 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ciout: 284062306a36Sopenharmony_ci /* Scan state should be updated upon scan completion but in case 284162306a36Sopenharmony_ci * firmware fails to deliver the event (for whatever reason) it is 284262306a36Sopenharmony_ci * desired to clean up scan state anyway. Firmware may have just 284362306a36Sopenharmony_ci * dropped the scan completion event delivery due to transport pipe 284462306a36Sopenharmony_ci * being overflown with data and/or it can recover on its own before 284562306a36Sopenharmony_ci * next scan request is submitted. 284662306a36Sopenharmony_ci */ 284762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 284862306a36Sopenharmony_ci if (ar->scan.state != ATH12K_SCAN_IDLE) 284962306a36Sopenharmony_ci __ath12k_mac_scan_finish(ar); 285062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci return ret; 285362306a36Sopenharmony_ci} 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_cistatic void ath12k_scan_abort(struct ath12k *ar) 285662306a36Sopenharmony_ci{ 285762306a36Sopenharmony_ci int ret; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci switch (ar->scan.state) { 286462306a36Sopenharmony_ci case ATH12K_SCAN_IDLE: 286562306a36Sopenharmony_ci /* This can happen if timeout worker kicked in and called 286662306a36Sopenharmony_ci * abortion while scan completion was being processed. 286762306a36Sopenharmony_ci */ 286862306a36Sopenharmony_ci break; 286962306a36Sopenharmony_ci case ATH12K_SCAN_STARTING: 287062306a36Sopenharmony_ci case ATH12K_SCAN_ABORTING: 287162306a36Sopenharmony_ci ath12k_warn(ar->ab, "refusing scan abortion due to invalid scan state: %d\n", 287262306a36Sopenharmony_ci ar->scan.state); 287362306a36Sopenharmony_ci break; 287462306a36Sopenharmony_ci case ATH12K_SCAN_RUNNING: 287562306a36Sopenharmony_ci ar->scan.state = ATH12K_SCAN_ABORTING; 287662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci ret = ath12k_scan_stop(ar); 287962306a36Sopenharmony_ci if (ret) 288062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to abort scan: %d\n", ret); 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 288362306a36Sopenharmony_ci break; 288462306a36Sopenharmony_ci } 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 288762306a36Sopenharmony_ci} 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_cistatic void ath12k_scan_timeout_work(struct work_struct *work) 289062306a36Sopenharmony_ci{ 289162306a36Sopenharmony_ci struct ath12k *ar = container_of(work, struct ath12k, 289262306a36Sopenharmony_ci scan.timeout.work); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 289562306a36Sopenharmony_ci ath12k_scan_abort(ar); 289662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 289762306a36Sopenharmony_ci} 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_cistatic int ath12k_start_scan(struct ath12k *ar, 290062306a36Sopenharmony_ci struct ath12k_wmi_scan_req_arg *arg) 290162306a36Sopenharmony_ci{ 290262306a36Sopenharmony_ci int ret; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci ret = ath12k_wmi_send_scan_start_cmd(ar, arg); 290762306a36Sopenharmony_ci if (ret) 290862306a36Sopenharmony_ci return ret; 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ); 291162306a36Sopenharmony_ci if (ret == 0) { 291262306a36Sopenharmony_ci ret = ath12k_scan_stop(ar); 291362306a36Sopenharmony_ci if (ret) 291462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret); 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_ci return -ETIMEDOUT; 291762306a36Sopenharmony_ci } 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci /* If we failed to start the scan, return error code at 292062306a36Sopenharmony_ci * this point. This is probably due to some issue in the 292162306a36Sopenharmony_ci * firmware, but no need to wedge the driver due to that... 292262306a36Sopenharmony_ci */ 292362306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 292462306a36Sopenharmony_ci if (ar->scan.state == ATH12K_SCAN_IDLE) { 292562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 292662306a36Sopenharmony_ci return -EINVAL; 292762306a36Sopenharmony_ci } 292862306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci return 0; 293162306a36Sopenharmony_ci} 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_cistatic int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, 293462306a36Sopenharmony_ci struct ieee80211_vif *vif, 293562306a36Sopenharmony_ci struct ieee80211_scan_request *hw_req) 293662306a36Sopenharmony_ci{ 293762306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 293862306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 293962306a36Sopenharmony_ci struct cfg80211_scan_request *req = &hw_req->req; 294062306a36Sopenharmony_ci struct ath12k_wmi_scan_req_arg arg = {}; 294162306a36Sopenharmony_ci int ret; 294262306a36Sopenharmony_ci int i; 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 294762306a36Sopenharmony_ci switch (ar->scan.state) { 294862306a36Sopenharmony_ci case ATH12K_SCAN_IDLE: 294962306a36Sopenharmony_ci reinit_completion(&ar->scan.started); 295062306a36Sopenharmony_ci reinit_completion(&ar->scan.completed); 295162306a36Sopenharmony_ci ar->scan.state = ATH12K_SCAN_STARTING; 295262306a36Sopenharmony_ci ar->scan.is_roc = false; 295362306a36Sopenharmony_ci ar->scan.vdev_id = arvif->vdev_id; 295462306a36Sopenharmony_ci ret = 0; 295562306a36Sopenharmony_ci break; 295662306a36Sopenharmony_ci case ATH12K_SCAN_STARTING: 295762306a36Sopenharmony_ci case ATH12K_SCAN_RUNNING: 295862306a36Sopenharmony_ci case ATH12K_SCAN_ABORTING: 295962306a36Sopenharmony_ci ret = -EBUSY; 296062306a36Sopenharmony_ci break; 296162306a36Sopenharmony_ci } 296262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (ret) 296562306a36Sopenharmony_ci goto exit; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci ath12k_wmi_start_scan_init(ar, &arg); 296862306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 296962306a36Sopenharmony_ci arg.scan_id = ATH12K_SCAN_ID; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci if (req->ie_len) { 297262306a36Sopenharmony_ci arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL); 297362306a36Sopenharmony_ci if (!arg.extraie.ptr) { 297462306a36Sopenharmony_ci ret = -ENOMEM; 297562306a36Sopenharmony_ci goto exit; 297662306a36Sopenharmony_ci } 297762306a36Sopenharmony_ci arg.extraie.len = req->ie_len; 297862306a36Sopenharmony_ci } 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci if (req->n_ssids) { 298162306a36Sopenharmony_ci arg.num_ssids = req->n_ssids; 298262306a36Sopenharmony_ci for (i = 0; i < arg.num_ssids; i++) 298362306a36Sopenharmony_ci arg.ssid[i] = req->ssids[i]; 298462306a36Sopenharmony_ci } else { 298562306a36Sopenharmony_ci arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; 298662306a36Sopenharmony_ci } 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci if (req->n_channels) { 298962306a36Sopenharmony_ci arg.num_chan = req->n_channels; 299062306a36Sopenharmony_ci arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), 299162306a36Sopenharmony_ci GFP_KERNEL); 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci if (!arg.chan_list) { 299462306a36Sopenharmony_ci ret = -ENOMEM; 299562306a36Sopenharmony_ci goto exit; 299662306a36Sopenharmony_ci } 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci for (i = 0; i < arg.num_chan; i++) 299962306a36Sopenharmony_ci arg.chan_list[i] = req->channels[i]->center_freq; 300062306a36Sopenharmony_ci } 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci ret = ath12k_start_scan(ar, &arg); 300362306a36Sopenharmony_ci if (ret) { 300462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret); 300562306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 300662306a36Sopenharmony_ci ar->scan.state = ATH12K_SCAN_IDLE; 300762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 300862306a36Sopenharmony_ci } 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci /* Add a margin to account for event/command processing */ 301162306a36Sopenharmony_ci ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, 301262306a36Sopenharmony_ci msecs_to_jiffies(arg.max_scan_time + 301362306a36Sopenharmony_ci ATH12K_MAC_SCAN_TIMEOUT_MSECS)); 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ciexit: 301662306a36Sopenharmony_ci kfree(arg.chan_list); 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if (req->ie_len) 301962306a36Sopenharmony_ci kfree(arg.extraie.ptr); 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 302262306a36Sopenharmony_ci return ret; 302362306a36Sopenharmony_ci} 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_cistatic void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, 302662306a36Sopenharmony_ci struct ieee80211_vif *vif) 302762306a36Sopenharmony_ci{ 302862306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 303162306a36Sopenharmony_ci ath12k_scan_abort(ar); 303262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci cancel_delayed_work_sync(&ar->scan.timeout); 303562306a36Sopenharmony_ci} 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_cistatic int ath12k_install_key(struct ath12k_vif *arvif, 303862306a36Sopenharmony_ci struct ieee80211_key_conf *key, 303962306a36Sopenharmony_ci enum set_key_cmd cmd, 304062306a36Sopenharmony_ci const u8 *macaddr, u32 flags) 304162306a36Sopenharmony_ci{ 304262306a36Sopenharmony_ci int ret; 304362306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 304462306a36Sopenharmony_ci struct wmi_vdev_install_key_arg arg = { 304562306a36Sopenharmony_ci .vdev_id = arvif->vdev_id, 304662306a36Sopenharmony_ci .key_idx = key->keyidx, 304762306a36Sopenharmony_ci .key_len = key->keylen, 304862306a36Sopenharmony_ci .key_data = key->key, 304962306a36Sopenharmony_ci .key_flags = flags, 305062306a36Sopenharmony_ci .macaddr = macaddr, 305162306a36Sopenharmony_ci }; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci lockdep_assert_held(&arvif->ar->conf_mutex); 305462306a36Sopenharmony_ci 305562306a36Sopenharmony_ci reinit_completion(&ar->install_key_done); 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) 305862306a36Sopenharmony_ci return 0; 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci if (cmd == DISABLE_KEY) { 306162306a36Sopenharmony_ci /* TODO: Check if FW expects value other than NONE for del */ 306262306a36Sopenharmony_ci /* arg.key_cipher = WMI_CIPHER_NONE; */ 306362306a36Sopenharmony_ci arg.key_len = 0; 306462306a36Sopenharmony_ci arg.key_data = NULL; 306562306a36Sopenharmony_ci goto install; 306662306a36Sopenharmony_ci } 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci switch (key->cipher) { 306962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 307062306a36Sopenharmony_ci arg.key_cipher = WMI_CIPHER_AES_CCM; 307162306a36Sopenharmony_ci /* TODO: Re-check if flag is valid */ 307262306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; 307362306a36Sopenharmony_ci break; 307462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 307562306a36Sopenharmony_ci arg.key_cipher = WMI_CIPHER_TKIP; 307662306a36Sopenharmony_ci arg.key_txmic_len = 8; 307762306a36Sopenharmony_ci arg.key_rxmic_len = 8; 307862306a36Sopenharmony_ci break; 307962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 308062306a36Sopenharmony_ci arg.key_cipher = WMI_CIPHER_AES_CCM; 308162306a36Sopenharmony_ci break; 308262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 308362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 308462306a36Sopenharmony_ci arg.key_cipher = WMI_CIPHER_AES_GCM; 308562306a36Sopenharmony_ci break; 308662306a36Sopenharmony_ci default: 308762306a36Sopenharmony_ci ath12k_warn(ar->ab, "cipher %d is not supported\n", key->cipher); 308862306a36Sopenharmony_ci return -EOPNOTSUPP; 308962306a36Sopenharmony_ci } 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) 309262306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV | 309362306a36Sopenharmony_ci IEEE80211_KEY_FLAG_RESERVE_TAILROOM; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ciinstall: 309662306a36Sopenharmony_ci ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci if (ret) 309962306a36Sopenharmony_ci return ret; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ)) 310262306a36Sopenharmony_ci return -ETIMEDOUT; 310362306a36Sopenharmony_ci 310462306a36Sopenharmony_ci if (ether_addr_equal(macaddr, arvif->vif->addr)) 310562306a36Sopenharmony_ci arvif->key_cipher = key->cipher; 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci return ar->install_key_status ? -EINVAL : 0; 310862306a36Sopenharmony_ci} 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_cistatic int ath12k_clear_peer_keys(struct ath12k_vif *arvif, 311162306a36Sopenharmony_ci const u8 *addr) 311262306a36Sopenharmony_ci{ 311362306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 311462306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 311562306a36Sopenharmony_ci struct ath12k_peer *peer; 311662306a36Sopenharmony_ci int first_errno = 0; 311762306a36Sopenharmony_ci int ret; 311862306a36Sopenharmony_ci int i; 311962306a36Sopenharmony_ci u32 flags = 0; 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 312462306a36Sopenharmony_ci peer = ath12k_peer_find(ab, arvif->vdev_id, addr); 312562306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci if (!peer) 312862306a36Sopenharmony_ci return -ENOENT; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { 313162306a36Sopenharmony_ci if (!peer->keys[i]) 313262306a36Sopenharmony_ci continue; 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ci /* key flags are not required to delete the key */ 313562306a36Sopenharmony_ci ret = ath12k_install_key(arvif, peer->keys[i], 313662306a36Sopenharmony_ci DISABLE_KEY, addr, flags); 313762306a36Sopenharmony_ci if (ret < 0 && first_errno == 0) 313862306a36Sopenharmony_ci first_errno = ret; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci if (ret < 0) 314162306a36Sopenharmony_ci ath12k_warn(ab, "failed to remove peer key %d: %d\n", 314262306a36Sopenharmony_ci i, ret); 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 314562306a36Sopenharmony_ci peer->keys[i] = NULL; 314662306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 314762306a36Sopenharmony_ci } 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_ci return first_errno; 315062306a36Sopenharmony_ci} 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_cistatic int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 315362306a36Sopenharmony_ci struct ieee80211_vif *vif, struct ieee80211_sta *sta, 315462306a36Sopenharmony_ci struct ieee80211_key_conf *key) 315562306a36Sopenharmony_ci{ 315662306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 315762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 315862306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 315962306a36Sopenharmony_ci struct ath12k_peer *peer; 316062306a36Sopenharmony_ci struct ath12k_sta *arsta; 316162306a36Sopenharmony_ci const u8 *peer_addr; 316262306a36Sopenharmony_ci int ret = 0; 316362306a36Sopenharmony_ci u32 flags = 0; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci /* BIP needs to be done in software */ 316662306a36Sopenharmony_ci if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || 316762306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || 316862306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || 316962306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) 317062306a36Sopenharmony_ci return 1; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) 317362306a36Sopenharmony_ci return 1; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci if (key->keyidx > WMI_MAX_KEY_INDEX) 317662306a36Sopenharmony_ci return -ENOSPC; 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci if (sta) 318162306a36Sopenharmony_ci peer_addr = sta->addr; 318262306a36Sopenharmony_ci else if (arvif->vdev_type == WMI_VDEV_TYPE_STA) 318362306a36Sopenharmony_ci peer_addr = vif->bss_conf.bssid; 318462306a36Sopenharmony_ci else 318562306a36Sopenharmony_ci peer_addr = vif->addr; 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci key->hw_key_idx = key->keyidx; 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_ci /* the peer should not disappear in mid-way (unless FW goes awry) since 319062306a36Sopenharmony_ci * we already hold conf_mutex. we just make sure its there now. 319162306a36Sopenharmony_ci */ 319262306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 319362306a36Sopenharmony_ci peer = ath12k_peer_find(ab, arvif->vdev_id, peer_addr); 319462306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci if (!peer) { 319762306a36Sopenharmony_ci if (cmd == SET_KEY) { 319862306a36Sopenharmony_ci ath12k_warn(ab, "cannot install key for non-existent peer %pM\n", 319962306a36Sopenharmony_ci peer_addr); 320062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 320162306a36Sopenharmony_ci goto exit; 320262306a36Sopenharmony_ci } else { 320362306a36Sopenharmony_ci /* if the peer doesn't exist there is no key to disable 320462306a36Sopenharmony_ci * anymore 320562306a36Sopenharmony_ci */ 320662306a36Sopenharmony_ci goto exit; 320762306a36Sopenharmony_ci } 320862306a36Sopenharmony_ci } 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 321162306a36Sopenharmony_ci flags |= WMI_KEY_PAIRWISE; 321262306a36Sopenharmony_ci else 321362306a36Sopenharmony_ci flags |= WMI_KEY_GROUP; 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci ret = ath12k_install_key(arvif, key, cmd, peer_addr, flags); 321662306a36Sopenharmony_ci if (ret) { 321762306a36Sopenharmony_ci ath12k_warn(ab, "ath12k_install_key failed (%d)\n", ret); 321862306a36Sopenharmony_ci goto exit; 321962306a36Sopenharmony_ci } 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci ret = ath12k_dp_rx_peer_pn_replay_config(arvif, peer_addr, cmd, key); 322262306a36Sopenharmony_ci if (ret) { 322362306a36Sopenharmony_ci ath12k_warn(ab, "failed to offload PN replay detection %d\n", ret); 322462306a36Sopenharmony_ci goto exit; 322562306a36Sopenharmony_ci } 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 322862306a36Sopenharmony_ci peer = ath12k_peer_find(ab, arvif->vdev_id, peer_addr); 322962306a36Sopenharmony_ci if (peer && cmd == SET_KEY) { 323062306a36Sopenharmony_ci peer->keys[key->keyidx] = key; 323162306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { 323262306a36Sopenharmony_ci peer->ucast_keyidx = key->keyidx; 323362306a36Sopenharmony_ci peer->sec_type = ath12k_dp_tx_get_encrypt_type(key->cipher); 323462306a36Sopenharmony_ci } else { 323562306a36Sopenharmony_ci peer->mcast_keyidx = key->keyidx; 323662306a36Sopenharmony_ci peer->sec_type_grp = ath12k_dp_tx_get_encrypt_type(key->cipher); 323762306a36Sopenharmony_ci } 323862306a36Sopenharmony_ci } else if (peer && cmd == DISABLE_KEY) { 323962306a36Sopenharmony_ci peer->keys[key->keyidx] = NULL; 324062306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 324162306a36Sopenharmony_ci peer->ucast_keyidx = 0; 324262306a36Sopenharmony_ci else 324362306a36Sopenharmony_ci peer->mcast_keyidx = 0; 324462306a36Sopenharmony_ci } else if (!peer) 324562306a36Sopenharmony_ci /* impossible unless FW goes crazy */ 324662306a36Sopenharmony_ci ath12k_warn(ab, "peer %pM disappeared!\n", peer_addr); 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci if (sta) { 324962306a36Sopenharmony_ci arsta = (struct ath12k_sta *)sta->drv_priv; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci switch (key->cipher) { 325262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 325362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 325462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 325562306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 325662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 325762306a36Sopenharmony_ci if (cmd == SET_KEY) 325862306a36Sopenharmony_ci arsta->pn_type = HAL_PN_TYPE_WPA; 325962306a36Sopenharmony_ci else 326062306a36Sopenharmony_ci arsta->pn_type = HAL_PN_TYPE_NONE; 326162306a36Sopenharmony_ci break; 326262306a36Sopenharmony_ci default: 326362306a36Sopenharmony_ci arsta->pn_type = HAL_PN_TYPE_NONE; 326462306a36Sopenharmony_ci break; 326562306a36Sopenharmony_ci } 326662306a36Sopenharmony_ci } 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ciexit: 327162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 327262306a36Sopenharmony_ci return ret; 327362306a36Sopenharmony_ci} 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_cistatic int 327662306a36Sopenharmony_ciath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar, 327762306a36Sopenharmony_ci enum nl80211_band band, 327862306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 327962306a36Sopenharmony_ci{ 328062306a36Sopenharmony_ci int num_rates = 0; 328162306a36Sopenharmony_ci int i; 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) 328462306a36Sopenharmony_ci num_rates += hweight16(mask->control[band].vht_mcs[i]); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci return num_rates; 328762306a36Sopenharmony_ci} 328862306a36Sopenharmony_ci 328962306a36Sopenharmony_cistatic int 329062306a36Sopenharmony_ciath12k_mac_set_peer_vht_fixed_rate(struct ath12k_vif *arvif, 329162306a36Sopenharmony_ci struct ieee80211_sta *sta, 329262306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 329362306a36Sopenharmony_ci enum nl80211_band band) 329462306a36Sopenharmony_ci{ 329562306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 329662306a36Sopenharmony_ci u8 vht_rate, nss; 329762306a36Sopenharmony_ci u32 rate_code; 329862306a36Sopenharmony_ci int ret, i; 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_ci nss = 0; 330362306a36Sopenharmony_ci 330462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { 330562306a36Sopenharmony_ci if (hweight16(mask->control[band].vht_mcs[i]) == 1) { 330662306a36Sopenharmony_ci nss = i + 1; 330762306a36Sopenharmony_ci vht_rate = ffs(mask->control[band].vht_mcs[i]) - 1; 330862306a36Sopenharmony_ci } 330962306a36Sopenharmony_ci } 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci if (!nss) { 331262306a36Sopenharmony_ci ath12k_warn(ar->ab, "No single VHT Fixed rate found to set for %pM", 331362306a36Sopenharmony_ci sta->addr); 331462306a36Sopenharmony_ci return -EINVAL; 331562306a36Sopenharmony_ci } 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 331862306a36Sopenharmony_ci "Setting Fixed VHT Rate for peer %pM. Device will not switch to any other selected rates", 331962306a36Sopenharmony_ci sta->addr); 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci rate_code = ATH12K_HW_RATE_CODE(vht_rate, nss - 1, 332262306a36Sopenharmony_ci WMI_RATE_PREAMBLE_VHT); 332362306a36Sopenharmony_ci ret = ath12k_wmi_set_peer_param(ar, sta->addr, 332462306a36Sopenharmony_ci arvif->vdev_id, 332562306a36Sopenharmony_ci WMI_PEER_PARAM_FIXED_RATE, 332662306a36Sopenharmony_ci rate_code); 332762306a36Sopenharmony_ci if (ret) 332862306a36Sopenharmony_ci ath12k_warn(ar->ab, 332962306a36Sopenharmony_ci "failed to update STA %pM Fixed Rate %d: %d\n", 333062306a36Sopenharmony_ci sta->addr, rate_code, ret); 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_ci return ret; 333362306a36Sopenharmony_ci} 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_cistatic int ath12k_station_assoc(struct ath12k *ar, 333662306a36Sopenharmony_ci struct ieee80211_vif *vif, 333762306a36Sopenharmony_ci struct ieee80211_sta *sta, 333862306a36Sopenharmony_ci bool reassoc) 333962306a36Sopenharmony_ci{ 334062306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 334162306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg peer_arg; 334262306a36Sopenharmony_ci int ret; 334362306a36Sopenharmony_ci struct cfg80211_chan_def def; 334462306a36Sopenharmony_ci enum nl80211_band band; 334562306a36Sopenharmony_ci struct cfg80211_bitrate_mask *mask; 334662306a36Sopenharmony_ci u8 num_vht_rates; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) 335162306a36Sopenharmony_ci return -EPERM; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci band = def.chan->band; 335462306a36Sopenharmony_ci mask = &arvif->bitrate_mask; 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci ath12k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc); 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci ret = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); 335962306a36Sopenharmony_ci if (ret) { 336062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", 336162306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 336262306a36Sopenharmony_ci return ret; 336362306a36Sopenharmony_ci } 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) { 336662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", 336762306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 336862306a36Sopenharmony_ci return -ETIMEDOUT; 336962306a36Sopenharmony_ci } 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask); 337262306a36Sopenharmony_ci 337362306a36Sopenharmony_ci /* If single VHT rate is configured (by set_bitrate_mask()), 337462306a36Sopenharmony_ci * peer_assoc will disable VHT. This is now enabled by a peer specific 337562306a36Sopenharmony_ci * fixed param. 337662306a36Sopenharmony_ci * Note that all other rates and NSS will be disabled for this peer. 337762306a36Sopenharmony_ci */ 337862306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) { 337962306a36Sopenharmony_ci ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, 338062306a36Sopenharmony_ci band); 338162306a36Sopenharmony_ci if (ret) 338262306a36Sopenharmony_ci return ret; 338362306a36Sopenharmony_ci } 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci /* Re-assoc is run only to update supported rates for given station. It 338662306a36Sopenharmony_ci * doesn't make much sense to reconfigure the peer completely. 338762306a36Sopenharmony_ci */ 338862306a36Sopenharmony_ci if (reassoc) 338962306a36Sopenharmony_ci return 0; 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci ret = ath12k_setup_peer_smps(ar, arvif, sta->addr, 339262306a36Sopenharmony_ci &sta->deflink.ht_cap); 339362306a36Sopenharmony_ci if (ret) { 339462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n", 339562306a36Sopenharmony_ci arvif->vdev_id, ret); 339662306a36Sopenharmony_ci return ret; 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci if (!sta->wme) { 340062306a36Sopenharmony_ci arvif->num_legacy_stations++; 340162306a36Sopenharmony_ci ret = ath12k_recalc_rtscts_prot(arvif); 340262306a36Sopenharmony_ci if (ret) 340362306a36Sopenharmony_ci return ret; 340462306a36Sopenharmony_ci } 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci if (sta->wme && sta->uapsd_queues) { 340762306a36Sopenharmony_ci ret = ath12k_peer_assoc_qos_ap(ar, arvif, sta); 340862306a36Sopenharmony_ci if (ret) { 340962306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set qos params for STA %pM for vdev %i: %d\n", 341062306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 341162306a36Sopenharmony_ci return ret; 341262306a36Sopenharmony_ci } 341362306a36Sopenharmony_ci } 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci return 0; 341662306a36Sopenharmony_ci} 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_cistatic int ath12k_station_disassoc(struct ath12k *ar, 341962306a36Sopenharmony_ci struct ieee80211_vif *vif, 342062306a36Sopenharmony_ci struct ieee80211_sta *sta) 342162306a36Sopenharmony_ci{ 342262306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 342362306a36Sopenharmony_ci int ret; 342462306a36Sopenharmony_ci 342562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci if (!sta->wme) { 342862306a36Sopenharmony_ci arvif->num_legacy_stations--; 342962306a36Sopenharmony_ci ret = ath12k_recalc_rtscts_prot(arvif); 343062306a36Sopenharmony_ci if (ret) 343162306a36Sopenharmony_ci return ret; 343262306a36Sopenharmony_ci } 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci ret = ath12k_clear_peer_keys(arvif, sta->addr); 343562306a36Sopenharmony_ci if (ret) { 343662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to clear all peer keys for vdev %i: %d\n", 343762306a36Sopenharmony_ci arvif->vdev_id, ret); 343862306a36Sopenharmony_ci return ret; 343962306a36Sopenharmony_ci } 344062306a36Sopenharmony_ci return 0; 344162306a36Sopenharmony_ci} 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_cistatic void ath12k_sta_rc_update_wk(struct work_struct *wk) 344462306a36Sopenharmony_ci{ 344562306a36Sopenharmony_ci struct ath12k *ar; 344662306a36Sopenharmony_ci struct ath12k_vif *arvif; 344762306a36Sopenharmony_ci struct ath12k_sta *arsta; 344862306a36Sopenharmony_ci struct ieee80211_sta *sta; 344962306a36Sopenharmony_ci struct cfg80211_chan_def def; 345062306a36Sopenharmony_ci enum nl80211_band band; 345162306a36Sopenharmony_ci const u8 *ht_mcs_mask; 345262306a36Sopenharmony_ci const u16 *vht_mcs_mask; 345362306a36Sopenharmony_ci u32 changed, bw, nss, smps, bw_prev; 345462306a36Sopenharmony_ci int err, num_vht_rates; 345562306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask; 345662306a36Sopenharmony_ci struct ath12k_wmi_peer_assoc_arg peer_arg; 345762306a36Sopenharmony_ci enum wmi_phy_mode peer_phymode; 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci arsta = container_of(wk, struct ath12k_sta, update_wk); 346062306a36Sopenharmony_ci sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv); 346162306a36Sopenharmony_ci arvif = arsta->arvif; 346262306a36Sopenharmony_ci ar = arvif->ar; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci if (WARN_ON(ath12k_mac_vif_chan(arvif->vif, &def))) 346562306a36Sopenharmony_ci return; 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci band = def.chan->band; 346862306a36Sopenharmony_ci ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; 346962306a36Sopenharmony_ci vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_ci changed = arsta->changed; 347462306a36Sopenharmony_ci arsta->changed = 0; 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci bw = arsta->bw; 347762306a36Sopenharmony_ci bw_prev = arsta->bw_prev; 347862306a36Sopenharmony_ci nss = arsta->nss; 347962306a36Sopenharmony_ci smps = arsta->smps; 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci nss = max_t(u32, 1, nss); 348662306a36Sopenharmony_ci nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask), 348762306a36Sopenharmony_ci ath12k_mac_max_vht_nss(vht_mcs_mask))); 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci if (changed & IEEE80211_RC_BW_CHANGED) { 349062306a36Sopenharmony_ci ath12k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg); 349162306a36Sopenharmony_ci peer_phymode = peer_arg.peer_phymode; 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci if (bw > bw_prev) { 349462306a36Sopenharmony_ci /* Phymode shows maximum supported channel width, if we 349562306a36Sopenharmony_ci * upgrade bandwidth then due to sanity check of firmware, 349662306a36Sopenharmony_ci * we have to send WMI_PEER_PHYMODE followed by 349762306a36Sopenharmony_ci * WMI_PEER_CHWIDTH 349862306a36Sopenharmony_ci */ 349962306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac bandwidth upgrade for sta %pM new %d old %d\n", 350062306a36Sopenharmony_ci sta->addr, bw, bw_prev); 350162306a36Sopenharmony_ci err = ath12k_wmi_set_peer_param(ar, sta->addr, 350262306a36Sopenharmony_ci arvif->vdev_id, WMI_PEER_PHYMODE, 350362306a36Sopenharmony_ci peer_phymode); 350462306a36Sopenharmony_ci if (err) { 350562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update STA %pM to peer phymode %d: %d\n", 350662306a36Sopenharmony_ci sta->addr, peer_phymode, err); 350762306a36Sopenharmony_ci goto err_rc_bw_changed; 350862306a36Sopenharmony_ci } 350962306a36Sopenharmony_ci err = ath12k_wmi_set_peer_param(ar, sta->addr, 351062306a36Sopenharmony_ci arvif->vdev_id, WMI_PEER_CHWIDTH, 351162306a36Sopenharmony_ci bw); 351262306a36Sopenharmony_ci if (err) 351362306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update STA %pM to peer bandwidth %d: %d\n", 351462306a36Sopenharmony_ci sta->addr, bw, err); 351562306a36Sopenharmony_ci } else { 351662306a36Sopenharmony_ci /* When we downgrade bandwidth this will conflict with phymode 351762306a36Sopenharmony_ci * and cause to trigger firmware crash. In this case we send 351862306a36Sopenharmony_ci * WMI_PEER_CHWIDTH followed by WMI_PEER_PHYMODE 351962306a36Sopenharmony_ci */ 352062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac bandwidth downgrade for sta %pM new %d old %d\n", 352162306a36Sopenharmony_ci sta->addr, bw, bw_prev); 352262306a36Sopenharmony_ci err = ath12k_wmi_set_peer_param(ar, sta->addr, 352362306a36Sopenharmony_ci arvif->vdev_id, WMI_PEER_CHWIDTH, 352462306a36Sopenharmony_ci bw); 352562306a36Sopenharmony_ci if (err) { 352662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update STA %pM peer to bandwidth %d: %d\n", 352762306a36Sopenharmony_ci sta->addr, bw, err); 352862306a36Sopenharmony_ci goto err_rc_bw_changed; 352962306a36Sopenharmony_ci } 353062306a36Sopenharmony_ci err = ath12k_wmi_set_peer_param(ar, sta->addr, 353162306a36Sopenharmony_ci arvif->vdev_id, WMI_PEER_PHYMODE, 353262306a36Sopenharmony_ci peer_phymode); 353362306a36Sopenharmony_ci if (err) 353462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update STA %pM to peer phymode %d: %d\n", 353562306a36Sopenharmony_ci sta->addr, peer_phymode, err); 353662306a36Sopenharmony_ci } 353762306a36Sopenharmony_ci } 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_ci if (changed & IEEE80211_RC_NSS_CHANGED) { 354062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac update sta %pM nss %d\n", 354162306a36Sopenharmony_ci sta->addr, nss); 354262306a36Sopenharmony_ci 354362306a36Sopenharmony_ci err = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, 354462306a36Sopenharmony_ci WMI_PEER_NSS, nss); 354562306a36Sopenharmony_ci if (err) 354662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update STA %pM nss %d: %d\n", 354762306a36Sopenharmony_ci sta->addr, nss, err); 354862306a36Sopenharmony_ci } 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci if (changed & IEEE80211_RC_SMPS_CHANGED) { 355162306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac update sta %pM smps %d\n", 355262306a36Sopenharmony_ci sta->addr, smps); 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci err = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, 355562306a36Sopenharmony_ci WMI_PEER_MIMO_PS_STATE, smps); 355662306a36Sopenharmony_ci if (err) 355762306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to update STA %pM smps %d: %d\n", 355862306a36Sopenharmony_ci sta->addr, smps, err); 355962306a36Sopenharmony_ci } 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { 356262306a36Sopenharmony_ci mask = &arvif->bitrate_mask; 356362306a36Sopenharmony_ci num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, 356462306a36Sopenharmony_ci mask); 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_ci /* Peer_assoc_prepare will reject vht rates in 356762306a36Sopenharmony_ci * bitrate_mask if its not available in range format and 356862306a36Sopenharmony_ci * sets vht tx_rateset as unsupported. So multiple VHT MCS 356962306a36Sopenharmony_ci * setting(eg. MCS 4,5,6) per peer is not supported here. 357062306a36Sopenharmony_ci * But, Single rate in VHT mask can be set as per-peer 357162306a36Sopenharmony_ci * fixed rate. But even if any HT rates are configured in 357262306a36Sopenharmony_ci * the bitrate mask, device will not switch to those rates 357362306a36Sopenharmony_ci * when per-peer Fixed rate is set. 357462306a36Sopenharmony_ci * TODO: Check RATEMASK_CMDID to support auto rates selection 357562306a36Sopenharmony_ci * across HT/VHT and for multiple VHT MCS support. 357662306a36Sopenharmony_ci */ 357762306a36Sopenharmony_ci if (sta->deflink.vht_cap.vht_supported && num_vht_rates == 1) { 357862306a36Sopenharmony_ci ath12k_mac_set_peer_vht_fixed_rate(arvif, sta, mask, 357962306a36Sopenharmony_ci band); 358062306a36Sopenharmony_ci } else { 358162306a36Sopenharmony_ci /* If the peer is non-VHT or no fixed VHT rate 358262306a36Sopenharmony_ci * is provided in the new bitrate mask we set the 358362306a36Sopenharmony_ci * other rates using peer_assoc command. 358462306a36Sopenharmony_ci */ 358562306a36Sopenharmony_ci ath12k_peer_assoc_prepare(ar, arvif->vif, sta, 358662306a36Sopenharmony_ci &peer_arg, true); 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci err = ath12k_wmi_send_peer_assoc_cmd(ar, &peer_arg); 358962306a36Sopenharmony_ci if (err) 359062306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", 359162306a36Sopenharmony_ci sta->addr, arvif->vdev_id, err); 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) 359462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n", 359562306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 359662306a36Sopenharmony_ci } 359762306a36Sopenharmony_ci } 359862306a36Sopenharmony_cierr_rc_bw_changed: 359962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 360062306a36Sopenharmony_ci} 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_cistatic int ath12k_mac_inc_num_stations(struct ath12k_vif *arvif, 360362306a36Sopenharmony_ci struct ieee80211_sta *sta) 360462306a36Sopenharmony_ci{ 360562306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 360662306a36Sopenharmony_ci 360762306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) 361062306a36Sopenharmony_ci return 0; 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci if (ar->num_stations >= ar->max_num_stations) 361362306a36Sopenharmony_ci return -ENOBUFS; 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci ar->num_stations++; 361662306a36Sopenharmony_ci 361762306a36Sopenharmony_ci return 0; 361862306a36Sopenharmony_ci} 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_cistatic void ath12k_mac_dec_num_stations(struct ath12k_vif *arvif, 362162306a36Sopenharmony_ci struct ieee80211_sta *sta) 362262306a36Sopenharmony_ci{ 362362306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls) 362862306a36Sopenharmony_ci return; 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci ar->num_stations--; 363162306a36Sopenharmony_ci} 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_cistatic int ath12k_mac_station_add(struct ath12k *ar, 363462306a36Sopenharmony_ci struct ieee80211_vif *vif, 363562306a36Sopenharmony_ci struct ieee80211_sta *sta) 363662306a36Sopenharmony_ci{ 363762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 363862306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 363962306a36Sopenharmony_ci struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; 364062306a36Sopenharmony_ci struct ath12k_wmi_peer_create_arg peer_param; 364162306a36Sopenharmony_ci int ret; 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci ret = ath12k_mac_inc_num_stations(arvif, sta); 364662306a36Sopenharmony_ci if (ret) { 364762306a36Sopenharmony_ci ath12k_warn(ab, "refusing to associate station: too many connected already (%d)\n", 364862306a36Sopenharmony_ci ar->max_num_stations); 364962306a36Sopenharmony_ci goto exit; 365062306a36Sopenharmony_ci } 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); 365362306a36Sopenharmony_ci if (!arsta->rx_stats) { 365462306a36Sopenharmony_ci ret = -ENOMEM; 365562306a36Sopenharmony_ci goto dec_num_station; 365662306a36Sopenharmony_ci } 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci peer_param.vdev_id = arvif->vdev_id; 365962306a36Sopenharmony_ci peer_param.peer_addr = sta->addr; 366062306a36Sopenharmony_ci peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; 366162306a36Sopenharmony_ci 366262306a36Sopenharmony_ci ret = ath12k_peer_create(ar, arvif, sta, &peer_param); 366362306a36Sopenharmony_ci if (ret) { 366462306a36Sopenharmony_ci ath12k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n", 366562306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 366662306a36Sopenharmony_ci goto free_peer; 366762306a36Sopenharmony_ci } 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "Added peer: %pM for VDEV: %d\n", 367062306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_ci if (ieee80211_vif_is_mesh(vif)) { 367362306a36Sopenharmony_ci ret = ath12k_wmi_set_peer_param(ar, sta->addr, 367462306a36Sopenharmony_ci arvif->vdev_id, 367562306a36Sopenharmony_ci WMI_PEER_USE_4ADDR, 1); 367662306a36Sopenharmony_ci if (ret) { 367762306a36Sopenharmony_ci ath12k_warn(ab, "failed to STA %pM 4addr capability: %d\n", 367862306a36Sopenharmony_ci sta->addr, ret); 367962306a36Sopenharmony_ci goto free_peer; 368062306a36Sopenharmony_ci } 368162306a36Sopenharmony_ci } 368262306a36Sopenharmony_ci 368362306a36Sopenharmony_ci ret = ath12k_dp_peer_setup(ar, arvif->vdev_id, sta->addr); 368462306a36Sopenharmony_ci if (ret) { 368562306a36Sopenharmony_ci ath12k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n", 368662306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 368762306a36Sopenharmony_ci goto free_peer; 368862306a36Sopenharmony_ci } 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_ci if (ab->hw_params->vdev_start_delay && 369162306a36Sopenharmony_ci !arvif->is_started && 369262306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_AP) { 369362306a36Sopenharmony_ci ret = ath12k_start_vdev_delay(ar->hw, vif); 369462306a36Sopenharmony_ci if (ret) { 369562306a36Sopenharmony_ci ath12k_warn(ab, "failed to delay vdev start: %d\n", ret); 369662306a36Sopenharmony_ci goto free_peer; 369762306a36Sopenharmony_ci } 369862306a36Sopenharmony_ci } 369962306a36Sopenharmony_ci 370062306a36Sopenharmony_ci return 0; 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_cifree_peer: 370362306a36Sopenharmony_ci ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); 370462306a36Sopenharmony_cidec_num_station: 370562306a36Sopenharmony_ci ath12k_mac_dec_num_stations(arvif, sta); 370662306a36Sopenharmony_ciexit: 370762306a36Sopenharmony_ci return ret; 370862306a36Sopenharmony_ci} 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_cistatic u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar, 371162306a36Sopenharmony_ci struct ieee80211_sta *sta) 371262306a36Sopenharmony_ci{ 371362306a36Sopenharmony_ci u32 bw = WMI_PEER_CHWIDTH_20MHZ; 371462306a36Sopenharmony_ci 371562306a36Sopenharmony_ci switch (sta->deflink.bandwidth) { 371662306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_20: 371762306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_20MHZ; 371862306a36Sopenharmony_ci break; 371962306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_40: 372062306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_40MHZ; 372162306a36Sopenharmony_ci break; 372262306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_80: 372362306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_80MHZ; 372462306a36Sopenharmony_ci break; 372562306a36Sopenharmony_ci case IEEE80211_STA_RX_BW_160: 372662306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_160MHZ; 372762306a36Sopenharmony_ci break; 372862306a36Sopenharmony_ci default: 372962306a36Sopenharmony_ci ath12k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n", 373062306a36Sopenharmony_ci sta->deflink.bandwidth, sta->addr); 373162306a36Sopenharmony_ci bw = WMI_PEER_CHWIDTH_20MHZ; 373262306a36Sopenharmony_ci break; 373362306a36Sopenharmony_ci } 373462306a36Sopenharmony_ci 373562306a36Sopenharmony_ci return bw; 373662306a36Sopenharmony_ci} 373762306a36Sopenharmony_ci 373862306a36Sopenharmony_cistatic int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, 373962306a36Sopenharmony_ci struct ieee80211_vif *vif, 374062306a36Sopenharmony_ci struct ieee80211_sta *sta, 374162306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 374262306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 374362306a36Sopenharmony_ci{ 374462306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 374562306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 374662306a36Sopenharmony_ci struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; 374762306a36Sopenharmony_ci struct ath12k_peer *peer; 374862306a36Sopenharmony_ci int ret = 0; 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci /* cancel must be done outside the mutex to avoid deadlock */ 375162306a36Sopenharmony_ci if ((old_state == IEEE80211_STA_NONE && 375262306a36Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST)) 375362306a36Sopenharmony_ci cancel_work_sync(&arsta->update_wk); 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST && 375862306a36Sopenharmony_ci new_state == IEEE80211_STA_NONE) { 375962306a36Sopenharmony_ci memset(arsta, 0, sizeof(*arsta)); 376062306a36Sopenharmony_ci arsta->arvif = arvif; 376162306a36Sopenharmony_ci INIT_WORK(&arsta->update_wk, ath12k_sta_rc_update_wk); 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ci ret = ath12k_mac_station_add(ar, vif, sta); 376462306a36Sopenharmony_ci if (ret) 376562306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n", 376662306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 376762306a36Sopenharmony_ci } else if ((old_state == IEEE80211_STA_NONE && 376862306a36Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST)) { 376962306a36Sopenharmony_ci ath12k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_ci ret = ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); 377262306a36Sopenharmony_ci if (ret) 377362306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n", 377462306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 377562306a36Sopenharmony_ci else 377662306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n", 377762306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci ath12k_mac_dec_num_stations(arvif, sta); 378062306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 378162306a36Sopenharmony_ci peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); 378262306a36Sopenharmony_ci if (peer && peer->sta == sta) { 378362306a36Sopenharmony_ci ath12k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n", 378462306a36Sopenharmony_ci vif->addr, arvif->vdev_id); 378562306a36Sopenharmony_ci peer->sta = NULL; 378662306a36Sopenharmony_ci list_del(&peer->list); 378762306a36Sopenharmony_ci kfree(peer); 378862306a36Sopenharmony_ci ar->num_peers--; 378962306a36Sopenharmony_ci } 379062306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci kfree(arsta->rx_stats); 379362306a36Sopenharmony_ci arsta->rx_stats = NULL; 379462306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_AUTH && 379562306a36Sopenharmony_ci new_state == IEEE80211_STA_ASSOC && 379662306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_AP || 379762306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT || 379862306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_ADHOC)) { 379962306a36Sopenharmony_ci ret = ath12k_station_assoc(ar, vif, sta, false); 380062306a36Sopenharmony_ci if (ret) 380162306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to associate station: %pM\n", 380262306a36Sopenharmony_ci sta->addr); 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 380562306a36Sopenharmony_ci 380662306a36Sopenharmony_ci arsta->bw = ath12k_mac_ieee80211_sta_bw_to_wmi(ar, sta); 380762306a36Sopenharmony_ci arsta->bw_prev = sta->deflink.bandwidth; 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 381062306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_ASSOC && 381162306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTHORIZED) { 381262306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); 381562306a36Sopenharmony_ci if (peer) 381662306a36Sopenharmony_ci peer->is_authorized = true; 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && arvif->is_up) { 382162306a36Sopenharmony_ci ret = ath12k_wmi_set_peer_param(ar, sta->addr, 382262306a36Sopenharmony_ci arvif->vdev_id, 382362306a36Sopenharmony_ci WMI_PEER_AUTHORIZE, 382462306a36Sopenharmony_ci 1); 382562306a36Sopenharmony_ci if (ret) 382662306a36Sopenharmony_ci ath12k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", 382762306a36Sopenharmony_ci sta->addr, arvif->vdev_id, ret); 382862306a36Sopenharmony_ci } 382962306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_AUTHORIZED && 383062306a36Sopenharmony_ci new_state == IEEE80211_STA_ASSOC) { 383162306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 383262306a36Sopenharmony_ci 383362306a36Sopenharmony_ci peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); 383462306a36Sopenharmony_ci if (peer) 383562306a36Sopenharmony_ci peer->is_authorized = false; 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 383862306a36Sopenharmony_ci } else if (old_state == IEEE80211_STA_ASSOC && 383962306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTH && 384062306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_AP || 384162306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT || 384262306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_ADHOC)) { 384362306a36Sopenharmony_ci ret = ath12k_station_disassoc(ar, vif, sta); 384462306a36Sopenharmony_ci if (ret) 384562306a36Sopenharmony_ci ath12k_warn(ar->ab, "Failed to disassociate station: %pM\n", 384662306a36Sopenharmony_ci sta->addr); 384762306a36Sopenharmony_ci } 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 385062306a36Sopenharmony_ci return ret; 385162306a36Sopenharmony_ci} 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_cistatic int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, 385462306a36Sopenharmony_ci struct ieee80211_vif *vif, 385562306a36Sopenharmony_ci struct ieee80211_sta *sta) 385662306a36Sopenharmony_ci{ 385762306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 385862306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 385962306a36Sopenharmony_ci int ret; 386062306a36Sopenharmony_ci s16 txpwr; 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) { 386362306a36Sopenharmony_ci txpwr = 0; 386462306a36Sopenharmony_ci } else { 386562306a36Sopenharmony_ci txpwr = sta->deflink.txpwr.power; 386662306a36Sopenharmony_ci if (!txpwr) 386762306a36Sopenharmony_ci return -EINVAL; 386862306a36Sopenharmony_ci } 386962306a36Sopenharmony_ci 387062306a36Sopenharmony_ci if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) 387162306a36Sopenharmony_ci return -EINVAL; 387262306a36Sopenharmony_ci 387362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, 387662306a36Sopenharmony_ci WMI_PEER_USE_FIXED_PWR, txpwr); 387762306a36Sopenharmony_ci if (ret) { 387862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set tx power for station ret: %d\n", 387962306a36Sopenharmony_ci ret); 388062306a36Sopenharmony_ci goto out; 388162306a36Sopenharmony_ci } 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ciout: 388462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 388562306a36Sopenharmony_ci return ret; 388662306a36Sopenharmony_ci} 388762306a36Sopenharmony_ci 388862306a36Sopenharmony_cistatic void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, 388962306a36Sopenharmony_ci struct ieee80211_vif *vif, 389062306a36Sopenharmony_ci struct ieee80211_sta *sta, 389162306a36Sopenharmony_ci u32 changed) 389262306a36Sopenharmony_ci{ 389362306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 389462306a36Sopenharmony_ci struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; 389562306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 389662306a36Sopenharmony_ci struct ath12k_peer *peer; 389762306a36Sopenharmony_ci u32 bw, smps; 389862306a36Sopenharmony_ci 389962306a36Sopenharmony_ci spin_lock_bh(&ar->ab->base_lock); 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); 390262306a36Sopenharmony_ci if (!peer) { 390362306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 390462306a36Sopenharmony_ci ath12k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n", 390562306a36Sopenharmony_ci sta->addr, arvif->vdev_id); 390662306a36Sopenharmony_ci return; 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci spin_unlock_bh(&ar->ab->base_lock); 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 391262306a36Sopenharmony_ci "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", 391362306a36Sopenharmony_ci sta->addr, changed, sta->deflink.bandwidth, sta->deflink.rx_nss, 391462306a36Sopenharmony_ci sta->deflink.smps_mode); 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci if (changed & IEEE80211_RC_BW_CHANGED) { 391962306a36Sopenharmony_ci bw = ath12k_mac_ieee80211_sta_bw_to_wmi(ar, sta); 392062306a36Sopenharmony_ci arsta->bw_prev = arsta->bw; 392162306a36Sopenharmony_ci arsta->bw = bw; 392262306a36Sopenharmony_ci } 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci if (changed & IEEE80211_RC_NSS_CHANGED) 392562306a36Sopenharmony_ci arsta->nss = sta->deflink.rx_nss; 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ci if (changed & IEEE80211_RC_SMPS_CHANGED) { 392862306a36Sopenharmony_ci smps = WMI_PEER_SMPS_PS_NONE; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci switch (sta->deflink.smps_mode) { 393162306a36Sopenharmony_ci case IEEE80211_SMPS_AUTOMATIC: 393262306a36Sopenharmony_ci case IEEE80211_SMPS_OFF: 393362306a36Sopenharmony_ci smps = WMI_PEER_SMPS_PS_NONE; 393462306a36Sopenharmony_ci break; 393562306a36Sopenharmony_ci case IEEE80211_SMPS_STATIC: 393662306a36Sopenharmony_ci smps = WMI_PEER_SMPS_STATIC; 393762306a36Sopenharmony_ci break; 393862306a36Sopenharmony_ci case IEEE80211_SMPS_DYNAMIC: 393962306a36Sopenharmony_ci smps = WMI_PEER_SMPS_DYNAMIC; 394062306a36Sopenharmony_ci break; 394162306a36Sopenharmony_ci default: 394262306a36Sopenharmony_ci ath12k_warn(ar->ab, "Invalid smps %d in sta rc update for %pM\n", 394362306a36Sopenharmony_ci sta->deflink.smps_mode, sta->addr); 394462306a36Sopenharmony_ci smps = WMI_PEER_SMPS_PS_NONE; 394562306a36Sopenharmony_ci break; 394662306a36Sopenharmony_ci } 394762306a36Sopenharmony_ci 394862306a36Sopenharmony_ci arsta->smps = smps; 394962306a36Sopenharmony_ci } 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_ci arsta->changed |= changed; 395262306a36Sopenharmony_ci 395362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci ieee80211_queue_work(hw, &arsta->update_wk); 395662306a36Sopenharmony_ci} 395762306a36Sopenharmony_ci 395862306a36Sopenharmony_cistatic int ath12k_conf_tx_uapsd(struct ath12k *ar, struct ieee80211_vif *vif, 395962306a36Sopenharmony_ci u16 ac, bool enable) 396062306a36Sopenharmony_ci{ 396162306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 396262306a36Sopenharmony_ci u32 value; 396362306a36Sopenharmony_ci int ret; 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_STA) 396662306a36Sopenharmony_ci return 0; 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci switch (ac) { 396962306a36Sopenharmony_ci case IEEE80211_AC_VO: 397062306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | 397162306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; 397262306a36Sopenharmony_ci break; 397362306a36Sopenharmony_ci case IEEE80211_AC_VI: 397462306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | 397562306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; 397662306a36Sopenharmony_ci break; 397762306a36Sopenharmony_ci case IEEE80211_AC_BE: 397862306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | 397962306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; 398062306a36Sopenharmony_ci break; 398162306a36Sopenharmony_ci case IEEE80211_AC_BK: 398262306a36Sopenharmony_ci value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | 398362306a36Sopenharmony_ci WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; 398462306a36Sopenharmony_ci break; 398562306a36Sopenharmony_ci } 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci if (enable) 398862306a36Sopenharmony_ci arvif->u.sta.uapsd |= value; 398962306a36Sopenharmony_ci else 399062306a36Sopenharmony_ci arvif->u.sta.uapsd &= ~value; 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_ci ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 399362306a36Sopenharmony_ci WMI_STA_PS_PARAM_UAPSD, 399462306a36Sopenharmony_ci arvif->u.sta.uapsd); 399562306a36Sopenharmony_ci if (ret) { 399662306a36Sopenharmony_ci ath12k_warn(ar->ab, "could not set uapsd params %d\n", ret); 399762306a36Sopenharmony_ci goto exit; 399862306a36Sopenharmony_ci } 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_ci if (arvif->u.sta.uapsd) 400162306a36Sopenharmony_ci value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; 400262306a36Sopenharmony_ci else 400362306a36Sopenharmony_ci value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 400662306a36Sopenharmony_ci WMI_STA_PS_PARAM_RX_WAKE_POLICY, 400762306a36Sopenharmony_ci value); 400862306a36Sopenharmony_ci if (ret) 400962306a36Sopenharmony_ci ath12k_warn(ar->ab, "could not set rx wake param %d\n", ret); 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ciexit: 401262306a36Sopenharmony_ci return ret; 401362306a36Sopenharmony_ci} 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_cistatic int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, 401662306a36Sopenharmony_ci struct ieee80211_vif *vif, 401762306a36Sopenharmony_ci unsigned int link_id, u16 ac, 401862306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 401962306a36Sopenharmony_ci{ 402062306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 402162306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 402262306a36Sopenharmony_ci struct wmi_wmm_params_arg *p = NULL; 402362306a36Sopenharmony_ci int ret; 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci switch (ac) { 402862306a36Sopenharmony_ci case IEEE80211_AC_VO: 402962306a36Sopenharmony_ci p = &arvif->wmm_params.ac_vo; 403062306a36Sopenharmony_ci break; 403162306a36Sopenharmony_ci case IEEE80211_AC_VI: 403262306a36Sopenharmony_ci p = &arvif->wmm_params.ac_vi; 403362306a36Sopenharmony_ci break; 403462306a36Sopenharmony_ci case IEEE80211_AC_BE: 403562306a36Sopenharmony_ci p = &arvif->wmm_params.ac_be; 403662306a36Sopenharmony_ci break; 403762306a36Sopenharmony_ci case IEEE80211_AC_BK: 403862306a36Sopenharmony_ci p = &arvif->wmm_params.ac_bk; 403962306a36Sopenharmony_ci break; 404062306a36Sopenharmony_ci } 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_ci if (WARN_ON(!p)) { 404362306a36Sopenharmony_ci ret = -EINVAL; 404462306a36Sopenharmony_ci goto exit; 404562306a36Sopenharmony_ci } 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_ci p->cwmin = params->cw_min; 404862306a36Sopenharmony_ci p->cwmax = params->cw_max; 404962306a36Sopenharmony_ci p->aifs = params->aifs; 405062306a36Sopenharmony_ci p->txop = params->txop; 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_ci ret = ath12k_wmi_send_wmm_update_cmd(ar, arvif->vdev_id, 405362306a36Sopenharmony_ci &arvif->wmm_params); 405462306a36Sopenharmony_ci if (ret) { 405562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set wmm params: %d\n", ret); 405662306a36Sopenharmony_ci goto exit; 405762306a36Sopenharmony_ci } 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_ci ret = ath12k_conf_tx_uapsd(ar, vif, ac, params->uapsd); 406062306a36Sopenharmony_ci 406162306a36Sopenharmony_ci if (ret) 406262306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set sta uapsd: %d\n", ret); 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ciexit: 406562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 406662306a36Sopenharmony_ci return ret; 406762306a36Sopenharmony_ci} 406862306a36Sopenharmony_ci 406962306a36Sopenharmony_cistatic struct ieee80211_sta_ht_cap 407062306a36Sopenharmony_ciath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask) 407162306a36Sopenharmony_ci{ 407262306a36Sopenharmony_ci int i; 407362306a36Sopenharmony_ci struct ieee80211_sta_ht_cap ht_cap = {0}; 407462306a36Sopenharmony_ci u32 ar_vht_cap = ar->pdev->cap.vht_cap; 407562306a36Sopenharmony_ci 407662306a36Sopenharmony_ci if (!(ar_ht_cap & WMI_HT_CAP_ENABLED)) 407762306a36Sopenharmony_ci return ht_cap; 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci ht_cap.ht_supported = 1; 408062306a36Sopenharmony_ci ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 408162306a36Sopenharmony_ci ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; 408262306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; 408362306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; 408462306a36Sopenharmony_ci ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT; 408562306a36Sopenharmony_ci 408662306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_HT20_SGI) 408762306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_HT40_SGI) 409062306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; 409162306a36Sopenharmony_ci 409262306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) { 409362306a36Sopenharmony_ci u32 smps; 409462306a36Sopenharmony_ci 409562306a36Sopenharmony_ci smps = WLAN_HT_CAP_SM_PS_DYNAMIC; 409662306a36Sopenharmony_ci smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT; 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_ci ht_cap.cap |= smps; 409962306a36Sopenharmony_ci } 410062306a36Sopenharmony_ci 410162306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_TX_STBC) 410262306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_RX_STBC) { 410562306a36Sopenharmony_ci u32 stbc; 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_ci stbc = ar_ht_cap; 410862306a36Sopenharmony_ci stbc &= WMI_HT_CAP_RX_STBC; 410962306a36Sopenharmony_ci stbc >>= WMI_HT_CAP_RX_STBC_MASK_SHIFT; 411062306a36Sopenharmony_ci stbc <<= IEEE80211_HT_CAP_RX_STBC_SHIFT; 411162306a36Sopenharmony_ci stbc &= IEEE80211_HT_CAP_RX_STBC; 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci ht_cap.cap |= stbc; 411462306a36Sopenharmony_ci } 411562306a36Sopenharmony_ci 411662306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_RX_LDPC) 411762306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_ci if (ar_ht_cap & WMI_HT_CAP_L_SIG_TXOP_PROT) 412062306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_LSIG_TXOP_PROT; 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ci if (ar_vht_cap & WMI_VHT_CAP_MAX_MPDU_LEN_MASK) 412362306a36Sopenharmony_ci ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU; 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_ci for (i = 0; i < ar->num_rx_chains; i++) { 412662306a36Sopenharmony_ci if (rate_cap_rx_chainmask & BIT(i)) 412762306a36Sopenharmony_ci ht_cap.mcs.rx_mask[i] = 0xFF; 412862306a36Sopenharmony_ci } 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED; 413162306a36Sopenharmony_ci 413262306a36Sopenharmony_ci return ht_cap; 413362306a36Sopenharmony_ci} 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_cistatic int ath12k_mac_set_txbf_conf(struct ath12k_vif *arvif) 413662306a36Sopenharmony_ci{ 413762306a36Sopenharmony_ci u32 value = 0; 413862306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 413962306a36Sopenharmony_ci int nsts; 414062306a36Sopenharmony_ci int sound_dim; 414162306a36Sopenharmony_ci u32 vht_cap = ar->pdev->cap.vht_cap; 414262306a36Sopenharmony_ci u32 vdev_param = WMI_VDEV_PARAM_TXBF; 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_ci if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) { 414562306a36Sopenharmony_ci nsts = vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; 414662306a36Sopenharmony_ci nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; 414762306a36Sopenharmony_ci value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET); 414862306a36Sopenharmony_ci } 414962306a36Sopenharmony_ci 415062306a36Sopenharmony_ci if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { 415162306a36Sopenharmony_ci sound_dim = vht_cap & 415262306a36Sopenharmony_ci IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; 415362306a36Sopenharmony_ci sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; 415462306a36Sopenharmony_ci if (sound_dim > (ar->num_tx_chains - 1)) 415562306a36Sopenharmony_ci sound_dim = ar->num_tx_chains - 1; 415662306a36Sopenharmony_ci value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET); 415762306a36Sopenharmony_ci } 415862306a36Sopenharmony_ci 415962306a36Sopenharmony_ci if (!value) 416062306a36Sopenharmony_ci return 0; 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ci if (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) { 416362306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER; 416462306a36Sopenharmony_ci 416562306a36Sopenharmony_ci if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) && 416662306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_AP) 416762306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER; 416862306a36Sopenharmony_ci } 416962306a36Sopenharmony_ci 417062306a36Sopenharmony_ci if (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { 417162306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE; 417262306a36Sopenharmony_ci 417362306a36Sopenharmony_ci if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && 417462306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_STA) 417562306a36Sopenharmony_ci value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE; 417662306a36Sopenharmony_ci } 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ci return ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 417962306a36Sopenharmony_ci vdev_param, value); 418062306a36Sopenharmony_ci} 418162306a36Sopenharmony_ci 418262306a36Sopenharmony_cistatic void ath12k_set_vht_txbf_cap(struct ath12k *ar, u32 *vht_cap) 418362306a36Sopenharmony_ci{ 418462306a36Sopenharmony_ci bool subfer, subfee; 418562306a36Sopenharmony_ci int sound_dim = 0; 418662306a36Sopenharmony_ci 418762306a36Sopenharmony_ci subfer = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)); 418862306a36Sopenharmony_ci subfee = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)); 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci if (ar->num_tx_chains < 2) { 419162306a36Sopenharmony_ci *vht_cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE); 419262306a36Sopenharmony_ci subfer = false; 419362306a36Sopenharmony_ci } 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci /* If SU Beaformer is not set, then disable MU Beamformer Capability */ 419662306a36Sopenharmony_ci if (!subfer) 419762306a36Sopenharmony_ci *vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE); 419862306a36Sopenharmony_ci 419962306a36Sopenharmony_ci /* If SU Beaformee is not set, then disable MU Beamformee Capability */ 420062306a36Sopenharmony_ci if (!subfee) 420162306a36Sopenharmony_ci *vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci sound_dim = u32_get_bits(*vht_cap, 420462306a36Sopenharmony_ci IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); 420562306a36Sopenharmony_ci *vht_cap = u32_replace_bits(*vht_cap, 0, 420662306a36Sopenharmony_ci IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ci /* TODO: Need to check invalid STS and Sound_dim values set by FW? */ 420962306a36Sopenharmony_ci 421062306a36Sopenharmony_ci /* Enable Sounding Dimension Field only if SU BF is enabled */ 421162306a36Sopenharmony_ci if (subfer) { 421262306a36Sopenharmony_ci if (sound_dim > (ar->num_tx_chains - 1)) 421362306a36Sopenharmony_ci sound_dim = ar->num_tx_chains - 1; 421462306a36Sopenharmony_ci 421562306a36Sopenharmony_ci *vht_cap = u32_replace_bits(*vht_cap, sound_dim, 421662306a36Sopenharmony_ci IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); 421762306a36Sopenharmony_ci } 421862306a36Sopenharmony_ci 421962306a36Sopenharmony_ci /* Use the STS advertised by FW unless SU Beamformee is not supported*/ 422062306a36Sopenharmony_ci if (!subfee) 422162306a36Sopenharmony_ci *vht_cap &= ~(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK); 422262306a36Sopenharmony_ci} 422362306a36Sopenharmony_ci 422462306a36Sopenharmony_cistatic struct ieee80211_sta_vht_cap 422562306a36Sopenharmony_ciath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, 422662306a36Sopenharmony_ci u32 rate_cap_rx_chainmask) 422762306a36Sopenharmony_ci{ 422862306a36Sopenharmony_ci struct ieee80211_sta_vht_cap vht_cap = {0}; 422962306a36Sopenharmony_ci u16 txmcs_map, rxmcs_map; 423062306a36Sopenharmony_ci int i; 423162306a36Sopenharmony_ci 423262306a36Sopenharmony_ci vht_cap.vht_supported = 1; 423362306a36Sopenharmony_ci vht_cap.cap = ar->pdev->cap.vht_cap; 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_ci ath12k_set_vht_txbf_cap(ar, &vht_cap.cap); 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci /* TODO: Enable back VHT160 mode once association issues are fixed */ 423862306a36Sopenharmony_ci /* Disabling VHT160 and VHT80+80 modes */ 423962306a36Sopenharmony_ci vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; 424062306a36Sopenharmony_ci vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci rxmcs_map = 0; 424362306a36Sopenharmony_ci txmcs_map = 0; 424462306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 424562306a36Sopenharmony_ci if (i < ar->num_tx_chains && rate_cap_tx_chainmask & BIT(i)) 424662306a36Sopenharmony_ci txmcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2); 424762306a36Sopenharmony_ci else 424862306a36Sopenharmony_ci txmcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci if (i < ar->num_rx_chains && rate_cap_rx_chainmask & BIT(i)) 425162306a36Sopenharmony_ci rxmcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2); 425262306a36Sopenharmony_ci else 425362306a36Sopenharmony_ci rxmcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2); 425462306a36Sopenharmony_ci } 425562306a36Sopenharmony_ci 425662306a36Sopenharmony_ci if (rate_cap_tx_chainmask <= 1) 425762306a36Sopenharmony_ci vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC; 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_ci vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_map); 426062306a36Sopenharmony_ci vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_map); 426162306a36Sopenharmony_ci 426262306a36Sopenharmony_ci return vht_cap; 426362306a36Sopenharmony_ci} 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_cistatic void ath12k_mac_setup_ht_vht_cap(struct ath12k *ar, 426662306a36Sopenharmony_ci struct ath12k_pdev_cap *cap, 426762306a36Sopenharmony_ci u32 *ht_cap_info) 426862306a36Sopenharmony_ci{ 426962306a36Sopenharmony_ci struct ieee80211_supported_band *band; 427062306a36Sopenharmony_ci u32 rate_cap_tx_chainmask; 427162306a36Sopenharmony_ci u32 rate_cap_rx_chainmask; 427262306a36Sopenharmony_ci u32 ht_cap; 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci rate_cap_tx_chainmask = ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift; 427562306a36Sopenharmony_ci rate_cap_rx_chainmask = ar->cfg_rx_chainmask >> cap->rx_chain_mask_shift; 427662306a36Sopenharmony_ci 427762306a36Sopenharmony_ci if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) { 427862306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_2GHZ]; 427962306a36Sopenharmony_ci ht_cap = cap->band[NL80211_BAND_2GHZ].ht_cap_info; 428062306a36Sopenharmony_ci if (ht_cap_info) 428162306a36Sopenharmony_ci *ht_cap_info = ht_cap; 428262306a36Sopenharmony_ci band->ht_cap = ath12k_create_ht_cap(ar, ht_cap, 428362306a36Sopenharmony_ci rate_cap_rx_chainmask); 428462306a36Sopenharmony_ci } 428562306a36Sopenharmony_ci 428662306a36Sopenharmony_ci if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && 428762306a36Sopenharmony_ci (ar->ab->hw_params->single_pdev_only || 428862306a36Sopenharmony_ci !ar->supports_6ghz)) { 428962306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_5GHZ]; 429062306a36Sopenharmony_ci ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info; 429162306a36Sopenharmony_ci if (ht_cap_info) 429262306a36Sopenharmony_ci *ht_cap_info = ht_cap; 429362306a36Sopenharmony_ci band->ht_cap = ath12k_create_ht_cap(ar, ht_cap, 429462306a36Sopenharmony_ci rate_cap_rx_chainmask); 429562306a36Sopenharmony_ci band->vht_cap = ath12k_create_vht_cap(ar, rate_cap_tx_chainmask, 429662306a36Sopenharmony_ci rate_cap_rx_chainmask); 429762306a36Sopenharmony_ci } 429862306a36Sopenharmony_ci} 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_cistatic int ath12k_check_chain_mask(struct ath12k *ar, u32 ant, bool is_tx_ant) 430162306a36Sopenharmony_ci{ 430262306a36Sopenharmony_ci /* TODO: Check the request chainmask against the supported 430362306a36Sopenharmony_ci * chainmask table which is advertised in extented_service_ready event 430462306a36Sopenharmony_ci */ 430562306a36Sopenharmony_ci 430662306a36Sopenharmony_ci return 0; 430762306a36Sopenharmony_ci} 430862306a36Sopenharmony_ci 430962306a36Sopenharmony_cistatic void ath12k_gen_ppe_thresh(struct ath12k_wmi_ppe_threshold_arg *fw_ppet, 431062306a36Sopenharmony_ci u8 *he_ppet) 431162306a36Sopenharmony_ci{ 431262306a36Sopenharmony_ci int nss, ru; 431362306a36Sopenharmony_ci u8 bit = 7; 431462306a36Sopenharmony_ci 431562306a36Sopenharmony_ci he_ppet[0] = fw_ppet->numss_m1 & IEEE80211_PPE_THRES_NSS_MASK; 431662306a36Sopenharmony_ci he_ppet[0] |= (fw_ppet->ru_bit_mask << 431762306a36Sopenharmony_ci IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) & 431862306a36Sopenharmony_ci IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK; 431962306a36Sopenharmony_ci for (nss = 0; nss <= fw_ppet->numss_m1; nss++) { 432062306a36Sopenharmony_ci for (ru = 0; ru < 4; ru++) { 432162306a36Sopenharmony_ci u8 val; 432262306a36Sopenharmony_ci int i; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci if ((fw_ppet->ru_bit_mask & BIT(ru)) == 0) 432562306a36Sopenharmony_ci continue; 432662306a36Sopenharmony_ci val = (fw_ppet->ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) & 432762306a36Sopenharmony_ci 0x3f; 432862306a36Sopenharmony_ci val = ((val >> 3) & 0x7) | ((val & 0x7) << 3); 432962306a36Sopenharmony_ci for (i = 5; i >= 0; i--) { 433062306a36Sopenharmony_ci he_ppet[bit / 8] |= 433162306a36Sopenharmony_ci ((val >> i) & 0x1) << ((bit % 8)); 433262306a36Sopenharmony_ci bit++; 433362306a36Sopenharmony_ci } 433462306a36Sopenharmony_ci } 433562306a36Sopenharmony_ci } 433662306a36Sopenharmony_ci} 433762306a36Sopenharmony_ci 433862306a36Sopenharmony_cistatic void 433962306a36Sopenharmony_ciath12k_mac_filter_he_cap_mesh(struct ieee80211_he_cap_elem *he_cap_elem) 434062306a36Sopenharmony_ci{ 434162306a36Sopenharmony_ci u8 m; 434262306a36Sopenharmony_ci 434362306a36Sopenharmony_ci m = IEEE80211_HE_MAC_CAP0_TWT_RES | 434462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP0_TWT_REQ; 434562306a36Sopenharmony_ci he_cap_elem->mac_cap_info[0] &= ~m; 434662306a36Sopenharmony_ci 434762306a36Sopenharmony_ci m = IEEE80211_HE_MAC_CAP2_TRS | 434862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BCAST_TWT | 434962306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING; 435062306a36Sopenharmony_ci he_cap_elem->mac_cap_info[2] &= ~m; 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ci m = IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED | 435362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_BCAST_TWT | 435462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP2_MU_CASCADING; 435562306a36Sopenharmony_ci he_cap_elem->mac_cap_info[3] &= ~m; 435662306a36Sopenharmony_ci 435762306a36Sopenharmony_ci m = IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG | 435862306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP4_BQR; 435962306a36Sopenharmony_ci he_cap_elem->mac_cap_info[4] &= ~m; 436062306a36Sopenharmony_ci 436162306a36Sopenharmony_ci m = IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECTIVE_TRANSMISSION | 436262306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | 436362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING | 436462306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; 436562306a36Sopenharmony_ci he_cap_elem->mac_cap_info[5] &= ~m; 436662306a36Sopenharmony_ci 436762306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | 436862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; 436962306a36Sopenharmony_ci he_cap_elem->phy_cap_info[2] &= ~m; 437062306a36Sopenharmony_ci 437162306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU | 437262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK | 437362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK; 437462306a36Sopenharmony_ci he_cap_elem->phy_cap_info[3] &= ~m; 437562306a36Sopenharmony_ci 437662306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; 437762306a36Sopenharmony_ci he_cap_elem->phy_cap_info[4] &= ~m; 437862306a36Sopenharmony_ci 437962306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; 438062306a36Sopenharmony_ci he_cap_elem->phy_cap_info[5] &= ~m; 438162306a36Sopenharmony_ci 438262306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | 438362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | 438462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | 438562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; 438662306a36Sopenharmony_ci he_cap_elem->phy_cap_info[6] &= ~m; 438762306a36Sopenharmony_ci 438862306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP7_PSR_BASED_SR | 438962306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | 439062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | 439162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; 439262306a36Sopenharmony_ci he_cap_elem->phy_cap_info[7] &= ~m; 439362306a36Sopenharmony_ci 439462306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | 439562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | 439662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | 439762306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; 439862306a36Sopenharmony_ci he_cap_elem->phy_cap_info[8] &= ~m; 439962306a36Sopenharmony_ci 440062306a36Sopenharmony_ci m = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | 440162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | 440262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | 440362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | 440462306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | 440562306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; 440662306a36Sopenharmony_ci he_cap_elem->phy_cap_info[9] &= ~m; 440762306a36Sopenharmony_ci} 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_cistatic __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap, 441062306a36Sopenharmony_ci struct ath12k_band_cap *bcap) 441162306a36Sopenharmony_ci{ 441262306a36Sopenharmony_ci u8 val; 441362306a36Sopenharmony_ci 441462306a36Sopenharmony_ci bcap->he_6ghz_capa = IEEE80211_HT_MPDU_DENSITY_NONE; 441562306a36Sopenharmony_ci if (bcap->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) 441662306a36Sopenharmony_ci bcap->he_6ghz_capa |= 441762306a36Sopenharmony_ci u32_encode_bits(WLAN_HT_CAP_SM_PS_DYNAMIC, 441862306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_SM_PS); 441962306a36Sopenharmony_ci else 442062306a36Sopenharmony_ci bcap->he_6ghz_capa |= 442162306a36Sopenharmony_ci u32_encode_bits(WLAN_HT_CAP_SM_PS_DISABLED, 442262306a36Sopenharmony_ci IEEE80211_HE_6GHZ_CAP_SM_PS); 442362306a36Sopenharmony_ci val = u32_get_bits(pcap->vht_cap, 442462306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); 442562306a36Sopenharmony_ci bcap->he_6ghz_capa |= 442662306a36Sopenharmony_ci u32_encode_bits(val, IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP); 442762306a36Sopenharmony_ci val = u32_get_bits(pcap->vht_cap, 442862306a36Sopenharmony_ci IEEE80211_VHT_CAP_MAX_MPDU_MASK); 442962306a36Sopenharmony_ci bcap->he_6ghz_capa |= 443062306a36Sopenharmony_ci u32_encode_bits(val, IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); 443162306a36Sopenharmony_ci if (pcap->vht_cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN) 443262306a36Sopenharmony_ci bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; 443362306a36Sopenharmony_ci if (pcap->vht_cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN) 443462306a36Sopenharmony_ci bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS; 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci return cpu_to_le16(bcap->he_6ghz_capa); 443762306a36Sopenharmony_ci} 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_cistatic void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, 444062306a36Sopenharmony_ci int iftype, u8 num_tx_chains, 444162306a36Sopenharmony_ci struct ieee80211_sta_he_cap *he_cap) 444262306a36Sopenharmony_ci{ 444362306a36Sopenharmony_ci struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; 444462306a36Sopenharmony_ci struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; 444562306a36Sopenharmony_ci 444662306a36Sopenharmony_ci he_cap->has_he = true; 444762306a36Sopenharmony_ci memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info, 444862306a36Sopenharmony_ci sizeof(he_cap_elem->mac_cap_info)); 444962306a36Sopenharmony_ci memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info, 445062306a36Sopenharmony_ci sizeof(he_cap_elem->phy_cap_info)); 445162306a36Sopenharmony_ci 445262306a36Sopenharmony_ci he_cap_elem->mac_cap_info[1] &= 445362306a36Sopenharmony_ci IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; 445462306a36Sopenharmony_ci 445562306a36Sopenharmony_ci he_cap_elem->phy_cap_info[5] &= 445662306a36Sopenharmony_ci ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; 445762306a36Sopenharmony_ci he_cap_elem->phy_cap_info[5] &= 445862306a36Sopenharmony_ci ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; 445962306a36Sopenharmony_ci he_cap_elem->phy_cap_info[5] |= num_tx_chains - 1; 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci switch (iftype) { 446262306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 446362306a36Sopenharmony_ci he_cap_elem->phy_cap_info[3] &= 446462306a36Sopenharmony_ci ~IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK; 446562306a36Sopenharmony_ci he_cap_elem->phy_cap_info[9] |= 446662306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; 446762306a36Sopenharmony_ci break; 446862306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 446962306a36Sopenharmony_ci he_cap_elem->mac_cap_info[0] &= ~IEEE80211_HE_MAC_CAP0_TWT_RES; 447062306a36Sopenharmony_ci he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; 447162306a36Sopenharmony_ci he_cap_elem->phy_cap_info[9] |= 447262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; 447362306a36Sopenharmony_ci break; 447462306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 447562306a36Sopenharmony_ci ath12k_mac_filter_he_cap_mesh(he_cap_elem); 447662306a36Sopenharmony_ci break; 447762306a36Sopenharmony_ci } 447862306a36Sopenharmony_ci 447962306a36Sopenharmony_ci mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); 448062306a36Sopenharmony_ci mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); 448162306a36Sopenharmony_ci mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); 448262306a36Sopenharmony_ci mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); 448362306a36Sopenharmony_ci mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); 448462306a36Sopenharmony_ci mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); 448562306a36Sopenharmony_ci 448662306a36Sopenharmony_ci memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); 448762306a36Sopenharmony_ci if (he_cap_elem->phy_cap_info[6] & 448862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) 448962306a36Sopenharmony_ci ath12k_gen_ppe_thresh(&band_cap->he_ppet, he_cap->ppe_thres); 449062306a36Sopenharmony_ci} 449162306a36Sopenharmony_ci 449262306a36Sopenharmony_cistatic void 449362306a36Sopenharmony_ciath12k_mac_copy_eht_mcs_nss(struct ath12k_band_cap *band_cap, 449462306a36Sopenharmony_ci struct ieee80211_eht_mcs_nss_supp *mcs_nss, 449562306a36Sopenharmony_ci const struct ieee80211_he_cap_elem *he_cap, 449662306a36Sopenharmony_ci const struct ieee80211_eht_cap_elem_fixed *eht_cap) 449762306a36Sopenharmony_ci{ 449862306a36Sopenharmony_ci if ((he_cap->phy_cap_info[0] & 449962306a36Sopenharmony_ci (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | 450062306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | 450162306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | 450262306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) 450362306a36Sopenharmony_ci memcpy(&mcs_nss->only_20mhz, &band_cap->eht_mcs_20_only, 450462306a36Sopenharmony_ci sizeof(struct ieee80211_eht_mcs_nss_supp_20mhz_only)); 450562306a36Sopenharmony_ci 450662306a36Sopenharmony_ci if (he_cap->phy_cap_info[0] & 450762306a36Sopenharmony_ci (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | 450862306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) 450962306a36Sopenharmony_ci memcpy(&mcs_nss->bw._80, &band_cap->eht_mcs_80, 451062306a36Sopenharmony_ci sizeof(struct ieee80211_eht_mcs_nss_supp_bw)); 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci if (he_cap->phy_cap_info[0] & 451362306a36Sopenharmony_ci IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) 451462306a36Sopenharmony_ci memcpy(&mcs_nss->bw._160, &band_cap->eht_mcs_160, 451562306a36Sopenharmony_ci sizeof(struct ieee80211_eht_mcs_nss_supp_bw)); 451662306a36Sopenharmony_ci 451762306a36Sopenharmony_ci if (eht_cap->phy_cap_info[0] & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) 451862306a36Sopenharmony_ci memcpy(&mcs_nss->bw._320, &band_cap->eht_mcs_320, 451962306a36Sopenharmony_ci sizeof(struct ieee80211_eht_mcs_nss_supp_bw)); 452062306a36Sopenharmony_ci} 452162306a36Sopenharmony_ci 452262306a36Sopenharmony_cistatic void ath12k_mac_copy_eht_ppe_thresh(struct ath12k_wmi_ppe_threshold_arg *fw_ppet, 452362306a36Sopenharmony_ci struct ieee80211_sta_eht_cap *cap) 452462306a36Sopenharmony_ci{ 452562306a36Sopenharmony_ci u16 bit = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE; 452662306a36Sopenharmony_ci u8 i, nss, ru, ppet_bit_len_per_ru = IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci u8p_replace_bits(&cap->eht_ppe_thres[0], fw_ppet->numss_m1, 452962306a36Sopenharmony_ci IEEE80211_EHT_PPE_THRES_NSS_MASK); 453062306a36Sopenharmony_ci 453162306a36Sopenharmony_ci u16p_replace_bits((u16 *)&cap->eht_ppe_thres[0], fw_ppet->ru_bit_mask, 453262306a36Sopenharmony_ci IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); 453362306a36Sopenharmony_ci 453462306a36Sopenharmony_ci for (nss = 0; nss <= fw_ppet->numss_m1; nss++) { 453562306a36Sopenharmony_ci for (ru = 0; 453662306a36Sopenharmony_ci ru < hweight16(IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); 453762306a36Sopenharmony_ci ru++) { 453862306a36Sopenharmony_ci u32 val = 0; 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci if ((fw_ppet->ru_bit_mask & BIT(ru)) == 0) 454162306a36Sopenharmony_ci continue; 454262306a36Sopenharmony_ci 454362306a36Sopenharmony_ci u32p_replace_bits(&val, fw_ppet->ppet16_ppet8_ru3_ru0[nss] >> 454462306a36Sopenharmony_ci (ru * ppet_bit_len_per_ru), 454562306a36Sopenharmony_ci GENMASK(ppet_bit_len_per_ru - 1, 0)); 454662306a36Sopenharmony_ci 454762306a36Sopenharmony_ci for (i = 0; i < ppet_bit_len_per_ru; i++) { 454862306a36Sopenharmony_ci cap->eht_ppe_thres[bit / 8] |= 454962306a36Sopenharmony_ci (((val >> i) & 0x1) << ((bit % 8))); 455062306a36Sopenharmony_ci bit++; 455162306a36Sopenharmony_ci } 455262306a36Sopenharmony_ci } 455362306a36Sopenharmony_ci } 455462306a36Sopenharmony_ci} 455562306a36Sopenharmony_ci 455662306a36Sopenharmony_cistatic void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap, 455762306a36Sopenharmony_ci struct ieee80211_he_cap_elem *he_cap_elem, 455862306a36Sopenharmony_ci int iftype, 455962306a36Sopenharmony_ci struct ieee80211_sta_eht_cap *eht_cap) 456062306a36Sopenharmony_ci{ 456162306a36Sopenharmony_ci struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; 456262306a36Sopenharmony_ci 456362306a36Sopenharmony_ci memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap)); 456462306a36Sopenharmony_ci eht_cap->has_eht = true; 456562306a36Sopenharmony_ci memcpy(eht_cap_elem->mac_cap_info, band_cap->eht_cap_mac_info, 456662306a36Sopenharmony_ci sizeof(eht_cap_elem->mac_cap_info)); 456762306a36Sopenharmony_ci memcpy(eht_cap_elem->phy_cap_info, band_cap->eht_cap_phy_info, 456862306a36Sopenharmony_ci sizeof(eht_cap_elem->phy_cap_info)); 456962306a36Sopenharmony_ci 457062306a36Sopenharmony_ci switch (iftype) { 457162306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 457262306a36Sopenharmony_ci eht_cap_elem->phy_cap_info[0] &= 457362306a36Sopenharmony_ci ~IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ; 457462306a36Sopenharmony_ci eht_cap_elem->phy_cap_info[4] &= 457562306a36Sopenharmony_ci ~IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO; 457662306a36Sopenharmony_ci eht_cap_elem->phy_cap_info[5] &= 457762306a36Sopenharmony_ci ~IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP; 457862306a36Sopenharmony_ci break; 457962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 458062306a36Sopenharmony_ci eht_cap_elem->phy_cap_info[7] &= 458162306a36Sopenharmony_ci ~(IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ | 458262306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ | 458362306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ); 458462306a36Sopenharmony_ci eht_cap_elem->phy_cap_info[7] &= 458562306a36Sopenharmony_ci ~(IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ | 458662306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ | 458762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ); 458862306a36Sopenharmony_ci break; 458962306a36Sopenharmony_ci default: 459062306a36Sopenharmony_ci break; 459162306a36Sopenharmony_ci } 459262306a36Sopenharmony_ci 459362306a36Sopenharmony_ci ath12k_mac_copy_eht_mcs_nss(band_cap, &eht_cap->eht_mcs_nss_supp, 459462306a36Sopenharmony_ci he_cap_elem, eht_cap_elem); 459562306a36Sopenharmony_ci 459662306a36Sopenharmony_ci if (eht_cap_elem->phy_cap_info[5] & 459762306a36Sopenharmony_ci IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT) 459862306a36Sopenharmony_ci ath12k_mac_copy_eht_ppe_thresh(&band_cap->eht_ppet, eht_cap); 459962306a36Sopenharmony_ci} 460062306a36Sopenharmony_ci 460162306a36Sopenharmony_cistatic int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, 460262306a36Sopenharmony_ci struct ath12k_pdev_cap *cap, 460362306a36Sopenharmony_ci struct ieee80211_sband_iftype_data *data, 460462306a36Sopenharmony_ci int band) 460562306a36Sopenharmony_ci{ 460662306a36Sopenharmony_ci struct ath12k_band_cap *band_cap = &cap->band[band]; 460762306a36Sopenharmony_ci int i, idx = 0; 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci for (i = 0; i < NUM_NL80211_IFTYPES; i++) { 461062306a36Sopenharmony_ci struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap; 461162306a36Sopenharmony_ci 461262306a36Sopenharmony_ci switch (i) { 461362306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 461462306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 461562306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 461662306a36Sopenharmony_ci break; 461762306a36Sopenharmony_ci 461862306a36Sopenharmony_ci default: 461962306a36Sopenharmony_ci continue; 462062306a36Sopenharmony_ci } 462162306a36Sopenharmony_ci 462262306a36Sopenharmony_ci data[idx].types_mask = BIT(i); 462362306a36Sopenharmony_ci 462462306a36Sopenharmony_ci ath12k_mac_copy_he_cap(band_cap, i, ar->num_tx_chains, he_cap); 462562306a36Sopenharmony_ci if (band == NL80211_BAND_6GHZ) { 462662306a36Sopenharmony_ci data[idx].he_6ghz_capa.capa = 462762306a36Sopenharmony_ci ath12k_mac_setup_he_6ghz_cap(cap, band_cap); 462862306a36Sopenharmony_ci } 462962306a36Sopenharmony_ci ath12k_mac_copy_eht_cap(band_cap, &he_cap->he_cap_elem, i, 463062306a36Sopenharmony_ci &data[idx].eht_cap); 463162306a36Sopenharmony_ci idx++; 463262306a36Sopenharmony_ci } 463362306a36Sopenharmony_ci 463462306a36Sopenharmony_ci return idx; 463562306a36Sopenharmony_ci} 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_cistatic void ath12k_mac_setup_sband_iftype_data(struct ath12k *ar, 463862306a36Sopenharmony_ci struct ath12k_pdev_cap *cap) 463962306a36Sopenharmony_ci{ 464062306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 464162306a36Sopenharmony_ci enum nl80211_band band; 464262306a36Sopenharmony_ci int count; 464362306a36Sopenharmony_ci 464462306a36Sopenharmony_ci if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) { 464562306a36Sopenharmony_ci band = NL80211_BAND_2GHZ; 464662306a36Sopenharmony_ci count = ath12k_mac_copy_sband_iftype_data(ar, cap, 464762306a36Sopenharmony_ci ar->mac.iftype[band], 464862306a36Sopenharmony_ci band); 464962306a36Sopenharmony_ci sband = &ar->mac.sbands[band]; 465062306a36Sopenharmony_ci sband->iftype_data = ar->mac.iftype[band]; 465162306a36Sopenharmony_ci sband->n_iftype_data = count; 465262306a36Sopenharmony_ci } 465362306a36Sopenharmony_ci 465462306a36Sopenharmony_ci if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) { 465562306a36Sopenharmony_ci band = NL80211_BAND_5GHZ; 465662306a36Sopenharmony_ci count = ath12k_mac_copy_sband_iftype_data(ar, cap, 465762306a36Sopenharmony_ci ar->mac.iftype[band], 465862306a36Sopenharmony_ci band); 465962306a36Sopenharmony_ci sband = &ar->mac.sbands[band]; 466062306a36Sopenharmony_ci sband->iftype_data = ar->mac.iftype[band]; 466162306a36Sopenharmony_ci sband->n_iftype_data = count; 466262306a36Sopenharmony_ci } 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_ci if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && 466562306a36Sopenharmony_ci ar->supports_6ghz) { 466662306a36Sopenharmony_ci band = NL80211_BAND_6GHZ; 466762306a36Sopenharmony_ci count = ath12k_mac_copy_sband_iftype_data(ar, cap, 466862306a36Sopenharmony_ci ar->mac.iftype[band], 466962306a36Sopenharmony_ci band); 467062306a36Sopenharmony_ci sband = &ar->mac.sbands[band]; 467162306a36Sopenharmony_ci sband->iftype_data = ar->mac.iftype[band]; 467262306a36Sopenharmony_ci sband->n_iftype_data = count; 467362306a36Sopenharmony_ci } 467462306a36Sopenharmony_ci} 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_cistatic int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) 467762306a36Sopenharmony_ci{ 467862306a36Sopenharmony_ci int ret; 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci if (ath12k_check_chain_mask(ar, tx_ant, true)) 468362306a36Sopenharmony_ci return -EINVAL; 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci if (ath12k_check_chain_mask(ar, rx_ant, false)) 468662306a36Sopenharmony_ci return -EINVAL; 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci ar->cfg_tx_chainmask = tx_ant; 468962306a36Sopenharmony_ci ar->cfg_rx_chainmask = rx_ant; 469062306a36Sopenharmony_ci 469162306a36Sopenharmony_ci if (ar->state != ATH12K_STATE_ON && 469262306a36Sopenharmony_ci ar->state != ATH12K_STATE_RESTARTED) 469362306a36Sopenharmony_ci return 0; 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_TX_CHAIN_MASK, 469662306a36Sopenharmony_ci tx_ant, ar->pdev->pdev_id); 469762306a36Sopenharmony_ci if (ret) { 469862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set tx-chainmask: %d, req 0x%x\n", 469962306a36Sopenharmony_ci ret, tx_ant); 470062306a36Sopenharmony_ci return ret; 470162306a36Sopenharmony_ci } 470262306a36Sopenharmony_ci 470362306a36Sopenharmony_ci ar->num_tx_chains = hweight32(tx_ant); 470462306a36Sopenharmony_ci 470562306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RX_CHAIN_MASK, 470662306a36Sopenharmony_ci rx_ant, ar->pdev->pdev_id); 470762306a36Sopenharmony_ci if (ret) { 470862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set rx-chainmask: %d, req 0x%x\n", 470962306a36Sopenharmony_ci ret, rx_ant); 471062306a36Sopenharmony_ci return ret; 471162306a36Sopenharmony_ci } 471262306a36Sopenharmony_ci 471362306a36Sopenharmony_ci ar->num_rx_chains = hweight32(rx_ant); 471462306a36Sopenharmony_ci 471562306a36Sopenharmony_ci /* Reload HT/VHT/HE capability */ 471662306a36Sopenharmony_ci ath12k_mac_setup_ht_vht_cap(ar, &ar->pdev->cap, NULL); 471762306a36Sopenharmony_ci ath12k_mac_setup_sband_iftype_data(ar, &ar->pdev->cap); 471862306a36Sopenharmony_ci 471962306a36Sopenharmony_ci return 0; 472062306a36Sopenharmony_ci} 472162306a36Sopenharmony_ci 472262306a36Sopenharmony_cistatic void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb) 472362306a36Sopenharmony_ci{ 472462306a36Sopenharmony_ci int num_mgmt; 472562306a36Sopenharmony_ci 472662306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 472762306a36Sopenharmony_ci 472862306a36Sopenharmony_ci num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); 472962306a36Sopenharmony_ci 473062306a36Sopenharmony_ci if (num_mgmt < 0) 473162306a36Sopenharmony_ci WARN_ON_ONCE(1); 473262306a36Sopenharmony_ci 473362306a36Sopenharmony_ci if (!num_mgmt) 473462306a36Sopenharmony_ci wake_up(&ar->txmgmt_empty_waitq); 473562306a36Sopenharmony_ci} 473662306a36Sopenharmony_ci 473762306a36Sopenharmony_ciint ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx) 473862306a36Sopenharmony_ci{ 473962306a36Sopenharmony_ci struct sk_buff *msdu = skb; 474062306a36Sopenharmony_ci struct ieee80211_tx_info *info; 474162306a36Sopenharmony_ci struct ath12k *ar = ctx; 474262306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 474362306a36Sopenharmony_ci 474462306a36Sopenharmony_ci spin_lock_bh(&ar->txmgmt_idr_lock); 474562306a36Sopenharmony_ci idr_remove(&ar->txmgmt_idr, buf_id); 474662306a36Sopenharmony_ci spin_unlock_bh(&ar->txmgmt_idr_lock); 474762306a36Sopenharmony_ci dma_unmap_single(ab->dev, ATH12K_SKB_CB(msdu)->paddr, msdu->len, 474862306a36Sopenharmony_ci DMA_TO_DEVICE); 474962306a36Sopenharmony_ci 475062306a36Sopenharmony_ci info = IEEE80211_SKB_CB(msdu); 475162306a36Sopenharmony_ci memset(&info->status, 0, sizeof(info->status)); 475262306a36Sopenharmony_ci 475362306a36Sopenharmony_ci ath12k_mgmt_over_wmi_tx_drop(ar, skb); 475462306a36Sopenharmony_ci 475562306a36Sopenharmony_ci return 0; 475662306a36Sopenharmony_ci} 475762306a36Sopenharmony_ci 475862306a36Sopenharmony_cistatic int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx) 475962306a36Sopenharmony_ci{ 476062306a36Sopenharmony_ci struct ieee80211_vif *vif = ctx; 476162306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); 476262306a36Sopenharmony_ci struct sk_buff *msdu = skb; 476362306a36Sopenharmony_ci struct ath12k *ar = skb_cb->ar; 476462306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 476562306a36Sopenharmony_ci 476662306a36Sopenharmony_ci if (skb_cb->vif == vif) { 476762306a36Sopenharmony_ci spin_lock_bh(&ar->txmgmt_idr_lock); 476862306a36Sopenharmony_ci idr_remove(&ar->txmgmt_idr, buf_id); 476962306a36Sopenharmony_ci spin_unlock_bh(&ar->txmgmt_idr_lock); 477062306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, 477162306a36Sopenharmony_ci DMA_TO_DEVICE); 477262306a36Sopenharmony_ci } 477362306a36Sopenharmony_ci 477462306a36Sopenharmony_ci return 0; 477562306a36Sopenharmony_ci} 477662306a36Sopenharmony_ci 477762306a36Sopenharmony_cistatic int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_vif *arvif, 477862306a36Sopenharmony_ci struct sk_buff *skb) 477962306a36Sopenharmony_ci{ 478062306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 478162306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 478262306a36Sopenharmony_ci struct ieee80211_tx_info *info; 478362306a36Sopenharmony_ci dma_addr_t paddr; 478462306a36Sopenharmony_ci int buf_id; 478562306a36Sopenharmony_ci int ret; 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ci ATH12K_SKB_CB(skb)->ar = ar; 478862306a36Sopenharmony_ci spin_lock_bh(&ar->txmgmt_idr_lock); 478962306a36Sopenharmony_ci buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0, 479062306a36Sopenharmony_ci ATH12K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC); 479162306a36Sopenharmony_ci spin_unlock_bh(&ar->txmgmt_idr_lock); 479262306a36Sopenharmony_ci if (buf_id < 0) 479362306a36Sopenharmony_ci return -ENOSPC; 479462306a36Sopenharmony_ci 479562306a36Sopenharmony_ci info = IEEE80211_SKB_CB(skb); 479662306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) { 479762306a36Sopenharmony_ci if ((ieee80211_is_action(hdr->frame_control) || 479862306a36Sopenharmony_ci ieee80211_is_deauth(hdr->frame_control) || 479962306a36Sopenharmony_ci ieee80211_is_disassoc(hdr->frame_control)) && 480062306a36Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 480162306a36Sopenharmony_ci skb_put(skb, IEEE80211_CCMP_MIC_LEN); 480262306a36Sopenharmony_ci } 480362306a36Sopenharmony_ci } 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); 480662306a36Sopenharmony_ci if (dma_mapping_error(ab->dev, paddr)) { 480762306a36Sopenharmony_ci ath12k_warn(ab, "failed to DMA map mgmt Tx buffer\n"); 480862306a36Sopenharmony_ci ret = -EIO; 480962306a36Sopenharmony_ci goto err_free_idr; 481062306a36Sopenharmony_ci } 481162306a36Sopenharmony_ci 481262306a36Sopenharmony_ci ATH12K_SKB_CB(skb)->paddr = paddr; 481362306a36Sopenharmony_ci 481462306a36Sopenharmony_ci ret = ath12k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb); 481562306a36Sopenharmony_ci if (ret) { 481662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret); 481762306a36Sopenharmony_ci goto err_unmap_buf; 481862306a36Sopenharmony_ci } 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci return 0; 482162306a36Sopenharmony_ci 482262306a36Sopenharmony_cierr_unmap_buf: 482362306a36Sopenharmony_ci dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr, 482462306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 482562306a36Sopenharmony_cierr_free_idr: 482662306a36Sopenharmony_ci spin_lock_bh(&ar->txmgmt_idr_lock); 482762306a36Sopenharmony_ci idr_remove(&ar->txmgmt_idr, buf_id); 482862306a36Sopenharmony_ci spin_unlock_bh(&ar->txmgmt_idr_lock); 482962306a36Sopenharmony_ci 483062306a36Sopenharmony_ci return ret; 483162306a36Sopenharmony_ci} 483262306a36Sopenharmony_ci 483362306a36Sopenharmony_cistatic void ath12k_mgmt_over_wmi_tx_purge(struct ath12k *ar) 483462306a36Sopenharmony_ci{ 483562306a36Sopenharmony_ci struct sk_buff *skb; 483662306a36Sopenharmony_ci 483762306a36Sopenharmony_ci while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) 483862306a36Sopenharmony_ci ath12k_mgmt_over_wmi_tx_drop(ar, skb); 483962306a36Sopenharmony_ci} 484062306a36Sopenharmony_ci 484162306a36Sopenharmony_cistatic void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) 484262306a36Sopenharmony_ci{ 484362306a36Sopenharmony_ci struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work); 484462306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb; 484562306a36Sopenharmony_ci struct ath12k_vif *arvif; 484662306a36Sopenharmony_ci struct sk_buff *skb; 484762306a36Sopenharmony_ci int ret; 484862306a36Sopenharmony_ci 484962306a36Sopenharmony_ci while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) { 485062306a36Sopenharmony_ci skb_cb = ATH12K_SKB_CB(skb); 485162306a36Sopenharmony_ci if (!skb_cb->vif) { 485262306a36Sopenharmony_ci ath12k_warn(ar->ab, "no vif found for mgmt frame\n"); 485362306a36Sopenharmony_ci ath12k_mgmt_over_wmi_tx_drop(ar, skb); 485462306a36Sopenharmony_ci continue; 485562306a36Sopenharmony_ci } 485662306a36Sopenharmony_ci 485762306a36Sopenharmony_ci arvif = ath12k_vif_to_arvif(skb_cb->vif); 485862306a36Sopenharmony_ci if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && 485962306a36Sopenharmony_ci arvif->is_started) { 486062306a36Sopenharmony_ci ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb); 486162306a36Sopenharmony_ci if (ret) { 486262306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", 486362306a36Sopenharmony_ci arvif->vdev_id, ret); 486462306a36Sopenharmony_ci ath12k_mgmt_over_wmi_tx_drop(ar, skb); 486562306a36Sopenharmony_ci } 486662306a36Sopenharmony_ci } else { 486762306a36Sopenharmony_ci ath12k_warn(ar->ab, 486862306a36Sopenharmony_ci "dropping mgmt frame for vdev %d, is_started %d\n", 486962306a36Sopenharmony_ci arvif->vdev_id, 487062306a36Sopenharmony_ci arvif->is_started); 487162306a36Sopenharmony_ci ath12k_mgmt_over_wmi_tx_drop(ar, skb); 487262306a36Sopenharmony_ci } 487362306a36Sopenharmony_ci } 487462306a36Sopenharmony_ci} 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_cistatic int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, 487762306a36Sopenharmony_ci bool is_prb_rsp) 487862306a36Sopenharmony_ci{ 487962306a36Sopenharmony_ci struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue; 488062306a36Sopenharmony_ci 488162306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) 488262306a36Sopenharmony_ci return -ESHUTDOWN; 488362306a36Sopenharmony_ci 488462306a36Sopenharmony_ci /* Drop probe response packets when the pending management tx 488562306a36Sopenharmony_ci * count has reached a certain threshold, so as to prioritize 488662306a36Sopenharmony_ci * other mgmt packets like auth and assoc to be sent on time 488762306a36Sopenharmony_ci * for establishing successful connections. 488862306a36Sopenharmony_ci */ 488962306a36Sopenharmony_ci if (is_prb_rsp && 489062306a36Sopenharmony_ci atomic_read(&ar->num_pending_mgmt_tx) > ATH12K_PRB_RSP_DROP_THRESHOLD) { 489162306a36Sopenharmony_ci ath12k_warn(ar->ab, 489262306a36Sopenharmony_ci "dropping probe response as pending queue is almost full\n"); 489362306a36Sopenharmony_ci return -ENOSPC; 489462306a36Sopenharmony_ci } 489562306a36Sopenharmony_ci 489662306a36Sopenharmony_ci if (skb_queue_len_lockless(q) >= ATH12K_TX_MGMT_NUM_PENDING_MAX) { 489762306a36Sopenharmony_ci ath12k_warn(ar->ab, "mgmt tx queue is full\n"); 489862306a36Sopenharmony_ci return -ENOSPC; 489962306a36Sopenharmony_ci } 490062306a36Sopenharmony_ci 490162306a36Sopenharmony_ci skb_queue_tail(q, skb); 490262306a36Sopenharmony_ci atomic_inc(&ar->num_pending_mgmt_tx); 490362306a36Sopenharmony_ci ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); 490462306a36Sopenharmony_ci 490562306a36Sopenharmony_ci return 0; 490662306a36Sopenharmony_ci} 490762306a36Sopenharmony_ci 490862306a36Sopenharmony_cistatic void ath12k_mac_op_tx(struct ieee80211_hw *hw, 490962306a36Sopenharmony_ci struct ieee80211_tx_control *control, 491062306a36Sopenharmony_ci struct sk_buff *skb) 491162306a36Sopenharmony_ci{ 491262306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); 491362306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 491462306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 491562306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 491662306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 491762306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 491862306a36Sopenharmony_ci struct ieee80211_key_conf *key = info->control.hw_key; 491962306a36Sopenharmony_ci u32 info_flags = info->flags; 492062306a36Sopenharmony_ci bool is_prb_rsp; 492162306a36Sopenharmony_ci int ret; 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci memset(skb_cb, 0, sizeof(*skb_cb)); 492462306a36Sopenharmony_ci skb_cb->vif = vif; 492562306a36Sopenharmony_ci 492662306a36Sopenharmony_ci if (key) { 492762306a36Sopenharmony_ci skb_cb->cipher = key->cipher; 492862306a36Sopenharmony_ci skb_cb->flags |= ATH12K_SKB_CIPHER_SET; 492962306a36Sopenharmony_ci } 493062306a36Sopenharmony_ci 493162306a36Sopenharmony_ci if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { 493262306a36Sopenharmony_ci skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP; 493362306a36Sopenharmony_ci } else if (ieee80211_is_mgmt(hdr->frame_control)) { 493462306a36Sopenharmony_ci is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); 493562306a36Sopenharmony_ci ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp); 493662306a36Sopenharmony_ci if (ret) { 493762306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to queue management frame %d\n", 493862306a36Sopenharmony_ci ret); 493962306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 494062306a36Sopenharmony_ci } 494162306a36Sopenharmony_ci return; 494262306a36Sopenharmony_ci } 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci ret = ath12k_dp_tx(ar, arvif, skb); 494562306a36Sopenharmony_ci if (ret) { 494662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); 494762306a36Sopenharmony_ci ieee80211_free_txskb(ar->hw, skb); 494862306a36Sopenharmony_ci } 494962306a36Sopenharmony_ci} 495062306a36Sopenharmony_ci 495162306a36Sopenharmony_civoid ath12k_mac_drain_tx(struct ath12k *ar) 495262306a36Sopenharmony_ci{ 495362306a36Sopenharmony_ci /* make sure rcu-protected mac80211 tx path itself is drained */ 495462306a36Sopenharmony_ci synchronize_net(); 495562306a36Sopenharmony_ci 495662306a36Sopenharmony_ci cancel_work_sync(&ar->wmi_mgmt_tx_work); 495762306a36Sopenharmony_ci ath12k_mgmt_over_wmi_tx_purge(ar); 495862306a36Sopenharmony_ci} 495962306a36Sopenharmony_ci 496062306a36Sopenharmony_cistatic int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable) 496162306a36Sopenharmony_ci{ 496262306a36Sopenharmony_ci return -ENOTSUPP; 496362306a36Sopenharmony_ci /* TODO: Need to support new monitor mode */ 496462306a36Sopenharmony_ci} 496562306a36Sopenharmony_ci 496662306a36Sopenharmony_cistatic void ath12k_mac_wait_reconfigure(struct ath12k_base *ab) 496762306a36Sopenharmony_ci{ 496862306a36Sopenharmony_ci int recovery_start_count; 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci if (!ab->is_reset) 497162306a36Sopenharmony_ci return; 497262306a36Sopenharmony_ci 497362306a36Sopenharmony_ci recovery_start_count = atomic_inc_return(&ab->recovery_start_count); 497462306a36Sopenharmony_ci 497562306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "recovery start count %d\n", recovery_start_count); 497662306a36Sopenharmony_ci 497762306a36Sopenharmony_ci if (recovery_start_count == ab->num_radios) { 497862306a36Sopenharmony_ci complete(&ab->recovery_start); 497962306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "recovery started success\n"); 498062306a36Sopenharmony_ci } 498162306a36Sopenharmony_ci 498262306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "waiting reconfigure...\n"); 498362306a36Sopenharmony_ci 498462306a36Sopenharmony_ci wait_for_completion_timeout(&ab->reconfigure_complete, 498562306a36Sopenharmony_ci ATH12K_RECONFIGURE_TIMEOUT_HZ); 498662306a36Sopenharmony_ci} 498762306a36Sopenharmony_ci 498862306a36Sopenharmony_cistatic int ath12k_mac_op_start(struct ieee80211_hw *hw) 498962306a36Sopenharmony_ci{ 499062306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 499162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 499262306a36Sopenharmony_ci struct ath12k_pdev *pdev = ar->pdev; 499362306a36Sopenharmony_ci int ret; 499462306a36Sopenharmony_ci 499562306a36Sopenharmony_ci ath12k_mac_drain_tx(ar); 499662306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 499762306a36Sopenharmony_ci 499862306a36Sopenharmony_ci switch (ar->state) { 499962306a36Sopenharmony_ci case ATH12K_STATE_OFF: 500062306a36Sopenharmony_ci ar->state = ATH12K_STATE_ON; 500162306a36Sopenharmony_ci break; 500262306a36Sopenharmony_ci case ATH12K_STATE_RESTARTING: 500362306a36Sopenharmony_ci ar->state = ATH12K_STATE_RESTARTED; 500462306a36Sopenharmony_ci ath12k_mac_wait_reconfigure(ab); 500562306a36Sopenharmony_ci break; 500662306a36Sopenharmony_ci case ATH12K_STATE_RESTARTED: 500762306a36Sopenharmony_ci case ATH12K_STATE_WEDGED: 500862306a36Sopenharmony_ci case ATH12K_STATE_ON: 500962306a36Sopenharmony_ci WARN_ON(1); 501062306a36Sopenharmony_ci ret = -EINVAL; 501162306a36Sopenharmony_ci goto err; 501262306a36Sopenharmony_ci } 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS, 501562306a36Sopenharmony_ci 1, pdev->pdev_id); 501662306a36Sopenharmony_ci 501762306a36Sopenharmony_ci if (ret) { 501862306a36Sopenharmony_ci ath12k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret); 501962306a36Sopenharmony_ci goto err; 502062306a36Sopenharmony_ci } 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1, 502362306a36Sopenharmony_ci pdev->pdev_id); 502462306a36Sopenharmony_ci if (ret) { 502562306a36Sopenharmony_ci ath12k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret); 502662306a36Sopenharmony_ci goto err; 502762306a36Sopenharmony_ci } 502862306a36Sopenharmony_ci 502962306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE, 503062306a36Sopenharmony_ci 0, pdev->pdev_id); 503162306a36Sopenharmony_ci if (ret) { 503262306a36Sopenharmony_ci ath12k_err(ab, "failed to set ac override for ARP: %d\n", 503362306a36Sopenharmony_ci ret); 503462306a36Sopenharmony_ci goto err; 503562306a36Sopenharmony_ci } 503662306a36Sopenharmony_ci 503762306a36Sopenharmony_ci ret = ath12k_wmi_send_dfs_phyerr_offload_enable_cmd(ar, pdev->pdev_id); 503862306a36Sopenharmony_ci if (ret) { 503962306a36Sopenharmony_ci ath12k_err(ab, "failed to offload radar detection: %d\n", 504062306a36Sopenharmony_ci ret); 504162306a36Sopenharmony_ci goto err; 504262306a36Sopenharmony_ci } 504362306a36Sopenharmony_ci 504462306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_h2t_ppdu_stats_req(ar, 504562306a36Sopenharmony_ci HTT_PPDU_STATS_TAG_DEFAULT); 504662306a36Sopenharmony_ci if (ret) { 504762306a36Sopenharmony_ci ath12k_err(ab, "failed to req ppdu stats: %d\n", ret); 504862306a36Sopenharmony_ci goto err; 504962306a36Sopenharmony_ci } 505062306a36Sopenharmony_ci 505162306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_MESH_MCAST_ENABLE, 505262306a36Sopenharmony_ci 1, pdev->pdev_id); 505362306a36Sopenharmony_ci 505462306a36Sopenharmony_ci if (ret) { 505562306a36Sopenharmony_ci ath12k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); 505662306a36Sopenharmony_ci goto err; 505762306a36Sopenharmony_ci } 505862306a36Sopenharmony_ci 505962306a36Sopenharmony_ci __ath12k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask); 506062306a36Sopenharmony_ci 506162306a36Sopenharmony_ci /* TODO: Do we need to enable ANI? */ 506262306a36Sopenharmony_ci 506362306a36Sopenharmony_ci ath12k_reg_update_chan_list(ar); 506462306a36Sopenharmony_ci 506562306a36Sopenharmony_ci ar->num_started_vdevs = 0; 506662306a36Sopenharmony_ci ar->num_created_vdevs = 0; 506762306a36Sopenharmony_ci ar->num_peers = 0; 506862306a36Sopenharmony_ci ar->allocated_vdev_map = 0; 506962306a36Sopenharmony_ci 507062306a36Sopenharmony_ci /* Configure monitor status ring with default rx_filter to get rx status 507162306a36Sopenharmony_ci * such as rssi, rx_duration. 507262306a36Sopenharmony_ci */ 507362306a36Sopenharmony_ci ret = ath12k_mac_config_mon_status_default(ar, true); 507462306a36Sopenharmony_ci if (ret && (ret != -ENOTSUPP)) { 507562306a36Sopenharmony_ci ath12k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n", 507662306a36Sopenharmony_ci ret); 507762306a36Sopenharmony_ci goto err; 507862306a36Sopenharmony_ci } 507962306a36Sopenharmony_ci 508062306a36Sopenharmony_ci if (ret == -ENOTSUPP) 508162306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 508262306a36Sopenharmony_ci "monitor status config is not yet supported"); 508362306a36Sopenharmony_ci 508462306a36Sopenharmony_ci /* Configure the hash seed for hash based reo dest ring selection */ 508562306a36Sopenharmony_ci ath12k_wmi_pdev_lro_cfg(ar, ar->pdev->pdev_id); 508662306a36Sopenharmony_ci 508762306a36Sopenharmony_ci /* allow device to enter IMPS */ 508862306a36Sopenharmony_ci if (ab->hw_params->idle_ps) { 508962306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_IDLE_PS_CONFIG, 509062306a36Sopenharmony_ci 1, pdev->pdev_id); 509162306a36Sopenharmony_ci if (ret) { 509262306a36Sopenharmony_ci ath12k_err(ab, "failed to enable idle ps: %d\n", ret); 509362306a36Sopenharmony_ci goto err; 509462306a36Sopenharmony_ci } 509562306a36Sopenharmony_ci } 509662306a36Sopenharmony_ci 509762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 509862306a36Sopenharmony_ci 509962306a36Sopenharmony_ci rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], 510062306a36Sopenharmony_ci &ab->pdevs[ar->pdev_idx]); 510162306a36Sopenharmony_ci 510262306a36Sopenharmony_ci return 0; 510362306a36Sopenharmony_ci 510462306a36Sopenharmony_cierr: 510562306a36Sopenharmony_ci ar->state = ATH12K_STATE_OFF; 510662306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 510762306a36Sopenharmony_ci 510862306a36Sopenharmony_ci return ret; 510962306a36Sopenharmony_ci} 511062306a36Sopenharmony_ci 511162306a36Sopenharmony_cistatic void ath12k_mac_op_stop(struct ieee80211_hw *hw) 511262306a36Sopenharmony_ci{ 511362306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 511462306a36Sopenharmony_ci struct htt_ppdu_stats_info *ppdu_stats, *tmp; 511562306a36Sopenharmony_ci int ret; 511662306a36Sopenharmony_ci 511762306a36Sopenharmony_ci ath12k_mac_drain_tx(ar); 511862306a36Sopenharmony_ci 511962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 512062306a36Sopenharmony_ci ret = ath12k_mac_config_mon_status_default(ar, false); 512162306a36Sopenharmony_ci if (ret && (ret != -ENOTSUPP)) 512262306a36Sopenharmony_ci ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", 512362306a36Sopenharmony_ci ret); 512462306a36Sopenharmony_ci 512562306a36Sopenharmony_ci clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); 512662306a36Sopenharmony_ci ar->state = ATH12K_STATE_OFF; 512762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 512862306a36Sopenharmony_ci 512962306a36Sopenharmony_ci cancel_delayed_work_sync(&ar->scan.timeout); 513062306a36Sopenharmony_ci cancel_work_sync(&ar->regd_update_work); 513162306a36Sopenharmony_ci 513262306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 513362306a36Sopenharmony_ci list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { 513462306a36Sopenharmony_ci list_del(&ppdu_stats->list); 513562306a36Sopenharmony_ci kfree(ppdu_stats); 513662306a36Sopenharmony_ci } 513762306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 513862306a36Sopenharmony_ci 513962306a36Sopenharmony_ci rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL); 514062306a36Sopenharmony_ci 514162306a36Sopenharmony_ci synchronize_rcu(); 514262306a36Sopenharmony_ci 514362306a36Sopenharmony_ci atomic_set(&ar->num_pending_mgmt_tx, 0); 514462306a36Sopenharmony_ci} 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_cistatic u8 514762306a36Sopenharmony_ciath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) 514862306a36Sopenharmony_ci{ 514962306a36Sopenharmony_ci struct ath12k_base *ab = arvif->ar->ab; 515062306a36Sopenharmony_ci u8 vdev_stats_id = 0; 515162306a36Sopenharmony_ci 515262306a36Sopenharmony_ci do { 515362306a36Sopenharmony_ci if (ab->free_vdev_stats_id_map & (1LL << vdev_stats_id)) { 515462306a36Sopenharmony_ci vdev_stats_id++; 515562306a36Sopenharmony_ci if (vdev_stats_id >= ATH12K_MAX_VDEV_STATS_ID) { 515662306a36Sopenharmony_ci vdev_stats_id = ATH12K_INVAL_VDEV_STATS_ID; 515762306a36Sopenharmony_ci break; 515862306a36Sopenharmony_ci } 515962306a36Sopenharmony_ci } else { 516062306a36Sopenharmony_ci ab->free_vdev_stats_id_map |= (1LL << vdev_stats_id); 516162306a36Sopenharmony_ci break; 516262306a36Sopenharmony_ci } 516362306a36Sopenharmony_ci } while (vdev_stats_id); 516462306a36Sopenharmony_ci 516562306a36Sopenharmony_ci arvif->vdev_stats_id = vdev_stats_id; 516662306a36Sopenharmony_ci return vdev_stats_id; 516762306a36Sopenharmony_ci} 516862306a36Sopenharmony_ci 516962306a36Sopenharmony_cistatic void ath12k_mac_setup_vdev_create_arg(struct ath12k_vif *arvif, 517062306a36Sopenharmony_ci struct ath12k_wmi_vdev_create_arg *arg) 517162306a36Sopenharmony_ci{ 517262306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 517362306a36Sopenharmony_ci struct ath12k_pdev *pdev = ar->pdev; 517462306a36Sopenharmony_ci 517562306a36Sopenharmony_ci arg->if_id = arvif->vdev_id; 517662306a36Sopenharmony_ci arg->type = arvif->vdev_type; 517762306a36Sopenharmony_ci arg->subtype = arvif->vdev_subtype; 517862306a36Sopenharmony_ci arg->pdev_id = pdev->pdev_id; 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) { 518162306a36Sopenharmony_ci arg->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains; 518262306a36Sopenharmony_ci arg->chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains; 518362306a36Sopenharmony_ci } 518462306a36Sopenharmony_ci if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) { 518562306a36Sopenharmony_ci arg->chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains; 518662306a36Sopenharmony_ci arg->chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains; 518762306a36Sopenharmony_ci } 518862306a36Sopenharmony_ci if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP && 518962306a36Sopenharmony_ci ar->supports_6ghz) { 519062306a36Sopenharmony_ci arg->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains; 519162306a36Sopenharmony_ci arg->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains; 519262306a36Sopenharmony_ci } 519362306a36Sopenharmony_ci 519462306a36Sopenharmony_ci arg->if_stats_id = ath12k_mac_get_vdev_stats_id(arvif); 519562306a36Sopenharmony_ci} 519662306a36Sopenharmony_ci 519762306a36Sopenharmony_cistatic u32 519862306a36Sopenharmony_ciath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype) 519962306a36Sopenharmony_ci{ 520062306a36Sopenharmony_ci struct ath12k_pdev_cap *pdev_cap = &pdev->cap; 520162306a36Sopenharmony_ci struct ath12k_band_cap *cap_band = NULL; 520262306a36Sopenharmony_ci u32 *hecap_phy_ptr = NULL; 520362306a36Sopenharmony_ci u32 hemode; 520462306a36Sopenharmony_ci 520562306a36Sopenharmony_ci if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) 520662306a36Sopenharmony_ci cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; 520762306a36Sopenharmony_ci else 520862306a36Sopenharmony_ci cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; 520962306a36Sopenharmony_ci 521062306a36Sopenharmony_ci hecap_phy_ptr = &cap_band->he_cap_phy_info[0]; 521162306a36Sopenharmony_ci 521262306a36Sopenharmony_ci hemode = u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE) | 521362306a36Sopenharmony_ci u32_encode_bits(HECAP_PHY_SUBFMR_GET(hecap_phy_ptr), 521462306a36Sopenharmony_ci HE_MODE_SU_TX_BFER) | 521562306a36Sopenharmony_ci u32_encode_bits(HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr), 521662306a36Sopenharmony_ci HE_MODE_UL_MUMIMO); 521762306a36Sopenharmony_ci 521862306a36Sopenharmony_ci /* TODO: WDS and other modes */ 521962306a36Sopenharmony_ci if (viftype == NL80211_IFTYPE_AP) { 522062306a36Sopenharmony_ci hemode |= u32_encode_bits(HECAP_PHY_MUBFMR_GET(hecap_phy_ptr), 522162306a36Sopenharmony_ci HE_MODE_MU_TX_BFER) | 522262306a36Sopenharmony_ci u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | 522362306a36Sopenharmony_ci u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); 522462306a36Sopenharmony_ci } else { 522562306a36Sopenharmony_ci hemode |= u32_encode_bits(HE_MU_BFEE_ENABLE, HE_MODE_MU_TX_BFEE); 522662306a36Sopenharmony_ci } 522762306a36Sopenharmony_ci 522862306a36Sopenharmony_ci return hemode; 522962306a36Sopenharmony_ci} 523062306a36Sopenharmony_ci 523162306a36Sopenharmony_cistatic int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, 523262306a36Sopenharmony_ci struct ath12k_vif *arvif) 523362306a36Sopenharmony_ci{ 523462306a36Sopenharmony_ci u32 param_id, param_value; 523562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 523662306a36Sopenharmony_ci int ret; 523762306a36Sopenharmony_ci 523862306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; 523962306a36Sopenharmony_ci param_value = ath12k_mac_prepare_he_mode(ar->pdev, arvif->vif->type); 524062306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 524162306a36Sopenharmony_ci param_id, param_value); 524262306a36Sopenharmony_ci if (ret) { 524362306a36Sopenharmony_ci ath12k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n", 524462306a36Sopenharmony_ci arvif->vdev_id, ret, param_value); 524562306a36Sopenharmony_ci return ret; 524662306a36Sopenharmony_ci } 524762306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; 524862306a36Sopenharmony_ci param_value = 524962306a36Sopenharmony_ci u32_encode_bits(HE_VHT_SOUNDING_MODE_ENABLE, HE_VHT_SOUNDING_MODE) | 525062306a36Sopenharmony_ci u32_encode_bits(HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE, 525162306a36Sopenharmony_ci HE_TRIG_NONTRIG_SOUNDING_MODE); 525262306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 525362306a36Sopenharmony_ci param_id, param_value); 525462306a36Sopenharmony_ci if (ret) { 525562306a36Sopenharmony_ci ath12k_warn(ab, "failed to set vdev %d HE MU mode: %d\n", 525662306a36Sopenharmony_ci arvif->vdev_id, ret); 525762306a36Sopenharmony_ci return ret; 525862306a36Sopenharmony_ci } 525962306a36Sopenharmony_ci return ret; 526062306a36Sopenharmony_ci} 526162306a36Sopenharmony_ci 526262306a36Sopenharmony_cistatic void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, 526362306a36Sopenharmony_ci struct ieee80211_vif *vif) 526462306a36Sopenharmony_ci{ 526562306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 526662306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 526762306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 526862306a36Sopenharmony_ci u32 param_id, param_value; 526962306a36Sopenharmony_ci int ret; 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE; 527262306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION && 527362306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_AP) 527462306a36Sopenharmony_ci vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED | 527562306a36Sopenharmony_ci IEEE80211_OFFLOAD_DECAP_ENABLED); 527662306a36Sopenharmony_ci 527762306a36Sopenharmony_ci if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) 527862306a36Sopenharmony_ci arvif->tx_encap_type = ATH12K_HW_TXRX_ETHERNET; 527962306a36Sopenharmony_ci else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) 528062306a36Sopenharmony_ci arvif->tx_encap_type = ATH12K_HW_TXRX_RAW; 528162306a36Sopenharmony_ci else 528262306a36Sopenharmony_ci arvif->tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI; 528362306a36Sopenharmony_ci 528462306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 528562306a36Sopenharmony_ci param_id, arvif->tx_encap_type); 528662306a36Sopenharmony_ci if (ret) { 528762306a36Sopenharmony_ci ath12k_warn(ab, "failed to set vdev %d tx encap mode: %d\n", 528862306a36Sopenharmony_ci arvif->vdev_id, ret); 528962306a36Sopenharmony_ci vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; 529062306a36Sopenharmony_ci } 529162306a36Sopenharmony_ci 529262306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE; 529362306a36Sopenharmony_ci if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED) 529462306a36Sopenharmony_ci param_value = ATH12K_HW_TXRX_ETHERNET; 529562306a36Sopenharmony_ci else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) 529662306a36Sopenharmony_ci param_value = ATH12K_HW_TXRX_RAW; 529762306a36Sopenharmony_ci else 529862306a36Sopenharmony_ci param_value = ATH12K_HW_TXRX_NATIVE_WIFI; 529962306a36Sopenharmony_ci 530062306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 530162306a36Sopenharmony_ci param_id, param_value); 530262306a36Sopenharmony_ci if (ret) { 530362306a36Sopenharmony_ci ath12k_warn(ab, "failed to set vdev %d rx decap mode: %d\n", 530462306a36Sopenharmony_ci arvif->vdev_id, ret); 530562306a36Sopenharmony_ci vif->offload_flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; 530662306a36Sopenharmony_ci } 530762306a36Sopenharmony_ci} 530862306a36Sopenharmony_ci 530962306a36Sopenharmony_cistatic int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, 531062306a36Sopenharmony_ci struct ieee80211_vif *vif) 531162306a36Sopenharmony_ci{ 531262306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 531362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 531462306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 531562306a36Sopenharmony_ci struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; 531662306a36Sopenharmony_ci struct ath12k_wmi_peer_create_arg peer_param; 531762306a36Sopenharmony_ci u32 param_id, param_value; 531862306a36Sopenharmony_ci u16 nss; 531962306a36Sopenharmony_ci int i; 532062306a36Sopenharmony_ci int ret; 532162306a36Sopenharmony_ci int bit; 532262306a36Sopenharmony_ci 532362306a36Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; 532462306a36Sopenharmony_ci 532562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 532662306a36Sopenharmony_ci 532762306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP && 532862306a36Sopenharmony_ci ar->num_peers > (ar->max_num_peers - 1)) { 532962306a36Sopenharmony_ci ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n"); 533062306a36Sopenharmony_ci ret = -ENOBUFS; 533162306a36Sopenharmony_ci goto err; 533262306a36Sopenharmony_ci } 533362306a36Sopenharmony_ci 533462306a36Sopenharmony_ci if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { 533562306a36Sopenharmony_ci ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", 533662306a36Sopenharmony_ci TARGET_NUM_VDEVS); 533762306a36Sopenharmony_ci ret = -EBUSY; 533862306a36Sopenharmony_ci goto err; 533962306a36Sopenharmony_ci } 534062306a36Sopenharmony_ci 534162306a36Sopenharmony_ci memset(arvif, 0, sizeof(*arvif)); 534262306a36Sopenharmony_ci 534362306a36Sopenharmony_ci arvif->ar = ar; 534462306a36Sopenharmony_ci arvif->vif = vif; 534562306a36Sopenharmony_ci 534662306a36Sopenharmony_ci INIT_LIST_HEAD(&arvif->list); 534762306a36Sopenharmony_ci 534862306a36Sopenharmony_ci /* Should we initialize any worker to handle connection loss indication 534962306a36Sopenharmony_ci * from firmware in sta mode? 535062306a36Sopenharmony_ci */ 535162306a36Sopenharmony_ci 535262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { 535362306a36Sopenharmony_ci arvif->bitrate_mask.control[i].legacy = 0xffffffff; 535462306a36Sopenharmony_ci memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, 535562306a36Sopenharmony_ci sizeof(arvif->bitrate_mask.control[i].ht_mcs)); 535662306a36Sopenharmony_ci memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, 535762306a36Sopenharmony_ci sizeof(arvif->bitrate_mask.control[i].vht_mcs)); 535862306a36Sopenharmony_ci } 535962306a36Sopenharmony_ci 536062306a36Sopenharmony_ci bit = __ffs64(ab->free_vdev_map); 536162306a36Sopenharmony_ci 536262306a36Sopenharmony_ci arvif->vdev_id = bit; 536362306a36Sopenharmony_ci arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; 536462306a36Sopenharmony_ci 536562306a36Sopenharmony_ci switch (vif->type) { 536662306a36Sopenharmony_ci case NL80211_IFTYPE_UNSPECIFIED: 536762306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 536862306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_STA; 536962306a36Sopenharmony_ci break; 537062306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 537162306a36Sopenharmony_ci arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; 537262306a36Sopenharmony_ci fallthrough; 537362306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 537462306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_AP; 537562306a36Sopenharmony_ci break; 537662306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 537762306a36Sopenharmony_ci arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; 537862306a36Sopenharmony_ci ar->monitor_vdev_id = bit; 537962306a36Sopenharmony_ci break; 538062306a36Sopenharmony_ci default: 538162306a36Sopenharmony_ci WARN_ON(1); 538262306a36Sopenharmony_ci break; 538362306a36Sopenharmony_ci } 538462306a36Sopenharmony_ci 538562306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n", 538662306a36Sopenharmony_ci arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, 538762306a36Sopenharmony_ci ab->free_vdev_map); 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci vif->cab_queue = arvif->vdev_id % (ATH12K_HW_MAX_QUEUES - 1); 539062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) 539162306a36Sopenharmony_ci vif->hw_queue[i] = i % (ATH12K_HW_MAX_QUEUES - 1); 539262306a36Sopenharmony_ci 539362306a36Sopenharmony_ci ath12k_mac_setup_vdev_create_arg(arvif, &vdev_arg); 539462306a36Sopenharmony_ci 539562306a36Sopenharmony_ci ret = ath12k_wmi_vdev_create(ar, vif->addr, &vdev_arg); 539662306a36Sopenharmony_ci if (ret) { 539762306a36Sopenharmony_ci ath12k_warn(ab, "failed to create WMI vdev %d: %d\n", 539862306a36Sopenharmony_ci arvif->vdev_id, ret); 539962306a36Sopenharmony_ci goto err; 540062306a36Sopenharmony_ci } 540162306a36Sopenharmony_ci 540262306a36Sopenharmony_ci ar->num_created_vdevs++; 540362306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM created, vdev_id %d\n", 540462306a36Sopenharmony_ci vif->addr, arvif->vdev_id); 540562306a36Sopenharmony_ci ar->allocated_vdev_map |= 1LL << arvif->vdev_id; 540662306a36Sopenharmony_ci ab->free_vdev_map &= ~(1LL << arvif->vdev_id); 540762306a36Sopenharmony_ci 540862306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 540962306a36Sopenharmony_ci list_add(&arvif->list, &ar->arvifs); 541062306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 541162306a36Sopenharmony_ci 541262306a36Sopenharmony_ci ath12k_mac_op_update_vif_offload(hw, vif); 541362306a36Sopenharmony_ci 541462306a36Sopenharmony_ci nss = hweight32(ar->cfg_tx_chainmask) ? : 1; 541562306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 541662306a36Sopenharmony_ci WMI_VDEV_PARAM_NSS, nss); 541762306a36Sopenharmony_ci if (ret) { 541862306a36Sopenharmony_ci ath12k_warn(ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n", 541962306a36Sopenharmony_ci arvif->vdev_id, ar->cfg_tx_chainmask, nss, ret); 542062306a36Sopenharmony_ci goto err_vdev_del; 542162306a36Sopenharmony_ci } 542262306a36Sopenharmony_ci 542362306a36Sopenharmony_ci switch (arvif->vdev_type) { 542462306a36Sopenharmony_ci case WMI_VDEV_TYPE_AP: 542562306a36Sopenharmony_ci peer_param.vdev_id = arvif->vdev_id; 542662306a36Sopenharmony_ci peer_param.peer_addr = vif->addr; 542762306a36Sopenharmony_ci peer_param.peer_type = WMI_PEER_TYPE_DEFAULT; 542862306a36Sopenharmony_ci ret = ath12k_peer_create(ar, arvif, NULL, &peer_param); 542962306a36Sopenharmony_ci if (ret) { 543062306a36Sopenharmony_ci ath12k_warn(ab, "failed to vdev %d create peer for AP: %d\n", 543162306a36Sopenharmony_ci arvif->vdev_id, ret); 543262306a36Sopenharmony_ci goto err_vdev_del; 543362306a36Sopenharmony_ci } 543462306a36Sopenharmony_ci 543562306a36Sopenharmony_ci ret = ath12k_mac_set_kickout(arvif); 543662306a36Sopenharmony_ci if (ret) { 543762306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %i kickout parameters: %d\n", 543862306a36Sopenharmony_ci arvif->vdev_id, ret); 543962306a36Sopenharmony_ci goto err_peer_del; 544062306a36Sopenharmony_ci } 544162306a36Sopenharmony_ci break; 544262306a36Sopenharmony_ci case WMI_VDEV_TYPE_STA: 544362306a36Sopenharmony_ci param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY; 544462306a36Sopenharmony_ci param_value = WMI_STA_PS_RX_WAKE_POLICY_WAKE; 544562306a36Sopenharmony_ci ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 544662306a36Sopenharmony_ci param_id, param_value); 544762306a36Sopenharmony_ci if (ret) { 544862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %d RX wake policy: %d\n", 544962306a36Sopenharmony_ci arvif->vdev_id, ret); 545062306a36Sopenharmony_ci goto err_peer_del; 545162306a36Sopenharmony_ci } 545262306a36Sopenharmony_ci 545362306a36Sopenharmony_ci param_id = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD; 545462306a36Sopenharmony_ci param_value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; 545562306a36Sopenharmony_ci ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 545662306a36Sopenharmony_ci param_id, param_value); 545762306a36Sopenharmony_ci if (ret) { 545862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %d TX wake threshold: %d\n", 545962306a36Sopenharmony_ci arvif->vdev_id, ret); 546062306a36Sopenharmony_ci goto err_peer_del; 546162306a36Sopenharmony_ci } 546262306a36Sopenharmony_ci 546362306a36Sopenharmony_ci param_id = WMI_STA_PS_PARAM_PSPOLL_COUNT; 546462306a36Sopenharmony_ci param_value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; 546562306a36Sopenharmony_ci ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, 546662306a36Sopenharmony_ci param_id, param_value); 546762306a36Sopenharmony_ci if (ret) { 546862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set vdev %d pspoll count: %d\n", 546962306a36Sopenharmony_ci arvif->vdev_id, ret); 547062306a36Sopenharmony_ci goto err_peer_del; 547162306a36Sopenharmony_ci } 547262306a36Sopenharmony_ci 547362306a36Sopenharmony_ci ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, false); 547462306a36Sopenharmony_ci if (ret) { 547562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to disable vdev %d ps mode: %d\n", 547662306a36Sopenharmony_ci arvif->vdev_id, ret); 547762306a36Sopenharmony_ci goto err_peer_del; 547862306a36Sopenharmony_ci } 547962306a36Sopenharmony_ci break; 548062306a36Sopenharmony_ci default: 548162306a36Sopenharmony_ci break; 548262306a36Sopenharmony_ci } 548362306a36Sopenharmony_ci 548462306a36Sopenharmony_ci arvif->txpower = vif->bss_conf.txpower; 548562306a36Sopenharmony_ci ret = ath12k_mac_txpower_recalc(ar); 548662306a36Sopenharmony_ci if (ret) 548762306a36Sopenharmony_ci goto err_peer_del; 548862306a36Sopenharmony_ci 548962306a36Sopenharmony_ci param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; 549062306a36Sopenharmony_ci param_value = ar->hw->wiphy->rts_threshold; 549162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 549262306a36Sopenharmony_ci param_id, param_value); 549362306a36Sopenharmony_ci if (ret) { 549462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set rts threshold for vdev %d: %d\n", 549562306a36Sopenharmony_ci arvif->vdev_id, ret); 549662306a36Sopenharmony_ci } 549762306a36Sopenharmony_ci 549862306a36Sopenharmony_ci ath12k_dp_vdev_tx_attach(ar, arvif); 549962306a36Sopenharmony_ci 550062306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled) 550162306a36Sopenharmony_ci ath12k_mac_monitor_vdev_create(ar); 550262306a36Sopenharmony_ci 550362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 550462306a36Sopenharmony_ci 550562306a36Sopenharmony_ci return ret; 550662306a36Sopenharmony_ci 550762306a36Sopenharmony_cierr_peer_del: 550862306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { 550962306a36Sopenharmony_ci reinit_completion(&ar->peer_delete_done); 551062306a36Sopenharmony_ci 551162306a36Sopenharmony_ci ret = ath12k_wmi_send_peer_delete_cmd(ar, vif->addr, 551262306a36Sopenharmony_ci arvif->vdev_id); 551362306a36Sopenharmony_ci if (ret) { 551462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", 551562306a36Sopenharmony_ci arvif->vdev_id, vif->addr); 551662306a36Sopenharmony_ci goto err; 551762306a36Sopenharmony_ci } 551862306a36Sopenharmony_ci 551962306a36Sopenharmony_ci ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id, 552062306a36Sopenharmony_ci vif->addr); 552162306a36Sopenharmony_ci if (ret) 552262306a36Sopenharmony_ci goto err; 552362306a36Sopenharmony_ci 552462306a36Sopenharmony_ci ar->num_peers--; 552562306a36Sopenharmony_ci } 552662306a36Sopenharmony_ci 552762306a36Sopenharmony_cierr_vdev_del: 552862306a36Sopenharmony_ci ath12k_wmi_vdev_delete(ar, arvif->vdev_id); 552962306a36Sopenharmony_ci ar->num_created_vdevs--; 553062306a36Sopenharmony_ci ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); 553162306a36Sopenharmony_ci ab->free_vdev_map |= 1LL << arvif->vdev_id; 553262306a36Sopenharmony_ci ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id); 553362306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 553462306a36Sopenharmony_ci list_del(&arvif->list); 553562306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 553662306a36Sopenharmony_ci 553762306a36Sopenharmony_cierr: 553862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 553962306a36Sopenharmony_ci 554062306a36Sopenharmony_ci return ret; 554162306a36Sopenharmony_ci} 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_cistatic void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif) 554462306a36Sopenharmony_ci{ 554562306a36Sopenharmony_ci struct ath12k_tx_desc_info *tx_desc_info; 554662306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb; 554762306a36Sopenharmony_ci struct sk_buff *skb; 554862306a36Sopenharmony_ci int i; 554962306a36Sopenharmony_ci 555062306a36Sopenharmony_ci for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) { 555162306a36Sopenharmony_ci spin_lock_bh(&dp->tx_desc_lock[i]); 555262306a36Sopenharmony_ci 555362306a36Sopenharmony_ci list_for_each_entry(tx_desc_info, &dp->tx_desc_used_list[i], 555462306a36Sopenharmony_ci list) { 555562306a36Sopenharmony_ci skb = tx_desc_info->skb; 555662306a36Sopenharmony_ci if (!skb) 555762306a36Sopenharmony_ci continue; 555862306a36Sopenharmony_ci 555962306a36Sopenharmony_ci skb_cb = ATH12K_SKB_CB(skb); 556062306a36Sopenharmony_ci if (skb_cb->vif == vif) 556162306a36Sopenharmony_ci skb_cb->vif = NULL; 556262306a36Sopenharmony_ci } 556362306a36Sopenharmony_ci 556462306a36Sopenharmony_ci spin_unlock_bh(&dp->tx_desc_lock[i]); 556562306a36Sopenharmony_ci } 556662306a36Sopenharmony_ci} 556762306a36Sopenharmony_ci 556862306a36Sopenharmony_cistatic void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, 556962306a36Sopenharmony_ci struct ieee80211_vif *vif) 557062306a36Sopenharmony_ci{ 557162306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 557262306a36Sopenharmony_ci struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); 557362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 557462306a36Sopenharmony_ci unsigned long time_left; 557562306a36Sopenharmony_ci int ret; 557662306a36Sopenharmony_ci 557762306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", 558062306a36Sopenharmony_ci arvif->vdev_id); 558162306a36Sopenharmony_ci 558262306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { 558362306a36Sopenharmony_ci ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr); 558462306a36Sopenharmony_ci if (ret) 558562306a36Sopenharmony_ci ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n", 558662306a36Sopenharmony_ci arvif->vdev_id, ret); 558762306a36Sopenharmony_ci } 558862306a36Sopenharmony_ci 558962306a36Sopenharmony_ci reinit_completion(&ar->vdev_delete_done); 559062306a36Sopenharmony_ci 559162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_delete(ar, arvif->vdev_id); 559262306a36Sopenharmony_ci if (ret) { 559362306a36Sopenharmony_ci ath12k_warn(ab, "failed to delete WMI vdev %d: %d\n", 559462306a36Sopenharmony_ci arvif->vdev_id, ret); 559562306a36Sopenharmony_ci goto err_vdev_del; 559662306a36Sopenharmony_ci } 559762306a36Sopenharmony_ci 559862306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&ar->vdev_delete_done, 559962306a36Sopenharmony_ci ATH12K_VDEV_DELETE_TIMEOUT_HZ); 560062306a36Sopenharmony_ci if (time_left == 0) { 560162306a36Sopenharmony_ci ath12k_warn(ab, "Timeout in receiving vdev delete response\n"); 560262306a36Sopenharmony_ci goto err_vdev_del; 560362306a36Sopenharmony_ci } 560462306a36Sopenharmony_ci 560562306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { 560662306a36Sopenharmony_ci ar->monitor_vdev_id = -1; 560762306a36Sopenharmony_ci ar->monitor_vdev_created = false; 560862306a36Sopenharmony_ci } else if (ar->monitor_vdev_created && !ar->monitor_started) { 560962306a36Sopenharmony_ci ret = ath12k_mac_monitor_vdev_delete(ar); 561062306a36Sopenharmony_ci } 561162306a36Sopenharmony_ci 561262306a36Sopenharmony_ci ab->free_vdev_map |= 1LL << (arvif->vdev_id); 561362306a36Sopenharmony_ci ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); 561462306a36Sopenharmony_ci ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id); 561562306a36Sopenharmony_ci ar->num_created_vdevs--; 561662306a36Sopenharmony_ci 561762306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", 561862306a36Sopenharmony_ci vif->addr, arvif->vdev_id); 561962306a36Sopenharmony_ci 562062306a36Sopenharmony_cierr_vdev_del: 562162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 562262306a36Sopenharmony_ci list_del(&arvif->list); 562362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 562462306a36Sopenharmony_ci 562562306a36Sopenharmony_ci ath12k_peer_cleanup(ar, arvif->vdev_id); 562662306a36Sopenharmony_ci 562762306a36Sopenharmony_ci idr_for_each(&ar->txmgmt_idr, 562862306a36Sopenharmony_ci ath12k_mac_vif_txmgmt_idr_remove, vif); 562962306a36Sopenharmony_ci 563062306a36Sopenharmony_ci ath12k_mac_vif_unref(&ab->dp, vif); 563162306a36Sopenharmony_ci ath12k_dp_tx_put_bank_profile(&ab->dp, arvif->bank_id); 563262306a36Sopenharmony_ci 563362306a36Sopenharmony_ci /* Recalc txpower for remaining vdev */ 563462306a36Sopenharmony_ci ath12k_mac_txpower_recalc(ar); 563562306a36Sopenharmony_ci clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); 563662306a36Sopenharmony_ci 563762306a36Sopenharmony_ci /* TODO: recal traffic pause state based on the available vdevs */ 563862306a36Sopenharmony_ci 563962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 564062306a36Sopenharmony_ci} 564162306a36Sopenharmony_ci 564262306a36Sopenharmony_ci/* FIXME: Has to be verified. */ 564362306a36Sopenharmony_ci#define SUPPORTED_FILTERS \ 564462306a36Sopenharmony_ci (FIF_ALLMULTI | \ 564562306a36Sopenharmony_ci FIF_CONTROL | \ 564662306a36Sopenharmony_ci FIF_PSPOLL | \ 564762306a36Sopenharmony_ci FIF_OTHER_BSS | \ 564862306a36Sopenharmony_ci FIF_BCN_PRBRESP_PROMISC | \ 564962306a36Sopenharmony_ci FIF_PROBE_REQ | \ 565062306a36Sopenharmony_ci FIF_FCSFAIL) 565162306a36Sopenharmony_ci 565262306a36Sopenharmony_cistatic void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, 565362306a36Sopenharmony_ci unsigned int changed_flags, 565462306a36Sopenharmony_ci unsigned int *total_flags, 565562306a36Sopenharmony_ci u64 multicast) 565662306a36Sopenharmony_ci{ 565762306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 565862306a36Sopenharmony_ci bool reset_flag; 565962306a36Sopenharmony_ci int ret; 566062306a36Sopenharmony_ci 566162306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 566262306a36Sopenharmony_ci 566362306a36Sopenharmony_ci *total_flags &= SUPPORTED_FILTERS; 566462306a36Sopenharmony_ci ar->filter_flags = *total_flags; 566562306a36Sopenharmony_ci 566662306a36Sopenharmony_ci /* For monitor mode */ 566762306a36Sopenharmony_ci reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC); 566862306a36Sopenharmony_ci 566962306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag); 567062306a36Sopenharmony_ci if (!ret) { 567162306a36Sopenharmony_ci if (!reset_flag) 567262306a36Sopenharmony_ci set_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); 567362306a36Sopenharmony_ci else 567462306a36Sopenharmony_ci clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); 567562306a36Sopenharmony_ci } else { 567662306a36Sopenharmony_ci ath12k_warn(ar->ab, 567762306a36Sopenharmony_ci "fail to set monitor filter: %d\n", ret); 567862306a36Sopenharmony_ci } 567962306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 568062306a36Sopenharmony_ci "total_flags:0x%x, reset_flag:%d\n", 568162306a36Sopenharmony_ci *total_flags, reset_flag); 568262306a36Sopenharmony_ci 568362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 568462306a36Sopenharmony_ci} 568562306a36Sopenharmony_ci 568662306a36Sopenharmony_cistatic int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 568762306a36Sopenharmony_ci{ 568862306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 568962306a36Sopenharmony_ci 569062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 569162306a36Sopenharmony_ci 569262306a36Sopenharmony_ci *tx_ant = ar->cfg_tx_chainmask; 569362306a36Sopenharmony_ci *rx_ant = ar->cfg_rx_chainmask; 569462306a36Sopenharmony_ci 569562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 569662306a36Sopenharmony_ci 569762306a36Sopenharmony_ci return 0; 569862306a36Sopenharmony_ci} 569962306a36Sopenharmony_ci 570062306a36Sopenharmony_cistatic int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 570162306a36Sopenharmony_ci{ 570262306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 570362306a36Sopenharmony_ci int ret; 570462306a36Sopenharmony_ci 570562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 570662306a36Sopenharmony_ci ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); 570762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 570862306a36Sopenharmony_ci 570962306a36Sopenharmony_ci return ret; 571062306a36Sopenharmony_ci} 571162306a36Sopenharmony_ci 571262306a36Sopenharmony_cistatic int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, 571362306a36Sopenharmony_ci struct ieee80211_vif *vif, 571462306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 571562306a36Sopenharmony_ci{ 571662306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 571762306a36Sopenharmony_ci int ret = -EINVAL; 571862306a36Sopenharmony_ci 571962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 572062306a36Sopenharmony_ci 572162306a36Sopenharmony_ci switch (params->action) { 572262306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 572362306a36Sopenharmony_ci ret = ath12k_dp_rx_ampdu_start(ar, params); 572462306a36Sopenharmony_ci break; 572562306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 572662306a36Sopenharmony_ci ret = ath12k_dp_rx_ampdu_stop(ar, params); 572762306a36Sopenharmony_ci break; 572862306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 572962306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 573062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 573162306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 573262306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 573362306a36Sopenharmony_ci /* Tx A-MPDU aggregation offloaded to hw/fw so deny mac80211 573462306a36Sopenharmony_ci * Tx aggregation requests. 573562306a36Sopenharmony_ci */ 573662306a36Sopenharmony_ci ret = -EOPNOTSUPP; 573762306a36Sopenharmony_ci break; 573862306a36Sopenharmony_ci } 573962306a36Sopenharmony_ci 574062306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 574162306a36Sopenharmony_ci 574262306a36Sopenharmony_ci return ret; 574362306a36Sopenharmony_ci} 574462306a36Sopenharmony_ci 574562306a36Sopenharmony_cistatic int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, 574662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 574762306a36Sopenharmony_ci{ 574862306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 574962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 575062306a36Sopenharmony_ci 575162306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 575262306a36Sopenharmony_ci "mac chanctx add freq %u width %d ptr %pK\n", 575362306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, ctx); 575462306a36Sopenharmony_ci 575562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 575662306a36Sopenharmony_ci 575762306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 575862306a36Sopenharmony_ci /* TODO: In case of multiple channel context, populate rx_channel from 575962306a36Sopenharmony_ci * Rx PPDU desc information. 576062306a36Sopenharmony_ci */ 576162306a36Sopenharmony_ci ar->rx_channel = ctx->def.chan; 576262306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 576362306a36Sopenharmony_ci 576462306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 576562306a36Sopenharmony_ci 576662306a36Sopenharmony_ci return 0; 576762306a36Sopenharmony_ci} 576862306a36Sopenharmony_ci 576962306a36Sopenharmony_cistatic void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, 577062306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 577162306a36Sopenharmony_ci{ 577262306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 577362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 577462306a36Sopenharmony_ci 577562306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 577662306a36Sopenharmony_ci "mac chanctx remove freq %u width %d ptr %pK\n", 577762306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, ctx); 577862306a36Sopenharmony_ci 577962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 578062306a36Sopenharmony_ci 578162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 578262306a36Sopenharmony_ci /* TODO: In case of there is one more channel context left, populate 578362306a36Sopenharmony_ci * rx_channel with the channel of that remaining channel context. 578462306a36Sopenharmony_ci */ 578562306a36Sopenharmony_ci ar->rx_channel = NULL; 578662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 578762306a36Sopenharmony_ci 578862306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 578962306a36Sopenharmony_ci} 579062306a36Sopenharmony_ci 579162306a36Sopenharmony_cistatic int 579262306a36Sopenharmony_ciath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, 579362306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef, 579462306a36Sopenharmony_ci bool restart) 579562306a36Sopenharmony_ci{ 579662306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 579762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 579862306a36Sopenharmony_ci struct wmi_vdev_start_req_arg arg = {}; 579962306a36Sopenharmony_ci int he_support = arvif->vif->bss_conf.he_support; 580062306a36Sopenharmony_ci int ret; 580162306a36Sopenharmony_ci 580262306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 580362306a36Sopenharmony_ci 580462306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 580562306a36Sopenharmony_ci 580662306a36Sopenharmony_ci arg.vdev_id = arvif->vdev_id; 580762306a36Sopenharmony_ci arg.dtim_period = arvif->dtim_period; 580862306a36Sopenharmony_ci arg.bcn_intval = arvif->beacon_interval; 580962306a36Sopenharmony_ci arg.punct_bitmap = ~arvif->punct_bitmap; 581062306a36Sopenharmony_ci 581162306a36Sopenharmony_ci arg.freq = chandef->chan->center_freq; 581262306a36Sopenharmony_ci arg.band_center_freq1 = chandef->center_freq1; 581362306a36Sopenharmony_ci arg.band_center_freq2 = chandef->center_freq2; 581462306a36Sopenharmony_ci arg.mode = ath12k_phymodes[chandef->chan->band][chandef->width]; 581562306a36Sopenharmony_ci 581662306a36Sopenharmony_ci arg.min_power = 0; 581762306a36Sopenharmony_ci arg.max_power = chandef->chan->max_power * 2; 581862306a36Sopenharmony_ci arg.max_reg_power = chandef->chan->max_reg_power * 2; 581962306a36Sopenharmony_ci arg.max_antenna_gain = chandef->chan->max_antenna_gain * 2; 582062306a36Sopenharmony_ci 582162306a36Sopenharmony_ci arg.pref_tx_streams = ar->num_tx_chains; 582262306a36Sopenharmony_ci arg.pref_rx_streams = ar->num_rx_chains; 582362306a36Sopenharmony_ci 582462306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { 582562306a36Sopenharmony_ci arg.ssid = arvif->u.ap.ssid; 582662306a36Sopenharmony_ci arg.ssid_len = arvif->u.ap.ssid_len; 582762306a36Sopenharmony_ci arg.hidden_ssid = arvif->u.ap.hidden_ssid; 582862306a36Sopenharmony_ci 582962306a36Sopenharmony_ci /* For now allow DFS for AP mode */ 583062306a36Sopenharmony_ci arg.chan_radar = !!(chandef->chan->flags & IEEE80211_CHAN_RADAR); 583162306a36Sopenharmony_ci 583262306a36Sopenharmony_ci arg.passive = arg.chan_radar; 583362306a36Sopenharmony_ci 583462306a36Sopenharmony_ci spin_lock_bh(&ab->base_lock); 583562306a36Sopenharmony_ci arg.regdomain = ar->ab->dfs_region; 583662306a36Sopenharmony_ci spin_unlock_bh(&ab->base_lock); 583762306a36Sopenharmony_ci 583862306a36Sopenharmony_ci /* TODO: Notify if secondary 80Mhz also needs radar detection */ 583962306a36Sopenharmony_ci if (he_support) { 584062306a36Sopenharmony_ci ret = ath12k_set_he_mu_sounding_mode(ar, arvif); 584162306a36Sopenharmony_ci if (ret) { 584262306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set he mode vdev %i\n", 584362306a36Sopenharmony_ci arg.vdev_id); 584462306a36Sopenharmony_ci return ret; 584562306a36Sopenharmony_ci } 584662306a36Sopenharmony_ci } 584762306a36Sopenharmony_ci } 584862306a36Sopenharmony_ci 584962306a36Sopenharmony_ci arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); 585062306a36Sopenharmony_ci 585162306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 585262306a36Sopenharmony_ci "mac vdev %d start center_freq %d phymode %s punct_bitmap 0x%x\n", 585362306a36Sopenharmony_ci arg.vdev_id, arg.freq, 585462306a36Sopenharmony_ci ath12k_mac_phymode_str(arg.mode), arg.punct_bitmap); 585562306a36Sopenharmony_ci 585662306a36Sopenharmony_ci ret = ath12k_wmi_vdev_start(ar, &arg, restart); 585762306a36Sopenharmony_ci if (ret) { 585862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to %s WMI vdev %i\n", 585962306a36Sopenharmony_ci restart ? "restart" : "start", arg.vdev_id); 586062306a36Sopenharmony_ci return ret; 586162306a36Sopenharmony_ci } 586262306a36Sopenharmony_ci 586362306a36Sopenharmony_ci ret = ath12k_mac_vdev_setup_sync(ar); 586462306a36Sopenharmony_ci if (ret) { 586562306a36Sopenharmony_ci ath12k_warn(ab, "failed to synchronize setup for vdev %i %s: %d\n", 586662306a36Sopenharmony_ci arg.vdev_id, restart ? "restart" : "start", ret); 586762306a36Sopenharmony_ci return ret; 586862306a36Sopenharmony_ci } 586962306a36Sopenharmony_ci 587062306a36Sopenharmony_ci ar->num_started_vdevs++; 587162306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM started, vdev_id %d\n", 587262306a36Sopenharmony_ci arvif->vif->addr, arvif->vdev_id); 587362306a36Sopenharmony_ci 587462306a36Sopenharmony_ci /* Enable CAC Flag in the driver by checking the channel DFS cac time, 587562306a36Sopenharmony_ci * i.e dfs_cac_ms value which will be valid only for radar channels 587662306a36Sopenharmony_ci * and state as NL80211_DFS_USABLE which indicates CAC needs to be 587762306a36Sopenharmony_ci * done before channel usage. This flags is used to drop rx packets. 587862306a36Sopenharmony_ci * during CAC. 587962306a36Sopenharmony_ci */ 588062306a36Sopenharmony_ci /* TODO: Set the flag for other interface types as required */ 588162306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_AP && 588262306a36Sopenharmony_ci chandef->chan->dfs_cac_ms && 588362306a36Sopenharmony_ci chandef->chan->dfs_state == NL80211_DFS_USABLE) { 588462306a36Sopenharmony_ci set_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); 588562306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 588662306a36Sopenharmony_ci "CAC Started in chan_freq %d for vdev %d\n", 588762306a36Sopenharmony_ci arg.freq, arg.vdev_id); 588862306a36Sopenharmony_ci } 588962306a36Sopenharmony_ci 589062306a36Sopenharmony_ci ret = ath12k_mac_set_txbf_conf(arvif); 589162306a36Sopenharmony_ci if (ret) 589262306a36Sopenharmony_ci ath12k_warn(ab, "failed to set txbf conf for vdev %d: %d\n", 589362306a36Sopenharmony_ci arvif->vdev_id, ret); 589462306a36Sopenharmony_ci 589562306a36Sopenharmony_ci return 0; 589662306a36Sopenharmony_ci} 589762306a36Sopenharmony_ci 589862306a36Sopenharmony_cistatic int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) 589962306a36Sopenharmony_ci{ 590062306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 590162306a36Sopenharmony_ci int ret; 590262306a36Sopenharmony_ci 590362306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 590462306a36Sopenharmony_ci 590562306a36Sopenharmony_ci reinit_completion(&ar->vdev_setup_done); 590662306a36Sopenharmony_ci 590762306a36Sopenharmony_ci ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); 590862306a36Sopenharmony_ci if (ret) { 590962306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", 591062306a36Sopenharmony_ci arvif->vdev_id, ret); 591162306a36Sopenharmony_ci goto err; 591262306a36Sopenharmony_ci } 591362306a36Sopenharmony_ci 591462306a36Sopenharmony_ci ret = ath12k_mac_vdev_setup_sync(ar); 591562306a36Sopenharmony_ci if (ret) { 591662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", 591762306a36Sopenharmony_ci arvif->vdev_id, ret); 591862306a36Sopenharmony_ci goto err; 591962306a36Sopenharmony_ci } 592062306a36Sopenharmony_ci 592162306a36Sopenharmony_ci WARN_ON(ar->num_started_vdevs == 0); 592262306a36Sopenharmony_ci 592362306a36Sopenharmony_ci ar->num_started_vdevs--; 592462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", 592562306a36Sopenharmony_ci arvif->vif->addr, arvif->vdev_id); 592662306a36Sopenharmony_ci 592762306a36Sopenharmony_ci if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { 592862306a36Sopenharmony_ci clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); 592962306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", 593062306a36Sopenharmony_ci arvif->vdev_id); 593162306a36Sopenharmony_ci } 593262306a36Sopenharmony_ci 593362306a36Sopenharmony_ci return 0; 593462306a36Sopenharmony_cierr: 593562306a36Sopenharmony_ci return ret; 593662306a36Sopenharmony_ci} 593762306a36Sopenharmony_ci 593862306a36Sopenharmony_cistatic int ath12k_mac_vdev_start(struct ath12k_vif *arvif, 593962306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef) 594062306a36Sopenharmony_ci{ 594162306a36Sopenharmony_ci return ath12k_mac_vdev_start_restart(arvif, chandef, false); 594262306a36Sopenharmony_ci} 594362306a36Sopenharmony_ci 594462306a36Sopenharmony_cistatic int ath12k_mac_vdev_restart(struct ath12k_vif *arvif, 594562306a36Sopenharmony_ci const struct cfg80211_chan_def *chandef) 594662306a36Sopenharmony_ci{ 594762306a36Sopenharmony_ci return ath12k_mac_vdev_start_restart(arvif, chandef, true); 594862306a36Sopenharmony_ci} 594962306a36Sopenharmony_ci 595062306a36Sopenharmony_cistruct ath12k_mac_change_chanctx_arg { 595162306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx; 595262306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs; 595362306a36Sopenharmony_ci int n_vifs; 595462306a36Sopenharmony_ci int next_vif; 595562306a36Sopenharmony_ci}; 595662306a36Sopenharmony_ci 595762306a36Sopenharmony_cistatic void 595862306a36Sopenharmony_ciath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, 595962306a36Sopenharmony_ci struct ieee80211_vif *vif) 596062306a36Sopenharmony_ci{ 596162306a36Sopenharmony_ci struct ath12k_mac_change_chanctx_arg *arg = data; 596262306a36Sopenharmony_ci 596362306a36Sopenharmony_ci if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) 596462306a36Sopenharmony_ci return; 596562306a36Sopenharmony_ci 596662306a36Sopenharmony_ci arg->n_vifs++; 596762306a36Sopenharmony_ci} 596862306a36Sopenharmony_ci 596962306a36Sopenharmony_cistatic void 597062306a36Sopenharmony_ciath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac, 597162306a36Sopenharmony_ci struct ieee80211_vif *vif) 597262306a36Sopenharmony_ci{ 597362306a36Sopenharmony_ci struct ath12k_mac_change_chanctx_arg *arg = data; 597462306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx; 597562306a36Sopenharmony_ci 597662306a36Sopenharmony_ci ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); 597762306a36Sopenharmony_ci if (ctx != arg->ctx) 597862306a36Sopenharmony_ci return; 597962306a36Sopenharmony_ci 598062306a36Sopenharmony_ci if (WARN_ON(arg->next_vif == arg->n_vifs)) 598162306a36Sopenharmony_ci return; 598262306a36Sopenharmony_ci 598362306a36Sopenharmony_ci arg->vifs[arg->next_vif].vif = vif; 598462306a36Sopenharmony_ci arg->vifs[arg->next_vif].old_ctx = ctx; 598562306a36Sopenharmony_ci arg->vifs[arg->next_vif].new_ctx = ctx; 598662306a36Sopenharmony_ci arg->next_vif++; 598762306a36Sopenharmony_ci} 598862306a36Sopenharmony_ci 598962306a36Sopenharmony_cistatic void 599062306a36Sopenharmony_ciath12k_mac_update_vif_chan(struct ath12k *ar, 599162306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs, 599262306a36Sopenharmony_ci int n_vifs) 599362306a36Sopenharmony_ci{ 599462306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 599562306a36Sopenharmony_ci struct ath12k_vif *arvif; 599662306a36Sopenharmony_ci int ret; 599762306a36Sopenharmony_ci int i; 599862306a36Sopenharmony_ci bool monitor_vif = false; 599962306a36Sopenharmony_ci 600062306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 600162306a36Sopenharmony_ci 600262306a36Sopenharmony_ci for (i = 0; i < n_vifs; i++) { 600362306a36Sopenharmony_ci arvif = (void *)vifs[i].vif->drv_priv; 600462306a36Sopenharmony_ci 600562306a36Sopenharmony_ci if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR) 600662306a36Sopenharmony_ci monitor_vif = true; 600762306a36Sopenharmony_ci 600862306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 600962306a36Sopenharmony_ci "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n", 601062306a36Sopenharmony_ci arvif->vdev_id, 601162306a36Sopenharmony_ci vifs[i].old_ctx->def.chan->center_freq, 601262306a36Sopenharmony_ci vifs[i].new_ctx->def.chan->center_freq, 601362306a36Sopenharmony_ci vifs[i].old_ctx->def.width, 601462306a36Sopenharmony_ci vifs[i].new_ctx->def.width); 601562306a36Sopenharmony_ci 601662306a36Sopenharmony_ci if (WARN_ON(!arvif->is_started)) 601762306a36Sopenharmony_ci continue; 601862306a36Sopenharmony_ci 601962306a36Sopenharmony_ci if (WARN_ON(!arvif->is_up)) 602062306a36Sopenharmony_ci continue; 602162306a36Sopenharmony_ci 602262306a36Sopenharmony_ci ret = ath12k_wmi_vdev_down(ar, arvif->vdev_id); 602362306a36Sopenharmony_ci if (ret) { 602462306a36Sopenharmony_ci ath12k_warn(ab, "failed to down vdev %d: %d\n", 602562306a36Sopenharmony_ci arvif->vdev_id, ret); 602662306a36Sopenharmony_ci continue; 602762306a36Sopenharmony_ci } 602862306a36Sopenharmony_ci } 602962306a36Sopenharmony_ci 603062306a36Sopenharmony_ci /* All relevant vdevs are downed and associated channel resources 603162306a36Sopenharmony_ci * should be available for the channel switch now. 603262306a36Sopenharmony_ci */ 603362306a36Sopenharmony_ci 603462306a36Sopenharmony_ci /* TODO: Update ar->rx_channel */ 603562306a36Sopenharmony_ci 603662306a36Sopenharmony_ci for (i = 0; i < n_vifs; i++) { 603762306a36Sopenharmony_ci arvif = (void *)vifs[i].vif->drv_priv; 603862306a36Sopenharmony_ci 603962306a36Sopenharmony_ci if (WARN_ON(!arvif->is_started)) 604062306a36Sopenharmony_ci continue; 604162306a36Sopenharmony_ci 604262306a36Sopenharmony_ci if (WARN_ON(!arvif->is_up)) 604362306a36Sopenharmony_ci continue; 604462306a36Sopenharmony_ci 604562306a36Sopenharmony_ci ret = ath12k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def); 604662306a36Sopenharmony_ci if (ret) { 604762306a36Sopenharmony_ci ath12k_warn(ab, "failed to restart vdev %d: %d\n", 604862306a36Sopenharmony_ci arvif->vdev_id, ret); 604962306a36Sopenharmony_ci continue; 605062306a36Sopenharmony_ci } 605162306a36Sopenharmony_ci 605262306a36Sopenharmony_ci ret = ath12k_mac_setup_bcn_tmpl(arvif); 605362306a36Sopenharmony_ci if (ret) 605462306a36Sopenharmony_ci ath12k_warn(ab, "failed to update bcn tmpl during csa: %d\n", 605562306a36Sopenharmony_ci ret); 605662306a36Sopenharmony_ci 605762306a36Sopenharmony_ci ret = ath12k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid, 605862306a36Sopenharmony_ci arvif->bssid); 605962306a36Sopenharmony_ci if (ret) { 606062306a36Sopenharmony_ci ath12k_warn(ab, "failed to bring vdev up %d: %d\n", 606162306a36Sopenharmony_ci arvif->vdev_id, ret); 606262306a36Sopenharmony_ci continue; 606362306a36Sopenharmony_ci } 606462306a36Sopenharmony_ci } 606562306a36Sopenharmony_ci 606662306a36Sopenharmony_ci /* Restart the internal monitor vdev on new channel */ 606762306a36Sopenharmony_ci if (!monitor_vif && ar->monitor_vdev_created) { 606862306a36Sopenharmony_ci if (!ath12k_mac_monitor_stop(ar)) 606962306a36Sopenharmony_ci ath12k_mac_monitor_start(ar); 607062306a36Sopenharmony_ci } 607162306a36Sopenharmony_ci} 607262306a36Sopenharmony_ci 607362306a36Sopenharmony_cistatic void 607462306a36Sopenharmony_ciath12k_mac_update_active_vif_chan(struct ath12k *ar, 607562306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 607662306a36Sopenharmony_ci{ 607762306a36Sopenharmony_ci struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx }; 607862306a36Sopenharmony_ci 607962306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 608062306a36Sopenharmony_ci 608162306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 608262306a36Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 608362306a36Sopenharmony_ci ath12k_mac_change_chanctx_cnt_iter, 608462306a36Sopenharmony_ci &arg); 608562306a36Sopenharmony_ci if (arg.n_vifs == 0) 608662306a36Sopenharmony_ci return; 608762306a36Sopenharmony_ci 608862306a36Sopenharmony_ci arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]), GFP_KERNEL); 608962306a36Sopenharmony_ci if (!arg.vifs) 609062306a36Sopenharmony_ci return; 609162306a36Sopenharmony_ci 609262306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(ar->hw, 609362306a36Sopenharmony_ci IEEE80211_IFACE_ITER_NORMAL, 609462306a36Sopenharmony_ci ath12k_mac_change_chanctx_fill_iter, 609562306a36Sopenharmony_ci &arg); 609662306a36Sopenharmony_ci 609762306a36Sopenharmony_ci ath12k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs); 609862306a36Sopenharmony_ci 609962306a36Sopenharmony_ci kfree(arg.vifs); 610062306a36Sopenharmony_ci} 610162306a36Sopenharmony_ci 610262306a36Sopenharmony_cistatic void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, 610362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx, 610462306a36Sopenharmony_ci u32 changed) 610562306a36Sopenharmony_ci{ 610662306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 610762306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 610862306a36Sopenharmony_ci 610962306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 611062306a36Sopenharmony_ci 611162306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 611262306a36Sopenharmony_ci "mac chanctx change freq %u width %d ptr %pK changed %x\n", 611362306a36Sopenharmony_ci ctx->def.chan->center_freq, ctx->def.width, ctx, changed); 611462306a36Sopenharmony_ci 611562306a36Sopenharmony_ci /* This shouldn't really happen because channel switching should use 611662306a36Sopenharmony_ci * switch_vif_chanctx(). 611762306a36Sopenharmony_ci */ 611862306a36Sopenharmony_ci if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL)) 611962306a36Sopenharmony_ci goto unlock; 612062306a36Sopenharmony_ci 612162306a36Sopenharmony_ci if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) 612262306a36Sopenharmony_ci ath12k_mac_update_active_vif_chan(ar, ctx); 612362306a36Sopenharmony_ci 612462306a36Sopenharmony_ci /* TODO: Recalc radar detection */ 612562306a36Sopenharmony_ci 612662306a36Sopenharmony_ciunlock: 612762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 612862306a36Sopenharmony_ci} 612962306a36Sopenharmony_ci 613062306a36Sopenharmony_cistatic int ath12k_start_vdev_delay(struct ieee80211_hw *hw, 613162306a36Sopenharmony_ci struct ieee80211_vif *vif) 613262306a36Sopenharmony_ci{ 613362306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 613462306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 613562306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 613662306a36Sopenharmony_ci int ret; 613762306a36Sopenharmony_ci 613862306a36Sopenharmony_ci if (WARN_ON(arvif->is_started)) 613962306a36Sopenharmony_ci return -EBUSY; 614062306a36Sopenharmony_ci 614162306a36Sopenharmony_ci ret = ath12k_mac_vdev_start(arvif, &arvif->chanctx.def); 614262306a36Sopenharmony_ci if (ret) { 614362306a36Sopenharmony_ci ath12k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", 614462306a36Sopenharmony_ci arvif->vdev_id, vif->addr, 614562306a36Sopenharmony_ci arvif->chanctx.def.chan->center_freq, ret); 614662306a36Sopenharmony_ci return ret; 614762306a36Sopenharmony_ci } 614862306a36Sopenharmony_ci 614962306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { 615062306a36Sopenharmony_ci ret = ath12k_monitor_vdev_up(ar, arvif->vdev_id); 615162306a36Sopenharmony_ci if (ret) { 615262306a36Sopenharmony_ci ath12k_warn(ab, "failed put monitor up: %d\n", ret); 615362306a36Sopenharmony_ci return ret; 615462306a36Sopenharmony_ci } 615562306a36Sopenharmony_ci } 615662306a36Sopenharmony_ci 615762306a36Sopenharmony_ci arvif->is_started = true; 615862306a36Sopenharmony_ci 615962306a36Sopenharmony_ci /* TODO: Setup ps and cts/rts protection */ 616062306a36Sopenharmony_ci return 0; 616162306a36Sopenharmony_ci} 616262306a36Sopenharmony_ci 616362306a36Sopenharmony_cistatic int 616462306a36Sopenharmony_ciath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, 616562306a36Sopenharmony_ci struct ieee80211_vif *vif, 616662306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 616762306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 616862306a36Sopenharmony_ci{ 616962306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 617062306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 617162306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 617262306a36Sopenharmony_ci int ret; 617362306a36Sopenharmony_ci struct ath12k_wmi_peer_create_arg param; 617462306a36Sopenharmony_ci 617562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 617662306a36Sopenharmony_ci 617762306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 617862306a36Sopenharmony_ci "mac chanctx assign ptr %pK vdev_id %i\n", 617962306a36Sopenharmony_ci ctx, arvif->vdev_id); 618062306a36Sopenharmony_ci 618162306a36Sopenharmony_ci arvif->punct_bitmap = link_conf->eht_puncturing; 618262306a36Sopenharmony_ci 618362306a36Sopenharmony_ci /* for some targets bss peer must be created before vdev_start */ 618462306a36Sopenharmony_ci if (ab->hw_params->vdev_start_delay && 618562306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_AP && 618662306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && 618762306a36Sopenharmony_ci !ath12k_peer_exist_by_vdev_id(ab, arvif->vdev_id)) { 618862306a36Sopenharmony_ci memcpy(&arvif->chanctx, ctx, sizeof(*ctx)); 618962306a36Sopenharmony_ci ret = 0; 619062306a36Sopenharmony_ci goto out; 619162306a36Sopenharmony_ci } 619262306a36Sopenharmony_ci 619362306a36Sopenharmony_ci if (WARN_ON(arvif->is_started)) { 619462306a36Sopenharmony_ci ret = -EBUSY; 619562306a36Sopenharmony_ci goto out; 619662306a36Sopenharmony_ci } 619762306a36Sopenharmony_ci 619862306a36Sopenharmony_ci if (ab->hw_params->vdev_start_delay && 619962306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_AP && 620062306a36Sopenharmony_ci arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { 620162306a36Sopenharmony_ci param.vdev_id = arvif->vdev_id; 620262306a36Sopenharmony_ci param.peer_type = WMI_PEER_TYPE_DEFAULT; 620362306a36Sopenharmony_ci param.peer_addr = ar->mac_addr; 620462306a36Sopenharmony_ci 620562306a36Sopenharmony_ci ret = ath12k_peer_create(ar, arvif, NULL, ¶m); 620662306a36Sopenharmony_ci if (ret) { 620762306a36Sopenharmony_ci ath12k_warn(ab, "failed to create peer after vdev start delay: %d", 620862306a36Sopenharmony_ci ret); 620962306a36Sopenharmony_ci goto out; 621062306a36Sopenharmony_ci } 621162306a36Sopenharmony_ci } 621262306a36Sopenharmony_ci 621362306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { 621462306a36Sopenharmony_ci ret = ath12k_mac_monitor_start(ar); 621562306a36Sopenharmony_ci if (ret) 621662306a36Sopenharmony_ci goto out; 621762306a36Sopenharmony_ci arvif->is_started = true; 621862306a36Sopenharmony_ci goto out; 621962306a36Sopenharmony_ci } 622062306a36Sopenharmony_ci 622162306a36Sopenharmony_ci ret = ath12k_mac_vdev_start(arvif, &ctx->def); 622262306a36Sopenharmony_ci if (ret) { 622362306a36Sopenharmony_ci ath12k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", 622462306a36Sopenharmony_ci arvif->vdev_id, vif->addr, 622562306a36Sopenharmony_ci ctx->def.chan->center_freq, ret); 622662306a36Sopenharmony_ci goto out; 622762306a36Sopenharmony_ci } 622862306a36Sopenharmony_ci 622962306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && ar->monitor_vdev_created) 623062306a36Sopenharmony_ci ath12k_mac_monitor_start(ar); 623162306a36Sopenharmony_ci 623262306a36Sopenharmony_ci arvif->is_started = true; 623362306a36Sopenharmony_ci 623462306a36Sopenharmony_ci /* TODO: Setup ps and cts/rts protection */ 623562306a36Sopenharmony_ci 623662306a36Sopenharmony_ciout: 623762306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 623862306a36Sopenharmony_ci 623962306a36Sopenharmony_ci return ret; 624062306a36Sopenharmony_ci} 624162306a36Sopenharmony_ci 624262306a36Sopenharmony_cistatic void 624362306a36Sopenharmony_ciath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, 624462306a36Sopenharmony_ci struct ieee80211_vif *vif, 624562306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 624662306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 624762306a36Sopenharmony_ci{ 624862306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 624962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 625062306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 625162306a36Sopenharmony_ci int ret; 625262306a36Sopenharmony_ci 625362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 625462306a36Sopenharmony_ci 625562306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_MAC, 625662306a36Sopenharmony_ci "mac chanctx unassign ptr %pK vdev_id %i\n", 625762306a36Sopenharmony_ci ctx, arvif->vdev_id); 625862306a36Sopenharmony_ci 625962306a36Sopenharmony_ci WARN_ON(!arvif->is_started); 626062306a36Sopenharmony_ci 626162306a36Sopenharmony_ci if (ab->hw_params->vdev_start_delay && 626262306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_MONITOR && 626362306a36Sopenharmony_ci ath12k_peer_find_by_addr(ab, ar->mac_addr)) 626462306a36Sopenharmony_ci ath12k_peer_delete(ar, arvif->vdev_id, ar->mac_addr); 626562306a36Sopenharmony_ci 626662306a36Sopenharmony_ci if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { 626762306a36Sopenharmony_ci ret = ath12k_mac_monitor_stop(ar); 626862306a36Sopenharmony_ci if (ret) { 626962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 627062306a36Sopenharmony_ci return; 627162306a36Sopenharmony_ci } 627262306a36Sopenharmony_ci 627362306a36Sopenharmony_ci arvif->is_started = false; 627462306a36Sopenharmony_ci } 627562306a36Sopenharmony_ci 627662306a36Sopenharmony_ci ret = ath12k_mac_vdev_stop(arvif); 627762306a36Sopenharmony_ci if (ret) 627862306a36Sopenharmony_ci ath12k_warn(ab, "failed to stop vdev %i: %d\n", 627962306a36Sopenharmony_ci arvif->vdev_id, ret); 628062306a36Sopenharmony_ci 628162306a36Sopenharmony_ci arvif->is_started = false; 628262306a36Sopenharmony_ci 628362306a36Sopenharmony_ci if (ab->hw_params->vdev_start_delay && 628462306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) 628562306a36Sopenharmony_ci ath12k_wmi_vdev_down(ar, arvif->vdev_id); 628662306a36Sopenharmony_ci 628762306a36Sopenharmony_ci if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR && 628862306a36Sopenharmony_ci ar->num_started_vdevs == 1 && ar->monitor_vdev_created) 628962306a36Sopenharmony_ci ath12k_mac_monitor_stop(ar); 629062306a36Sopenharmony_ci 629162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 629262306a36Sopenharmony_ci} 629362306a36Sopenharmony_ci 629462306a36Sopenharmony_cistatic int 629562306a36Sopenharmony_ciath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, 629662306a36Sopenharmony_ci struct ieee80211_vif_chanctx_switch *vifs, 629762306a36Sopenharmony_ci int n_vifs, 629862306a36Sopenharmony_ci enum ieee80211_chanctx_switch_mode mode) 629962306a36Sopenharmony_ci{ 630062306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 630162306a36Sopenharmony_ci 630262306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 630362306a36Sopenharmony_ci 630462306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 630562306a36Sopenharmony_ci "mac chanctx switch n_vifs %d mode %d\n", 630662306a36Sopenharmony_ci n_vifs, mode); 630762306a36Sopenharmony_ci ath12k_mac_update_vif_chan(ar, vifs, n_vifs); 630862306a36Sopenharmony_ci 630962306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 631062306a36Sopenharmony_ci 631162306a36Sopenharmony_ci return 0; 631262306a36Sopenharmony_ci} 631362306a36Sopenharmony_ci 631462306a36Sopenharmony_cistatic int 631562306a36Sopenharmony_ciath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) 631662306a36Sopenharmony_ci{ 631762306a36Sopenharmony_ci struct ath12k_vif *arvif; 631862306a36Sopenharmony_ci int ret = 0; 631962306a36Sopenharmony_ci 632062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 632162306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 632262306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "setting mac vdev %d param %d value %d\n", 632362306a36Sopenharmony_ci param, arvif->vdev_id, value); 632462306a36Sopenharmony_ci 632562306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 632662306a36Sopenharmony_ci param, value); 632762306a36Sopenharmony_ci if (ret) { 632862306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set param %d for vdev %d: %d\n", 632962306a36Sopenharmony_ci param, arvif->vdev_id, ret); 633062306a36Sopenharmony_ci break; 633162306a36Sopenharmony_ci } 633262306a36Sopenharmony_ci } 633362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 633462306a36Sopenharmony_ci return ret; 633562306a36Sopenharmony_ci} 633662306a36Sopenharmony_ci 633762306a36Sopenharmony_ci/* mac80211 stores device specific RTS/Fragmentation threshold value, 633862306a36Sopenharmony_ci * this is set interface specific to firmware from ath12k driver 633962306a36Sopenharmony_ci */ 634062306a36Sopenharmony_cistatic int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 634162306a36Sopenharmony_ci{ 634262306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 634362306a36Sopenharmony_ci int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; 634462306a36Sopenharmony_ci 634562306a36Sopenharmony_ci return ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); 634662306a36Sopenharmony_ci} 634762306a36Sopenharmony_ci 634862306a36Sopenharmony_cistatic int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) 634962306a36Sopenharmony_ci{ 635062306a36Sopenharmony_ci /* Even though there's a WMI vdev param for fragmentation threshold no 635162306a36Sopenharmony_ci * known firmware actually implements it. Moreover it is not possible to 635262306a36Sopenharmony_ci * rely frame fragmentation to mac80211 because firmware clears the 635362306a36Sopenharmony_ci * "more fragments" bit in frame control making it impossible for remote 635462306a36Sopenharmony_ci * devices to reassemble frames. 635562306a36Sopenharmony_ci * 635662306a36Sopenharmony_ci * Hence implement a dummy callback just to say fragmentation isn't 635762306a36Sopenharmony_ci * supported. This effectively prevents mac80211 from doing frame 635862306a36Sopenharmony_ci * fragmentation in software. 635962306a36Sopenharmony_ci */ 636062306a36Sopenharmony_ci return -EOPNOTSUPP; 636162306a36Sopenharmony_ci} 636262306a36Sopenharmony_ci 636362306a36Sopenharmony_cistatic void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 636462306a36Sopenharmony_ci u32 queues, bool drop) 636562306a36Sopenharmony_ci{ 636662306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 636762306a36Sopenharmony_ci long time_left; 636862306a36Sopenharmony_ci 636962306a36Sopenharmony_ci if (drop) 637062306a36Sopenharmony_ci return; 637162306a36Sopenharmony_ci 637262306a36Sopenharmony_ci time_left = wait_event_timeout(ar->dp.tx_empty_waitq, 637362306a36Sopenharmony_ci (atomic_read(&ar->dp.num_tx_pending) == 0), 637462306a36Sopenharmony_ci ATH12K_FLUSH_TIMEOUT); 637562306a36Sopenharmony_ci if (time_left == 0) 637662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); 637762306a36Sopenharmony_ci 637862306a36Sopenharmony_ci time_left = wait_event_timeout(ar->txmgmt_empty_waitq, 637962306a36Sopenharmony_ci (atomic_read(&ar->num_pending_mgmt_tx) == 0), 638062306a36Sopenharmony_ci ATH12K_FLUSH_TIMEOUT); 638162306a36Sopenharmony_ci if (time_left == 0) 638262306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", 638362306a36Sopenharmony_ci time_left); 638462306a36Sopenharmony_ci} 638562306a36Sopenharmony_ci 638662306a36Sopenharmony_cistatic int 638762306a36Sopenharmony_ciath12k_mac_bitrate_mask_num_ht_rates(struct ath12k *ar, 638862306a36Sopenharmony_ci enum nl80211_band band, 638962306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 639062306a36Sopenharmony_ci{ 639162306a36Sopenharmony_ci int num_rates = 0; 639262306a36Sopenharmony_ci int i; 639362306a36Sopenharmony_ci 639462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) 639562306a36Sopenharmony_ci num_rates += hweight16(mask->control[band].ht_mcs[i]); 639662306a36Sopenharmony_ci 639762306a36Sopenharmony_ci return num_rates; 639862306a36Sopenharmony_ci} 639962306a36Sopenharmony_ci 640062306a36Sopenharmony_cistatic bool 640162306a36Sopenharmony_ciath12k_mac_has_single_legacy_rate(struct ath12k *ar, 640262306a36Sopenharmony_ci enum nl80211_band band, 640362306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 640462306a36Sopenharmony_ci{ 640562306a36Sopenharmony_ci int num_rates = 0; 640662306a36Sopenharmony_ci 640762306a36Sopenharmony_ci num_rates = hweight32(mask->control[band].legacy); 640862306a36Sopenharmony_ci 640962306a36Sopenharmony_ci if (ath12k_mac_bitrate_mask_num_ht_rates(ar, band, mask)) 641062306a36Sopenharmony_ci return false; 641162306a36Sopenharmony_ci 641262306a36Sopenharmony_ci if (ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask)) 641362306a36Sopenharmony_ci return false; 641462306a36Sopenharmony_ci 641562306a36Sopenharmony_ci return num_rates == 1; 641662306a36Sopenharmony_ci} 641762306a36Sopenharmony_ci 641862306a36Sopenharmony_cistatic bool 641962306a36Sopenharmony_ciath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar, 642062306a36Sopenharmony_ci enum nl80211_band band, 642162306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 642262306a36Sopenharmony_ci int *nss) 642362306a36Sopenharmony_ci{ 642462306a36Sopenharmony_ci struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; 642562306a36Sopenharmony_ci u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); 642662306a36Sopenharmony_ci u8 ht_nss_mask = 0; 642762306a36Sopenharmony_ci u8 vht_nss_mask = 0; 642862306a36Sopenharmony_ci int i; 642962306a36Sopenharmony_ci 643062306a36Sopenharmony_ci /* No need to consider legacy here. Basic rates are always present 643162306a36Sopenharmony_ci * in bitrate mask 643262306a36Sopenharmony_ci */ 643362306a36Sopenharmony_ci 643462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) { 643562306a36Sopenharmony_ci if (mask->control[band].ht_mcs[i] == 0) 643662306a36Sopenharmony_ci continue; 643762306a36Sopenharmony_ci else if (mask->control[band].ht_mcs[i] == 643862306a36Sopenharmony_ci sband->ht_cap.mcs.rx_mask[i]) 643962306a36Sopenharmony_ci ht_nss_mask |= BIT(i); 644062306a36Sopenharmony_ci else 644162306a36Sopenharmony_ci return false; 644262306a36Sopenharmony_ci } 644362306a36Sopenharmony_ci 644462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) { 644562306a36Sopenharmony_ci if (mask->control[band].vht_mcs[i] == 0) 644662306a36Sopenharmony_ci continue; 644762306a36Sopenharmony_ci else if (mask->control[band].vht_mcs[i] == 644862306a36Sopenharmony_ci ath12k_mac_get_max_vht_mcs_map(vht_mcs_map, i)) 644962306a36Sopenharmony_ci vht_nss_mask |= BIT(i); 645062306a36Sopenharmony_ci else 645162306a36Sopenharmony_ci return false; 645262306a36Sopenharmony_ci } 645362306a36Sopenharmony_ci 645462306a36Sopenharmony_ci if (ht_nss_mask != vht_nss_mask) 645562306a36Sopenharmony_ci return false; 645662306a36Sopenharmony_ci 645762306a36Sopenharmony_ci if (ht_nss_mask == 0) 645862306a36Sopenharmony_ci return false; 645962306a36Sopenharmony_ci 646062306a36Sopenharmony_ci if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask) 646162306a36Sopenharmony_ci return false; 646262306a36Sopenharmony_ci 646362306a36Sopenharmony_ci *nss = fls(ht_nss_mask); 646462306a36Sopenharmony_ci 646562306a36Sopenharmony_ci return true; 646662306a36Sopenharmony_ci} 646762306a36Sopenharmony_ci 646862306a36Sopenharmony_cistatic int 646962306a36Sopenharmony_ciath12k_mac_get_single_legacy_rate(struct ath12k *ar, 647062306a36Sopenharmony_ci enum nl80211_band band, 647162306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask, 647262306a36Sopenharmony_ci u32 *rate, u8 *nss) 647362306a36Sopenharmony_ci{ 647462306a36Sopenharmony_ci int rate_idx; 647562306a36Sopenharmony_ci u16 bitrate; 647662306a36Sopenharmony_ci u8 preamble; 647762306a36Sopenharmony_ci u8 hw_rate; 647862306a36Sopenharmony_ci 647962306a36Sopenharmony_ci if (hweight32(mask->control[band].legacy) != 1) 648062306a36Sopenharmony_ci return -EINVAL; 648162306a36Sopenharmony_ci 648262306a36Sopenharmony_ci rate_idx = ffs(mask->control[band].legacy) - 1; 648362306a36Sopenharmony_ci 648462306a36Sopenharmony_ci if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) 648562306a36Sopenharmony_ci rate_idx += ATH12K_MAC_FIRST_OFDM_RATE_IDX; 648662306a36Sopenharmony_ci 648762306a36Sopenharmony_ci hw_rate = ath12k_legacy_rates[rate_idx].hw_value; 648862306a36Sopenharmony_ci bitrate = ath12k_legacy_rates[rate_idx].bitrate; 648962306a36Sopenharmony_ci 649062306a36Sopenharmony_ci if (ath12k_mac_bitrate_is_cck(bitrate)) 649162306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_CCK; 649262306a36Sopenharmony_ci else 649362306a36Sopenharmony_ci preamble = WMI_RATE_PREAMBLE_OFDM; 649462306a36Sopenharmony_ci 649562306a36Sopenharmony_ci *nss = 1; 649662306a36Sopenharmony_ci *rate = ATH12K_HW_RATE_CODE(hw_rate, 0, preamble); 649762306a36Sopenharmony_ci 649862306a36Sopenharmony_ci return 0; 649962306a36Sopenharmony_ci} 650062306a36Sopenharmony_ci 650162306a36Sopenharmony_cistatic int ath12k_mac_set_fixed_rate_params(struct ath12k_vif *arvif, 650262306a36Sopenharmony_ci u32 rate, u8 nss, u8 sgi, u8 ldpc) 650362306a36Sopenharmony_ci{ 650462306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 650562306a36Sopenharmony_ci u32 vdev_param; 650662306a36Sopenharmony_ci int ret; 650762306a36Sopenharmony_ci 650862306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 650962306a36Sopenharmony_ci 651062306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", 651162306a36Sopenharmony_ci arvif->vdev_id, rate, nss, sgi); 651262306a36Sopenharmony_ci 651362306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_FIXED_RATE; 651462306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 651562306a36Sopenharmony_ci vdev_param, rate); 651662306a36Sopenharmony_ci if (ret) { 651762306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", 651862306a36Sopenharmony_ci rate, ret); 651962306a36Sopenharmony_ci return ret; 652062306a36Sopenharmony_ci } 652162306a36Sopenharmony_ci 652262306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_NSS; 652362306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 652462306a36Sopenharmony_ci vdev_param, nss); 652562306a36Sopenharmony_ci if (ret) { 652662306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set nss param %d: %d\n", 652762306a36Sopenharmony_ci nss, ret); 652862306a36Sopenharmony_ci return ret; 652962306a36Sopenharmony_ci } 653062306a36Sopenharmony_ci 653162306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_SGI; 653262306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 653362306a36Sopenharmony_ci vdev_param, sgi); 653462306a36Sopenharmony_ci if (ret) { 653562306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set sgi param %d: %d\n", 653662306a36Sopenharmony_ci sgi, ret); 653762306a36Sopenharmony_ci return ret; 653862306a36Sopenharmony_ci } 653962306a36Sopenharmony_ci 654062306a36Sopenharmony_ci vdev_param = WMI_VDEV_PARAM_LDPC; 654162306a36Sopenharmony_ci ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, 654262306a36Sopenharmony_ci vdev_param, ldpc); 654362306a36Sopenharmony_ci if (ret) { 654462306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set ldpc param %d: %d\n", 654562306a36Sopenharmony_ci ldpc, ret); 654662306a36Sopenharmony_ci return ret; 654762306a36Sopenharmony_ci } 654862306a36Sopenharmony_ci 654962306a36Sopenharmony_ci return 0; 655062306a36Sopenharmony_ci} 655162306a36Sopenharmony_ci 655262306a36Sopenharmony_cistatic bool 655362306a36Sopenharmony_ciath12k_mac_vht_mcs_range_present(struct ath12k *ar, 655462306a36Sopenharmony_ci enum nl80211_band band, 655562306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 655662306a36Sopenharmony_ci{ 655762306a36Sopenharmony_ci int i; 655862306a36Sopenharmony_ci u16 vht_mcs; 655962306a36Sopenharmony_ci 656062306a36Sopenharmony_ci for (i = 0; i < NL80211_VHT_NSS_MAX; i++) { 656162306a36Sopenharmony_ci vht_mcs = mask->control[band].vht_mcs[i]; 656262306a36Sopenharmony_ci 656362306a36Sopenharmony_ci switch (vht_mcs) { 656462306a36Sopenharmony_ci case 0: 656562306a36Sopenharmony_ci case BIT(8) - 1: 656662306a36Sopenharmony_ci case BIT(9) - 1: 656762306a36Sopenharmony_ci case BIT(10) - 1: 656862306a36Sopenharmony_ci break; 656962306a36Sopenharmony_ci default: 657062306a36Sopenharmony_ci return false; 657162306a36Sopenharmony_ci } 657262306a36Sopenharmony_ci } 657362306a36Sopenharmony_ci 657462306a36Sopenharmony_ci return true; 657562306a36Sopenharmony_ci} 657662306a36Sopenharmony_ci 657762306a36Sopenharmony_cistatic void ath12k_mac_set_bitrate_mask_iter(void *data, 657862306a36Sopenharmony_ci struct ieee80211_sta *sta) 657962306a36Sopenharmony_ci{ 658062306a36Sopenharmony_ci struct ath12k_vif *arvif = data; 658162306a36Sopenharmony_ci struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; 658262306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 658362306a36Sopenharmony_ci 658462306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 658562306a36Sopenharmony_ci arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; 658662306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 658762306a36Sopenharmony_ci 658862306a36Sopenharmony_ci ieee80211_queue_work(ar->hw, &arsta->update_wk); 658962306a36Sopenharmony_ci} 659062306a36Sopenharmony_ci 659162306a36Sopenharmony_cistatic void ath12k_mac_disable_peer_fixed_rate(void *data, 659262306a36Sopenharmony_ci struct ieee80211_sta *sta) 659362306a36Sopenharmony_ci{ 659462306a36Sopenharmony_ci struct ath12k_vif *arvif = data; 659562306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 659662306a36Sopenharmony_ci int ret; 659762306a36Sopenharmony_ci 659862306a36Sopenharmony_ci ret = ath12k_wmi_set_peer_param(ar, sta->addr, 659962306a36Sopenharmony_ci arvif->vdev_id, 660062306a36Sopenharmony_ci WMI_PEER_PARAM_FIXED_RATE, 660162306a36Sopenharmony_ci WMI_FIXED_RATE_NONE); 660262306a36Sopenharmony_ci if (ret) 660362306a36Sopenharmony_ci ath12k_warn(ar->ab, 660462306a36Sopenharmony_ci "failed to disable peer fixed rate for STA %pM ret %d\n", 660562306a36Sopenharmony_ci sta->addr, ret); 660662306a36Sopenharmony_ci} 660762306a36Sopenharmony_ci 660862306a36Sopenharmony_cistatic int 660962306a36Sopenharmony_ciath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, 661062306a36Sopenharmony_ci struct ieee80211_vif *vif, 661162306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 661262306a36Sopenharmony_ci{ 661362306a36Sopenharmony_ci struct ath12k_vif *arvif = (void *)vif->drv_priv; 661462306a36Sopenharmony_ci struct cfg80211_chan_def def; 661562306a36Sopenharmony_ci struct ath12k *ar = arvif->ar; 661662306a36Sopenharmony_ci enum nl80211_band band; 661762306a36Sopenharmony_ci const u8 *ht_mcs_mask; 661862306a36Sopenharmony_ci const u16 *vht_mcs_mask; 661962306a36Sopenharmony_ci u32 rate; 662062306a36Sopenharmony_ci u8 nss; 662162306a36Sopenharmony_ci u8 sgi; 662262306a36Sopenharmony_ci u8 ldpc; 662362306a36Sopenharmony_ci int single_nss; 662462306a36Sopenharmony_ci int ret; 662562306a36Sopenharmony_ci int num_rates; 662662306a36Sopenharmony_ci 662762306a36Sopenharmony_ci if (ath12k_mac_vif_chan(vif, &def)) 662862306a36Sopenharmony_ci return -EPERM; 662962306a36Sopenharmony_ci 663062306a36Sopenharmony_ci band = def.chan->band; 663162306a36Sopenharmony_ci ht_mcs_mask = mask->control[band].ht_mcs; 663262306a36Sopenharmony_ci vht_mcs_mask = mask->control[band].vht_mcs; 663362306a36Sopenharmony_ci ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); 663462306a36Sopenharmony_ci 663562306a36Sopenharmony_ci sgi = mask->control[band].gi; 663662306a36Sopenharmony_ci if (sgi == NL80211_TXRATE_FORCE_LGI) 663762306a36Sopenharmony_ci return -EINVAL; 663862306a36Sopenharmony_ci 663962306a36Sopenharmony_ci /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it 664062306a36Sopenharmony_ci * requires passing at least one of used basic rates along with them. 664162306a36Sopenharmony_ci * Fixed rate setting across different preambles(legacy, HT, VHT) is 664262306a36Sopenharmony_ci * not supported by the FW. Hence use of FIXED_RATE vdev param is not 664362306a36Sopenharmony_ci * suitable for setting single HT/VHT rates. 664462306a36Sopenharmony_ci * But, there could be a single basic rate passed from userspace which 664562306a36Sopenharmony_ci * can be done through the FIXED_RATE param. 664662306a36Sopenharmony_ci */ 664762306a36Sopenharmony_ci if (ath12k_mac_has_single_legacy_rate(ar, band, mask)) { 664862306a36Sopenharmony_ci ret = ath12k_mac_get_single_legacy_rate(ar, band, mask, &rate, 664962306a36Sopenharmony_ci &nss); 665062306a36Sopenharmony_ci if (ret) { 665162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to get single legacy rate for vdev %i: %d\n", 665262306a36Sopenharmony_ci arvif->vdev_id, ret); 665362306a36Sopenharmony_ci return ret; 665462306a36Sopenharmony_ci } 665562306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 665662306a36Sopenharmony_ci ath12k_mac_disable_peer_fixed_rate, 665762306a36Sopenharmony_ci arvif); 665862306a36Sopenharmony_ci } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, 665962306a36Sopenharmony_ci &single_nss)) { 666062306a36Sopenharmony_ci rate = WMI_FIXED_RATE_NONE; 666162306a36Sopenharmony_ci nss = single_nss; 666262306a36Sopenharmony_ci } else { 666362306a36Sopenharmony_ci rate = WMI_FIXED_RATE_NONE; 666462306a36Sopenharmony_ci nss = min_t(u32, ar->num_tx_chains, 666562306a36Sopenharmony_ci max(ath12k_mac_max_ht_nss(ht_mcs_mask), 666662306a36Sopenharmony_ci ath12k_mac_max_vht_nss(vht_mcs_mask))); 666762306a36Sopenharmony_ci 666862306a36Sopenharmony_ci /* If multiple rates across different preambles are given 666962306a36Sopenharmony_ci * we can reconfigure this info with all peers using PEER_ASSOC 667062306a36Sopenharmony_ci * command with the below exception cases. 667162306a36Sopenharmony_ci * - Single VHT Rate : peer_assoc command accommodates only MCS 667262306a36Sopenharmony_ci * range values i.e 0-7, 0-8, 0-9 for VHT. Though mac80211 667362306a36Sopenharmony_ci * mandates passing basic rates along with HT/VHT rates, FW 667462306a36Sopenharmony_ci * doesn't allow switching from VHT to Legacy. Hence instead of 667562306a36Sopenharmony_ci * setting legacy and VHT rates using RATEMASK_CMD vdev cmd, 667662306a36Sopenharmony_ci * we could set this VHT rate as peer fixed rate param, which 667762306a36Sopenharmony_ci * will override FIXED rate and FW rate control algorithm. 667862306a36Sopenharmony_ci * If single VHT rate is passed along with HT rates, we select 667962306a36Sopenharmony_ci * the VHT rate as fixed rate for vht peers. 668062306a36Sopenharmony_ci * - Multiple VHT Rates : When Multiple VHT rates are given,this 668162306a36Sopenharmony_ci * can be set using RATEMASK CMD which uses FW rate-ctl alg. 668262306a36Sopenharmony_ci * TODO: Setting multiple VHT MCS and replacing peer_assoc with 668362306a36Sopenharmony_ci * RATEMASK_CMDID can cover all use cases of setting rates 668462306a36Sopenharmony_ci * across multiple preambles and rates within same type. 668562306a36Sopenharmony_ci * But requires more validation of the command at this point. 668662306a36Sopenharmony_ci */ 668762306a36Sopenharmony_ci 668862306a36Sopenharmony_ci num_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, 668962306a36Sopenharmony_ci mask); 669062306a36Sopenharmony_ci 669162306a36Sopenharmony_ci if (!ath12k_mac_vht_mcs_range_present(ar, band, mask) && 669262306a36Sopenharmony_ci num_rates > 1) { 669362306a36Sopenharmony_ci /* TODO: Handle multiple VHT MCS values setting using 669462306a36Sopenharmony_ci * RATEMASK CMD 669562306a36Sopenharmony_ci */ 669662306a36Sopenharmony_ci ath12k_warn(ar->ab, 669762306a36Sopenharmony_ci "Setting more than one MCS Value in bitrate mask not supported\n"); 669862306a36Sopenharmony_ci return -EINVAL; 669962306a36Sopenharmony_ci } 670062306a36Sopenharmony_ci 670162306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 670262306a36Sopenharmony_ci ath12k_mac_disable_peer_fixed_rate, 670362306a36Sopenharmony_ci arvif); 670462306a36Sopenharmony_ci 670562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 670662306a36Sopenharmony_ci 670762306a36Sopenharmony_ci arvif->bitrate_mask = *mask; 670862306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(ar->hw, 670962306a36Sopenharmony_ci ath12k_mac_set_bitrate_mask_iter, 671062306a36Sopenharmony_ci arvif); 671162306a36Sopenharmony_ci 671262306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 671362306a36Sopenharmony_ci } 671462306a36Sopenharmony_ci 671562306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 671662306a36Sopenharmony_ci 671762306a36Sopenharmony_ci ret = ath12k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); 671862306a36Sopenharmony_ci if (ret) { 671962306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", 672062306a36Sopenharmony_ci arvif->vdev_id, ret); 672162306a36Sopenharmony_ci } 672262306a36Sopenharmony_ci 672362306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 672462306a36Sopenharmony_ci 672562306a36Sopenharmony_ci return ret; 672662306a36Sopenharmony_ci} 672762306a36Sopenharmony_ci 672862306a36Sopenharmony_cistatic void 672962306a36Sopenharmony_ciath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, 673062306a36Sopenharmony_ci enum ieee80211_reconfig_type reconfig_type) 673162306a36Sopenharmony_ci{ 673262306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 673362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 673462306a36Sopenharmony_ci struct ath12k_vif *arvif; 673562306a36Sopenharmony_ci int recovery_count; 673662306a36Sopenharmony_ci 673762306a36Sopenharmony_ci if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) 673862306a36Sopenharmony_ci return; 673962306a36Sopenharmony_ci 674062306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 674162306a36Sopenharmony_ci 674262306a36Sopenharmony_ci if (ar->state == ATH12K_STATE_RESTARTED) { 674362306a36Sopenharmony_ci ath12k_warn(ar->ab, "pdev %d successfully recovered\n", 674462306a36Sopenharmony_ci ar->pdev->pdev_id); 674562306a36Sopenharmony_ci ar->state = ATH12K_STATE_ON; 674662306a36Sopenharmony_ci ieee80211_wake_queues(ar->hw); 674762306a36Sopenharmony_ci 674862306a36Sopenharmony_ci if (ab->is_reset) { 674962306a36Sopenharmony_ci recovery_count = atomic_inc_return(&ab->recovery_count); 675062306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n", 675162306a36Sopenharmony_ci recovery_count); 675262306a36Sopenharmony_ci /* When there are multiple radios in an SOC, 675362306a36Sopenharmony_ci * the recovery has to be done for each radio 675462306a36Sopenharmony_ci */ 675562306a36Sopenharmony_ci if (recovery_count == ab->num_radios) { 675662306a36Sopenharmony_ci atomic_dec(&ab->reset_count); 675762306a36Sopenharmony_ci complete(&ab->reset_complete); 675862306a36Sopenharmony_ci ab->is_reset = false; 675962306a36Sopenharmony_ci atomic_set(&ab->fail_cont_count, 0); 676062306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset success\n"); 676162306a36Sopenharmony_ci } 676262306a36Sopenharmony_ci } 676362306a36Sopenharmony_ci 676462306a36Sopenharmony_ci list_for_each_entry(arvif, &ar->arvifs, list) { 676562306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_BOOT, 676662306a36Sopenharmony_ci "reconfig cipher %d up %d vdev type %d\n", 676762306a36Sopenharmony_ci arvif->key_cipher, 676862306a36Sopenharmony_ci arvif->is_up, 676962306a36Sopenharmony_ci arvif->vdev_type); 677062306a36Sopenharmony_ci /* After trigger disconnect, then upper layer will 677162306a36Sopenharmony_ci * trigger connect again, then the PN number of 677262306a36Sopenharmony_ci * upper layer will be reset to keep up with AP 677362306a36Sopenharmony_ci * side, hence PN number mismatch will not happen. 677462306a36Sopenharmony_ci */ 677562306a36Sopenharmony_ci if (arvif->is_up && 677662306a36Sopenharmony_ci arvif->vdev_type == WMI_VDEV_TYPE_STA && 677762306a36Sopenharmony_ci arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { 677862306a36Sopenharmony_ci ieee80211_hw_restart_disconnect(arvif->vif); 677962306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_BOOT, 678062306a36Sopenharmony_ci "restart disconnect\n"); 678162306a36Sopenharmony_ci } 678262306a36Sopenharmony_ci } 678362306a36Sopenharmony_ci } 678462306a36Sopenharmony_ci 678562306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 678662306a36Sopenharmony_ci} 678762306a36Sopenharmony_ci 678862306a36Sopenharmony_cistatic void 678962306a36Sopenharmony_ciath12k_mac_update_bss_chan_survey(struct ath12k *ar, 679062306a36Sopenharmony_ci struct ieee80211_channel *channel) 679162306a36Sopenharmony_ci{ 679262306a36Sopenharmony_ci int ret; 679362306a36Sopenharmony_ci enum wmi_bss_chan_info_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ; 679462306a36Sopenharmony_ci 679562306a36Sopenharmony_ci lockdep_assert_held(&ar->conf_mutex); 679662306a36Sopenharmony_ci 679762306a36Sopenharmony_ci if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_ab.svc_map) || 679862306a36Sopenharmony_ci ar->rx_channel != channel) 679962306a36Sopenharmony_ci return; 680062306a36Sopenharmony_ci 680162306a36Sopenharmony_ci if (ar->scan.state != ATH12K_SCAN_IDLE) { 680262306a36Sopenharmony_ci ath12k_dbg(ar->ab, ATH12K_DBG_MAC, 680362306a36Sopenharmony_ci "ignoring bss chan info req while scanning..\n"); 680462306a36Sopenharmony_ci return; 680562306a36Sopenharmony_ci } 680662306a36Sopenharmony_ci 680762306a36Sopenharmony_ci reinit_completion(&ar->bss_survey_done); 680862306a36Sopenharmony_ci 680962306a36Sopenharmony_ci ret = ath12k_wmi_pdev_bss_chan_info_request(ar, type); 681062306a36Sopenharmony_ci if (ret) { 681162306a36Sopenharmony_ci ath12k_warn(ar->ab, "failed to send pdev bss chan info request\n"); 681262306a36Sopenharmony_ci return; 681362306a36Sopenharmony_ci } 681462306a36Sopenharmony_ci 681562306a36Sopenharmony_ci ret = wait_for_completion_timeout(&ar->bss_survey_done, 3 * HZ); 681662306a36Sopenharmony_ci if (ret == 0) 681762306a36Sopenharmony_ci ath12k_warn(ar->ab, "bss channel survey timed out\n"); 681862306a36Sopenharmony_ci} 681962306a36Sopenharmony_ci 682062306a36Sopenharmony_cistatic int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, 682162306a36Sopenharmony_ci struct survey_info *survey) 682262306a36Sopenharmony_ci{ 682362306a36Sopenharmony_ci struct ath12k *ar = hw->priv; 682462306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 682562306a36Sopenharmony_ci struct survey_info *ar_survey; 682662306a36Sopenharmony_ci int ret = 0; 682762306a36Sopenharmony_ci 682862306a36Sopenharmony_ci if (idx >= ATH12K_NUM_CHANS) 682962306a36Sopenharmony_ci return -ENOENT; 683062306a36Sopenharmony_ci 683162306a36Sopenharmony_ci ar_survey = &ar->survey[idx]; 683262306a36Sopenharmony_ci 683362306a36Sopenharmony_ci mutex_lock(&ar->conf_mutex); 683462306a36Sopenharmony_ci 683562306a36Sopenharmony_ci sband = hw->wiphy->bands[NL80211_BAND_2GHZ]; 683662306a36Sopenharmony_ci if (sband && idx >= sband->n_channels) { 683762306a36Sopenharmony_ci idx -= sband->n_channels; 683862306a36Sopenharmony_ci sband = NULL; 683962306a36Sopenharmony_ci } 684062306a36Sopenharmony_ci 684162306a36Sopenharmony_ci if (!sband) 684262306a36Sopenharmony_ci sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; 684362306a36Sopenharmony_ci 684462306a36Sopenharmony_ci if (!sband || idx >= sband->n_channels) { 684562306a36Sopenharmony_ci ret = -ENOENT; 684662306a36Sopenharmony_ci goto exit; 684762306a36Sopenharmony_ci } 684862306a36Sopenharmony_ci 684962306a36Sopenharmony_ci ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]); 685062306a36Sopenharmony_ci 685162306a36Sopenharmony_ci spin_lock_bh(&ar->data_lock); 685262306a36Sopenharmony_ci memcpy(survey, ar_survey, sizeof(*survey)); 685362306a36Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 685462306a36Sopenharmony_ci 685562306a36Sopenharmony_ci survey->channel = &sband->channels[idx]; 685662306a36Sopenharmony_ci 685762306a36Sopenharmony_ci if (ar->rx_channel == survey->channel) 685862306a36Sopenharmony_ci survey->filled |= SURVEY_INFO_IN_USE; 685962306a36Sopenharmony_ci 686062306a36Sopenharmony_ciexit: 686162306a36Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 686262306a36Sopenharmony_ci return ret; 686362306a36Sopenharmony_ci} 686462306a36Sopenharmony_ci 686562306a36Sopenharmony_cistatic void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, 686662306a36Sopenharmony_ci struct ieee80211_vif *vif, 686762306a36Sopenharmony_ci struct ieee80211_sta *sta, 686862306a36Sopenharmony_ci struct station_info *sinfo) 686962306a36Sopenharmony_ci{ 687062306a36Sopenharmony_ci struct ath12k_sta *arsta = (struct ath12k_sta *)sta->drv_priv; 687162306a36Sopenharmony_ci 687262306a36Sopenharmony_ci sinfo->rx_duration = arsta->rx_duration; 687362306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); 687462306a36Sopenharmony_ci 687562306a36Sopenharmony_ci sinfo->tx_duration = arsta->tx_duration; 687662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); 687762306a36Sopenharmony_ci 687862306a36Sopenharmony_ci if (!arsta->txrate.legacy && !arsta->txrate.nss) 687962306a36Sopenharmony_ci return; 688062306a36Sopenharmony_ci 688162306a36Sopenharmony_ci if (arsta->txrate.legacy) { 688262306a36Sopenharmony_ci sinfo->txrate.legacy = arsta->txrate.legacy; 688362306a36Sopenharmony_ci } else { 688462306a36Sopenharmony_ci sinfo->txrate.mcs = arsta->txrate.mcs; 688562306a36Sopenharmony_ci sinfo->txrate.nss = arsta->txrate.nss; 688662306a36Sopenharmony_ci sinfo->txrate.bw = arsta->txrate.bw; 688762306a36Sopenharmony_ci sinfo->txrate.he_gi = arsta->txrate.he_gi; 688862306a36Sopenharmony_ci sinfo->txrate.he_dcm = arsta->txrate.he_dcm; 688962306a36Sopenharmony_ci sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc; 689062306a36Sopenharmony_ci } 689162306a36Sopenharmony_ci sinfo->txrate.flags = arsta->txrate.flags; 689262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 689362306a36Sopenharmony_ci 689462306a36Sopenharmony_ci /* TODO: Use real NF instead of default one. */ 689562306a36Sopenharmony_ci sinfo->signal = arsta->rssi_comb + ATH12K_DEFAULT_NOISE_FLOOR; 689662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); 689762306a36Sopenharmony_ci} 689862306a36Sopenharmony_ci 689962306a36Sopenharmony_cistatic const struct ieee80211_ops ath12k_ops = { 690062306a36Sopenharmony_ci .tx = ath12k_mac_op_tx, 690162306a36Sopenharmony_ci .wake_tx_queue = ieee80211_handle_wake_tx_queue, 690262306a36Sopenharmony_ci .start = ath12k_mac_op_start, 690362306a36Sopenharmony_ci .stop = ath12k_mac_op_stop, 690462306a36Sopenharmony_ci .reconfig_complete = ath12k_mac_op_reconfig_complete, 690562306a36Sopenharmony_ci .add_interface = ath12k_mac_op_add_interface, 690662306a36Sopenharmony_ci .remove_interface = ath12k_mac_op_remove_interface, 690762306a36Sopenharmony_ci .update_vif_offload = ath12k_mac_op_update_vif_offload, 690862306a36Sopenharmony_ci .config = ath12k_mac_op_config, 690962306a36Sopenharmony_ci .bss_info_changed = ath12k_mac_op_bss_info_changed, 691062306a36Sopenharmony_ci .configure_filter = ath12k_mac_op_configure_filter, 691162306a36Sopenharmony_ci .hw_scan = ath12k_mac_op_hw_scan, 691262306a36Sopenharmony_ci .cancel_hw_scan = ath12k_mac_op_cancel_hw_scan, 691362306a36Sopenharmony_ci .set_key = ath12k_mac_op_set_key, 691462306a36Sopenharmony_ci .sta_state = ath12k_mac_op_sta_state, 691562306a36Sopenharmony_ci .sta_set_txpwr = ath12k_mac_op_sta_set_txpwr, 691662306a36Sopenharmony_ci .sta_rc_update = ath12k_mac_op_sta_rc_update, 691762306a36Sopenharmony_ci .conf_tx = ath12k_mac_op_conf_tx, 691862306a36Sopenharmony_ci .set_antenna = ath12k_mac_op_set_antenna, 691962306a36Sopenharmony_ci .get_antenna = ath12k_mac_op_get_antenna, 692062306a36Sopenharmony_ci .ampdu_action = ath12k_mac_op_ampdu_action, 692162306a36Sopenharmony_ci .add_chanctx = ath12k_mac_op_add_chanctx, 692262306a36Sopenharmony_ci .remove_chanctx = ath12k_mac_op_remove_chanctx, 692362306a36Sopenharmony_ci .change_chanctx = ath12k_mac_op_change_chanctx, 692462306a36Sopenharmony_ci .assign_vif_chanctx = ath12k_mac_op_assign_vif_chanctx, 692562306a36Sopenharmony_ci .unassign_vif_chanctx = ath12k_mac_op_unassign_vif_chanctx, 692662306a36Sopenharmony_ci .switch_vif_chanctx = ath12k_mac_op_switch_vif_chanctx, 692762306a36Sopenharmony_ci .set_rts_threshold = ath12k_mac_op_set_rts_threshold, 692862306a36Sopenharmony_ci .set_frag_threshold = ath12k_mac_op_set_frag_threshold, 692962306a36Sopenharmony_ci .set_bitrate_mask = ath12k_mac_op_set_bitrate_mask, 693062306a36Sopenharmony_ci .get_survey = ath12k_mac_op_get_survey, 693162306a36Sopenharmony_ci .flush = ath12k_mac_op_flush, 693262306a36Sopenharmony_ci .sta_statistics = ath12k_mac_op_sta_statistics, 693362306a36Sopenharmony_ci}; 693462306a36Sopenharmony_ci 693562306a36Sopenharmony_cistatic void ath12k_mac_update_ch_list(struct ath12k *ar, 693662306a36Sopenharmony_ci struct ieee80211_supported_band *band, 693762306a36Sopenharmony_ci u32 freq_low, u32 freq_high) 693862306a36Sopenharmony_ci{ 693962306a36Sopenharmony_ci int i; 694062306a36Sopenharmony_ci 694162306a36Sopenharmony_ci if (!(freq_low && freq_high)) 694262306a36Sopenharmony_ci return; 694362306a36Sopenharmony_ci 694462306a36Sopenharmony_ci for (i = 0; i < band->n_channels; i++) { 694562306a36Sopenharmony_ci if (band->channels[i].center_freq < freq_low || 694662306a36Sopenharmony_ci band->channels[i].center_freq > freq_high) 694762306a36Sopenharmony_ci band->channels[i].flags |= IEEE80211_CHAN_DISABLED; 694862306a36Sopenharmony_ci } 694962306a36Sopenharmony_ci} 695062306a36Sopenharmony_ci 695162306a36Sopenharmony_cistatic u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) 695262306a36Sopenharmony_ci{ 695362306a36Sopenharmony_ci struct ath12k_pdev *pdev = ar->pdev; 695462306a36Sopenharmony_ci struct ath12k_pdev_cap *pdev_cap = &pdev->cap; 695562306a36Sopenharmony_ci 695662306a36Sopenharmony_ci if (band == WMI_HOST_WLAN_2G_CAP) 695762306a36Sopenharmony_ci return pdev_cap->band[NL80211_BAND_2GHZ].phy_id; 695862306a36Sopenharmony_ci 695962306a36Sopenharmony_ci if (band == WMI_HOST_WLAN_5G_CAP) 696062306a36Sopenharmony_ci return pdev_cap->band[NL80211_BAND_5GHZ].phy_id; 696162306a36Sopenharmony_ci 696262306a36Sopenharmony_ci ath12k_warn(ar->ab, "unsupported phy cap:%d\n", band); 696362306a36Sopenharmony_ci 696462306a36Sopenharmony_ci return 0; 696562306a36Sopenharmony_ci} 696662306a36Sopenharmony_ci 696762306a36Sopenharmony_cistatic int ath12k_mac_setup_channels_rates(struct ath12k *ar, 696862306a36Sopenharmony_ci u32 supported_bands) 696962306a36Sopenharmony_ci{ 697062306a36Sopenharmony_ci struct ieee80211_supported_band *band; 697162306a36Sopenharmony_ci struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; 697262306a36Sopenharmony_ci void *channels; 697362306a36Sopenharmony_ci u32 phy_id; 697462306a36Sopenharmony_ci 697562306a36Sopenharmony_ci BUILD_BUG_ON((ARRAY_SIZE(ath12k_2ghz_channels) + 697662306a36Sopenharmony_ci ARRAY_SIZE(ath12k_5ghz_channels) + 697762306a36Sopenharmony_ci ARRAY_SIZE(ath12k_6ghz_channels)) != 697862306a36Sopenharmony_ci ATH12K_NUM_CHANS); 697962306a36Sopenharmony_ci 698062306a36Sopenharmony_ci reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx]; 698162306a36Sopenharmony_ci 698262306a36Sopenharmony_ci if (supported_bands & WMI_HOST_WLAN_2G_CAP) { 698362306a36Sopenharmony_ci channels = kmemdup(ath12k_2ghz_channels, 698462306a36Sopenharmony_ci sizeof(ath12k_2ghz_channels), 698562306a36Sopenharmony_ci GFP_KERNEL); 698662306a36Sopenharmony_ci if (!channels) 698762306a36Sopenharmony_ci return -ENOMEM; 698862306a36Sopenharmony_ci 698962306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_2GHZ]; 699062306a36Sopenharmony_ci band->band = NL80211_BAND_2GHZ; 699162306a36Sopenharmony_ci band->n_channels = ARRAY_SIZE(ath12k_2ghz_channels); 699262306a36Sopenharmony_ci band->channels = channels; 699362306a36Sopenharmony_ci band->n_bitrates = ath12k_g_rates_size; 699462306a36Sopenharmony_ci band->bitrates = ath12k_g_rates; 699562306a36Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band; 699662306a36Sopenharmony_ci 699762306a36Sopenharmony_ci if (ar->ab->hw_params->single_pdev_only) { 699862306a36Sopenharmony_ci phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); 699962306a36Sopenharmony_ci reg_cap = &ar->ab->hal_reg_cap[phy_id]; 700062306a36Sopenharmony_ci } 700162306a36Sopenharmony_ci ath12k_mac_update_ch_list(ar, band, 700262306a36Sopenharmony_ci reg_cap->low_2ghz_chan, 700362306a36Sopenharmony_ci reg_cap->high_2ghz_chan); 700462306a36Sopenharmony_ci } 700562306a36Sopenharmony_ci 700662306a36Sopenharmony_ci if (supported_bands & WMI_HOST_WLAN_5G_CAP) { 700762306a36Sopenharmony_ci if (reg_cap->high_5ghz_chan >= ATH12K_MIN_6G_FREQ) { 700862306a36Sopenharmony_ci channels = kmemdup(ath12k_6ghz_channels, 700962306a36Sopenharmony_ci sizeof(ath12k_6ghz_channels), GFP_KERNEL); 701062306a36Sopenharmony_ci if (!channels) { 701162306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); 701262306a36Sopenharmony_ci return -ENOMEM; 701362306a36Sopenharmony_ci } 701462306a36Sopenharmony_ci 701562306a36Sopenharmony_ci ar->supports_6ghz = true; 701662306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_6GHZ]; 701762306a36Sopenharmony_ci band->band = NL80211_BAND_6GHZ; 701862306a36Sopenharmony_ci band->n_channels = ARRAY_SIZE(ath12k_6ghz_channels); 701962306a36Sopenharmony_ci band->channels = channels; 702062306a36Sopenharmony_ci band->n_bitrates = ath12k_a_rates_size; 702162306a36Sopenharmony_ci band->bitrates = ath12k_a_rates; 702262306a36Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band; 702362306a36Sopenharmony_ci ath12k_mac_update_ch_list(ar, band, 702462306a36Sopenharmony_ci reg_cap->low_5ghz_chan, 702562306a36Sopenharmony_ci reg_cap->high_5ghz_chan); 702662306a36Sopenharmony_ci } 702762306a36Sopenharmony_ci 702862306a36Sopenharmony_ci if (reg_cap->low_5ghz_chan < ATH12K_MIN_6G_FREQ) { 702962306a36Sopenharmony_ci channels = kmemdup(ath12k_5ghz_channels, 703062306a36Sopenharmony_ci sizeof(ath12k_5ghz_channels), 703162306a36Sopenharmony_ci GFP_KERNEL); 703262306a36Sopenharmony_ci if (!channels) { 703362306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); 703462306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); 703562306a36Sopenharmony_ci return -ENOMEM; 703662306a36Sopenharmony_ci } 703762306a36Sopenharmony_ci 703862306a36Sopenharmony_ci band = &ar->mac.sbands[NL80211_BAND_5GHZ]; 703962306a36Sopenharmony_ci band->band = NL80211_BAND_5GHZ; 704062306a36Sopenharmony_ci band->n_channels = ARRAY_SIZE(ath12k_5ghz_channels); 704162306a36Sopenharmony_ci band->channels = channels; 704262306a36Sopenharmony_ci band->n_bitrates = ath12k_a_rates_size; 704362306a36Sopenharmony_ci band->bitrates = ath12k_a_rates; 704462306a36Sopenharmony_ci ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; 704562306a36Sopenharmony_ci 704662306a36Sopenharmony_ci if (ar->ab->hw_params->single_pdev_only) { 704762306a36Sopenharmony_ci phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); 704862306a36Sopenharmony_ci reg_cap = &ar->ab->hal_reg_cap[phy_id]; 704962306a36Sopenharmony_ci } 705062306a36Sopenharmony_ci 705162306a36Sopenharmony_ci ath12k_mac_update_ch_list(ar, band, 705262306a36Sopenharmony_ci reg_cap->low_5ghz_chan, 705362306a36Sopenharmony_ci reg_cap->high_5ghz_chan); 705462306a36Sopenharmony_ci } 705562306a36Sopenharmony_ci } 705662306a36Sopenharmony_ci 705762306a36Sopenharmony_ci return 0; 705862306a36Sopenharmony_ci} 705962306a36Sopenharmony_ci 706062306a36Sopenharmony_cistatic int ath12k_mac_setup_iface_combinations(struct ath12k *ar) 706162306a36Sopenharmony_ci{ 706262306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 706362306a36Sopenharmony_ci struct ieee80211_iface_combination *combinations; 706462306a36Sopenharmony_ci struct ieee80211_iface_limit *limits; 706562306a36Sopenharmony_ci int n_limits, max_interfaces; 706662306a36Sopenharmony_ci bool ap, mesh; 706762306a36Sopenharmony_ci 706862306a36Sopenharmony_ci ap = ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_AP); 706962306a36Sopenharmony_ci 707062306a36Sopenharmony_ci mesh = IS_ENABLED(CONFIG_MAC80211_MESH) && 707162306a36Sopenharmony_ci ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT); 707262306a36Sopenharmony_ci 707362306a36Sopenharmony_ci combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); 707462306a36Sopenharmony_ci if (!combinations) 707562306a36Sopenharmony_ci return -ENOMEM; 707662306a36Sopenharmony_ci 707762306a36Sopenharmony_ci if (ap || mesh) { 707862306a36Sopenharmony_ci n_limits = 2; 707962306a36Sopenharmony_ci max_interfaces = 16; 708062306a36Sopenharmony_ci } else { 708162306a36Sopenharmony_ci n_limits = 1; 708262306a36Sopenharmony_ci max_interfaces = 1; 708362306a36Sopenharmony_ci } 708462306a36Sopenharmony_ci 708562306a36Sopenharmony_ci limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL); 708662306a36Sopenharmony_ci if (!limits) { 708762306a36Sopenharmony_ci kfree(combinations); 708862306a36Sopenharmony_ci return -ENOMEM; 708962306a36Sopenharmony_ci } 709062306a36Sopenharmony_ci 709162306a36Sopenharmony_ci limits[0].max = 1; 709262306a36Sopenharmony_ci limits[0].types |= BIT(NL80211_IFTYPE_STATION); 709362306a36Sopenharmony_ci 709462306a36Sopenharmony_ci if (ap) { 709562306a36Sopenharmony_ci limits[1].max = max_interfaces; 709662306a36Sopenharmony_ci limits[1].types |= BIT(NL80211_IFTYPE_AP); 709762306a36Sopenharmony_ci } 709862306a36Sopenharmony_ci 709962306a36Sopenharmony_ci if (mesh) 710062306a36Sopenharmony_ci limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); 710162306a36Sopenharmony_ci 710262306a36Sopenharmony_ci combinations[0].limits = limits; 710362306a36Sopenharmony_ci combinations[0].n_limits = n_limits; 710462306a36Sopenharmony_ci combinations[0].max_interfaces = max_interfaces; 710562306a36Sopenharmony_ci combinations[0].num_different_channels = 1; 710662306a36Sopenharmony_ci combinations[0].beacon_int_infra_match = true; 710762306a36Sopenharmony_ci combinations[0].beacon_int_min_gcd = 100; 710862306a36Sopenharmony_ci combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 710962306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 711062306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40) | 711162306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_80); 711262306a36Sopenharmony_ci 711362306a36Sopenharmony_ci ar->hw->wiphy->iface_combinations = combinations; 711462306a36Sopenharmony_ci ar->hw->wiphy->n_iface_combinations = 1; 711562306a36Sopenharmony_ci 711662306a36Sopenharmony_ci return 0; 711762306a36Sopenharmony_ci} 711862306a36Sopenharmony_ci 711962306a36Sopenharmony_cistatic const u8 ath12k_if_types_ext_capa[] = { 712062306a36Sopenharmony_ci [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, 712162306a36Sopenharmony_ci [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, 712262306a36Sopenharmony_ci}; 712362306a36Sopenharmony_ci 712462306a36Sopenharmony_cistatic const u8 ath12k_if_types_ext_capa_sta[] = { 712562306a36Sopenharmony_ci [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, 712662306a36Sopenharmony_ci [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, 712762306a36Sopenharmony_ci [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, 712862306a36Sopenharmony_ci}; 712962306a36Sopenharmony_ci 713062306a36Sopenharmony_cistatic const u8 ath12k_if_types_ext_capa_ap[] = { 713162306a36Sopenharmony_ci [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, 713262306a36Sopenharmony_ci [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, 713362306a36Sopenharmony_ci [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT, 713462306a36Sopenharmony_ci}; 713562306a36Sopenharmony_ci 713662306a36Sopenharmony_cistatic const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { 713762306a36Sopenharmony_ci { 713862306a36Sopenharmony_ci .extended_capabilities = ath12k_if_types_ext_capa, 713962306a36Sopenharmony_ci .extended_capabilities_mask = ath12k_if_types_ext_capa, 714062306a36Sopenharmony_ci .extended_capabilities_len = sizeof(ath12k_if_types_ext_capa), 714162306a36Sopenharmony_ci }, { 714262306a36Sopenharmony_ci .iftype = NL80211_IFTYPE_STATION, 714362306a36Sopenharmony_ci .extended_capabilities = ath12k_if_types_ext_capa_sta, 714462306a36Sopenharmony_ci .extended_capabilities_mask = ath12k_if_types_ext_capa_sta, 714562306a36Sopenharmony_ci .extended_capabilities_len = 714662306a36Sopenharmony_ci sizeof(ath12k_if_types_ext_capa_sta), 714762306a36Sopenharmony_ci }, { 714862306a36Sopenharmony_ci .iftype = NL80211_IFTYPE_AP, 714962306a36Sopenharmony_ci .extended_capabilities = ath12k_if_types_ext_capa_ap, 715062306a36Sopenharmony_ci .extended_capabilities_mask = ath12k_if_types_ext_capa_ap, 715162306a36Sopenharmony_ci .extended_capabilities_len = 715262306a36Sopenharmony_ci sizeof(ath12k_if_types_ext_capa_ap), 715362306a36Sopenharmony_ci }, 715462306a36Sopenharmony_ci}; 715562306a36Sopenharmony_ci 715662306a36Sopenharmony_cistatic void __ath12k_mac_unregister(struct ath12k *ar) 715762306a36Sopenharmony_ci{ 715862306a36Sopenharmony_ci cancel_work_sync(&ar->regd_update_work); 715962306a36Sopenharmony_ci 716062306a36Sopenharmony_ci ieee80211_unregister_hw(ar->hw); 716162306a36Sopenharmony_ci 716262306a36Sopenharmony_ci idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); 716362306a36Sopenharmony_ci idr_destroy(&ar->txmgmt_idr); 716462306a36Sopenharmony_ci 716562306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); 716662306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); 716762306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); 716862306a36Sopenharmony_ci 716962306a36Sopenharmony_ci kfree(ar->hw->wiphy->iface_combinations[0].limits); 717062306a36Sopenharmony_ci kfree(ar->hw->wiphy->iface_combinations); 717162306a36Sopenharmony_ci 717262306a36Sopenharmony_ci SET_IEEE80211_DEV(ar->hw, NULL); 717362306a36Sopenharmony_ci} 717462306a36Sopenharmony_ci 717562306a36Sopenharmony_civoid ath12k_mac_unregister(struct ath12k_base *ab) 717662306a36Sopenharmony_ci{ 717762306a36Sopenharmony_ci struct ath12k *ar; 717862306a36Sopenharmony_ci struct ath12k_pdev *pdev; 717962306a36Sopenharmony_ci int i; 718062306a36Sopenharmony_ci 718162306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 718262306a36Sopenharmony_ci pdev = &ab->pdevs[i]; 718362306a36Sopenharmony_ci ar = pdev->ar; 718462306a36Sopenharmony_ci if (!ar) 718562306a36Sopenharmony_ci continue; 718662306a36Sopenharmony_ci 718762306a36Sopenharmony_ci __ath12k_mac_unregister(ar); 718862306a36Sopenharmony_ci } 718962306a36Sopenharmony_ci} 719062306a36Sopenharmony_ci 719162306a36Sopenharmony_cistatic int __ath12k_mac_register(struct ath12k *ar) 719262306a36Sopenharmony_ci{ 719362306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 719462306a36Sopenharmony_ci struct ath12k_pdev_cap *cap = &ar->pdev->cap; 719562306a36Sopenharmony_ci static const u32 cipher_suites[] = { 719662306a36Sopenharmony_ci WLAN_CIPHER_SUITE_TKIP, 719762306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP, 719862306a36Sopenharmony_ci WLAN_CIPHER_SUITE_AES_CMAC, 719962306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_CMAC_256, 720062306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_128, 720162306a36Sopenharmony_ci WLAN_CIPHER_SUITE_BIP_GMAC_256, 720262306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP, 720362306a36Sopenharmony_ci WLAN_CIPHER_SUITE_GCMP_256, 720462306a36Sopenharmony_ci WLAN_CIPHER_SUITE_CCMP_256, 720562306a36Sopenharmony_ci }; 720662306a36Sopenharmony_ci int ret; 720762306a36Sopenharmony_ci u32 ht_cap = 0; 720862306a36Sopenharmony_ci 720962306a36Sopenharmony_ci ath12k_pdev_caps_update(ar); 721062306a36Sopenharmony_ci 721162306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr); 721262306a36Sopenharmony_ci 721362306a36Sopenharmony_ci SET_IEEE80211_DEV(ar->hw, ab->dev); 721462306a36Sopenharmony_ci 721562306a36Sopenharmony_ci ret = ath12k_mac_setup_channels_rates(ar, 721662306a36Sopenharmony_ci cap->supported_bands); 721762306a36Sopenharmony_ci if (ret) 721862306a36Sopenharmony_ci goto err; 721962306a36Sopenharmony_ci 722062306a36Sopenharmony_ci ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); 722162306a36Sopenharmony_ci ath12k_mac_setup_sband_iftype_data(ar, cap); 722262306a36Sopenharmony_ci 722362306a36Sopenharmony_ci ret = ath12k_mac_setup_iface_combinations(ar); 722462306a36Sopenharmony_ci if (ret) { 722562306a36Sopenharmony_ci ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); 722662306a36Sopenharmony_ci goto err_free_channels; 722762306a36Sopenharmony_ci } 722862306a36Sopenharmony_ci 722962306a36Sopenharmony_ci ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask; 723062306a36Sopenharmony_ci ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask; 723162306a36Sopenharmony_ci 723262306a36Sopenharmony_ci ar->hw->wiphy->interface_modes = ab->hw_params->interface_modes; 723362306a36Sopenharmony_ci 723462306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SIGNAL_DBM); 723562306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_PS); 723662306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS); 723762306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, MFP_CAPABLE); 723862306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS); 723962306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL); 724062306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, AP_LINK_PS); 724162306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SPECTRUM_MGMT); 724262306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, CONNECTION_MONITOR); 724362306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK); 724462306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA); 724562306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, QUEUE_CONTROL); 724662306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); 724762306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); 724862306a36Sopenharmony_ci 724962306a36Sopenharmony_ci if (ht_cap & WMI_HT_CAP_ENABLED) { 725062306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); 725162306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); 725262306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER); 725362306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU); 725462306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, USES_RSS); 725562306a36Sopenharmony_ci } 725662306a36Sopenharmony_ci 725762306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; 725862306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 725962306a36Sopenharmony_ci 726062306a36Sopenharmony_ci /* TODO: Check if HT capability advertised from firmware is different 726162306a36Sopenharmony_ci * for each band for a dual band capable radio. It will be tricky to 726262306a36Sopenharmony_ci * handle it when the ht capability different for each band. 726362306a36Sopenharmony_ci */ 726462306a36Sopenharmony_ci if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) 726562306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS; 726662306a36Sopenharmony_ci 726762306a36Sopenharmony_ci ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID; 726862306a36Sopenharmony_ci ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN; 726962306a36Sopenharmony_ci 727062306a36Sopenharmony_ci ar->hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL; 727162306a36Sopenharmony_ci 727262306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 727362306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; 727462306a36Sopenharmony_ci ar->hw->wiphy->max_remain_on_channel_duration = 5000; 727562306a36Sopenharmony_ci 727662306a36Sopenharmony_ci ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 727762306a36Sopenharmony_ci ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 727862306a36Sopenharmony_ci NL80211_FEATURE_AP_SCAN; 727962306a36Sopenharmony_ci 728062306a36Sopenharmony_ci ar->max_num_stations = TARGET_NUM_STATIONS; 728162306a36Sopenharmony_ci ar->max_num_peers = TARGET_NUM_PEERS_PDEV; 728262306a36Sopenharmony_ci 728362306a36Sopenharmony_ci ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations; 728462306a36Sopenharmony_ci 728562306a36Sopenharmony_ci ar->hw->queues = ATH12K_HW_MAX_QUEUES; 728662306a36Sopenharmony_ci ar->hw->wiphy->tx_queue_len = ATH12K_QUEUE_LEN; 728762306a36Sopenharmony_ci ar->hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; 728862306a36Sopenharmony_ci ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; 728962306a36Sopenharmony_ci 729062306a36Sopenharmony_ci ar->hw->vif_data_size = sizeof(struct ath12k_vif); 729162306a36Sopenharmony_ci ar->hw->sta_data_size = sizeof(struct ath12k_sta); 729262306a36Sopenharmony_ci 729362306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 729462306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); 729562306a36Sopenharmony_ci 729662306a36Sopenharmony_ci ar->hw->wiphy->cipher_suites = cipher_suites; 729762306a36Sopenharmony_ci ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); 729862306a36Sopenharmony_ci 729962306a36Sopenharmony_ci ar->hw->wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; 730062306a36Sopenharmony_ci ar->hw->wiphy->num_iftype_ext_capab = 730162306a36Sopenharmony_ci ARRAY_SIZE(ath12k_iftypes_ext_capa); 730262306a36Sopenharmony_ci 730362306a36Sopenharmony_ci if (ar->supports_6ghz) { 730462306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 730562306a36Sopenharmony_ci NL80211_EXT_FEATURE_FILS_DISCOVERY); 730662306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, 730762306a36Sopenharmony_ci NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); 730862306a36Sopenharmony_ci } 730962306a36Sopenharmony_ci 731062306a36Sopenharmony_ci wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_PUNCT); 731162306a36Sopenharmony_ci 731262306a36Sopenharmony_ci ath12k_reg_init(ar); 731362306a36Sopenharmony_ci 731462306a36Sopenharmony_ci if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { 731562306a36Sopenharmony_ci ar->hw->netdev_features = NETIF_F_HW_CSUM; 731662306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL); 731762306a36Sopenharmony_ci ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT); 731862306a36Sopenharmony_ci } 731962306a36Sopenharmony_ci 732062306a36Sopenharmony_ci ret = ieee80211_register_hw(ar->hw); 732162306a36Sopenharmony_ci if (ret) { 732262306a36Sopenharmony_ci ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); 732362306a36Sopenharmony_ci goto err_free_if_combs; 732462306a36Sopenharmony_ci } 732562306a36Sopenharmony_ci 732662306a36Sopenharmony_ci if (!ab->hw_params->supports_monitor) 732762306a36Sopenharmony_ci /* There's a race between calling ieee80211_register_hw() 732862306a36Sopenharmony_ci * and here where the monitor mode is enabled for a little 732962306a36Sopenharmony_ci * while. But that time is so short and in practise it make 733062306a36Sopenharmony_ci * a difference in real life. 733162306a36Sopenharmony_ci */ 733262306a36Sopenharmony_ci ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); 733362306a36Sopenharmony_ci 733462306a36Sopenharmony_ci /* Apply the regd received during initialization */ 733562306a36Sopenharmony_ci ret = ath12k_regd_update(ar, true); 733662306a36Sopenharmony_ci if (ret) { 733762306a36Sopenharmony_ci ath12k_err(ar->ab, "ath12k regd update failed: %d\n", ret); 733862306a36Sopenharmony_ci goto err_unregister_hw; 733962306a36Sopenharmony_ci } 734062306a36Sopenharmony_ci 734162306a36Sopenharmony_ci return 0; 734262306a36Sopenharmony_ci 734362306a36Sopenharmony_cierr_unregister_hw: 734462306a36Sopenharmony_ci ieee80211_unregister_hw(ar->hw); 734562306a36Sopenharmony_ci 734662306a36Sopenharmony_cierr_free_if_combs: 734762306a36Sopenharmony_ci kfree(ar->hw->wiphy->iface_combinations[0].limits); 734862306a36Sopenharmony_ci kfree(ar->hw->wiphy->iface_combinations); 734962306a36Sopenharmony_ci 735062306a36Sopenharmony_cierr_free_channels: 735162306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); 735262306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); 735362306a36Sopenharmony_ci kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); 735462306a36Sopenharmony_ci 735562306a36Sopenharmony_cierr: 735662306a36Sopenharmony_ci SET_IEEE80211_DEV(ar->hw, NULL); 735762306a36Sopenharmony_ci return ret; 735862306a36Sopenharmony_ci} 735962306a36Sopenharmony_ci 736062306a36Sopenharmony_ciint ath12k_mac_register(struct ath12k_base *ab) 736162306a36Sopenharmony_ci{ 736262306a36Sopenharmony_ci struct ath12k *ar; 736362306a36Sopenharmony_ci struct ath12k_pdev *pdev; 736462306a36Sopenharmony_ci int i; 736562306a36Sopenharmony_ci int ret; 736662306a36Sopenharmony_ci 736762306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) 736862306a36Sopenharmony_ci return 0; 736962306a36Sopenharmony_ci 737062306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 737162306a36Sopenharmony_ci pdev = &ab->pdevs[i]; 737262306a36Sopenharmony_ci ar = pdev->ar; 737362306a36Sopenharmony_ci if (ab->pdevs_macaddr_valid) { 737462306a36Sopenharmony_ci ether_addr_copy(ar->mac_addr, pdev->mac_addr); 737562306a36Sopenharmony_ci } else { 737662306a36Sopenharmony_ci ether_addr_copy(ar->mac_addr, ab->mac_addr); 737762306a36Sopenharmony_ci ar->mac_addr[4] += i; 737862306a36Sopenharmony_ci } 737962306a36Sopenharmony_ci 738062306a36Sopenharmony_ci ret = __ath12k_mac_register(ar); 738162306a36Sopenharmony_ci if (ret) 738262306a36Sopenharmony_ci goto err_cleanup; 738362306a36Sopenharmony_ci 738462306a36Sopenharmony_ci init_waitqueue_head(&ar->txmgmt_empty_waitq); 738562306a36Sopenharmony_ci idr_init(&ar->txmgmt_idr); 738662306a36Sopenharmony_ci spin_lock_init(&ar->txmgmt_idr_lock); 738762306a36Sopenharmony_ci } 738862306a36Sopenharmony_ci 738962306a36Sopenharmony_ci /* Initialize channel counters frequency value in hertz */ 739062306a36Sopenharmony_ci ab->cc_freq_hz = 320000; 739162306a36Sopenharmony_ci ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; 739262306a36Sopenharmony_ci 739362306a36Sopenharmony_ci return 0; 739462306a36Sopenharmony_ci 739562306a36Sopenharmony_cierr_cleanup: 739662306a36Sopenharmony_ci for (i = i - 1; i >= 0; i--) { 739762306a36Sopenharmony_ci pdev = &ab->pdevs[i]; 739862306a36Sopenharmony_ci ar = pdev->ar; 739962306a36Sopenharmony_ci __ath12k_mac_unregister(ar); 740062306a36Sopenharmony_ci } 740162306a36Sopenharmony_ci 740262306a36Sopenharmony_ci return ret; 740362306a36Sopenharmony_ci} 740462306a36Sopenharmony_ci 740562306a36Sopenharmony_ciint ath12k_mac_allocate(struct ath12k_base *ab) 740662306a36Sopenharmony_ci{ 740762306a36Sopenharmony_ci struct ieee80211_hw *hw; 740862306a36Sopenharmony_ci struct ath12k *ar; 740962306a36Sopenharmony_ci struct ath12k_pdev *pdev; 741062306a36Sopenharmony_ci int ret; 741162306a36Sopenharmony_ci int i; 741262306a36Sopenharmony_ci 741362306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) 741462306a36Sopenharmony_ci return 0; 741562306a36Sopenharmony_ci 741662306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 741762306a36Sopenharmony_ci pdev = &ab->pdevs[i]; 741862306a36Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); 741962306a36Sopenharmony_ci if (!hw) { 742062306a36Sopenharmony_ci ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); 742162306a36Sopenharmony_ci ret = -ENOMEM; 742262306a36Sopenharmony_ci goto err_free_mac; 742362306a36Sopenharmony_ci } 742462306a36Sopenharmony_ci 742562306a36Sopenharmony_ci ar = hw->priv; 742662306a36Sopenharmony_ci ar->hw = hw; 742762306a36Sopenharmony_ci ar->ab = ab; 742862306a36Sopenharmony_ci ar->pdev = pdev; 742962306a36Sopenharmony_ci ar->pdev_idx = i; 743062306a36Sopenharmony_ci ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, i); 743162306a36Sopenharmony_ci 743262306a36Sopenharmony_ci ar->wmi = &ab->wmi_ab.wmi[i]; 743362306a36Sopenharmony_ci /* FIXME: wmi[0] is already initialized during attach, 743462306a36Sopenharmony_ci * Should we do this again? 743562306a36Sopenharmony_ci */ 743662306a36Sopenharmony_ci ath12k_wmi_pdev_attach(ab, i); 743762306a36Sopenharmony_ci 743862306a36Sopenharmony_ci ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; 743962306a36Sopenharmony_ci ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; 744062306a36Sopenharmony_ci ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); 744162306a36Sopenharmony_ci ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); 744262306a36Sopenharmony_ci 744362306a36Sopenharmony_ci pdev->ar = ar; 744462306a36Sopenharmony_ci spin_lock_init(&ar->data_lock); 744562306a36Sopenharmony_ci INIT_LIST_HEAD(&ar->arvifs); 744662306a36Sopenharmony_ci INIT_LIST_HEAD(&ar->ppdu_stats_info); 744762306a36Sopenharmony_ci mutex_init(&ar->conf_mutex); 744862306a36Sopenharmony_ci init_completion(&ar->vdev_setup_done); 744962306a36Sopenharmony_ci init_completion(&ar->vdev_delete_done); 745062306a36Sopenharmony_ci init_completion(&ar->peer_assoc_done); 745162306a36Sopenharmony_ci init_completion(&ar->peer_delete_done); 745262306a36Sopenharmony_ci init_completion(&ar->install_key_done); 745362306a36Sopenharmony_ci init_completion(&ar->bss_survey_done); 745462306a36Sopenharmony_ci init_completion(&ar->scan.started); 745562306a36Sopenharmony_ci init_completion(&ar->scan.completed); 745662306a36Sopenharmony_ci 745762306a36Sopenharmony_ci INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); 745862306a36Sopenharmony_ci INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); 745962306a36Sopenharmony_ci 746062306a36Sopenharmony_ci INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); 746162306a36Sopenharmony_ci skb_queue_head_init(&ar->wmi_mgmt_tx_queue); 746262306a36Sopenharmony_ci clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); 746362306a36Sopenharmony_ci } 746462306a36Sopenharmony_ci 746562306a36Sopenharmony_ci return 0; 746662306a36Sopenharmony_ci 746762306a36Sopenharmony_cierr_free_mac: 746862306a36Sopenharmony_ci ath12k_mac_destroy(ab); 746962306a36Sopenharmony_ci 747062306a36Sopenharmony_ci return ret; 747162306a36Sopenharmony_ci} 747262306a36Sopenharmony_ci 747362306a36Sopenharmony_civoid ath12k_mac_destroy(struct ath12k_base *ab) 747462306a36Sopenharmony_ci{ 747562306a36Sopenharmony_ci struct ath12k *ar; 747662306a36Sopenharmony_ci struct ath12k_pdev *pdev; 747762306a36Sopenharmony_ci int i; 747862306a36Sopenharmony_ci 747962306a36Sopenharmony_ci for (i = 0; i < ab->num_radios; i++) { 748062306a36Sopenharmony_ci pdev = &ab->pdevs[i]; 748162306a36Sopenharmony_ci ar = pdev->ar; 748262306a36Sopenharmony_ci if (!ar) 748362306a36Sopenharmony_ci continue; 748462306a36Sopenharmony_ci 748562306a36Sopenharmony_ci ieee80211_free_hw(ar->hw); 748662306a36Sopenharmony_ci pdev->ar = NULL; 748762306a36Sopenharmony_ci } 748862306a36Sopenharmony_ci} 7489