18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <net/mac80211.h>
88c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
98c2ecf20Sopenharmony_ci#include "mac.h"
108c2ecf20Sopenharmony_ci#include "core.h"
118c2ecf20Sopenharmony_ci#include "debug.h"
128c2ecf20Sopenharmony_ci#include "wmi.h"
138c2ecf20Sopenharmony_ci#include "hw.h"
148c2ecf20Sopenharmony_ci#include "dp_tx.h"
158c2ecf20Sopenharmony_ci#include "dp_rx.h"
168c2ecf20Sopenharmony_ci#include "testmode.h"
178c2ecf20Sopenharmony_ci#include "peer.h"
188c2ecf20Sopenharmony_ci#include "debugfs_sta.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define CHAN2G(_channel, _freq, _flags) { \
218c2ecf20Sopenharmony_ci	.band                   = NL80211_BAND_2GHZ, \
228c2ecf20Sopenharmony_ci	.hw_value               = (_channel), \
238c2ecf20Sopenharmony_ci	.center_freq            = (_freq), \
248c2ecf20Sopenharmony_ci	.flags                  = (_flags), \
258c2ecf20Sopenharmony_ci	.max_antenna_gain       = 0, \
268c2ecf20Sopenharmony_ci	.max_power              = 30, \
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define CHAN5G(_channel, _freq, _flags) { \
308c2ecf20Sopenharmony_ci	.band                   = NL80211_BAND_5GHZ, \
318c2ecf20Sopenharmony_ci	.hw_value               = (_channel), \
328c2ecf20Sopenharmony_ci	.center_freq            = (_freq), \
338c2ecf20Sopenharmony_ci	.flags                  = (_flags), \
348c2ecf20Sopenharmony_ci	.max_antenna_gain       = 0, \
358c2ecf20Sopenharmony_ci	.max_power              = 30, \
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define CHAN6G(_channel, _freq, _flags) { \
398c2ecf20Sopenharmony_ci	.band                   = NL80211_BAND_6GHZ, \
408c2ecf20Sopenharmony_ci	.hw_value               = (_channel), \
418c2ecf20Sopenharmony_ci	.center_freq            = (_freq), \
428c2ecf20Sopenharmony_ci	.flags                  = (_flags), \
438c2ecf20Sopenharmony_ci	.max_antenna_gain       = 0, \
448c2ecf20Sopenharmony_ci	.max_power              = 30, \
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic const struct ieee80211_channel ath11k_2ghz_channels[] = {
488c2ecf20Sopenharmony_ci	CHAN2G(1, 2412, 0),
498c2ecf20Sopenharmony_ci	CHAN2G(2, 2417, 0),
508c2ecf20Sopenharmony_ci	CHAN2G(3, 2422, 0),
518c2ecf20Sopenharmony_ci	CHAN2G(4, 2427, 0),
528c2ecf20Sopenharmony_ci	CHAN2G(5, 2432, 0),
538c2ecf20Sopenharmony_ci	CHAN2G(6, 2437, 0),
548c2ecf20Sopenharmony_ci	CHAN2G(7, 2442, 0),
558c2ecf20Sopenharmony_ci	CHAN2G(8, 2447, 0),
568c2ecf20Sopenharmony_ci	CHAN2G(9, 2452, 0),
578c2ecf20Sopenharmony_ci	CHAN2G(10, 2457, 0),
588c2ecf20Sopenharmony_ci	CHAN2G(11, 2462, 0),
598c2ecf20Sopenharmony_ci	CHAN2G(12, 2467, 0),
608c2ecf20Sopenharmony_ci	CHAN2G(13, 2472, 0),
618c2ecf20Sopenharmony_ci	CHAN2G(14, 2484, 0),
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic const struct ieee80211_channel ath11k_5ghz_channels[] = {
658c2ecf20Sopenharmony_ci	CHAN5G(36, 5180, 0),
668c2ecf20Sopenharmony_ci	CHAN5G(40, 5200, 0),
678c2ecf20Sopenharmony_ci	CHAN5G(44, 5220, 0),
688c2ecf20Sopenharmony_ci	CHAN5G(48, 5240, 0),
698c2ecf20Sopenharmony_ci	CHAN5G(52, 5260, 0),
708c2ecf20Sopenharmony_ci	CHAN5G(56, 5280, 0),
718c2ecf20Sopenharmony_ci	CHAN5G(60, 5300, 0),
728c2ecf20Sopenharmony_ci	CHAN5G(64, 5320, 0),
738c2ecf20Sopenharmony_ci	CHAN5G(100, 5500, 0),
748c2ecf20Sopenharmony_ci	CHAN5G(104, 5520, 0),
758c2ecf20Sopenharmony_ci	CHAN5G(108, 5540, 0),
768c2ecf20Sopenharmony_ci	CHAN5G(112, 5560, 0),
778c2ecf20Sopenharmony_ci	CHAN5G(116, 5580, 0),
788c2ecf20Sopenharmony_ci	CHAN5G(120, 5600, 0),
798c2ecf20Sopenharmony_ci	CHAN5G(124, 5620, 0),
808c2ecf20Sopenharmony_ci	CHAN5G(128, 5640, 0),
818c2ecf20Sopenharmony_ci	CHAN5G(132, 5660, 0),
828c2ecf20Sopenharmony_ci	CHAN5G(136, 5680, 0),
838c2ecf20Sopenharmony_ci	CHAN5G(140, 5700, 0),
848c2ecf20Sopenharmony_ci	CHAN5G(144, 5720, 0),
858c2ecf20Sopenharmony_ci	CHAN5G(149, 5745, 0),
868c2ecf20Sopenharmony_ci	CHAN5G(153, 5765, 0),
878c2ecf20Sopenharmony_ci	CHAN5G(157, 5785, 0),
888c2ecf20Sopenharmony_ci	CHAN5G(161, 5805, 0),
898c2ecf20Sopenharmony_ci	CHAN5G(165, 5825, 0),
908c2ecf20Sopenharmony_ci	CHAN5G(169, 5845, 0),
918c2ecf20Sopenharmony_ci	CHAN5G(173, 5865, 0),
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic const struct ieee80211_channel ath11k_6ghz_channels[] = {
958c2ecf20Sopenharmony_ci	CHAN6G(1, 5955, 0),
968c2ecf20Sopenharmony_ci	CHAN6G(5, 5975, 0),
978c2ecf20Sopenharmony_ci	CHAN6G(9, 5995, 0),
988c2ecf20Sopenharmony_ci	CHAN6G(13, 6015, 0),
998c2ecf20Sopenharmony_ci	CHAN6G(17, 6035, 0),
1008c2ecf20Sopenharmony_ci	CHAN6G(21, 6055, 0),
1018c2ecf20Sopenharmony_ci	CHAN6G(25, 6075, 0),
1028c2ecf20Sopenharmony_ci	CHAN6G(29, 6095, 0),
1038c2ecf20Sopenharmony_ci	CHAN6G(33, 6115, 0),
1048c2ecf20Sopenharmony_ci	CHAN6G(37, 6135, 0),
1058c2ecf20Sopenharmony_ci	CHAN6G(41, 6155, 0),
1068c2ecf20Sopenharmony_ci	CHAN6G(45, 6175, 0),
1078c2ecf20Sopenharmony_ci	CHAN6G(49, 6195, 0),
1088c2ecf20Sopenharmony_ci	CHAN6G(53, 6215, 0),
1098c2ecf20Sopenharmony_ci	CHAN6G(57, 6235, 0),
1108c2ecf20Sopenharmony_ci	CHAN6G(61, 6255, 0),
1118c2ecf20Sopenharmony_ci	CHAN6G(65, 6275, 0),
1128c2ecf20Sopenharmony_ci	CHAN6G(69, 6295, 0),
1138c2ecf20Sopenharmony_ci	CHAN6G(73, 6315, 0),
1148c2ecf20Sopenharmony_ci	CHAN6G(77, 6335, 0),
1158c2ecf20Sopenharmony_ci	CHAN6G(81, 6355, 0),
1168c2ecf20Sopenharmony_ci	CHAN6G(85, 6375, 0),
1178c2ecf20Sopenharmony_ci	CHAN6G(89, 6395, 0),
1188c2ecf20Sopenharmony_ci	CHAN6G(93, 6415, 0),
1198c2ecf20Sopenharmony_ci	CHAN6G(97, 6435, 0),
1208c2ecf20Sopenharmony_ci	CHAN6G(101, 6455, 0),
1218c2ecf20Sopenharmony_ci	CHAN6G(105, 6475, 0),
1228c2ecf20Sopenharmony_ci	CHAN6G(109, 6495, 0),
1238c2ecf20Sopenharmony_ci	CHAN6G(113, 6515, 0),
1248c2ecf20Sopenharmony_ci	CHAN6G(117, 6535, 0),
1258c2ecf20Sopenharmony_ci	CHAN6G(121, 6555, 0),
1268c2ecf20Sopenharmony_ci	CHAN6G(125, 6575, 0),
1278c2ecf20Sopenharmony_ci	CHAN6G(129, 6595, 0),
1288c2ecf20Sopenharmony_ci	CHAN6G(133, 6615, 0),
1298c2ecf20Sopenharmony_ci	CHAN6G(137, 6635, 0),
1308c2ecf20Sopenharmony_ci	CHAN6G(141, 6655, 0),
1318c2ecf20Sopenharmony_ci	CHAN6G(145, 6675, 0),
1328c2ecf20Sopenharmony_ci	CHAN6G(149, 6695, 0),
1338c2ecf20Sopenharmony_ci	CHAN6G(153, 6715, 0),
1348c2ecf20Sopenharmony_ci	CHAN6G(157, 6735, 0),
1358c2ecf20Sopenharmony_ci	CHAN6G(161, 6755, 0),
1368c2ecf20Sopenharmony_ci	CHAN6G(165, 6775, 0),
1378c2ecf20Sopenharmony_ci	CHAN6G(169, 6795, 0),
1388c2ecf20Sopenharmony_ci	CHAN6G(173, 6815, 0),
1398c2ecf20Sopenharmony_ci	CHAN6G(177, 6835, 0),
1408c2ecf20Sopenharmony_ci	CHAN6G(181, 6855, 0),
1418c2ecf20Sopenharmony_ci	CHAN6G(185, 6875, 0),
1428c2ecf20Sopenharmony_ci	CHAN6G(189, 6895, 0),
1438c2ecf20Sopenharmony_ci	CHAN6G(193, 6915, 0),
1448c2ecf20Sopenharmony_ci	CHAN6G(197, 6935, 0),
1458c2ecf20Sopenharmony_ci	CHAN6G(201, 6955, 0),
1468c2ecf20Sopenharmony_ci	CHAN6G(205, 6975, 0),
1478c2ecf20Sopenharmony_ci	CHAN6G(209, 6995, 0),
1488c2ecf20Sopenharmony_ci	CHAN6G(213, 7015, 0),
1498c2ecf20Sopenharmony_ci	CHAN6G(217, 7035, 0),
1508c2ecf20Sopenharmony_ci	CHAN6G(221, 7055, 0),
1518c2ecf20Sopenharmony_ci	CHAN6G(225, 7075, 0),
1528c2ecf20Sopenharmony_ci	CHAN6G(229, 7095, 0),
1538c2ecf20Sopenharmony_ci	CHAN6G(233, 7115, 0),
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic struct ieee80211_rate ath11k_legacy_rates[] = {
1578c2ecf20Sopenharmony_ci	{ .bitrate = 10,
1588c2ecf20Sopenharmony_ci	  .hw_value = ATH11K_HW_RATE_CCK_LP_1M },
1598c2ecf20Sopenharmony_ci	{ .bitrate = 20,
1608c2ecf20Sopenharmony_ci	  .hw_value = ATH11K_HW_RATE_CCK_LP_2M,
1618c2ecf20Sopenharmony_ci	  .hw_value_short = ATH11K_HW_RATE_CCK_SP_2M,
1628c2ecf20Sopenharmony_ci	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1638c2ecf20Sopenharmony_ci	{ .bitrate = 55,
1648c2ecf20Sopenharmony_ci	  .hw_value = ATH11K_HW_RATE_CCK_LP_5_5M,
1658c2ecf20Sopenharmony_ci	  .hw_value_short = ATH11K_HW_RATE_CCK_SP_5_5M,
1668c2ecf20Sopenharmony_ci	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1678c2ecf20Sopenharmony_ci	{ .bitrate = 110,
1688c2ecf20Sopenharmony_ci	  .hw_value = ATH11K_HW_RATE_CCK_LP_11M,
1698c2ecf20Sopenharmony_ci	  .hw_value_short = ATH11K_HW_RATE_CCK_SP_11M,
1708c2ecf20Sopenharmony_ci	  .flags = IEEE80211_RATE_SHORT_PREAMBLE },
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	{ .bitrate = 60, .hw_value = ATH11K_HW_RATE_OFDM_6M },
1738c2ecf20Sopenharmony_ci	{ .bitrate = 90, .hw_value = ATH11K_HW_RATE_OFDM_9M },
1748c2ecf20Sopenharmony_ci	{ .bitrate = 120, .hw_value = ATH11K_HW_RATE_OFDM_12M },
1758c2ecf20Sopenharmony_ci	{ .bitrate = 180, .hw_value = ATH11K_HW_RATE_OFDM_18M },
1768c2ecf20Sopenharmony_ci	{ .bitrate = 240, .hw_value = ATH11K_HW_RATE_OFDM_24M },
1778c2ecf20Sopenharmony_ci	{ .bitrate = 360, .hw_value = ATH11K_HW_RATE_OFDM_36M },
1788c2ecf20Sopenharmony_ci	{ .bitrate = 480, .hw_value = ATH11K_HW_RATE_OFDM_48M },
1798c2ecf20Sopenharmony_ci	{ .bitrate = 540, .hw_value = ATH11K_HW_RATE_OFDM_54M },
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic const int
1838c2ecf20Sopenharmony_ciath11k_phymodes[NUM_NL80211_BANDS][ATH11K_CHAN_WIDTH_NUM] = {
1848c2ecf20Sopenharmony_ci	[NL80211_BAND_2GHZ] = {
1858c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
1868c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
1878c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20_2G,
1888c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20_2G,
1898c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40_2G,
1908c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80_2G,
1918c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN,
1928c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_160] = MODE_UNKNOWN,
1938c2ecf20Sopenharmony_ci	},
1948c2ecf20Sopenharmony_ci	[NL80211_BAND_5GHZ] = {
1958c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
1968c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
1978c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20,
1988c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
1998c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
2008c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
2018c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
2028c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
2038c2ecf20Sopenharmony_ci	},
2048c2ecf20Sopenharmony_ci	[NL80211_BAND_6GHZ] = {
2058c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
2068c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
2078c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20,
2088c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
2098c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
2108c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
2118c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
2128c2ecf20Sopenharmony_ci			[NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
2138c2ecf20Sopenharmony_ci	},
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci};
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ciconst struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default = {
2188c2ecf20Sopenharmony_ci	.rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START |
2198c2ecf20Sopenharmony_ci		     HTT_RX_FILTER_TLV_FLAGS_PPDU_END |
2208c2ecf20Sopenharmony_ci		     HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE,
2218c2ecf20Sopenharmony_ci	.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0,
2228c2ecf20Sopenharmony_ci	.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1,
2238c2ecf20Sopenharmony_ci	.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2,
2248c2ecf20Sopenharmony_ci	.pkt_filter_flags3 = HTT_RX_FP_DATA_FILTER_FLASG3 |
2258c2ecf20Sopenharmony_ci			     HTT_RX_FP_CTRL_FILTER_FLASG3
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci#define ATH11K_MAC_FIRST_OFDM_RATE_IDX 4
2298c2ecf20Sopenharmony_ci#define ath11k_g_rates ath11k_legacy_rates
2308c2ecf20Sopenharmony_ci#define ath11k_g_rates_size (ARRAY_SIZE(ath11k_legacy_rates))
2318c2ecf20Sopenharmony_ci#define ath11k_a_rates (ath11k_legacy_rates + 4)
2328c2ecf20Sopenharmony_ci#define ath11k_a_rates_size (ARRAY_SIZE(ath11k_legacy_rates) - 4)
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci#define ATH11K_MAC_SCAN_TIMEOUT_MSECS 200 /* in msecs */
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic const u32 ath11k_smps_map[] = {
2378c2ecf20Sopenharmony_ci	[WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
2388c2ecf20Sopenharmony_ci	[WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
2398c2ecf20Sopenharmony_ci	[WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
2408c2ecf20Sopenharmony_ci	[WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
2418c2ecf20Sopenharmony_ci};
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
2448c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciu8 ath11k_mac_bw_to_mac80211_bw(u8 bw)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u8 ret = 0;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	switch (bw) {
2518c2ecf20Sopenharmony_ci	case ATH11K_BW_20:
2528c2ecf20Sopenharmony_ci		ret = RATE_INFO_BW_20;
2538c2ecf20Sopenharmony_ci		break;
2548c2ecf20Sopenharmony_ci	case ATH11K_BW_40:
2558c2ecf20Sopenharmony_ci		ret = RATE_INFO_BW_40;
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci	case ATH11K_BW_80:
2588c2ecf20Sopenharmony_ci		ret = RATE_INFO_BW_80;
2598c2ecf20Sopenharmony_ci		break;
2608c2ecf20Sopenharmony_ci	case ATH11K_BW_160:
2618c2ecf20Sopenharmony_ci		ret = RATE_INFO_BW_160;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return ret;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cienum ath11k_supported_bw ath11k_mac_mac80211_bw_to_ath11k_bw(enum rate_info_bw bw)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	switch (bw) {
2718c2ecf20Sopenharmony_ci	case RATE_INFO_BW_20:
2728c2ecf20Sopenharmony_ci		return ATH11K_BW_20;
2738c2ecf20Sopenharmony_ci	case RATE_INFO_BW_40:
2748c2ecf20Sopenharmony_ci		return ATH11K_BW_40;
2758c2ecf20Sopenharmony_ci	case RATE_INFO_BW_80:
2768c2ecf20Sopenharmony_ci		return ATH11K_BW_80;
2778c2ecf20Sopenharmony_ci	case RATE_INFO_BW_160:
2788c2ecf20Sopenharmony_ci		return ATH11K_BW_160;
2798c2ecf20Sopenharmony_ci	default:
2808c2ecf20Sopenharmony_ci		return ATH11K_BW_20;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ciint ath11k_mac_hw_ratecode_to_legacy_rate(u8 hw_rc, u8 preamble, u8 *rateidx,
2858c2ecf20Sopenharmony_ci					  u16 *rate)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	/* As default, it is OFDM rates */
2888c2ecf20Sopenharmony_ci	int i = ATH11K_MAC_FIRST_OFDM_RATE_IDX;
2898c2ecf20Sopenharmony_ci	int max_rates_idx = ath11k_g_rates_size;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (preamble == WMI_RATE_PREAMBLE_CCK) {
2928c2ecf20Sopenharmony_ci		hw_rc &= ~ATH11k_HW_RATECODE_CCK_SHORT_PREAM_MASK;
2938c2ecf20Sopenharmony_ci		i = 0;
2948c2ecf20Sopenharmony_ci		max_rates_idx = ATH11K_MAC_FIRST_OFDM_RATE_IDX;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	while (i < max_rates_idx) {
2988c2ecf20Sopenharmony_ci		if (hw_rc == ath11k_legacy_rates[i].hw_value) {
2998c2ecf20Sopenharmony_ci			*rateidx = i;
3008c2ecf20Sopenharmony_ci			*rate = ath11k_legacy_rates[i].bitrate;
3018c2ecf20Sopenharmony_ci			return 0;
3028c2ecf20Sopenharmony_ci		}
3038c2ecf20Sopenharmony_ci		i++;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return -EINVAL;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int get_num_chains(u32 mask)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	int num_chains = 0;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	while (mask) {
3148c2ecf20Sopenharmony_ci		if (mask & BIT(0))
3158c2ecf20Sopenharmony_ci			num_chains++;
3168c2ecf20Sopenharmony_ci		mask >>= 1;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return num_chains;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ciu8 ath11k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
3238c2ecf20Sopenharmony_ci			     u32 bitrate)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	int i;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++)
3288c2ecf20Sopenharmony_ci		if (sband->bitrates[i].bitrate == bitrate)
3298c2ecf20Sopenharmony_ci			return i;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic u32
3358c2ecf20Sopenharmony_ciath11k_mac_max_ht_nss(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int nss;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	for (nss = IEEE80211_HT_MCS_MASK_LEN - 1; nss >= 0; nss--)
3408c2ecf20Sopenharmony_ci		if (ht_mcs_mask[nss])
3418c2ecf20Sopenharmony_ci			return nss + 1;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	return 1;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic u32
3478c2ecf20Sopenharmony_ciath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	int nss;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	for (nss = NL80211_VHT_NSS_MAX - 1; nss >= 0; nss--)
3528c2ecf20Sopenharmony_ci		if (vht_mcs_mask[nss])
3538c2ecf20Sopenharmony_ci			return nss + 1;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 1;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic u8 ath11k_parse_mpdudensity(u8 mpdudensity)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci/* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
3618c2ecf20Sopenharmony_ci *   0 for no restriction
3628c2ecf20Sopenharmony_ci *   1 for 1/4 us
3638c2ecf20Sopenharmony_ci *   2 for 1/2 us
3648c2ecf20Sopenharmony_ci *   3 for 1 us
3658c2ecf20Sopenharmony_ci *   4 for 2 us
3668c2ecf20Sopenharmony_ci *   5 for 4 us
3678c2ecf20Sopenharmony_ci *   6 for 8 us
3688c2ecf20Sopenharmony_ci *   7 for 16 us
3698c2ecf20Sopenharmony_ci */
3708c2ecf20Sopenharmony_ci	switch (mpdudensity) {
3718c2ecf20Sopenharmony_ci	case 0:
3728c2ecf20Sopenharmony_ci		return 0;
3738c2ecf20Sopenharmony_ci	case 1:
3748c2ecf20Sopenharmony_ci	case 2:
3758c2ecf20Sopenharmony_ci	case 3:
3768c2ecf20Sopenharmony_ci	/* Our lower layer calculations limit our precision to
3778c2ecf20Sopenharmony_ci	 * 1 microsecond
3788c2ecf20Sopenharmony_ci	 */
3798c2ecf20Sopenharmony_ci		return 1;
3808c2ecf20Sopenharmony_ci	case 4:
3818c2ecf20Sopenharmony_ci		return 2;
3828c2ecf20Sopenharmony_ci	case 5:
3838c2ecf20Sopenharmony_ci		return 4;
3848c2ecf20Sopenharmony_ci	case 6:
3858c2ecf20Sopenharmony_ci		return 8;
3868c2ecf20Sopenharmony_ci	case 7:
3878c2ecf20Sopenharmony_ci		return 16;
3888c2ecf20Sopenharmony_ci	default:
3898c2ecf20Sopenharmony_ci		return 0;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic int ath11k_mac_vif_chan(struct ieee80211_vif *vif,
3948c2ecf20Sopenharmony_ci			       struct cfg80211_chan_def *def)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct ieee80211_chanctx_conf *conf;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	rcu_read_lock();
3998c2ecf20Sopenharmony_ci	conf = rcu_dereference(vif->chanctx_conf);
4008c2ecf20Sopenharmony_ci	if (!conf) {
4018c2ecf20Sopenharmony_ci		rcu_read_unlock();
4028c2ecf20Sopenharmony_ci		return -ENOENT;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	*def = conf->def;
4068c2ecf20Sopenharmony_ci	rcu_read_unlock();
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic bool ath11k_mac_bitrate_is_cck(int bitrate)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	switch (bitrate) {
4148c2ecf20Sopenharmony_ci	case 10:
4158c2ecf20Sopenharmony_ci	case 20:
4168c2ecf20Sopenharmony_ci	case 55:
4178c2ecf20Sopenharmony_ci	case 110:
4188c2ecf20Sopenharmony_ci		return true;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return false;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ciu8 ath11k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
4258c2ecf20Sopenharmony_ci			     u8 hw_rate, bool cck)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	const struct ieee80211_rate *rate;
4288c2ecf20Sopenharmony_ci	int i;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	for (i = 0; i < sband->n_bitrates; i++) {
4318c2ecf20Sopenharmony_ci		rate = &sband->bitrates[i];
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		if (ath11k_mac_bitrate_is_cck(rate->bitrate) != cck)
4348c2ecf20Sopenharmony_ci			continue;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		if (rate->hw_value == hw_rate)
4378c2ecf20Sopenharmony_ci			return i;
4388c2ecf20Sopenharmony_ci		else if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE &&
4398c2ecf20Sopenharmony_ci			 rate->hw_value_short == hw_rate)
4408c2ecf20Sopenharmony_ci			return i;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic u8 ath11k_mac_bitrate_to_rate(int bitrate)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(bitrate, 5) |
4498c2ecf20Sopenharmony_ci	       (ath11k_mac_bitrate_is_cck(bitrate) ? BIT(7) : 0);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void ath11k_get_arvif_iter(void *data, u8 *mac,
4538c2ecf20Sopenharmony_ci				  struct ieee80211_vif *vif)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct ath11k_vif_iter *arvif_iter = data;
4568c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (arvif->vdev_id == arvif_iter->vdev_id)
4598c2ecf20Sopenharmony_ci		arvif_iter->arvif = arvif;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistruct ath11k_vif *ath11k_mac_get_arvif(struct ath11k *ar, u32 vdev_id)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct ath11k_vif_iter arvif_iter;
4658c2ecf20Sopenharmony_ci	u32 flags;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	memset(&arvif_iter, 0, sizeof(struct ath11k_vif_iter));
4688c2ecf20Sopenharmony_ci	arvif_iter.vdev_id = vdev_id;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	flags = IEEE80211_IFACE_ITER_RESUME_ALL;
4718c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(ar->hw,
4728c2ecf20Sopenharmony_ci						   flags,
4738c2ecf20Sopenharmony_ci						   ath11k_get_arvif_iter,
4748c2ecf20Sopenharmony_ci						   &arvif_iter);
4758c2ecf20Sopenharmony_ci	if (!arvif_iter.arvif) {
4768c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "No VIF found for vdev %d\n", vdev_id);
4778c2ecf20Sopenharmony_ci		return NULL;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	return arvif_iter.arvif;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistruct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab,
4848c2ecf20Sopenharmony_ci						   u32 vdev_id)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	int i;
4878c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
4888c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
4918c2ecf20Sopenharmony_ci		pdev = rcu_dereference(ab->pdevs_active[i]);
4928c2ecf20Sopenharmony_ci		if (pdev && pdev->ar) {
4938c2ecf20Sopenharmony_ci			arvif = ath11k_mac_get_arvif(pdev->ar, vdev_id);
4948c2ecf20Sopenharmony_ci			if (arvif)
4958c2ecf20Sopenharmony_ci				return arvif;
4968c2ecf20Sopenharmony_ci		}
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	return NULL;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistruct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	int i;
5058c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
5088c2ecf20Sopenharmony_ci		pdev = rcu_dereference(ab->pdevs_active[i]);
5098c2ecf20Sopenharmony_ci		if (pdev && pdev->ar) {
5108c2ecf20Sopenharmony_ci			if (pdev->ar->allocated_vdev_map & (1LL << vdev_id))
5118c2ecf20Sopenharmony_ci				return pdev->ar;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	return NULL;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistruct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int i;
5218c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (ab->hw_params.single_pdev_only) {
5248c2ecf20Sopenharmony_ci		pdev = rcu_dereference(ab->pdevs_active[0]);
5258c2ecf20Sopenharmony_ci		return pdev ? pdev->ar : NULL;
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (WARN_ON(pdev_id > ab->num_radios))
5298c2ecf20Sopenharmony_ci		return NULL;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
5328c2ecf20Sopenharmony_ci		pdev = rcu_dereference(ab->pdevs_active[i]);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci		if (pdev && pdev->pdev_id == pdev_id)
5358c2ecf20Sopenharmony_ci			return (pdev->ar ? pdev->ar : NULL);
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	return NULL;
5398c2ecf20Sopenharmony_ci}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_cistruct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab,
5428c2ecf20Sopenharmony_ci						  u32 vdev_id)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	int i;
5458c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
5468c2ecf20Sopenharmony_ci	struct ath11k *ar;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
5498c2ecf20Sopenharmony_ci		pdev = rcu_dereference(ab->pdevs_active[i]);
5508c2ecf20Sopenharmony_ci		if (pdev && pdev->ar) {
5518c2ecf20Sopenharmony_ci			ar = pdev->ar;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci			spin_lock_bh(&ar->data_lock);
5548c2ecf20Sopenharmony_ci			if (ar->vdev_stop_status.stop_in_progress &&
5558c2ecf20Sopenharmony_ci			    ar->vdev_stop_status.vdev_id == vdev_id) {
5568c2ecf20Sopenharmony_ci				ar->vdev_stop_status.stop_in_progress = false;
5578c2ecf20Sopenharmony_ci				spin_unlock_bh(&ar->data_lock);
5588c2ecf20Sopenharmony_ci				return ar;
5598c2ecf20Sopenharmony_ci			}
5608c2ecf20Sopenharmony_ci			spin_unlock_bh(&ar->data_lock);
5618c2ecf20Sopenharmony_ci		}
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci	return NULL;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic void ath11k_pdev_caps_update(struct ath11k *ar)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	ar->max_tx_power = ab->target_caps.hw_max_tx_power;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	/* FIXME Set min_tx_power to ab->target_caps.hw_min_tx_power.
5738c2ecf20Sopenharmony_ci	 * But since the received value in svcrdy is same as hw_max_tx_power,
5748c2ecf20Sopenharmony_ci	 * we can set ar->min_tx_power to 0 currently until
5758c2ecf20Sopenharmony_ci	 * this is fixed in firmware
5768c2ecf20Sopenharmony_ci	 */
5778c2ecf20Sopenharmony_ci	ar->min_tx_power = 0;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	ar->txpower_limit_2g = ar->max_tx_power;
5808c2ecf20Sopenharmony_ci	ar->txpower_limit_5g = ar->max_tx_power;
5818c2ecf20Sopenharmony_ci	ar->txpower_scale = WMI_HOST_TP_SCALE_MAX;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int ath11k_mac_txpower_recalc(struct ath11k *ar)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev = ar->pdev;
5878c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif;
5888c2ecf20Sopenharmony_ci	int ret, txpower = -1;
5898c2ecf20Sopenharmony_ci	u32 param;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	list_for_each_entry(arvif, &ar->arvifs, list) {
5948c2ecf20Sopenharmony_ci		if (arvif->txpower <= 0)
5958c2ecf20Sopenharmony_ci			continue;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci		if (txpower == -1)
5988c2ecf20Sopenharmony_ci			txpower = arvif->txpower;
5998c2ecf20Sopenharmony_ci		else
6008c2ecf20Sopenharmony_ci			txpower = min(txpower, arvif->txpower);
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (txpower == -1)
6048c2ecf20Sopenharmony_ci		return 0;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* txpwr is set as 2 units per dBm in FW*/
6078c2ecf20Sopenharmony_ci	txpower = min_t(u32, max_t(u32, ar->min_tx_power, txpower),
6088c2ecf20Sopenharmony_ci			ar->max_tx_power) * 2;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "txpower to set in hw %d\n",
6118c2ecf20Sopenharmony_ci		   txpower / 2);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	if ((pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) &&
6148c2ecf20Sopenharmony_ci	    ar->txpower_limit_2g != txpower) {
6158c2ecf20Sopenharmony_ci		param = WMI_PDEV_PARAM_TXPOWER_LIMIT2G;
6168c2ecf20Sopenharmony_ci		ret = ath11k_wmi_pdev_set_param(ar, param,
6178c2ecf20Sopenharmony_ci						txpower, ar->pdev->pdev_id);
6188c2ecf20Sopenharmony_ci		if (ret)
6198c2ecf20Sopenharmony_ci			goto fail;
6208c2ecf20Sopenharmony_ci		ar->txpower_limit_2g = txpower;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if ((pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) &&
6248c2ecf20Sopenharmony_ci	    ar->txpower_limit_5g != txpower) {
6258c2ecf20Sopenharmony_ci		param = WMI_PDEV_PARAM_TXPOWER_LIMIT5G;
6268c2ecf20Sopenharmony_ci		ret = ath11k_wmi_pdev_set_param(ar, param,
6278c2ecf20Sopenharmony_ci						txpower, ar->pdev->pdev_id);
6288c2ecf20Sopenharmony_ci		if (ret)
6298c2ecf20Sopenharmony_ci			goto fail;
6308c2ecf20Sopenharmony_ci		ar->txpower_limit_5g = txpower;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	return 0;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cifail:
6368c2ecf20Sopenharmony_ci	ath11k_warn(ar->ab, "failed to recalc txpower limit %d using pdev param %d: %d\n",
6378c2ecf20Sopenharmony_ci		    txpower / 2, param, ret);
6388c2ecf20Sopenharmony_ci	return ret;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic int ath11k_recalc_rtscts_prot(struct ath11k_vif *arvif)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
6448c2ecf20Sopenharmony_ci	u32 vdev_param, rts_cts = 0;
6458c2ecf20Sopenharmony_ci	int ret;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_ENABLE_RTSCTS;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	/* Enable RTS/CTS protection for sw retries (when legacy stations
6528c2ecf20Sopenharmony_ci	 * are in BSS) or by default only for second rate series.
6538c2ecf20Sopenharmony_ci	 * TODO: Check if we need to enable CTS 2 Self in any case
6548c2ecf20Sopenharmony_ci	 */
6558c2ecf20Sopenharmony_ci	rts_cts = WMI_USE_RTS_CTS;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (arvif->num_legacy_stations > 0)
6588c2ecf20Sopenharmony_ci		rts_cts |= WMI_RTSCTS_ACROSS_SW_RETRIES << 4;
6598c2ecf20Sopenharmony_ci	else
6608c2ecf20Sopenharmony_ci		rts_cts |= WMI_RTSCTS_FOR_SECOND_RATESERIES << 4;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* Need not send duplicate param value to firmware */
6638c2ecf20Sopenharmony_ci	if (arvif->rtscts_prot_mode == rts_cts)
6648c2ecf20Sopenharmony_ci		return 0;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	arvif->rtscts_prot_mode = rts_cts;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d recalc rts/cts prot %d\n",
6698c2ecf20Sopenharmony_ci		   arvif->vdev_id, rts_cts);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	ret =  ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
6728c2ecf20Sopenharmony_ci					     vdev_param, rts_cts);
6738c2ecf20Sopenharmony_ci	if (ret)
6748c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to recalculate rts/cts prot for vdev %d: %d\n",
6758c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	return ret;
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cistatic int ath11k_mac_set_kickout(struct ath11k_vif *arvif)
6818c2ecf20Sopenharmony_ci{
6828c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
6838c2ecf20Sopenharmony_ci	u32 param;
6848c2ecf20Sopenharmony_ci	int ret;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_STA_KICKOUT_TH,
6878c2ecf20Sopenharmony_ci					ATH11K_KICKOUT_THRESHOLD,
6888c2ecf20Sopenharmony_ci					ar->pdev->pdev_id);
6898c2ecf20Sopenharmony_ci	if (ret) {
6908c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set kickout threshold on vdev %i: %d\n",
6918c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
6928c2ecf20Sopenharmony_ci		return ret;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	param = WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS;
6968c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param,
6978c2ecf20Sopenharmony_ci					    ATH11K_KEEPALIVE_MIN_IDLE);
6988c2ecf20Sopenharmony_ci	if (ret) {
6998c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set keepalive minimum idle time on vdev %i: %d\n",
7008c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
7018c2ecf20Sopenharmony_ci		return ret;
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	param = WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS;
7058c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param,
7068c2ecf20Sopenharmony_ci					    ATH11K_KEEPALIVE_MAX_IDLE);
7078c2ecf20Sopenharmony_ci	if (ret) {
7088c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set keepalive maximum idle time on vdev %i: %d\n",
7098c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
7108c2ecf20Sopenharmony_ci		return ret;
7118c2ecf20Sopenharmony_ci	}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	param = WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS;
7148c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param,
7158c2ecf20Sopenharmony_ci					    ATH11K_KEEPALIVE_MAX_UNRESPONSIVE);
7168c2ecf20Sopenharmony_ci	if (ret) {
7178c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
7188c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
7198c2ecf20Sopenharmony_ci		return ret;
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	return 0;
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_civoid ath11k_mac_peer_cleanup_all(struct ath11k *ar)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	struct ath11k_peer *peer, *tmp;
7288c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
7338c2ecf20Sopenharmony_ci	list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
7348c2ecf20Sopenharmony_ci		ath11k_peer_rx_tid_cleanup(ar, peer);
7358c2ecf20Sopenharmony_ci		list_del(&peer->list);
7368c2ecf20Sopenharmony_ci		kfree(peer);
7378c2ecf20Sopenharmony_ci	}
7388c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	ar->num_peers = 0;
7418c2ecf20Sopenharmony_ci	ar->num_stations = 0;
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic int ath11k_monitor_vdev_up(struct ath11k *ar, int vdev_id)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	int ret = 0;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
7498c2ecf20Sopenharmony_ci	if (ret) {
7508c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n",
7518c2ecf20Sopenharmony_ci			    vdev_id, ret);
7528c2ecf20Sopenharmony_ci		return ret;
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n",
7568c2ecf20Sopenharmony_ci		   vdev_id);
7578c2ecf20Sopenharmony_ci	return 0;
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cistatic int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci	/* mac80211 requires this op to be present and that's why
7638c2ecf20Sopenharmony_ci	 * there's an empty function, this can be extended when
7648c2ecf20Sopenharmony_ci	 * required.
7658c2ecf20Sopenharmony_ci	 */
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
7738c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
7748c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw = ar->hw;
7758c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = arvif->vif;
7768c2ecf20Sopenharmony_ci	struct ieee80211_mutable_offsets offs = {};
7778c2ecf20Sopenharmony_ci	struct sk_buff *bcn;
7788c2ecf20Sopenharmony_ci	struct ieee80211_mgmt *mgmt;
7798c2ecf20Sopenharmony_ci	u8 *ies;
7808c2ecf20Sopenharmony_ci	int ret;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
7838c2ecf20Sopenharmony_ci		return 0;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	bcn = ieee80211_beacon_get_template(hw, vif, &offs);
7868c2ecf20Sopenharmony_ci	if (!bcn) {
7878c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to get beacon template from mac80211\n");
7888c2ecf20Sopenharmony_ci		return -EPERM;
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn);
7928c2ecf20Sopenharmony_ci	ies += sizeof(mgmt->u.beacon);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies)))
7958c2ecf20Sopenharmony_ci		arvif->rsnie_present = true;
7968c2ecf20Sopenharmony_ci	else
7978c2ecf20Sopenharmony_ci		arvif->rsnie_present = false;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
8008c2ecf20Sopenharmony_ci				    WLAN_OUI_TYPE_MICROSOFT_WPA,
8018c2ecf20Sopenharmony_ci				    ies, (skb_tail_pointer(bcn) - ies)))
8028c2ecf20Sopenharmony_ci		arvif->wpaie_present = true;
8038c2ecf20Sopenharmony_ci	else
8048c2ecf20Sopenharmony_ci		arvif->wpaie_present = false;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	kfree_skb(bcn);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	if (ret)
8118c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to submit beacon template command: %d\n",
8128c2ecf20Sopenharmony_ci			    ret);
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	return ret;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic void ath11k_control_beaconing(struct ath11k_vif *arvif,
8188c2ecf20Sopenharmony_ci				     struct ieee80211_bss_conf *info)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
8218c2ecf20Sopenharmony_ci	int ret = 0;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	lockdep_assert_held(&arvif->ar->conf_mutex);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	if (!info->enable_beacon) {
8268c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
8278c2ecf20Sopenharmony_ci		if (ret)
8288c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to down vdev_id %i: %d\n",
8298c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci		arvif->is_up = false;
8328c2ecf20Sopenharmony_ci		return;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	/* Install the beacon template to the FW */
8368c2ecf20Sopenharmony_ci	ret = ath11k_mac_setup_bcn_tmpl(arvif);
8378c2ecf20Sopenharmony_ci	if (ret) {
8388c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to update bcn tmpl during vdev up: %d\n",
8398c2ecf20Sopenharmony_ci			    ret);
8408c2ecf20Sopenharmony_ci		return;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	arvif->tx_seq_no = 0x1000;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	arvif->aid = 0;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	ether_addr_copy(arvif->bssid, info->bssid);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
8508c2ecf20Sopenharmony_ci				 arvif->bssid);
8518c2ecf20Sopenharmony_ci	if (ret) {
8528c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to bring up vdev %d: %i\n",
8538c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
8548c2ecf20Sopenharmony_ci		return;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	arvif->is_up = true;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_basic(struct ath11k *ar,
8638c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif,
8648c2ecf20Sopenharmony_ci				      struct ieee80211_sta *sta,
8658c2ecf20Sopenharmony_ci				      struct peer_assoc_params *arg)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
8688c2ecf20Sopenharmony_ci	u32 aid;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_STATION)
8738c2ecf20Sopenharmony_ci		aid = vif->bss_conf.aid;
8748c2ecf20Sopenharmony_ci	else
8758c2ecf20Sopenharmony_ci		aid = sta->aid;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	ether_addr_copy(arg->peer_mac, sta->addr);
8788c2ecf20Sopenharmony_ci	arg->vdev_id = arvif->vdev_id;
8798c2ecf20Sopenharmony_ci	arg->peer_associd = aid;
8808c2ecf20Sopenharmony_ci	arg->auth_flag = true;
8818c2ecf20Sopenharmony_ci	/* TODO: STA WAR in ath10k for listen interval required? */
8828c2ecf20Sopenharmony_ci	arg->peer_listen_intval = ar->hw->conf.listen_interval;
8838c2ecf20Sopenharmony_ci	arg->peer_nss = 1;
8848c2ecf20Sopenharmony_ci	arg->peer_caps = vif->bss_conf.assoc_capability;
8858c2ecf20Sopenharmony_ci}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_crypto(struct ath11k *ar,
8888c2ecf20Sopenharmony_ci				       struct ieee80211_vif *vif,
8898c2ecf20Sopenharmony_ci				       struct ieee80211_sta *sta,
8908c2ecf20Sopenharmony_ci				       struct peer_assoc_params *arg)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct ieee80211_bss_conf *info = &vif->bss_conf;
8938c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
8948c2ecf20Sopenharmony_ci	struct cfg80211_bss *bss;
8958c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (struct ath11k_vif *)vif->drv_priv;
8968c2ecf20Sopenharmony_ci	const u8 *rsnie = NULL;
8978c2ecf20Sopenharmony_ci	const u8 *wpaie = NULL;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
9028c2ecf20Sopenharmony_ci		return;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0,
9058c2ecf20Sopenharmony_ci			       IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	if (arvif->rsnie_present || arvif->wpaie_present) {
9088c2ecf20Sopenharmony_ci		arg->need_ptk_4_way = true;
9098c2ecf20Sopenharmony_ci		if (arvif->wpaie_present)
9108c2ecf20Sopenharmony_ci			arg->need_gtk_2_way = true;
9118c2ecf20Sopenharmony_ci	} else if (bss) {
9128c2ecf20Sopenharmony_ci		const struct cfg80211_bss_ies *ies;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		rcu_read_lock();
9158c2ecf20Sopenharmony_ci		rsnie = ieee80211_bss_get_ie(bss, WLAN_EID_RSN);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci		ies = rcu_dereference(bss->ies);
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
9208c2ecf20Sopenharmony_ci						WLAN_OUI_TYPE_MICROSOFT_WPA,
9218c2ecf20Sopenharmony_ci						ies->data,
9228c2ecf20Sopenharmony_ci						ies->len);
9238c2ecf20Sopenharmony_ci		rcu_read_unlock();
9248c2ecf20Sopenharmony_ci		cfg80211_put_bss(ar->hw->wiphy, bss);
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* FIXME: base on RSN IE/WPA IE is a correct idea? */
9288c2ecf20Sopenharmony_ci	if (rsnie || wpaie) {
9298c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
9308c2ecf20Sopenharmony_ci			   "%s: rsn ie found\n", __func__);
9318c2ecf20Sopenharmony_ci		arg->need_ptk_4_way = true;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	if (wpaie) {
9358c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
9368c2ecf20Sopenharmony_ci			   "%s: wpa ie found\n", __func__);
9378c2ecf20Sopenharmony_ci		arg->need_gtk_2_way = true;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (sta->mfp) {
9418c2ecf20Sopenharmony_ci		/* TODO: Need to check if FW supports PMF? */
9428c2ecf20Sopenharmony_ci		arg->is_pmf_enabled = true;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	/* TODO: safe_mode_enabled (bypass 4-way handshake) flag req? */
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_rates(struct ath11k *ar,
9498c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif,
9508c2ecf20Sopenharmony_ci				      struct ieee80211_sta *sta,
9518c2ecf20Sopenharmony_ci				      struct peer_assoc_params *arg)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
9548c2ecf20Sopenharmony_ci	struct wmi_rate_set_arg *rateset = &arg->peer_legacy_rates;
9558c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
9568c2ecf20Sopenharmony_ci	const struct ieee80211_supported_band *sband;
9578c2ecf20Sopenharmony_ci	const struct ieee80211_rate *rates;
9588c2ecf20Sopenharmony_ci	enum nl80211_band band;
9598c2ecf20Sopenharmony_ci	u32 ratemask;
9608c2ecf20Sopenharmony_ci	u8 rate;
9618c2ecf20Sopenharmony_ci	int i;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
9668c2ecf20Sopenharmony_ci		return;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	band = def.chan->band;
9698c2ecf20Sopenharmony_ci	sband = ar->hw->wiphy->bands[band];
9708c2ecf20Sopenharmony_ci	ratemask = sta->supp_rates[band];
9718c2ecf20Sopenharmony_ci	ratemask &= arvif->bitrate_mask.control[band].legacy;
9728c2ecf20Sopenharmony_ci	rates = sband->bitrates;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	rateset->num_rates = 0;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	for (i = 0; i < 32; i++, ratemask >>= 1, rates++) {
9778c2ecf20Sopenharmony_ci		if (!(ratemask & 1))
9788c2ecf20Sopenharmony_ci			continue;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci		rate = ath11k_mac_bitrate_to_rate(rates->bitrate);
9818c2ecf20Sopenharmony_ci		rateset->rates[rateset->num_rates] = rate;
9828c2ecf20Sopenharmony_ci		rateset->num_rates++;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic bool
9878c2ecf20Sopenharmony_ciath11k_peer_assoc_h_ht_masked(const u8 ht_mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	int nss;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	for (nss = 0; nss < IEEE80211_HT_MCS_MASK_LEN; nss++)
9928c2ecf20Sopenharmony_ci		if (ht_mcs_mask[nss])
9938c2ecf20Sopenharmony_ci			return false;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	return true;
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic bool
9998c2ecf20Sopenharmony_ciath11k_peer_assoc_h_vht_masked(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	int nss;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++)
10048c2ecf20Sopenharmony_ci		if (vht_mcs_mask[nss])
10058c2ecf20Sopenharmony_ci			return false;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	return true;
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_ht(struct ath11k *ar,
10118c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
10128c2ecf20Sopenharmony_ci				   struct ieee80211_sta *sta,
10138c2ecf20Sopenharmony_ci				   struct peer_assoc_params *arg)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
10168c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
10178c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
10188c2ecf20Sopenharmony_ci	enum nl80211_band band;
10198c2ecf20Sopenharmony_ci	const u8 *ht_mcs_mask;
10208c2ecf20Sopenharmony_ci	int i, n;
10218c2ecf20Sopenharmony_ci	u8 max_nss;
10228c2ecf20Sopenharmony_ci	u32 stbc;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
10278c2ecf20Sopenharmony_ci		return;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (!ht_cap->ht_supported)
10308c2ecf20Sopenharmony_ci		return;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	band = def.chan->band;
10338c2ecf20Sopenharmony_ci	ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (ath11k_peer_assoc_h_ht_masked(ht_mcs_mask))
10368c2ecf20Sopenharmony_ci		return;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	arg->ht_flag = true;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	arg->peer_max_mpdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
10418c2ecf20Sopenharmony_ci				    ht_cap->ampdu_factor)) - 1;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	arg->peer_mpdu_density =
10448c2ecf20Sopenharmony_ci		ath11k_parse_mpdudensity(ht_cap->ampdu_density);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	arg->peer_ht_caps = ht_cap->cap;
10478c2ecf20Sopenharmony_ci	arg->peer_rate_caps |= WMI_HOST_RC_HT_FLAG;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	if (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING)
10508c2ecf20Sopenharmony_ci		arg->ldpc_flag = true;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
10538c2ecf20Sopenharmony_ci		arg->bw_40 = true;
10548c2ecf20Sopenharmony_ci		arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) {
10588c2ecf20Sopenharmony_ci		if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 |
10598c2ecf20Sopenharmony_ci		    IEEE80211_HT_CAP_SGI_40))
10608c2ecf20Sopenharmony_ci			arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG;
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	if (ht_cap->cap & IEEE80211_HT_CAP_TX_STBC) {
10648c2ecf20Sopenharmony_ci		arg->peer_rate_caps |= WMI_HOST_RC_TX_STBC_FLAG;
10658c2ecf20Sopenharmony_ci		arg->stbc_flag = true;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
10698c2ecf20Sopenharmony_ci		stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC;
10708c2ecf20Sopenharmony_ci		stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
10718c2ecf20Sopenharmony_ci		stbc = stbc << WMI_HOST_RC_RX_STBC_FLAG_S;
10728c2ecf20Sopenharmony_ci		arg->peer_rate_caps |= stbc;
10738c2ecf20Sopenharmony_ci		arg->stbc_flag = true;
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
10778c2ecf20Sopenharmony_ci		arg->peer_rate_caps |= WMI_HOST_RC_TS_FLAG;
10788c2ecf20Sopenharmony_ci	else if (ht_cap->mcs.rx_mask[1])
10798c2ecf20Sopenharmony_ci		arg->peer_rate_caps |= WMI_HOST_RC_DS_FLAG;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	for (i = 0, n = 0, max_nss = 0; i < IEEE80211_HT_MCS_MASK_LEN * 8; i++)
10828c2ecf20Sopenharmony_ci		if ((ht_cap->mcs.rx_mask[i / 8] & BIT(i % 8)) &&
10838c2ecf20Sopenharmony_ci		    (ht_mcs_mask[i / 8] & BIT(i % 8))) {
10848c2ecf20Sopenharmony_ci			max_nss = (i / 8) + 1;
10858c2ecf20Sopenharmony_ci			arg->peer_ht_rates.rates[n++] = i;
10868c2ecf20Sopenharmony_ci		}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	/* This is a workaround for HT-enabled STAs which break the spec
10898c2ecf20Sopenharmony_ci	 * and have no HT capabilities RX mask (no HT RX MCS map).
10908c2ecf20Sopenharmony_ci	 *
10918c2ecf20Sopenharmony_ci	 * As per spec, in section 20.3.5 Modulation and coding scheme (MCS),
10928c2ecf20Sopenharmony_ci	 * MCS 0 through 7 are mandatory in 20MHz with 800 ns GI at all STAs.
10938c2ecf20Sopenharmony_ci	 *
10948c2ecf20Sopenharmony_ci	 * Firmware asserts if such situation occurs.
10958c2ecf20Sopenharmony_ci	 */
10968c2ecf20Sopenharmony_ci	if (n == 0) {
10978c2ecf20Sopenharmony_ci		arg->peer_ht_rates.num_rates = 8;
10988c2ecf20Sopenharmony_ci		for (i = 0; i < arg->peer_ht_rates.num_rates; i++)
10998c2ecf20Sopenharmony_ci			arg->peer_ht_rates.rates[i] = i;
11008c2ecf20Sopenharmony_ci	} else {
11018c2ecf20Sopenharmony_ci		arg->peer_ht_rates.num_rates = n;
11028c2ecf20Sopenharmony_ci		arg->peer_nss = min(sta->rx_nss, max_nss);
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
11068c2ecf20Sopenharmony_ci		   arg->peer_mac,
11078c2ecf20Sopenharmony_ci		   arg->peer_ht_rates.num_rates,
11088c2ecf20Sopenharmony_ci		   arg->peer_nss);
11098c2ecf20Sopenharmony_ci}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_cistatic int ath11k_mac_get_max_vht_mcs_map(u16 mcs_map, int nss)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	switch ((mcs_map >> (2 * nss)) & 0x3) {
11148c2ecf20Sopenharmony_ci	case IEEE80211_VHT_MCS_SUPPORT_0_7: return BIT(8) - 1;
11158c2ecf20Sopenharmony_ci	case IEEE80211_VHT_MCS_SUPPORT_0_8: return BIT(9) - 1;
11168c2ecf20Sopenharmony_ci	case IEEE80211_VHT_MCS_SUPPORT_0_9: return BIT(10) - 1;
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci	return 0;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic u16
11228c2ecf20Sopenharmony_ciath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
11238c2ecf20Sopenharmony_ci			      const u16 vht_mcs_limit[NL80211_VHT_NSS_MAX])
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	int idx_limit;
11268c2ecf20Sopenharmony_ci	int nss;
11278c2ecf20Sopenharmony_ci	u16 mcs_map;
11288c2ecf20Sopenharmony_ci	u16 mcs;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
11318c2ecf20Sopenharmony_ci		mcs_map = ath11k_mac_get_max_vht_mcs_map(tx_mcs_set, nss) &
11328c2ecf20Sopenharmony_ci			  vht_mcs_limit[nss];
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		if (mcs_map)
11358c2ecf20Sopenharmony_ci			idx_limit = fls(mcs_map) - 1;
11368c2ecf20Sopenharmony_ci		else
11378c2ecf20Sopenharmony_ci			idx_limit = -1;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci		switch (idx_limit) {
11408c2ecf20Sopenharmony_ci		case 0:
11418c2ecf20Sopenharmony_ci		case 1:
11428c2ecf20Sopenharmony_ci		case 2:
11438c2ecf20Sopenharmony_ci		case 3:
11448c2ecf20Sopenharmony_ci		case 4:
11458c2ecf20Sopenharmony_ci		case 5:
11468c2ecf20Sopenharmony_ci		case 6:
11478c2ecf20Sopenharmony_ci		case 7:
11488c2ecf20Sopenharmony_ci			mcs = IEEE80211_VHT_MCS_SUPPORT_0_7;
11498c2ecf20Sopenharmony_ci			break;
11508c2ecf20Sopenharmony_ci		case 8:
11518c2ecf20Sopenharmony_ci			mcs = IEEE80211_VHT_MCS_SUPPORT_0_8;
11528c2ecf20Sopenharmony_ci			break;
11538c2ecf20Sopenharmony_ci		case 9:
11548c2ecf20Sopenharmony_ci			mcs = IEEE80211_VHT_MCS_SUPPORT_0_9;
11558c2ecf20Sopenharmony_ci			break;
11568c2ecf20Sopenharmony_ci		default:
11578c2ecf20Sopenharmony_ci			WARN_ON(1);
11588c2ecf20Sopenharmony_ci			fallthrough;
11598c2ecf20Sopenharmony_ci		case -1:
11608c2ecf20Sopenharmony_ci			mcs = IEEE80211_VHT_MCS_NOT_SUPPORTED;
11618c2ecf20Sopenharmony_ci			break;
11628c2ecf20Sopenharmony_ci		}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci		tx_mcs_set &= ~(0x3 << (nss * 2));
11658c2ecf20Sopenharmony_ci		tx_mcs_set |= mcs << (nss * 2);
11668c2ecf20Sopenharmony_ci	}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	return tx_mcs_set;
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_vht(struct ath11k *ar,
11728c2ecf20Sopenharmony_ci				    struct ieee80211_vif *vif,
11738c2ecf20Sopenharmony_ci				    struct ieee80211_sta *sta,
11748c2ecf20Sopenharmony_ci				    struct peer_assoc_params *arg)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
11778c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
11788c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
11798c2ecf20Sopenharmony_ci	enum nl80211_band band;
11808c2ecf20Sopenharmony_ci	const u16 *vht_mcs_mask;
11818c2ecf20Sopenharmony_ci	u8 ampdu_factor;
11828c2ecf20Sopenharmony_ci	u8 max_nss, vht_mcs;
11838c2ecf20Sopenharmony_ci	int i;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
11868c2ecf20Sopenharmony_ci		return;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (!vht_cap->vht_supported)
11898c2ecf20Sopenharmony_ci		return;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	band = def.chan->band;
11928c2ecf20Sopenharmony_ci	vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	if (ath11k_peer_assoc_h_vht_masked(vht_mcs_mask))
11958c2ecf20Sopenharmony_ci		return;
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	arg->vht_flag = true;
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	/* TODO: similar flags required? */
12008c2ecf20Sopenharmony_ci	arg->vht_capable = true;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	if (def.chan->band == NL80211_BAND_2GHZ)
12038c2ecf20Sopenharmony_ci		arg->vht_ng_flag = true;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	arg->peer_vht_caps = vht_cap->cap;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	ampdu_factor = (vht_cap->cap &
12088c2ecf20Sopenharmony_ci			IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
12098c2ecf20Sopenharmony_ci		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	/* Workaround: Some Netgear/Linksys 11ac APs set Rx A-MPDU factor to
12128c2ecf20Sopenharmony_ci	 * zero in VHT IE. Using it would result in degraded throughput.
12138c2ecf20Sopenharmony_ci	 * arg->peer_max_mpdu at this point contains HT max_mpdu so keep
12148c2ecf20Sopenharmony_ci	 * it if VHT max_mpdu is smaller.
12158c2ecf20Sopenharmony_ci	 */
12168c2ecf20Sopenharmony_ci	arg->peer_max_mpdu = max(arg->peer_max_mpdu,
12178c2ecf20Sopenharmony_ci				 (1U << (IEEE80211_HT_MAX_AMPDU_FACTOR +
12188c2ecf20Sopenharmony_ci					ampdu_factor)) - 1);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
12218c2ecf20Sopenharmony_ci		arg->bw_80 = true;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_160)
12248c2ecf20Sopenharmony_ci		arg->bw_160 = true;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	/* Calculate peer NSS capability from VHT capabilities if STA
12278c2ecf20Sopenharmony_ci	 * supports VHT.
12288c2ecf20Sopenharmony_ci	 */
12298c2ecf20Sopenharmony_ci	for (i = 0, max_nss = 0, vht_mcs = 0; i < NL80211_VHT_NSS_MAX; i++) {
12308c2ecf20Sopenharmony_ci		vht_mcs = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map) >>
12318c2ecf20Sopenharmony_ci			  (2 * i) & 3;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci		if (vht_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED &&
12348c2ecf20Sopenharmony_ci		    vht_mcs_mask[i])
12358c2ecf20Sopenharmony_ci			max_nss = i + 1;
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci	arg->peer_nss = min(sta->rx_nss, max_nss);
12388c2ecf20Sopenharmony_ci	arg->rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest);
12398c2ecf20Sopenharmony_ci	arg->rx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
12408c2ecf20Sopenharmony_ci	arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest);
12418c2ecf20Sopenharmony_ci	arg->tx_mcs_set = ath11k_peer_assoc_h_vht_limit(
12428c2ecf20Sopenharmony_ci		__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	/* In IPQ8074 platform, VHT mcs rate 10 and 11 is enabled by default.
12458c2ecf20Sopenharmony_ci	 * VHT mcs rate 10 and 11 is not suppoerted in 11ac standard.
12468c2ecf20Sopenharmony_ci	 * so explicitly disable the VHT MCS rate 10 and 11 in 11ac mode.
12478c2ecf20Sopenharmony_ci	 */
12488c2ecf20Sopenharmony_ci	arg->tx_mcs_set &= ~IEEE80211_VHT_MCS_SUPPORT_0_11_MASK;
12498c2ecf20Sopenharmony_ci	arg->tx_mcs_set |= IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	if ((arg->tx_mcs_set & IEEE80211_VHT_MCS_NOT_SUPPORTED) ==
12528c2ecf20Sopenharmony_ci			IEEE80211_VHT_MCS_NOT_SUPPORTED)
12538c2ecf20Sopenharmony_ci		arg->peer_vht_caps &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	/* TODO:  Check */
12568c2ecf20Sopenharmony_ci	arg->tx_max_mcs_nss = 0xFF;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
12598c2ecf20Sopenharmony_ci		   sta->addr, arg->peer_max_mpdu, arg->peer_flags);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	/* TODO: rxnss_override */
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_he(struct ath11k *ar,
12658c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
12668c2ecf20Sopenharmony_ci				   struct ieee80211_sta *sta,
12678c2ecf20Sopenharmony_ci				   struct peer_assoc_params *arg)
12688c2ecf20Sopenharmony_ci{
12698c2ecf20Sopenharmony_ci	const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
12708c2ecf20Sopenharmony_ci	u8 ampdu_factor;
12718c2ecf20Sopenharmony_ci	u16 v;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	if (!he_cap->has_he)
12748c2ecf20Sopenharmony_ci		return;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	arg->he_flag = true;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info,
12798c2ecf20Sopenharmony_ci	       sizeof(arg->peer_he_cap_macinfo));
12808c2ecf20Sopenharmony_ci	memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
12818c2ecf20Sopenharmony_ci	       sizeof(arg->peer_he_cap_phyinfo));
12828c2ecf20Sopenharmony_ci	arg->peer_he_ops = vif->bss_conf.he_oper.params;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	/* the top most byte is used to indicate BSS color info */
12858c2ecf20Sopenharmony_ci	arg->peer_he_ops &= 0xffffff;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	/* As per section 26.6.1 11ax Draft5.0, if the Max AMPDU Exponent Extension
12888c2ecf20Sopenharmony_ci	 * in HE cap is zero, use the arg->peer_max_mpdu as calculated while parsing
12898c2ecf20Sopenharmony_ci	 * VHT caps(if VHT caps is present) or HT caps (if VHT caps is not present).
12908c2ecf20Sopenharmony_ci	 *
12918c2ecf20Sopenharmony_ci	 * For non-zero value of Max AMPDU Extponent Extension in HE MAC caps,
12928c2ecf20Sopenharmony_ci	 * if a HE STA sends VHT cap and HE cap IE in assoc request then, use
12938c2ecf20Sopenharmony_ci	 * MAX_AMPDU_LEN_FACTOR as 20 to calculate max_ampdu length.
12948c2ecf20Sopenharmony_ci	 * If a HE STA that does not send VHT cap, but HE and HT cap in assoc
12958c2ecf20Sopenharmony_ci	 * request, then use MAX_AMPDU_LEN_FACTOR as 16 to calculate max_ampdu
12968c2ecf20Sopenharmony_ci	 * length.
12978c2ecf20Sopenharmony_ci	 */
12988c2ecf20Sopenharmony_ci	ampdu_factor = (he_cap->he_cap_elem.mac_cap_info[3] &
12998c2ecf20Sopenharmony_ci			IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >>
13008c2ecf20Sopenharmony_ci			IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_SHIFT;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (ampdu_factor) {
13038c2ecf20Sopenharmony_ci		if (sta->vht_cap.vht_supported)
13048c2ecf20Sopenharmony_ci			arg->peer_max_mpdu = (1 << (IEEE80211_HE_VHT_MAX_AMPDU_FACTOR +
13058c2ecf20Sopenharmony_ci						    ampdu_factor)) - 1;
13068c2ecf20Sopenharmony_ci		else if (sta->ht_cap.ht_supported)
13078c2ecf20Sopenharmony_ci			arg->peer_max_mpdu = (1 << (IEEE80211_HE_HT_MAX_AMPDU_FACTOR +
13088c2ecf20Sopenharmony_ci						    ampdu_factor)) - 1;
13098c2ecf20Sopenharmony_ci	}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	if (he_cap->he_cap_elem.phy_cap_info[6] &
13128c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
13138c2ecf20Sopenharmony_ci		int bit = 7;
13148c2ecf20Sopenharmony_ci		int nss, ru;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		arg->peer_ppet.numss_m1 = he_cap->ppe_thres[0] &
13178c2ecf20Sopenharmony_ci					  IEEE80211_PPE_THRES_NSS_MASK;
13188c2ecf20Sopenharmony_ci		arg->peer_ppet.ru_bit_mask =
13198c2ecf20Sopenharmony_ci			(he_cap->ppe_thres[0] &
13208c2ecf20Sopenharmony_ci			 IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK) >>
13218c2ecf20Sopenharmony_ci			IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		for (nss = 0; nss <= arg->peer_ppet.numss_m1; nss++) {
13248c2ecf20Sopenharmony_ci			for (ru = 0; ru < 4; ru++) {
13258c2ecf20Sopenharmony_ci				u32 val = 0;
13268c2ecf20Sopenharmony_ci				int i;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci				if ((arg->peer_ppet.ru_bit_mask & BIT(ru)) == 0)
13298c2ecf20Sopenharmony_ci					continue;
13308c2ecf20Sopenharmony_ci				for (i = 0; i < 6; i++) {
13318c2ecf20Sopenharmony_ci					val >>= 1;
13328c2ecf20Sopenharmony_ci					val |= ((he_cap->ppe_thres[bit / 8] >>
13338c2ecf20Sopenharmony_ci						 (bit % 8)) & 0x1) << 5;
13348c2ecf20Sopenharmony_ci					bit++;
13358c2ecf20Sopenharmony_ci				}
13368c2ecf20Sopenharmony_ci				arg->peer_ppet.ppet16_ppet8_ru3_ru0[nss] |=
13378c2ecf20Sopenharmony_ci								val << (ru * 6);
13388c2ecf20Sopenharmony_ci			}
13398c2ecf20Sopenharmony_ci		}
13408c2ecf20Sopenharmony_ci	}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_RES)
13438c2ecf20Sopenharmony_ci		arg->twt_responder = true;
13448c2ecf20Sopenharmony_ci	if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ)
13458c2ecf20Sopenharmony_ci		arg->twt_requester = true;
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	switch (sta->bandwidth) {
13488c2ecf20Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
13498c2ecf20Sopenharmony_ci		if (he_cap->he_cap_elem.phy_cap_info[0] &
13508c2ecf20Sopenharmony_ci		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
13518c2ecf20Sopenharmony_ci			v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80);
13528c2ecf20Sopenharmony_ci			arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci			v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80);
13558c2ecf20Sopenharmony_ci			arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci			arg->peer_he_mcs_count++;
13588c2ecf20Sopenharmony_ci		}
13598c2ecf20Sopenharmony_ci		v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
13608c2ecf20Sopenharmony_ci		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci		v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160);
13638c2ecf20Sopenharmony_ci		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci		arg->peer_he_mcs_count++;
13668c2ecf20Sopenharmony_ci		fallthrough;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	default:
13698c2ecf20Sopenharmony_ci		v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
13708c2ecf20Sopenharmony_ci		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v;
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci		v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80);
13738c2ecf20Sopenharmony_ci		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		arg->peer_he_mcs_count++;
13768c2ecf20Sopenharmony_ci		break;
13778c2ecf20Sopenharmony_ci	}
13788c2ecf20Sopenharmony_ci}
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta,
13818c2ecf20Sopenharmony_ci				     struct peer_assoc_params *arg)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
13848c2ecf20Sopenharmony_ci	int smps;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	if (!ht_cap->ht_supported)
13878c2ecf20Sopenharmony_ci		return;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
13908c2ecf20Sopenharmony_ci	smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	switch (smps) {
13938c2ecf20Sopenharmony_ci	case WLAN_HT_CAP_SM_PS_STATIC:
13948c2ecf20Sopenharmony_ci		arg->static_mimops_flag = true;
13958c2ecf20Sopenharmony_ci		break;
13968c2ecf20Sopenharmony_ci	case WLAN_HT_CAP_SM_PS_DYNAMIC:
13978c2ecf20Sopenharmony_ci		arg->dynamic_mimops_flag = true;
13988c2ecf20Sopenharmony_ci		break;
13998c2ecf20Sopenharmony_ci	case WLAN_HT_CAP_SM_PS_DISABLED:
14008c2ecf20Sopenharmony_ci		arg->spatial_mux_flag = true;
14018c2ecf20Sopenharmony_ci		break;
14028c2ecf20Sopenharmony_ci	default:
14038c2ecf20Sopenharmony_ci		break;
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_qos(struct ath11k *ar,
14088c2ecf20Sopenharmony_ci				    struct ieee80211_vif *vif,
14098c2ecf20Sopenharmony_ci				    struct ieee80211_sta *sta,
14108c2ecf20Sopenharmony_ci				    struct peer_assoc_params *arg)
14118c2ecf20Sopenharmony_ci{
14128c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	switch (arvif->vdev_type) {
14158c2ecf20Sopenharmony_ci	case WMI_VDEV_TYPE_AP:
14168c2ecf20Sopenharmony_ci		if (sta->wme) {
14178c2ecf20Sopenharmony_ci			/* TODO: Check WME vs QoS */
14188c2ecf20Sopenharmony_ci			arg->is_wme_set = true;
14198c2ecf20Sopenharmony_ci			arg->qos_flag = true;
14208c2ecf20Sopenharmony_ci		}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci		if (sta->wme && sta->uapsd_queues) {
14238c2ecf20Sopenharmony_ci			/* TODO: Check WME vs QoS */
14248c2ecf20Sopenharmony_ci			arg->is_wme_set = true;
14258c2ecf20Sopenharmony_ci			arg->apsd_flag = true;
14268c2ecf20Sopenharmony_ci			arg->peer_rate_caps |= WMI_HOST_RC_UAPSD_FLAG;
14278c2ecf20Sopenharmony_ci		}
14288c2ecf20Sopenharmony_ci		break;
14298c2ecf20Sopenharmony_ci	case WMI_VDEV_TYPE_STA:
14308c2ecf20Sopenharmony_ci		if (sta->wme) {
14318c2ecf20Sopenharmony_ci			arg->is_wme_set = true;
14328c2ecf20Sopenharmony_ci			arg->qos_flag = true;
14338c2ecf20Sopenharmony_ci		}
14348c2ecf20Sopenharmony_ci		break;
14358c2ecf20Sopenharmony_ci	default:
14368c2ecf20Sopenharmony_ci		break;
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac peer %pM qos %d\n",
14408c2ecf20Sopenharmony_ci		   sta->addr, arg->qos_flag);
14418c2ecf20Sopenharmony_ci}
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_cistatic int ath11k_peer_assoc_qos_ap(struct ath11k *ar,
14448c2ecf20Sopenharmony_ci				    struct ath11k_vif *arvif,
14458c2ecf20Sopenharmony_ci				    struct ieee80211_sta *sta)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	struct ap_ps_params params;
14488c2ecf20Sopenharmony_ci	u32 max_sp;
14498c2ecf20Sopenharmony_ci	u32 uapsd;
14508c2ecf20Sopenharmony_ci	int ret;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	params.vdev_id = arvif->vdev_id;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
14578c2ecf20Sopenharmony_ci		   sta->uapsd_queues, sta->max_sp);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	uapsd = 0;
14608c2ecf20Sopenharmony_ci	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
14618c2ecf20Sopenharmony_ci		uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
14628c2ecf20Sopenharmony_ci			 WMI_AP_PS_UAPSD_AC3_TRIGGER_EN;
14638c2ecf20Sopenharmony_ci	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
14648c2ecf20Sopenharmony_ci		uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN |
14658c2ecf20Sopenharmony_ci			 WMI_AP_PS_UAPSD_AC2_TRIGGER_EN;
14668c2ecf20Sopenharmony_ci	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
14678c2ecf20Sopenharmony_ci		uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN |
14688c2ecf20Sopenharmony_ci			 WMI_AP_PS_UAPSD_AC1_TRIGGER_EN;
14698c2ecf20Sopenharmony_ci	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
14708c2ecf20Sopenharmony_ci		uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
14718c2ecf20Sopenharmony_ci			 WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	max_sp = 0;
14748c2ecf20Sopenharmony_ci	if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
14758c2ecf20Sopenharmony_ci		max_sp = sta->max_sp;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	params.param = WMI_AP_PS_PEER_PARAM_UAPSD;
14788c2ecf20Sopenharmony_ci	params.value = uapsd;
14798c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &params);
14808c2ecf20Sopenharmony_ci	if (ret)
14818c2ecf20Sopenharmony_ci		goto err;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	params.param = WMI_AP_PS_PEER_PARAM_MAX_SP;
14848c2ecf20Sopenharmony_ci	params.value = max_sp;
14858c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &params);
14868c2ecf20Sopenharmony_ci	if (ret)
14878c2ecf20Sopenharmony_ci		goto err;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	/* TODO revisit during testing */
14908c2ecf20Sopenharmony_ci	params.param = WMI_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE;
14918c2ecf20Sopenharmony_ci	params.value = DISABLE_SIFS_RESPONSE_TRIGGER;
14928c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &params);
14938c2ecf20Sopenharmony_ci	if (ret)
14948c2ecf20Sopenharmony_ci		goto err;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	params.param = WMI_AP_PS_PEER_PARAM_SIFS_RESP_UAPSD;
14978c2ecf20Sopenharmony_ci	params.value = DISABLE_SIFS_RESPONSE_TRIGGER;
14988c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_set_ap_ps_param_cmd(ar, sta->addr, &params);
14998c2ecf20Sopenharmony_ci	if (ret)
15008c2ecf20Sopenharmony_ci		goto err;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	return 0;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_cierr:
15058c2ecf20Sopenharmony_ci	ath11k_warn(ar->ab, "failed to set ap ps peer param %d for vdev %i: %d\n",
15068c2ecf20Sopenharmony_ci		    params.param, arvif->vdev_id, ret);
15078c2ecf20Sopenharmony_ci	return ret;
15088c2ecf20Sopenharmony_ci}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_cistatic bool ath11k_mac_sta_has_ofdm_only(struct ieee80211_sta *sta)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	return sta->supp_rates[NL80211_BAND_2GHZ] >>
15138c2ecf20Sopenharmony_ci	       ATH11K_MAC_FIRST_OFDM_RATE_IDX;
15148c2ecf20Sopenharmony_ci}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_cistatic enum wmi_phy_mode ath11k_mac_get_phymode_vht(struct ath11k *ar,
15178c2ecf20Sopenharmony_ci						    struct ieee80211_sta *sta)
15188c2ecf20Sopenharmony_ci{
15198c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_160) {
15208c2ecf20Sopenharmony_ci		switch (sta->vht_cap.cap &
15218c2ecf20Sopenharmony_ci			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
15228c2ecf20Sopenharmony_ci		case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
15238c2ecf20Sopenharmony_ci			return MODE_11AC_VHT160;
15248c2ecf20Sopenharmony_ci		case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
15258c2ecf20Sopenharmony_ci			return MODE_11AC_VHT80_80;
15268c2ecf20Sopenharmony_ci		default:
15278c2ecf20Sopenharmony_ci			/* not sure if this is a valid case? */
15288c2ecf20Sopenharmony_ci			return MODE_11AC_VHT160;
15298c2ecf20Sopenharmony_ci		}
15308c2ecf20Sopenharmony_ci	}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
15338c2ecf20Sopenharmony_ci		return MODE_11AC_VHT80;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
15368c2ecf20Sopenharmony_ci		return MODE_11AC_VHT40;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
15398c2ecf20Sopenharmony_ci		return MODE_11AC_VHT20;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return MODE_UNKNOWN;
15428c2ecf20Sopenharmony_ci}
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_cistatic enum wmi_phy_mode ath11k_mac_get_phymode_he(struct ath11k *ar,
15458c2ecf20Sopenharmony_ci						   struct ieee80211_sta *sta)
15468c2ecf20Sopenharmony_ci{
15478c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_160) {
15488c2ecf20Sopenharmony_ci		if (sta->he_cap.he_cap_elem.phy_cap_info[0] &
15498c2ecf20Sopenharmony_ci		     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
15508c2ecf20Sopenharmony_ci			return MODE_11AX_HE160;
15518c2ecf20Sopenharmony_ci		else if (sta->he_cap.he_cap_elem.phy_cap_info[0] &
15528c2ecf20Sopenharmony_ci		     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
15538c2ecf20Sopenharmony_ci			return MODE_11AX_HE80_80;
15548c2ecf20Sopenharmony_ci		/* not sure if this is a valid case? */
15558c2ecf20Sopenharmony_ci		return MODE_11AX_HE160;
15568c2ecf20Sopenharmony_ci	}
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
15598c2ecf20Sopenharmony_ci		return MODE_11AX_HE80;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
15628c2ecf20Sopenharmony_ci		return MODE_11AX_HE40;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
15658c2ecf20Sopenharmony_ci		return MODE_11AX_HE20;
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci	return MODE_UNKNOWN;
15688c2ecf20Sopenharmony_ci}
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
15718c2ecf20Sopenharmony_ci					struct ieee80211_vif *vif,
15728c2ecf20Sopenharmony_ci					struct ieee80211_sta *sta,
15738c2ecf20Sopenharmony_ci					struct peer_assoc_params *arg)
15748c2ecf20Sopenharmony_ci{
15758c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
15768c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
15778c2ecf20Sopenharmony_ci	enum nl80211_band band;
15788c2ecf20Sopenharmony_ci	const u8 *ht_mcs_mask;
15798c2ecf20Sopenharmony_ci	const u16 *vht_mcs_mask;
15808c2ecf20Sopenharmony_ci	enum wmi_phy_mode phymode = MODE_UNKNOWN;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
15838c2ecf20Sopenharmony_ci		return;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	band = def.chan->band;
15868c2ecf20Sopenharmony_ci	ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
15878c2ecf20Sopenharmony_ci	vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	switch (band) {
15908c2ecf20Sopenharmony_ci	case NL80211_BAND_2GHZ:
15918c2ecf20Sopenharmony_ci		if (sta->he_cap.has_he) {
15928c2ecf20Sopenharmony_ci			if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
15938c2ecf20Sopenharmony_ci				phymode = MODE_11AX_HE80_2G;
15948c2ecf20Sopenharmony_ci			else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
15958c2ecf20Sopenharmony_ci				phymode = MODE_11AX_HE40_2G;
15968c2ecf20Sopenharmony_ci			else
15978c2ecf20Sopenharmony_ci				phymode = MODE_11AX_HE20_2G;
15988c2ecf20Sopenharmony_ci		} else if (sta->vht_cap.vht_supported &&
15998c2ecf20Sopenharmony_ci		    !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
16008c2ecf20Sopenharmony_ci			if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
16018c2ecf20Sopenharmony_ci				phymode = MODE_11AC_VHT40;
16028c2ecf20Sopenharmony_ci			else
16038c2ecf20Sopenharmony_ci				phymode = MODE_11AC_VHT20;
16048c2ecf20Sopenharmony_ci		} else if (sta->ht_cap.ht_supported &&
16058c2ecf20Sopenharmony_ci			   !ath11k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
16068c2ecf20Sopenharmony_ci			if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
16078c2ecf20Sopenharmony_ci				phymode = MODE_11NG_HT40;
16088c2ecf20Sopenharmony_ci			else
16098c2ecf20Sopenharmony_ci				phymode = MODE_11NG_HT20;
16108c2ecf20Sopenharmony_ci		} else if (ath11k_mac_sta_has_ofdm_only(sta)) {
16118c2ecf20Sopenharmony_ci			phymode = MODE_11G;
16128c2ecf20Sopenharmony_ci		} else {
16138c2ecf20Sopenharmony_ci			phymode = MODE_11B;
16148c2ecf20Sopenharmony_ci		}
16158c2ecf20Sopenharmony_ci		break;
16168c2ecf20Sopenharmony_ci	case NL80211_BAND_5GHZ:
16178c2ecf20Sopenharmony_ci	case NL80211_BAND_6GHZ:
16188c2ecf20Sopenharmony_ci		/* Check HE first */
16198c2ecf20Sopenharmony_ci		if (sta->he_cap.has_he) {
16208c2ecf20Sopenharmony_ci			phymode = ath11k_mac_get_phymode_he(ar, sta);
16218c2ecf20Sopenharmony_ci		} else if (sta->vht_cap.vht_supported &&
16228c2ecf20Sopenharmony_ci		    !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
16238c2ecf20Sopenharmony_ci			phymode = ath11k_mac_get_phymode_vht(ar, sta);
16248c2ecf20Sopenharmony_ci		} else if (sta->ht_cap.ht_supported &&
16258c2ecf20Sopenharmony_ci			   !ath11k_peer_assoc_h_ht_masked(ht_mcs_mask)) {
16268c2ecf20Sopenharmony_ci			if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
16278c2ecf20Sopenharmony_ci				phymode = MODE_11NA_HT40;
16288c2ecf20Sopenharmony_ci			else
16298c2ecf20Sopenharmony_ci				phymode = MODE_11NA_HT20;
16308c2ecf20Sopenharmony_ci		} else {
16318c2ecf20Sopenharmony_ci			phymode = MODE_11A;
16328c2ecf20Sopenharmony_ci		}
16338c2ecf20Sopenharmony_ci		break;
16348c2ecf20Sopenharmony_ci	default:
16358c2ecf20Sopenharmony_ci		break;
16368c2ecf20Sopenharmony_ci	}
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac peer %pM phymode %s\n",
16398c2ecf20Sopenharmony_ci		   sta->addr, ath11k_wmi_phymode_str(phymode));
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	arg->peer_phymode = phymode;
16428c2ecf20Sopenharmony_ci	WARN_ON(phymode == MODE_UNKNOWN);
16438c2ecf20Sopenharmony_ci}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_cistatic void ath11k_peer_assoc_prepare(struct ath11k *ar,
16468c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif,
16478c2ecf20Sopenharmony_ci				      struct ieee80211_sta *sta,
16488c2ecf20Sopenharmony_ci				      struct peer_assoc_params *arg,
16498c2ecf20Sopenharmony_ci				      bool reassoc)
16508c2ecf20Sopenharmony_ci{
16518c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	memset(arg, 0, sizeof(*arg));
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	reinit_completion(&ar->peer_assoc_done);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	arg->peer_new_assoc = !reassoc;
16588c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_basic(ar, vif, sta, arg);
16598c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_crypto(ar, vif, sta, arg);
16608c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_rates(ar, vif, sta, arg);
16618c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_ht(ar, vif, sta, arg);
16628c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_vht(ar, vif, sta, arg);
16638c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_he(ar, vif, sta, arg);
16648c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_qos(ar, vif, sta, arg);
16658c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_phymode(ar, vif, sta, arg);
16668c2ecf20Sopenharmony_ci	ath11k_peer_assoc_h_smps(sta, arg);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	/* TODO: amsdu_disable req? */
16698c2ecf20Sopenharmony_ci}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_cistatic int ath11k_setup_peer_smps(struct ath11k *ar, struct ath11k_vif *arvif,
16728c2ecf20Sopenharmony_ci				  const u8 *addr,
16738c2ecf20Sopenharmony_ci				  const struct ieee80211_sta_ht_cap *ht_cap)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	int smps;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	if (!ht_cap->ht_supported)
16788c2ecf20Sopenharmony_ci		return 0;
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
16818c2ecf20Sopenharmony_ci	smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	if (smps >= ARRAY_SIZE(ath11k_smps_map))
16848c2ecf20Sopenharmony_ci		return -EINVAL;
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	return ath11k_wmi_set_peer_param(ar, addr, arvif->vdev_id,
16878c2ecf20Sopenharmony_ci					 WMI_PEER_MIMO_PS_STATE,
16888c2ecf20Sopenharmony_ci					 ath11k_smps_map[smps]);
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_cistatic void ath11k_bss_assoc(struct ieee80211_hw *hw,
16928c2ecf20Sopenharmony_ci			     struct ieee80211_vif *vif,
16938c2ecf20Sopenharmony_ci			     struct ieee80211_bss_conf *bss_conf)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
16968c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
16978c2ecf20Sopenharmony_ci	struct peer_assoc_params peer_arg;
16988c2ecf20Sopenharmony_ci	struct ieee80211_sta *ap_sta;
16998c2ecf20Sopenharmony_ci	int ret;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
17048c2ecf20Sopenharmony_ci		   arvif->vdev_id, arvif->bssid, arvif->aid);
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	rcu_read_lock();
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
17098c2ecf20Sopenharmony_ci	if (!ap_sta) {
17108c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to find station entry for bss %pM vdev %i\n",
17118c2ecf20Sopenharmony_ci			    bss_conf->bssid, arvif->vdev_id);
17128c2ecf20Sopenharmony_ci		rcu_read_unlock();
17138c2ecf20Sopenharmony_ci		return;
17148c2ecf20Sopenharmony_ci	}
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	ath11k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg, false);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	rcu_read_unlock();
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
17218c2ecf20Sopenharmony_ci	if (ret) {
17228c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n",
17238c2ecf20Sopenharmony_ci			    bss_conf->bssid, arvif->vdev_id, ret);
17248c2ecf20Sopenharmony_ci		return;
17258c2ecf20Sopenharmony_ci	}
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
17288c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
17298c2ecf20Sopenharmony_ci			    bss_conf->bssid, arvif->vdev_id);
17308c2ecf20Sopenharmony_ci		return;
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	ret = ath11k_setup_peer_smps(ar, arvif, bss_conf->bssid,
17348c2ecf20Sopenharmony_ci				     &ap_sta->ht_cap);
17358c2ecf20Sopenharmony_ci	if (ret) {
17368c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n",
17378c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
17388c2ecf20Sopenharmony_ci		return;
17398c2ecf20Sopenharmony_ci	}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	WARN_ON(arvif->is_up);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	arvif->aid = bss_conf->aid;
17448c2ecf20Sopenharmony_ci	ether_addr_copy(arvif->bssid, bss_conf->bssid);
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
17478c2ecf20Sopenharmony_ci	if (ret) {
17488c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set vdev %d up: %d\n",
17498c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
17508c2ecf20Sopenharmony_ci		return;
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	arvif->is_up = true;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
17568c2ecf20Sopenharmony_ci		   "mac vdev %d up (associated) bssid %pM aid %d\n",
17578c2ecf20Sopenharmony_ci		   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	/* Authorize BSS Peer */
17608c2ecf20Sopenharmony_ci	ret = ath11k_wmi_set_peer_param(ar, arvif->bssid,
17618c2ecf20Sopenharmony_ci					arvif->vdev_id,
17628c2ecf20Sopenharmony_ci					WMI_PEER_AUTHORIZE,
17638c2ecf20Sopenharmony_ci					1);
17648c2ecf20Sopenharmony_ci	if (ret)
17658c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "Unable to authorize BSS peer: %d\n", ret);
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id,
17688c2ecf20Sopenharmony_ci					   &bss_conf->he_obss_pd);
17698c2ecf20Sopenharmony_ci	if (ret)
17708c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
17718c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
17728c2ecf20Sopenharmony_ci}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_cistatic void ath11k_bss_disassoc(struct ieee80211_hw *hw,
17758c2ecf20Sopenharmony_ci				struct ieee80211_vif *vif)
17768c2ecf20Sopenharmony_ci{
17778c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
17788c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
17798c2ecf20Sopenharmony_ci	int ret;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
17848c2ecf20Sopenharmony_ci		   arvif->vdev_id, arvif->bssid);
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
17878c2ecf20Sopenharmony_ci	if (ret)
17888c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to down vdev %i: %d\n",
17898c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	arvif->is_up = false;
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	/* TODO: cancel connection_loss_work */
17948c2ecf20Sopenharmony_ci}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_cistatic u32 ath11k_mac_get_rate_hw_value(int bitrate)
17978c2ecf20Sopenharmony_ci{
17988c2ecf20Sopenharmony_ci	u32 preamble;
17998c2ecf20Sopenharmony_ci	u16 hw_value;
18008c2ecf20Sopenharmony_ci	int rate;
18018c2ecf20Sopenharmony_ci	size_t i;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	if (ath11k_mac_bitrate_is_cck(bitrate))
18048c2ecf20Sopenharmony_ci		preamble = WMI_RATE_PREAMBLE_CCK;
18058c2ecf20Sopenharmony_ci	else
18068c2ecf20Sopenharmony_ci		preamble = WMI_RATE_PREAMBLE_OFDM;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(ath11k_legacy_rates); i++) {
18098c2ecf20Sopenharmony_ci		if (ath11k_legacy_rates[i].bitrate != bitrate)
18108c2ecf20Sopenharmony_ci			continue;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci		hw_value = ath11k_legacy_rates[i].hw_value;
18138c2ecf20Sopenharmony_ci		rate = ATH11K_HW_RATE_CODE(hw_value, 0, preamble);
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci		return rate;
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	return -EINVAL;
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_cistatic void ath11k_recalculate_mgmt_rate(struct ath11k *ar,
18228c2ecf20Sopenharmony_ci					 struct ieee80211_vif *vif,
18238c2ecf20Sopenharmony_ci					 struct cfg80211_chan_def *def)
18248c2ecf20Sopenharmony_ci{
18258c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
18268c2ecf20Sopenharmony_ci	const struct ieee80211_supported_band *sband;
18278c2ecf20Sopenharmony_ci	u8 basic_rate_idx;
18288c2ecf20Sopenharmony_ci	int hw_rate_code;
18298c2ecf20Sopenharmony_ci	u32 vdev_param;
18308c2ecf20Sopenharmony_ci	u16 bitrate;
18318c2ecf20Sopenharmony_ci	int ret;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	sband = ar->hw->wiphy->bands[def->chan->band];
18368c2ecf20Sopenharmony_ci	basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1;
18378c2ecf20Sopenharmony_ci	bitrate = sband->bitrates[basic_rate_idx].bitrate;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	hw_rate_code = ath11k_mac_get_rate_hw_value(bitrate);
18408c2ecf20Sopenharmony_ci	if (hw_rate_code < 0) {
18418c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "bitrate not supported %d\n", bitrate);
18428c2ecf20Sopenharmony_ci		return;
18438c2ecf20Sopenharmony_ci	}
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_MGMT_RATE;
18468c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param,
18478c2ecf20Sopenharmony_ci					    hw_rate_code);
18488c2ecf20Sopenharmony_ci	if (ret)
18498c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set mgmt tx rate %d\n", ret);
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_BEACON_RATE;
18528c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, vdev_param,
18538c2ecf20Sopenharmony_ci					    hw_rate_code);
18548c2ecf20Sopenharmony_ci	if (ret)
18558c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret);
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_cistatic void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
18598c2ecf20Sopenharmony_ci					   struct ieee80211_vif *vif,
18608c2ecf20Sopenharmony_ci					   struct ieee80211_bss_conf *info,
18618c2ecf20Sopenharmony_ci					   u32 changed)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
18648c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
18658c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
18668c2ecf20Sopenharmony_ci	u32 param_id, param_value;
18678c2ecf20Sopenharmony_ci	enum nl80211_band band;
18688c2ecf20Sopenharmony_ci	u32 vdev_param;
18698c2ecf20Sopenharmony_ci	int mcast_rate;
18708c2ecf20Sopenharmony_ci	u32 preamble;
18718c2ecf20Sopenharmony_ci	u16 hw_value;
18728c2ecf20Sopenharmony_ci	u16 bitrate;
18738c2ecf20Sopenharmony_ci	int ret = 0;
18748c2ecf20Sopenharmony_ci	u8 rateidx;
18758c2ecf20Sopenharmony_ci	u32 rate;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_BEACON_INT) {
18808c2ecf20Sopenharmony_ci		arvif->beacon_interval = info->beacon_int;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci		param_id = WMI_VDEV_PARAM_BEACON_INTERVAL;
18838c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
18848c2ecf20Sopenharmony_ci						    param_id,
18858c2ecf20Sopenharmony_ci						    arvif->beacon_interval);
18868c2ecf20Sopenharmony_ci		if (ret)
18878c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to set beacon interval for VDEV: %d\n",
18888c2ecf20Sopenharmony_ci				    arvif->vdev_id);
18898c2ecf20Sopenharmony_ci		else
18908c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
18918c2ecf20Sopenharmony_ci				   "Beacon interval: %d set for VDEV: %d\n",
18928c2ecf20Sopenharmony_ci				   arvif->beacon_interval, arvif->vdev_id);
18938c2ecf20Sopenharmony_ci	}
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_BEACON) {
18968c2ecf20Sopenharmony_ci		param_id = WMI_PDEV_PARAM_BEACON_TX_MODE;
18978c2ecf20Sopenharmony_ci		param_value = WMI_BEACON_STAGGERED_MODE;
18988c2ecf20Sopenharmony_ci		ret = ath11k_wmi_pdev_set_param(ar, param_id,
18998c2ecf20Sopenharmony_ci						param_value, ar->pdev->pdev_id);
19008c2ecf20Sopenharmony_ci		if (ret)
19018c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to set beacon mode for VDEV: %d\n",
19028c2ecf20Sopenharmony_ci				    arvif->vdev_id);
19038c2ecf20Sopenharmony_ci		else
19048c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
19058c2ecf20Sopenharmony_ci				   "Set staggered beacon mode for VDEV: %d\n",
19068c2ecf20Sopenharmony_ci				   arvif->vdev_id);
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci		ret = ath11k_mac_setup_bcn_tmpl(arvif);
19098c2ecf20Sopenharmony_ci		if (ret)
19108c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to update bcn template: %d\n",
19118c2ecf20Sopenharmony_ci				    ret);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci		if (vif->bss_conf.he_support) {
19148c2ecf20Sopenharmony_ci			ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
19158c2ecf20Sopenharmony_ci							    WMI_VDEV_PARAM_BA_MODE,
19168c2ecf20Sopenharmony_ci							    WMI_BA_MODE_BUFFER_SIZE_256);
19178c2ecf20Sopenharmony_ci			if (ret)
19188c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab,
19198c2ecf20Sopenharmony_ci					    "failed to set BA BUFFER SIZE 256 for vdev: %d\n",
19208c2ecf20Sopenharmony_ci					    arvif->vdev_id);
19218c2ecf20Sopenharmony_ci			else
19228c2ecf20Sopenharmony_ci				ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
19238c2ecf20Sopenharmony_ci					   "Set BA BUFFER SIZE 256 for VDEV: %d\n",
19248c2ecf20Sopenharmony_ci					   arvif->vdev_id);
19258c2ecf20Sopenharmony_ci		}
19268c2ecf20Sopenharmony_ci	}
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
19298c2ecf20Sopenharmony_ci		arvif->dtim_period = info->dtim_period;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci		param_id = WMI_VDEV_PARAM_DTIM_PERIOD;
19328c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
19338c2ecf20Sopenharmony_ci						    param_id,
19348c2ecf20Sopenharmony_ci						    arvif->dtim_period);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci		if (ret)
19378c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to set dtim period for VDEV %d: %i\n",
19388c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
19398c2ecf20Sopenharmony_ci		else
19408c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
19418c2ecf20Sopenharmony_ci				   "DTIM period: %d set for VDEV: %d\n",
19428c2ecf20Sopenharmony_ci				   arvif->dtim_period, arvif->vdev_id);
19438c2ecf20Sopenharmony_ci	}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_SSID &&
19468c2ecf20Sopenharmony_ci	    vif->type == NL80211_IFTYPE_AP) {
19478c2ecf20Sopenharmony_ci		arvif->u.ap.ssid_len = info->ssid_len;
19488c2ecf20Sopenharmony_ci		if (info->ssid_len)
19498c2ecf20Sopenharmony_ci			memcpy(arvif->u.ap.ssid, info->ssid, info->ssid_len);
19508c2ecf20Sopenharmony_ci		arvif->u.ap.hidden_ssid = info->hidden_ssid;
19518c2ecf20Sopenharmony_ci	}
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
19548c2ecf20Sopenharmony_ci		ether_addr_copy(arvif->bssid, info->bssid);
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_BEACON_ENABLED)
19578c2ecf20Sopenharmony_ci		ath11k_control_beaconing(arvif, info);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_ERP_CTS_PROT) {
19608c2ecf20Sopenharmony_ci		u32 cts_prot;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci		cts_prot = !!(info->use_cts_prot);
19638c2ecf20Sopenharmony_ci		param_id = WMI_VDEV_PARAM_PROTECTION_MODE;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci		if (arvif->is_started) {
19668c2ecf20Sopenharmony_ci			ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
19678c2ecf20Sopenharmony_ci							    param_id, cts_prot);
19688c2ecf20Sopenharmony_ci			if (ret)
19698c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "Failed to set CTS prot for VDEV: %d\n",
19708c2ecf20Sopenharmony_ci					    arvif->vdev_id);
19718c2ecf20Sopenharmony_ci			else
19728c2ecf20Sopenharmony_ci				ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Set CTS prot: %d for VDEV: %d\n",
19738c2ecf20Sopenharmony_ci					   cts_prot, arvif->vdev_id);
19748c2ecf20Sopenharmony_ci		} else {
19758c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "defer protection mode setup, vdev is not ready yet\n");
19768c2ecf20Sopenharmony_ci		}
19778c2ecf20Sopenharmony_ci	}
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_ERP_SLOT) {
19808c2ecf20Sopenharmony_ci		u32 slottime;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci		if (info->use_short_slot)
19838c2ecf20Sopenharmony_ci			slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci		else
19868c2ecf20Sopenharmony_ci			slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci		param_id = WMI_VDEV_PARAM_SLOT_TIME;
19898c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
19908c2ecf20Sopenharmony_ci						    param_id, slottime);
19918c2ecf20Sopenharmony_ci		if (ret)
19928c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to set erp slot for VDEV: %d\n",
19938c2ecf20Sopenharmony_ci				    arvif->vdev_id);
19948c2ecf20Sopenharmony_ci		else
19958c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
19968c2ecf20Sopenharmony_ci				   "Set slottime: %d for VDEV: %d\n",
19978c2ecf20Sopenharmony_ci				   slottime, arvif->vdev_id);
19988c2ecf20Sopenharmony_ci	}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
20018c2ecf20Sopenharmony_ci		u32 preamble;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		if (info->use_short_preamble)
20048c2ecf20Sopenharmony_ci			preamble = WMI_VDEV_PREAMBLE_SHORT;
20058c2ecf20Sopenharmony_ci		else
20068c2ecf20Sopenharmony_ci			preamble = WMI_VDEV_PREAMBLE_LONG;
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci		param_id = WMI_VDEV_PARAM_PREAMBLE;
20098c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
20108c2ecf20Sopenharmony_ci						    param_id, preamble);
20118c2ecf20Sopenharmony_ci		if (ret)
20128c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to set preamble for VDEV: %d\n",
20138c2ecf20Sopenharmony_ci				    arvif->vdev_id);
20148c2ecf20Sopenharmony_ci		else
20158c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
20168c2ecf20Sopenharmony_ci				   "Set preamble: %d for VDEV: %d\n",
20178c2ecf20Sopenharmony_ci				   preamble, arvif->vdev_id);
20188c2ecf20Sopenharmony_ci	}
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_ASSOC) {
20218c2ecf20Sopenharmony_ci		if (info->assoc)
20228c2ecf20Sopenharmony_ci			ath11k_bss_assoc(hw, vif, info);
20238c2ecf20Sopenharmony_ci		else
20248c2ecf20Sopenharmony_ci			ath11k_bss_disassoc(hw, vif);
20258c2ecf20Sopenharmony_ci	}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_TXPOWER) {
20288c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vdev_id %i txpower %d\n",
20298c2ecf20Sopenharmony_ci			   arvif->vdev_id, info->txpower);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci		arvif->txpower = info->txpower;
20328c2ecf20Sopenharmony_ci		ath11k_mac_txpower_recalc(ar);
20338c2ecf20Sopenharmony_ci	}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_MCAST_RATE &&
20368c2ecf20Sopenharmony_ci	    !ath11k_mac_vif_chan(arvif->vif, &def)) {
20378c2ecf20Sopenharmony_ci		band = def.chan->band;
20388c2ecf20Sopenharmony_ci		mcast_rate = vif->bss_conf.mcast_rate[band];
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci		if (mcast_rate > 0)
20418c2ecf20Sopenharmony_ci			rateidx = mcast_rate - 1;
20428c2ecf20Sopenharmony_ci		else
20438c2ecf20Sopenharmony_ci			rateidx = ffs(vif->bss_conf.basic_rates) - 1;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci		if (ar->pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP)
20468c2ecf20Sopenharmony_ci			rateidx += ATH11K_MAC_FIRST_OFDM_RATE_IDX;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci		bitrate = ath11k_legacy_rates[rateidx].bitrate;
20498c2ecf20Sopenharmony_ci		hw_value = ath11k_legacy_rates[rateidx].hw_value;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci		if (ath11k_mac_bitrate_is_cck(bitrate))
20528c2ecf20Sopenharmony_ci			preamble = WMI_RATE_PREAMBLE_CCK;
20538c2ecf20Sopenharmony_ci		else
20548c2ecf20Sopenharmony_ci			preamble = WMI_RATE_PREAMBLE_OFDM;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci		rate = ATH11K_HW_RATE_CODE(hw_value, 0, preamble);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
20598c2ecf20Sopenharmony_ci			   "mac vdev %d mcast_rate %x\n",
20608c2ecf20Sopenharmony_ci			   arvif->vdev_id, rate);
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci		vdev_param = WMI_VDEV_PARAM_MCAST_DATA_RATE;
20638c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
20648c2ecf20Sopenharmony_ci						    vdev_param, rate);
20658c2ecf20Sopenharmony_ci		if (ret)
20668c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
20678c2ecf20Sopenharmony_ci				    "failed to set mcast rate on vdev %i: %d\n",
20688c2ecf20Sopenharmony_ci				    arvif->vdev_id,  ret);
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci		vdev_param = WMI_VDEV_PARAM_BCAST_DATA_RATE;
20718c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
20728c2ecf20Sopenharmony_ci						    vdev_param, rate);
20738c2ecf20Sopenharmony_ci		if (ret)
20748c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
20758c2ecf20Sopenharmony_ci				    "failed to set bcast rate on vdev %i: %d\n",
20768c2ecf20Sopenharmony_ci				    arvif->vdev_id,  ret);
20778c2ecf20Sopenharmony_ci	}
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_BASIC_RATES &&
20808c2ecf20Sopenharmony_ci	    !ath11k_mac_vif_chan(arvif->vif, &def))
20818c2ecf20Sopenharmony_ci		ath11k_recalculate_mgmt_rate(ar, vif, &def);
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_TWT) {
20848c2ecf20Sopenharmony_ci		if (info->twt_requester || info->twt_responder)
20858c2ecf20Sopenharmony_ci			ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id);
20868c2ecf20Sopenharmony_ci		else
20878c2ecf20Sopenharmony_ci			ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
20888c2ecf20Sopenharmony_ci	}
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_HE_OBSS_PD)
20918c2ecf20Sopenharmony_ci		ath11k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id,
20928c2ecf20Sopenharmony_ci					     &info->he_obss_pd);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	if (changed & BSS_CHANGED_HE_BSS_COLOR) {
20958c2ecf20Sopenharmony_ci		if (vif->type == NL80211_IFTYPE_AP) {
20968c2ecf20Sopenharmony_ci			ret = ath11k_wmi_send_obss_color_collision_cfg_cmd(
20978c2ecf20Sopenharmony_ci				ar, arvif->vdev_id, info->he_bss_color.color,
20988c2ecf20Sopenharmony_ci				ATH11K_BSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS,
20998c2ecf20Sopenharmony_ci				info->he_bss_color.enabled);
21008c2ecf20Sopenharmony_ci			if (ret)
21018c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n",
21028c2ecf20Sopenharmony_ci					    arvif->vdev_id,  ret);
21038c2ecf20Sopenharmony_ci		} else if (vif->type == NL80211_IFTYPE_STATION) {
21048c2ecf20Sopenharmony_ci			ret = ath11k_wmi_send_bss_color_change_enable_cmd(ar,
21058c2ecf20Sopenharmony_ci									  arvif->vdev_id,
21068c2ecf20Sopenharmony_ci									  1);
21078c2ecf20Sopenharmony_ci			if (ret)
21088c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to enable bss color change on vdev %i: %d\n",
21098c2ecf20Sopenharmony_ci					    arvif->vdev_id,  ret);
21108c2ecf20Sopenharmony_ci			ret = ath11k_wmi_send_obss_color_collision_cfg_cmd(
21118c2ecf20Sopenharmony_ci				ar, arvif->vdev_id, 0,
21128c2ecf20Sopenharmony_ci				ATH11K_BSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS, 1);
21138c2ecf20Sopenharmony_ci			if (ret)
21148c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n",
21158c2ecf20Sopenharmony_ci					    arvif->vdev_id,  ret);
21168c2ecf20Sopenharmony_ci		}
21178c2ecf20Sopenharmony_ci	}
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
21208c2ecf20Sopenharmony_ci}
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_civoid __ath11k_mac_scan_finish(struct ath11k *ar)
21238c2ecf20Sopenharmony_ci{
21248c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->data_lock);
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	switch (ar->scan.state) {
21278c2ecf20Sopenharmony_ci	case ATH11K_SCAN_IDLE:
21288c2ecf20Sopenharmony_ci		break;
21298c2ecf20Sopenharmony_ci	case ATH11K_SCAN_RUNNING:
21308c2ecf20Sopenharmony_ci	case ATH11K_SCAN_ABORTING:
21318c2ecf20Sopenharmony_ci		if (!ar->scan.is_roc) {
21328c2ecf20Sopenharmony_ci			struct cfg80211_scan_info info = {
21338c2ecf20Sopenharmony_ci				.aborted = (ar->scan.state ==
21348c2ecf20Sopenharmony_ci					    ATH11K_SCAN_ABORTING),
21358c2ecf20Sopenharmony_ci			};
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci			ieee80211_scan_completed(ar->hw, &info);
21388c2ecf20Sopenharmony_ci		} else if (ar->scan.roc_notify) {
21398c2ecf20Sopenharmony_ci			ieee80211_remain_on_channel_expired(ar->hw);
21408c2ecf20Sopenharmony_ci		}
21418c2ecf20Sopenharmony_ci		fallthrough;
21428c2ecf20Sopenharmony_ci	case ATH11K_SCAN_STARTING:
21438c2ecf20Sopenharmony_ci		ar->scan.state = ATH11K_SCAN_IDLE;
21448c2ecf20Sopenharmony_ci		ar->scan_channel = NULL;
21458c2ecf20Sopenharmony_ci		ar->scan.roc_freq = 0;
21468c2ecf20Sopenharmony_ci		cancel_delayed_work(&ar->scan.timeout);
21478c2ecf20Sopenharmony_ci		complete(&ar->scan.completed);
21488c2ecf20Sopenharmony_ci		break;
21498c2ecf20Sopenharmony_ci	}
21508c2ecf20Sopenharmony_ci}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_civoid ath11k_mac_scan_finish(struct ath11k *ar)
21538c2ecf20Sopenharmony_ci{
21548c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
21558c2ecf20Sopenharmony_ci	__ath11k_mac_scan_finish(ar);
21568c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
21578c2ecf20Sopenharmony_ci}
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_cistatic int ath11k_scan_stop(struct ath11k *ar)
21608c2ecf20Sopenharmony_ci{
21618c2ecf20Sopenharmony_ci	struct scan_cancel_param arg = {
21628c2ecf20Sopenharmony_ci		.req_type = WLAN_SCAN_CANCEL_SINGLE,
21638c2ecf20Sopenharmony_ci		.scan_id = ATH11K_SCAN_ID,
21648c2ecf20Sopenharmony_ci	};
21658c2ecf20Sopenharmony_ci	int ret;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	/* TODO: Fill other STOP Params */
21708c2ecf20Sopenharmony_ci	arg.pdev_id = ar->pdev->pdev_id;
21718c2ecf20Sopenharmony_ci
21728c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_scan_stop_cmd(ar, &arg);
21738c2ecf20Sopenharmony_ci	if (ret) {
21748c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to stop wmi scan: %d\n", ret);
21758c2ecf20Sopenharmony_ci		goto out;
21768c2ecf20Sopenharmony_ci	}
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	ret = wait_for_completion_timeout(&ar->scan.completed, 3 * HZ);
21798c2ecf20Sopenharmony_ci	if (ret == 0) {
21808c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
21818c2ecf20Sopenharmony_ci			    "failed to receive scan abort comple: timed out\n");
21828c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
21838c2ecf20Sopenharmony_ci	} else if (ret > 0) {
21848c2ecf20Sopenharmony_ci		ret = 0;
21858c2ecf20Sopenharmony_ci	}
21868c2ecf20Sopenharmony_ci
21878c2ecf20Sopenharmony_ciout:
21888c2ecf20Sopenharmony_ci	/* Scan state should be updated upon scan completion but in case
21898c2ecf20Sopenharmony_ci	 * firmware fails to deliver the event (for whatever reason) it is
21908c2ecf20Sopenharmony_ci	 * desired to clean up scan state anyway. Firmware may have just
21918c2ecf20Sopenharmony_ci	 * dropped the scan completion event delivery due to transport pipe
21928c2ecf20Sopenharmony_ci	 * being overflown with data and/or it can recover on its own before
21938c2ecf20Sopenharmony_ci	 * next scan request is submitted.
21948c2ecf20Sopenharmony_ci	 */
21958c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
21968c2ecf20Sopenharmony_ci	if (ar->scan.state != ATH11K_SCAN_IDLE)
21978c2ecf20Sopenharmony_ci		__ath11k_mac_scan_finish(ar);
21988c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci	return ret;
22018c2ecf20Sopenharmony_ci}
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_cistatic void ath11k_scan_abort(struct ath11k *ar)
22048c2ecf20Sopenharmony_ci{
22058c2ecf20Sopenharmony_ci	int ret;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	switch (ar->scan.state) {
22128c2ecf20Sopenharmony_ci	case ATH11K_SCAN_IDLE:
22138c2ecf20Sopenharmony_ci		/* This can happen if timeout worker kicked in and called
22148c2ecf20Sopenharmony_ci		 * abortion while scan completion was being processed.
22158c2ecf20Sopenharmony_ci		 */
22168c2ecf20Sopenharmony_ci		break;
22178c2ecf20Sopenharmony_ci	case ATH11K_SCAN_STARTING:
22188c2ecf20Sopenharmony_ci	case ATH11K_SCAN_ABORTING:
22198c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "refusing scan abortion due to invalid scan state: %d\n",
22208c2ecf20Sopenharmony_ci			    ar->scan.state);
22218c2ecf20Sopenharmony_ci		break;
22228c2ecf20Sopenharmony_ci	case ATH11K_SCAN_RUNNING:
22238c2ecf20Sopenharmony_ci		ar->scan.state = ATH11K_SCAN_ABORTING;
22248c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->data_lock);
22258c2ecf20Sopenharmony_ci
22268c2ecf20Sopenharmony_ci		ret = ath11k_scan_stop(ar);
22278c2ecf20Sopenharmony_ci		if (ret)
22288c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to abort scan: %d\n", ret);
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci		spin_lock_bh(&ar->data_lock);
22318c2ecf20Sopenharmony_ci		break;
22328c2ecf20Sopenharmony_ci	}
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
22358c2ecf20Sopenharmony_ci}
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_cistatic void ath11k_scan_timeout_work(struct work_struct *work)
22388c2ecf20Sopenharmony_ci{
22398c2ecf20Sopenharmony_ci	struct ath11k *ar = container_of(work, struct ath11k,
22408c2ecf20Sopenharmony_ci					 scan.timeout.work);
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
22438c2ecf20Sopenharmony_ci	ath11k_scan_abort(ar);
22448c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
22458c2ecf20Sopenharmony_ci}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_cistatic int ath11k_start_scan(struct ath11k *ar,
22488c2ecf20Sopenharmony_ci			     struct scan_req_params *arg)
22498c2ecf20Sopenharmony_ci{
22508c2ecf20Sopenharmony_ci	int ret;
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	if (ath11k_spectral_get_mode(ar) == ATH11K_SPECTRAL_BACKGROUND)
22558c2ecf20Sopenharmony_ci		ath11k_spectral_reset_buffer(ar);
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_scan_start_cmd(ar, arg);
22588c2ecf20Sopenharmony_ci	if (ret)
22598c2ecf20Sopenharmony_ci		return ret;
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ);
22628c2ecf20Sopenharmony_ci	if (ret == 0) {
22638c2ecf20Sopenharmony_ci		ret = ath11k_scan_stop(ar);
22648c2ecf20Sopenharmony_ci		if (ret)
22658c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret);
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
22688c2ecf20Sopenharmony_ci	}
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci	/* If we failed to start the scan, return error code at
22718c2ecf20Sopenharmony_ci	 * this point.  This is probably due to some issue in the
22728c2ecf20Sopenharmony_ci	 * firmware, but no need to wedge the driver due to that...
22738c2ecf20Sopenharmony_ci	 */
22748c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
22758c2ecf20Sopenharmony_ci	if (ar->scan.state == ATH11K_SCAN_IDLE) {
22768c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->data_lock);
22778c2ecf20Sopenharmony_ci		return -EINVAL;
22788c2ecf20Sopenharmony_ci	}
22798c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	return 0;
22828c2ecf20Sopenharmony_ci}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_cistatic int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
22858c2ecf20Sopenharmony_ci				 struct ieee80211_vif *vif,
22868c2ecf20Sopenharmony_ci				 struct ieee80211_scan_request *hw_req)
22878c2ecf20Sopenharmony_ci{
22888c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
22898c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
22908c2ecf20Sopenharmony_ci	struct cfg80211_scan_request *req = &hw_req->req;
22918c2ecf20Sopenharmony_ci	struct scan_req_params arg;
22928c2ecf20Sopenharmony_ci	int ret = 0;
22938c2ecf20Sopenharmony_ci	int i;
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
22988c2ecf20Sopenharmony_ci	switch (ar->scan.state) {
22998c2ecf20Sopenharmony_ci	case ATH11K_SCAN_IDLE:
23008c2ecf20Sopenharmony_ci		reinit_completion(&ar->scan.started);
23018c2ecf20Sopenharmony_ci		reinit_completion(&ar->scan.completed);
23028c2ecf20Sopenharmony_ci		ar->scan.state = ATH11K_SCAN_STARTING;
23038c2ecf20Sopenharmony_ci		ar->scan.is_roc = false;
23048c2ecf20Sopenharmony_ci		ar->scan.vdev_id = arvif->vdev_id;
23058c2ecf20Sopenharmony_ci		ret = 0;
23068c2ecf20Sopenharmony_ci		break;
23078c2ecf20Sopenharmony_ci	case ATH11K_SCAN_STARTING:
23088c2ecf20Sopenharmony_ci	case ATH11K_SCAN_RUNNING:
23098c2ecf20Sopenharmony_ci	case ATH11K_SCAN_ABORTING:
23108c2ecf20Sopenharmony_ci		ret = -EBUSY;
23118c2ecf20Sopenharmony_ci		break;
23128c2ecf20Sopenharmony_ci	}
23138c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
23148c2ecf20Sopenharmony_ci
23158c2ecf20Sopenharmony_ci	if (ret)
23168c2ecf20Sopenharmony_ci		goto exit;
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	memset(&arg, 0, sizeof(arg));
23198c2ecf20Sopenharmony_ci	ath11k_wmi_start_scan_init(ar, &arg);
23208c2ecf20Sopenharmony_ci	arg.vdev_id = arvif->vdev_id;
23218c2ecf20Sopenharmony_ci	arg.scan_id = ATH11K_SCAN_ID;
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	if (req->ie_len) {
23248c2ecf20Sopenharmony_ci		arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL);
23258c2ecf20Sopenharmony_ci		if (!arg.extraie.ptr) {
23268c2ecf20Sopenharmony_ci			ret = -ENOMEM;
23278c2ecf20Sopenharmony_ci			goto exit;
23288c2ecf20Sopenharmony_ci		}
23298c2ecf20Sopenharmony_ci		arg.extraie.len = req->ie_len;
23308c2ecf20Sopenharmony_ci	}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	if (req->n_ssids) {
23338c2ecf20Sopenharmony_ci		arg.num_ssids = req->n_ssids;
23348c2ecf20Sopenharmony_ci		for (i = 0; i < arg.num_ssids; i++) {
23358c2ecf20Sopenharmony_ci			arg.ssid[i].length  = req->ssids[i].ssid_len;
23368c2ecf20Sopenharmony_ci			memcpy(&arg.ssid[i].ssid, req->ssids[i].ssid,
23378c2ecf20Sopenharmony_ci			       req->ssids[i].ssid_len);
23388c2ecf20Sopenharmony_ci		}
23398c2ecf20Sopenharmony_ci	} else {
23408c2ecf20Sopenharmony_ci		arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE;
23418c2ecf20Sopenharmony_ci	}
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	if (req->n_channels) {
23448c2ecf20Sopenharmony_ci		arg.num_chan = req->n_channels;
23458c2ecf20Sopenharmony_ci		for (i = 0; i < arg.num_chan; i++)
23468c2ecf20Sopenharmony_ci			arg.chan_list[i] = req->channels[i]->center_freq;
23478c2ecf20Sopenharmony_ci	}
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci	ret = ath11k_start_scan(ar, &arg);
23508c2ecf20Sopenharmony_ci	if (ret) {
23518c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
23528c2ecf20Sopenharmony_ci		spin_lock_bh(&ar->data_lock);
23538c2ecf20Sopenharmony_ci		ar->scan.state = ATH11K_SCAN_IDLE;
23548c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->data_lock);
23558c2ecf20Sopenharmony_ci	}
23568c2ecf20Sopenharmony_ci
23578c2ecf20Sopenharmony_ci	/* Add a 200ms margin to account for event/command processing */
23588c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
23598c2ecf20Sopenharmony_ci				     msecs_to_jiffies(arg.max_scan_time +
23608c2ecf20Sopenharmony_ci						      ATH11K_MAC_SCAN_TIMEOUT_MSECS));
23618c2ecf20Sopenharmony_ci
23628c2ecf20Sopenharmony_ciexit:
23638c2ecf20Sopenharmony_ci	if (req->ie_len)
23648c2ecf20Sopenharmony_ci		kfree(arg.extraie.ptr);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
23678c2ecf20Sopenharmony_ci	return ret;
23688c2ecf20Sopenharmony_ci}
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_cistatic void ath11k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
23718c2ecf20Sopenharmony_ci					 struct ieee80211_vif *vif)
23728c2ecf20Sopenharmony_ci{
23738c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
23768c2ecf20Sopenharmony_ci	ath11k_scan_abort(ar);
23778c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&ar->scan.timeout);
23808c2ecf20Sopenharmony_ci}
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_cistatic int ath11k_install_key(struct ath11k_vif *arvif,
23838c2ecf20Sopenharmony_ci			      struct ieee80211_key_conf *key,
23848c2ecf20Sopenharmony_ci			      enum set_key_cmd cmd,
23858c2ecf20Sopenharmony_ci			      const u8 *macaddr, u32 flags)
23868c2ecf20Sopenharmony_ci{
23878c2ecf20Sopenharmony_ci	int ret;
23888c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
23898c2ecf20Sopenharmony_ci	struct wmi_vdev_install_key_arg arg = {
23908c2ecf20Sopenharmony_ci		.vdev_id = arvif->vdev_id,
23918c2ecf20Sopenharmony_ci		.key_idx = key->keyidx,
23928c2ecf20Sopenharmony_ci		.key_len = key->keylen,
23938c2ecf20Sopenharmony_ci		.key_data = key->key,
23948c2ecf20Sopenharmony_ci		.key_flags = flags,
23958c2ecf20Sopenharmony_ci		.macaddr = macaddr,
23968c2ecf20Sopenharmony_ci	};
23978c2ecf20Sopenharmony_ci
23988c2ecf20Sopenharmony_ci	lockdep_assert_held(&arvif->ar->conf_mutex);
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	reinit_completion(&ar->install_key_done);
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
24038c2ecf20Sopenharmony_ci		return 0;
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	if (cmd == DISABLE_KEY) {
24068c2ecf20Sopenharmony_ci		arg.key_cipher = WMI_CIPHER_NONE;
24078c2ecf20Sopenharmony_ci		arg.key_data = NULL;
24088c2ecf20Sopenharmony_ci		goto install;
24098c2ecf20Sopenharmony_ci	}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	switch (key->cipher) {
24128c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
24138c2ecf20Sopenharmony_ci		arg.key_cipher = WMI_CIPHER_AES_CCM;
24148c2ecf20Sopenharmony_ci		/* TODO: Re-check if flag is valid */
24158c2ecf20Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
24168c2ecf20Sopenharmony_ci		break;
24178c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
24188c2ecf20Sopenharmony_ci		arg.key_cipher = WMI_CIPHER_TKIP;
24198c2ecf20Sopenharmony_ci		arg.key_txmic_len = 8;
24208c2ecf20Sopenharmony_ci		arg.key_rxmic_len = 8;
24218c2ecf20Sopenharmony_ci		break;
24228c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
24238c2ecf20Sopenharmony_ci		arg.key_cipher = WMI_CIPHER_AES_CCM;
24248c2ecf20Sopenharmony_ci		break;
24258c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
24268c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
24278c2ecf20Sopenharmony_ci		arg.key_cipher = WMI_CIPHER_AES_GCM;
24288c2ecf20Sopenharmony_ci		break;
24298c2ecf20Sopenharmony_ci	default:
24308c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "cipher %d is not supported\n", key->cipher);
24318c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
24328c2ecf20Sopenharmony_ci	}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_RAW_MODE, &ar->ab->dev_flags))
24358c2ecf20Sopenharmony_ci		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV |
24368c2ecf20Sopenharmony_ci			      IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ciinstall:
24398c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_install_key(arvif->ar, &arg);
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci	if (ret)
24428c2ecf20Sopenharmony_ci		return ret;
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ))
24458c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
24468c2ecf20Sopenharmony_ci
24478c2ecf20Sopenharmony_ci	return ar->install_key_status ? -EINVAL : 0;
24488c2ecf20Sopenharmony_ci}
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_cistatic int ath11k_clear_peer_keys(struct ath11k_vif *arvif,
24518c2ecf20Sopenharmony_ci				  const u8 *addr)
24528c2ecf20Sopenharmony_ci{
24538c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
24548c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
24558c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
24568c2ecf20Sopenharmony_ci	int first_errno = 0;
24578c2ecf20Sopenharmony_ci	int ret;
24588c2ecf20Sopenharmony_ci	int i;
24598c2ecf20Sopenharmony_ci	u32 flags = 0;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
24648c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, arvif->vdev_id, addr);
24658c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	if (!peer)
24688c2ecf20Sopenharmony_ci		return -ENOENT;
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
24718c2ecf20Sopenharmony_ci		if (!peer->keys[i])
24728c2ecf20Sopenharmony_ci			continue;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci		/* key flags are not required to delete the key */
24758c2ecf20Sopenharmony_ci		ret = ath11k_install_key(arvif, peer->keys[i],
24768c2ecf20Sopenharmony_ci					 DISABLE_KEY, addr, flags);
24778c2ecf20Sopenharmony_ci		if (ret < 0 && first_errno == 0)
24788c2ecf20Sopenharmony_ci			first_errno = ret;
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci		if (ret < 0)
24818c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to remove peer key %d: %d\n",
24828c2ecf20Sopenharmony_ci				    i, ret);
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci		spin_lock_bh(&ab->base_lock);
24858c2ecf20Sopenharmony_ci		peer->keys[i] = NULL;
24868c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	return first_errno;
24908c2ecf20Sopenharmony_ci}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_cistatic int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
24938c2ecf20Sopenharmony_ci				 struct ieee80211_vif *vif, struct ieee80211_sta *sta,
24948c2ecf20Sopenharmony_ci				 struct ieee80211_key_conf *key)
24958c2ecf20Sopenharmony_ci{
24968c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
24978c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
24988c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
24998c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
25008c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta;
25018c2ecf20Sopenharmony_ci	const u8 *peer_addr;
25028c2ecf20Sopenharmony_ci	int ret = 0;
25038c2ecf20Sopenharmony_ci	u32 flags = 0;
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	/* BIP needs to be done in software */
25068c2ecf20Sopenharmony_ci	if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
25078c2ecf20Sopenharmony_ci	    key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
25088c2ecf20Sopenharmony_ci	    key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
25098c2ecf20Sopenharmony_ci	    key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
25108c2ecf20Sopenharmony_ci		return 1;
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags))
25138c2ecf20Sopenharmony_ci		return 1;
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	if (key->keyidx > WMI_MAX_KEY_INDEX)
25168c2ecf20Sopenharmony_ci		return -ENOSPC;
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	if (sta)
25218c2ecf20Sopenharmony_ci		peer_addr = sta->addr;
25228c2ecf20Sopenharmony_ci	else if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
25238c2ecf20Sopenharmony_ci		peer_addr = vif->bss_conf.bssid;
25248c2ecf20Sopenharmony_ci	else
25258c2ecf20Sopenharmony_ci		peer_addr = vif->addr;
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	key->hw_key_idx = key->keyidx;
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	/* the peer should not disappear in mid-way (unless FW goes awry) since
25308c2ecf20Sopenharmony_ci	 * we already hold conf_mutex. we just make sure its there now.
25318c2ecf20Sopenharmony_ci	 */
25328c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
25338c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci	/* flush the fragments cache during key (re)install to
25368c2ecf20Sopenharmony_ci	 * ensure all frags in the new frag list belong to the same key.
25378c2ecf20Sopenharmony_ci	 */
25388c2ecf20Sopenharmony_ci	if (peer && sta && cmd == SET_KEY)
25398c2ecf20Sopenharmony_ci		ath11k_peer_frags_flush(ar, peer);
25408c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_ci	if (!peer) {
25438c2ecf20Sopenharmony_ci		if (cmd == SET_KEY) {
25448c2ecf20Sopenharmony_ci			ath11k_warn(ab, "cannot install key for non-existent peer %pM\n",
25458c2ecf20Sopenharmony_ci				    peer_addr);
25468c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
25478c2ecf20Sopenharmony_ci			goto exit;
25488c2ecf20Sopenharmony_ci		} else {
25498c2ecf20Sopenharmony_ci			/* if the peer doesn't exist there is no key to disable
25508c2ecf20Sopenharmony_ci			 * anymore
25518c2ecf20Sopenharmony_ci			 */
25528c2ecf20Sopenharmony_ci			goto exit;
25538c2ecf20Sopenharmony_ci		}
25548c2ecf20Sopenharmony_ci	}
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
25578c2ecf20Sopenharmony_ci		flags |= WMI_KEY_PAIRWISE;
25588c2ecf20Sopenharmony_ci	else
25598c2ecf20Sopenharmony_ci		flags |= WMI_KEY_GROUP;
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags);
25628c2ecf20Sopenharmony_ci	if (ret) {
25638c2ecf20Sopenharmony_ci		ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret);
25648c2ecf20Sopenharmony_ci		goto exit;
25658c2ecf20Sopenharmony_ci	}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key);
25688c2ecf20Sopenharmony_ci	if (ret) {
25698c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to offload PN replay detection %d\n", ret);
25708c2ecf20Sopenharmony_ci		goto exit;
25718c2ecf20Sopenharmony_ci	}
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	spin_lock_bh(&ab->base_lock);
25748c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ab, arvif->vdev_id, peer_addr);
25758c2ecf20Sopenharmony_ci	if (peer && cmd == SET_KEY) {
25768c2ecf20Sopenharmony_ci		peer->keys[key->keyidx] = key;
25778c2ecf20Sopenharmony_ci		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
25788c2ecf20Sopenharmony_ci			peer->ucast_keyidx = key->keyidx;
25798c2ecf20Sopenharmony_ci			peer->sec_type = ath11k_dp_tx_get_encrypt_type(key->cipher);
25808c2ecf20Sopenharmony_ci		} else {
25818c2ecf20Sopenharmony_ci			peer->mcast_keyidx = key->keyidx;
25828c2ecf20Sopenharmony_ci			peer->sec_type_grp = ath11k_dp_tx_get_encrypt_type(key->cipher);
25838c2ecf20Sopenharmony_ci		}
25848c2ecf20Sopenharmony_ci	} else if (peer && cmd == DISABLE_KEY) {
25858c2ecf20Sopenharmony_ci		peer->keys[key->keyidx] = NULL;
25868c2ecf20Sopenharmony_ci		if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
25878c2ecf20Sopenharmony_ci			peer->ucast_keyidx = 0;
25888c2ecf20Sopenharmony_ci		else
25898c2ecf20Sopenharmony_ci			peer->mcast_keyidx = 0;
25908c2ecf20Sopenharmony_ci	} else if (!peer)
25918c2ecf20Sopenharmony_ci		/* impossible unless FW goes crazy */
25928c2ecf20Sopenharmony_ci		ath11k_warn(ab, "peer %pM disappeared!\n", peer_addr);
25938c2ecf20Sopenharmony_ci
25948c2ecf20Sopenharmony_ci	if (sta) {
25958c2ecf20Sopenharmony_ci		arsta = (struct ath11k_sta *)sta->drv_priv;
25968c2ecf20Sopenharmony_ci
25978c2ecf20Sopenharmony_ci		switch (key->cipher) {
25988c2ecf20Sopenharmony_ci		case WLAN_CIPHER_SUITE_TKIP:
25998c2ecf20Sopenharmony_ci		case WLAN_CIPHER_SUITE_CCMP:
26008c2ecf20Sopenharmony_ci		case WLAN_CIPHER_SUITE_CCMP_256:
26018c2ecf20Sopenharmony_ci		case WLAN_CIPHER_SUITE_GCMP:
26028c2ecf20Sopenharmony_ci		case WLAN_CIPHER_SUITE_GCMP_256:
26038c2ecf20Sopenharmony_ci			if (cmd == SET_KEY)
26048c2ecf20Sopenharmony_ci				arsta->pn_type = HAL_PN_TYPE_WPA;
26058c2ecf20Sopenharmony_ci			else
26068c2ecf20Sopenharmony_ci				arsta->pn_type = HAL_PN_TYPE_NONE;
26078c2ecf20Sopenharmony_ci			break;
26088c2ecf20Sopenharmony_ci		default:
26098c2ecf20Sopenharmony_ci			arsta->pn_type = HAL_PN_TYPE_NONE;
26108c2ecf20Sopenharmony_ci			break;
26118c2ecf20Sopenharmony_ci		}
26128c2ecf20Sopenharmony_ci	}
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	spin_unlock_bh(&ab->base_lock);
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ciexit:
26178c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
26188c2ecf20Sopenharmony_ci	return ret;
26198c2ecf20Sopenharmony_ci}
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_cistatic int
26228c2ecf20Sopenharmony_ciath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar,
26238c2ecf20Sopenharmony_ci				      enum nl80211_band band,
26248c2ecf20Sopenharmony_ci				      const struct cfg80211_bitrate_mask *mask)
26258c2ecf20Sopenharmony_ci{
26268c2ecf20Sopenharmony_ci	int num_rates = 0;
26278c2ecf20Sopenharmony_ci	int i;
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++)
26308c2ecf20Sopenharmony_ci		num_rates += hweight16(mask->control[band].vht_mcs[i]);
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	return num_rates;
26338c2ecf20Sopenharmony_ci}
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_cistatic int
26368c2ecf20Sopenharmony_ciath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif,
26378c2ecf20Sopenharmony_ci				   struct ieee80211_sta *sta,
26388c2ecf20Sopenharmony_ci				   const struct cfg80211_bitrate_mask *mask,
26398c2ecf20Sopenharmony_ci				   enum nl80211_band band)
26408c2ecf20Sopenharmony_ci{
26418c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
26428c2ecf20Sopenharmony_ci	u8 vht_rate, nss;
26438c2ecf20Sopenharmony_ci	u32 rate_code;
26448c2ecf20Sopenharmony_ci	int ret, i;
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	nss = 0;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
26518c2ecf20Sopenharmony_ci		if (hweight16(mask->control[band].vht_mcs[i]) == 1) {
26528c2ecf20Sopenharmony_ci			nss = i + 1;
26538c2ecf20Sopenharmony_ci			vht_rate = ffs(mask->control[band].vht_mcs[i]) - 1;
26548c2ecf20Sopenharmony_ci		}
26558c2ecf20Sopenharmony_ci	}
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci	if (!nss) {
26588c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "No single VHT Fixed rate found to set for %pM",
26598c2ecf20Sopenharmony_ci			    sta->addr);
26608c2ecf20Sopenharmony_ci		return -EINVAL;
26618c2ecf20Sopenharmony_ci	}
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
26648c2ecf20Sopenharmony_ci		   "Setting Fixed VHT Rate for peer %pM. Device will not switch to any other selected rates",
26658c2ecf20Sopenharmony_ci		   sta->addr);
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	rate_code = ATH11K_HW_RATE_CODE(vht_rate, nss - 1,
26688c2ecf20Sopenharmony_ci					WMI_RATE_PREAMBLE_VHT);
26698c2ecf20Sopenharmony_ci	ret = ath11k_wmi_set_peer_param(ar, sta->addr,
26708c2ecf20Sopenharmony_ci					arvif->vdev_id,
26718c2ecf20Sopenharmony_ci					WMI_PEER_PARAM_FIXED_RATE,
26728c2ecf20Sopenharmony_ci					rate_code);
26738c2ecf20Sopenharmony_ci	if (ret)
26748c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
26758c2ecf20Sopenharmony_ci			    "failed to update STA %pM Fixed Rate %d: %d\n",
26768c2ecf20Sopenharmony_ci			     sta->addr, rate_code, ret);
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_ci	return ret;
26798c2ecf20Sopenharmony_ci}
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_cistatic int ath11k_station_assoc(struct ath11k *ar,
26828c2ecf20Sopenharmony_ci				struct ieee80211_vif *vif,
26838c2ecf20Sopenharmony_ci				struct ieee80211_sta *sta,
26848c2ecf20Sopenharmony_ci				bool reassoc)
26858c2ecf20Sopenharmony_ci{
26868c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
26878c2ecf20Sopenharmony_ci	struct peer_assoc_params peer_arg;
26888c2ecf20Sopenharmony_ci	int ret = 0;
26898c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
26908c2ecf20Sopenharmony_ci	enum nl80211_band band;
26918c2ecf20Sopenharmony_ci	struct cfg80211_bitrate_mask *mask;
26928c2ecf20Sopenharmony_ci	u8 num_vht_rates;
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
26958c2ecf20Sopenharmony_ci
26968c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
26978c2ecf20Sopenharmony_ci		return -EPERM;
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	band = def.chan->band;
27008c2ecf20Sopenharmony_ci	mask = &arvif->bitrate_mask;
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci	ath11k_peer_assoc_prepare(ar, vif, sta, &peer_arg, reassoc);
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
27058c2ecf20Sopenharmony_ci	if (ret) {
27068c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
27078c2ecf20Sopenharmony_ci			    sta->addr, arvif->vdev_id, ret);
27088c2ecf20Sopenharmony_ci		return ret;
27098c2ecf20Sopenharmony_ci	}
27108c2ecf20Sopenharmony_ci
27118c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
27128c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
27138c2ecf20Sopenharmony_ci			    sta->addr, arvif->vdev_id);
27148c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
27158c2ecf20Sopenharmony_ci	}
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask);
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci	/* If single VHT rate is configured (by set_bitrate_mask()),
27208c2ecf20Sopenharmony_ci	 * peer_assoc will disable VHT. This is now enabled by a peer specific
27218c2ecf20Sopenharmony_ci	 * fixed param.
27228c2ecf20Sopenharmony_ci	 * Note that all other rates and NSS will be disabled for this peer.
27238c2ecf20Sopenharmony_ci	 */
27248c2ecf20Sopenharmony_ci	if (sta->vht_cap.vht_supported && num_vht_rates == 1) {
27258c2ecf20Sopenharmony_ci		ret = ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
27268c2ecf20Sopenharmony_ci							 band);
27278c2ecf20Sopenharmony_ci		if (ret)
27288c2ecf20Sopenharmony_ci			return ret;
27298c2ecf20Sopenharmony_ci	}
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	/* Re-assoc is run only to update supported rates for given station. It
27328c2ecf20Sopenharmony_ci	 * doesn't make much sense to reconfigure the peer completely.
27338c2ecf20Sopenharmony_ci	 */
27348c2ecf20Sopenharmony_ci	if (reassoc)
27358c2ecf20Sopenharmony_ci		return 0;
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	ret = ath11k_setup_peer_smps(ar, arvif, sta->addr,
27388c2ecf20Sopenharmony_ci				     &sta->ht_cap);
27398c2ecf20Sopenharmony_ci	if (ret) {
27408c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to setup peer SMPS for vdev %d: %d\n",
27418c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
27428c2ecf20Sopenharmony_ci		return ret;
27438c2ecf20Sopenharmony_ci	}
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	if (!sta->wme) {
27468c2ecf20Sopenharmony_ci		arvif->num_legacy_stations++;
27478c2ecf20Sopenharmony_ci		ret = ath11k_recalc_rtscts_prot(arvif);
27488c2ecf20Sopenharmony_ci		if (ret)
27498c2ecf20Sopenharmony_ci			return ret;
27508c2ecf20Sopenharmony_ci	}
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	if (sta->wme && sta->uapsd_queues) {
27538c2ecf20Sopenharmony_ci		ret = ath11k_peer_assoc_qos_ap(ar, arvif, sta);
27548c2ecf20Sopenharmony_ci		if (ret) {
27558c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to set qos params for STA %pM for vdev %i: %d\n",
27568c2ecf20Sopenharmony_ci				    sta->addr, arvif->vdev_id, ret);
27578c2ecf20Sopenharmony_ci			return ret;
27588c2ecf20Sopenharmony_ci		}
27598c2ecf20Sopenharmony_ci	}
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci	return 0;
27628c2ecf20Sopenharmony_ci}
27638c2ecf20Sopenharmony_ci
27648c2ecf20Sopenharmony_cistatic int ath11k_station_disassoc(struct ath11k *ar,
27658c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
27668c2ecf20Sopenharmony_ci				   struct ieee80211_sta *sta)
27678c2ecf20Sopenharmony_ci{
27688c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
27698c2ecf20Sopenharmony_ci	int ret = 0;
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	if (!sta->wme) {
27748c2ecf20Sopenharmony_ci		arvif->num_legacy_stations--;
27758c2ecf20Sopenharmony_ci		ret = ath11k_recalc_rtscts_prot(arvif);
27768c2ecf20Sopenharmony_ci		if (ret)
27778c2ecf20Sopenharmony_ci			return ret;
27788c2ecf20Sopenharmony_ci	}
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	ret = ath11k_clear_peer_keys(arvif, sta->addr);
27818c2ecf20Sopenharmony_ci	if (ret) {
27828c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to clear all peer keys for vdev %i: %d\n",
27838c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
27848c2ecf20Sopenharmony_ci		return ret;
27858c2ecf20Sopenharmony_ci	}
27868c2ecf20Sopenharmony_ci	return 0;
27878c2ecf20Sopenharmony_ci}
27888c2ecf20Sopenharmony_ci
27898c2ecf20Sopenharmony_cistatic void ath11k_sta_rc_update_wk(struct work_struct *wk)
27908c2ecf20Sopenharmony_ci{
27918c2ecf20Sopenharmony_ci	struct ath11k *ar;
27928c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif;
27938c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta;
27948c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
27958c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
27968c2ecf20Sopenharmony_ci	enum nl80211_band band;
27978c2ecf20Sopenharmony_ci	const u8 *ht_mcs_mask;
27988c2ecf20Sopenharmony_ci	const u16 *vht_mcs_mask;
27998c2ecf20Sopenharmony_ci	u32 changed, bw, nss, smps;
28008c2ecf20Sopenharmony_ci	int err, num_vht_rates;
28018c2ecf20Sopenharmony_ci	const struct cfg80211_bitrate_mask *mask;
28028c2ecf20Sopenharmony_ci	struct peer_assoc_params peer_arg;
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ci	arsta = container_of(wk, struct ath11k_sta, update_wk);
28058c2ecf20Sopenharmony_ci	sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
28068c2ecf20Sopenharmony_ci	arvif = arsta->arvif;
28078c2ecf20Sopenharmony_ci	ar = arvif->ar;
28088c2ecf20Sopenharmony_ci
28098c2ecf20Sopenharmony_ci	if (WARN_ON(ath11k_mac_vif_chan(arvif->vif, &def)))
28108c2ecf20Sopenharmony_ci		return;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	band = def.chan->band;
28138c2ecf20Sopenharmony_ci	ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
28148c2ecf20Sopenharmony_ci	vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	changed = arsta->changed;
28198c2ecf20Sopenharmony_ci	arsta->changed = 0;
28208c2ecf20Sopenharmony_ci
28218c2ecf20Sopenharmony_ci	bw = arsta->bw;
28228c2ecf20Sopenharmony_ci	nss = arsta->nss;
28238c2ecf20Sopenharmony_ci	smps = arsta->smps;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	nss = max_t(u32, 1, nss);
28308c2ecf20Sopenharmony_ci	nss = min(nss, max(ath11k_mac_max_ht_nss(ht_mcs_mask),
28318c2ecf20Sopenharmony_ci			   ath11k_mac_max_vht_nss(vht_mcs_mask)));
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_BW_CHANGED) {
28348c2ecf20Sopenharmony_ci		err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
28358c2ecf20Sopenharmony_ci						WMI_PEER_CHWIDTH, bw);
28368c2ecf20Sopenharmony_ci		if (err)
28378c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
28388c2ecf20Sopenharmony_ci				    sta->addr, bw, err);
28398c2ecf20Sopenharmony_ci	}
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_NSS_CHANGED) {
28428c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM nss %d\n",
28438c2ecf20Sopenharmony_ci			   sta->addr, nss);
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_ci		err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
28468c2ecf20Sopenharmony_ci						WMI_PEER_NSS, nss);
28478c2ecf20Sopenharmony_ci		if (err)
28488c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to update STA %pM nss %d: %d\n",
28498c2ecf20Sopenharmony_ci				    sta->addr, nss, err);
28508c2ecf20Sopenharmony_ci	}
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_SMPS_CHANGED) {
28538c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM smps %d\n",
28548c2ecf20Sopenharmony_ci			   sta->addr, smps);
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_ci		err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
28578c2ecf20Sopenharmony_ci						WMI_PEER_MIMO_PS_STATE, smps);
28588c2ecf20Sopenharmony_ci		if (err)
28598c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to update STA %pM smps %d: %d\n",
28608c2ecf20Sopenharmony_ci				    sta->addr, smps, err);
28618c2ecf20Sopenharmony_ci	}
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
28648c2ecf20Sopenharmony_ci		mask = &arvif->bitrate_mask;
28658c2ecf20Sopenharmony_ci		num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
28668c2ecf20Sopenharmony_ci								      mask);
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci		/* Peer_assoc_prepare will reject vht rates in
28698c2ecf20Sopenharmony_ci		 * bitrate_mask if its not available in range format and
28708c2ecf20Sopenharmony_ci		 * sets vht tx_rateset as unsupported. So multiple VHT MCS
28718c2ecf20Sopenharmony_ci		 * setting(eg. MCS 4,5,6) per peer is not supported here.
28728c2ecf20Sopenharmony_ci		 * But, Single rate in VHT mask can be set as per-peer
28738c2ecf20Sopenharmony_ci		 * fixed rate. But even if any HT rates are configured in
28748c2ecf20Sopenharmony_ci		 * the bitrate mask, device will not switch to those rates
28758c2ecf20Sopenharmony_ci		 * when per-peer Fixed rate is set.
28768c2ecf20Sopenharmony_ci		 * TODO: Check RATEMASK_CMDID to support auto rates selection
28778c2ecf20Sopenharmony_ci		 * across HT/VHT and for multiple VHT MCS support.
28788c2ecf20Sopenharmony_ci		 */
28798c2ecf20Sopenharmony_ci		if (sta->vht_cap.vht_supported && num_vht_rates == 1) {
28808c2ecf20Sopenharmony_ci			ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
28818c2ecf20Sopenharmony_ci							   band);
28828c2ecf20Sopenharmony_ci		} else {
28838c2ecf20Sopenharmony_ci			/* If the peer is non-VHT or no fixed VHT rate
28848c2ecf20Sopenharmony_ci			 * is provided in the new bitrate mask we set the
28858c2ecf20Sopenharmony_ci			 * other rates using peer_assoc command.
28868c2ecf20Sopenharmony_ci			 */
28878c2ecf20Sopenharmony_ci			ath11k_peer_assoc_prepare(ar, arvif->vif, sta,
28888c2ecf20Sopenharmony_ci						  &peer_arg, true);
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci			err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
28918c2ecf20Sopenharmony_ci			if (err)
28928c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n",
28938c2ecf20Sopenharmony_ci					    sta->addr, arvif->vdev_id, err);
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci			if (!wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ))
28968c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
28978c2ecf20Sopenharmony_ci					    sta->addr, arvif->vdev_id);
28988c2ecf20Sopenharmony_ci		}
28998c2ecf20Sopenharmony_ci	}
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
29028c2ecf20Sopenharmony_ci}
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_cistatic int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif,
29058c2ecf20Sopenharmony_ci				       struct ieee80211_sta *sta)
29068c2ecf20Sopenharmony_ci{
29078c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
29128c2ecf20Sopenharmony_ci		return 0;
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci	if (ar->num_stations >= ar->max_num_stations)
29158c2ecf20Sopenharmony_ci		return -ENOBUFS;
29168c2ecf20Sopenharmony_ci
29178c2ecf20Sopenharmony_ci	ar->num_stations++;
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_ci	return 0;
29208c2ecf20Sopenharmony_ci}
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_cistatic void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif,
29238c2ecf20Sopenharmony_ci					struct ieee80211_sta *sta)
29248c2ecf20Sopenharmony_ci{
29258c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_STA && !sta->tdls)
29308c2ecf20Sopenharmony_ci		return;
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci	ar->num_stations--;
29338c2ecf20Sopenharmony_ci}
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_cistatic int ath11k_mac_station_add(struct ath11k *ar,
29368c2ecf20Sopenharmony_ci				  struct ieee80211_vif *vif,
29378c2ecf20Sopenharmony_ci				  struct ieee80211_sta *sta)
29388c2ecf20Sopenharmony_ci{
29398c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
29408c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
29418c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
29428c2ecf20Sopenharmony_ci	struct peer_create_params peer_param;
29438c2ecf20Sopenharmony_ci	int ret;
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
29468c2ecf20Sopenharmony_ci
29478c2ecf20Sopenharmony_ci	ret = ath11k_mac_inc_num_stations(arvif, sta);
29488c2ecf20Sopenharmony_ci	if (ret) {
29498c2ecf20Sopenharmony_ci		ath11k_warn(ab, "refusing to associate station: too many connected already (%d)\n",
29508c2ecf20Sopenharmony_ci			    ar->max_num_stations);
29518c2ecf20Sopenharmony_ci		goto exit;
29528c2ecf20Sopenharmony_ci	}
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL);
29558c2ecf20Sopenharmony_ci	if (!arsta->rx_stats) {
29568c2ecf20Sopenharmony_ci		ret = -ENOMEM;
29578c2ecf20Sopenharmony_ci		goto dec_num_station;
29588c2ecf20Sopenharmony_ci	}
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci	peer_param.vdev_id = arvif->vdev_id;
29618c2ecf20Sopenharmony_ci	peer_param.peer_addr = sta->addr;
29628c2ecf20Sopenharmony_ci	peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	ret = ath11k_peer_create(ar, arvif, sta, &peer_param);
29658c2ecf20Sopenharmony_ci	if (ret) {
29668c2ecf20Sopenharmony_ci		ath11k_warn(ab, "Failed to add peer: %pM for VDEV: %d\n",
29678c2ecf20Sopenharmony_ci			    sta->addr, arvif->vdev_id);
29688c2ecf20Sopenharmony_ci		goto free_rx_stats;
29698c2ecf20Sopenharmony_ci	}
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
29728c2ecf20Sopenharmony_ci		   sta->addr, arvif->vdev_id);
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci	if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
29758c2ecf20Sopenharmony_ci		arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
29768c2ecf20Sopenharmony_ci		if (!arsta->tx_stats) {
29778c2ecf20Sopenharmony_ci			ret = -ENOMEM;
29788c2ecf20Sopenharmony_ci			goto free_peer;
29798c2ecf20Sopenharmony_ci		}
29808c2ecf20Sopenharmony_ci	}
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci	if (ieee80211_vif_is_mesh(vif)) {
29838c2ecf20Sopenharmony_ci		ret = ath11k_wmi_set_peer_param(ar, sta->addr,
29848c2ecf20Sopenharmony_ci						arvif->vdev_id,
29858c2ecf20Sopenharmony_ci						WMI_PEER_USE_4ADDR, 1);
29868c2ecf20Sopenharmony_ci		if (ret) {
29878c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to STA %pM 4addr capability: %d\n",
29888c2ecf20Sopenharmony_ci				    sta->addr, ret);
29898c2ecf20Sopenharmony_ci			goto free_tx_stats;
29908c2ecf20Sopenharmony_ci		}
29918c2ecf20Sopenharmony_ci	}
29928c2ecf20Sopenharmony_ci
29938c2ecf20Sopenharmony_ci	ret = ath11k_dp_peer_setup(ar, arvif->vdev_id, sta->addr);
29948c2ecf20Sopenharmony_ci	if (ret) {
29958c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to setup dp for peer %pM on vdev %i (%d)\n",
29968c2ecf20Sopenharmony_ci			    sta->addr, arvif->vdev_id, ret);
29978c2ecf20Sopenharmony_ci		goto free_tx_stats;
29988c2ecf20Sopenharmony_ci	}
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci	if (ab->hw_params.vdev_start_delay &&
30018c2ecf20Sopenharmony_ci	    !arvif->is_started &&
30028c2ecf20Sopenharmony_ci	    arvif->vdev_type != WMI_VDEV_TYPE_AP) {
30038c2ecf20Sopenharmony_ci		ret = ath11k_start_vdev_delay(ar->hw, vif);
30048c2ecf20Sopenharmony_ci		if (ret) {
30058c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to delay vdev start: %d\n", ret);
30068c2ecf20Sopenharmony_ci			goto free_tx_stats;
30078c2ecf20Sopenharmony_ci		}
30088c2ecf20Sopenharmony_ci	}
30098c2ecf20Sopenharmony_ci
30108c2ecf20Sopenharmony_ci	return 0;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_cifree_tx_stats:
30138c2ecf20Sopenharmony_ci	kfree(arsta->tx_stats);
30148c2ecf20Sopenharmony_ci	arsta->tx_stats = NULL;
30158c2ecf20Sopenharmony_cifree_peer:
30168c2ecf20Sopenharmony_ci	ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
30178c2ecf20Sopenharmony_cifree_rx_stats:
30188c2ecf20Sopenharmony_ci	kfree(arsta->rx_stats);
30198c2ecf20Sopenharmony_ci	arsta->rx_stats = NULL;
30208c2ecf20Sopenharmony_cidec_num_station:
30218c2ecf20Sopenharmony_ci	ath11k_mac_dec_num_stations(arvif, sta);
30228c2ecf20Sopenharmony_ciexit:
30238c2ecf20Sopenharmony_ci	return ret;
30248c2ecf20Sopenharmony_ci}
30258c2ecf20Sopenharmony_ci
30268c2ecf20Sopenharmony_cistatic int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
30278c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
30288c2ecf20Sopenharmony_ci				   struct ieee80211_sta *sta,
30298c2ecf20Sopenharmony_ci				   enum ieee80211_sta_state old_state,
30308c2ecf20Sopenharmony_ci				   enum ieee80211_sta_state new_state)
30318c2ecf20Sopenharmony_ci{
30328c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
30338c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
30348c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
30358c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
30368c2ecf20Sopenharmony_ci	int ret = 0;
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	/* cancel must be done outside the mutex to avoid deadlock */
30398c2ecf20Sopenharmony_ci	if ((old_state == IEEE80211_STA_NONE &&
30408c2ecf20Sopenharmony_ci	     new_state == IEEE80211_STA_NOTEXIST))
30418c2ecf20Sopenharmony_ci		cancel_work_sync(&arsta->update_wk);
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	if (old_state == IEEE80211_STA_NOTEXIST &&
30468c2ecf20Sopenharmony_ci	    new_state == IEEE80211_STA_NONE) {
30478c2ecf20Sopenharmony_ci		memset(arsta, 0, sizeof(*arsta));
30488c2ecf20Sopenharmony_ci		arsta->arvif = arvif;
30498c2ecf20Sopenharmony_ci		INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci		ret = ath11k_mac_station_add(ar, vif, sta);
30528c2ecf20Sopenharmony_ci		if (ret)
30538c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to add station: %pM for VDEV: %d\n",
30548c2ecf20Sopenharmony_ci				    sta->addr, arvif->vdev_id);
30558c2ecf20Sopenharmony_ci	} else if ((old_state == IEEE80211_STA_NONE &&
30568c2ecf20Sopenharmony_ci		    new_state == IEEE80211_STA_NOTEXIST)) {
30578c2ecf20Sopenharmony_ci		ath11k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr);
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_ci		ret = ath11k_peer_delete(ar, arvif->vdev_id, sta->addr);
30608c2ecf20Sopenharmony_ci		if (ret)
30618c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to delete peer: %pM for VDEV: %d\n",
30628c2ecf20Sopenharmony_ci				    sta->addr, arvif->vdev_id);
30638c2ecf20Sopenharmony_ci		else
30648c2ecf20Sopenharmony_ci			ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "Removed peer: %pM for VDEV: %d\n",
30658c2ecf20Sopenharmony_ci				   sta->addr, arvif->vdev_id);
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci		ath11k_mac_dec_num_stations(arvif, sta);
30688c2ecf20Sopenharmony_ci		spin_lock_bh(&ar->ab->base_lock);
30698c2ecf20Sopenharmony_ci		peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
30708c2ecf20Sopenharmony_ci		if (peer && peer->sta == sta) {
30718c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Found peer entry %pM n vdev %i after it was supposedly removed\n",
30728c2ecf20Sopenharmony_ci				    vif->addr, arvif->vdev_id);
30738c2ecf20Sopenharmony_ci			peer->sta = NULL;
30748c2ecf20Sopenharmony_ci			list_del(&peer->list);
30758c2ecf20Sopenharmony_ci			kfree(peer);
30768c2ecf20Sopenharmony_ci			ar->num_peers--;
30778c2ecf20Sopenharmony_ci		}
30788c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->ab->base_lock);
30798c2ecf20Sopenharmony_ci
30808c2ecf20Sopenharmony_ci		kfree(arsta->tx_stats);
30818c2ecf20Sopenharmony_ci		arsta->tx_stats = NULL;
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci		kfree(arsta->rx_stats);
30848c2ecf20Sopenharmony_ci		arsta->rx_stats = NULL;
30858c2ecf20Sopenharmony_ci	} else if (old_state == IEEE80211_STA_AUTH &&
30868c2ecf20Sopenharmony_ci		   new_state == IEEE80211_STA_ASSOC &&
30878c2ecf20Sopenharmony_ci		   (vif->type == NL80211_IFTYPE_AP ||
30888c2ecf20Sopenharmony_ci		    vif->type == NL80211_IFTYPE_MESH_POINT ||
30898c2ecf20Sopenharmony_ci		    vif->type == NL80211_IFTYPE_ADHOC)) {
30908c2ecf20Sopenharmony_ci		ret = ath11k_station_assoc(ar, vif, sta, false);
30918c2ecf20Sopenharmony_ci		if (ret)
30928c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to associate station: %pM\n",
30938c2ecf20Sopenharmony_ci				    sta->addr);
30948c2ecf20Sopenharmony_ci	} else if (old_state == IEEE80211_STA_ASSOC &&
30958c2ecf20Sopenharmony_ci		   new_state == IEEE80211_STA_AUTH &&
30968c2ecf20Sopenharmony_ci		   (vif->type == NL80211_IFTYPE_AP ||
30978c2ecf20Sopenharmony_ci		    vif->type == NL80211_IFTYPE_MESH_POINT ||
30988c2ecf20Sopenharmony_ci		    vif->type == NL80211_IFTYPE_ADHOC)) {
30998c2ecf20Sopenharmony_ci		ret = ath11k_station_disassoc(ar, vif, sta);
31008c2ecf20Sopenharmony_ci		if (ret)
31018c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Failed to disassociate station: %pM\n",
31028c2ecf20Sopenharmony_ci				    sta->addr);
31038c2ecf20Sopenharmony_ci	}
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
31068c2ecf20Sopenharmony_ci	return ret;
31078c2ecf20Sopenharmony_ci}
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_cistatic int ath11k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
31108c2ecf20Sopenharmony_ci				       struct ieee80211_vif *vif,
31118c2ecf20Sopenharmony_ci				       struct ieee80211_sta *sta)
31128c2ecf20Sopenharmony_ci{
31138c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
31148c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
31158c2ecf20Sopenharmony_ci	int ret = 0;
31168c2ecf20Sopenharmony_ci	s16 txpwr;
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	if (sta->txpwr.type == NL80211_TX_POWER_AUTOMATIC) {
31198c2ecf20Sopenharmony_ci		txpwr = 0;
31208c2ecf20Sopenharmony_ci	} else {
31218c2ecf20Sopenharmony_ci		txpwr = sta->txpwr.power;
31228c2ecf20Sopenharmony_ci		if (!txpwr)
31238c2ecf20Sopenharmony_ci			return -EINVAL;
31248c2ecf20Sopenharmony_ci	}
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	if (txpwr > ATH11K_TX_POWER_MAX_VAL || txpwr < ATH11K_TX_POWER_MIN_VAL)
31278c2ecf20Sopenharmony_ci		return -EINVAL;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci	ret = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
31328c2ecf20Sopenharmony_ci					WMI_PEER_USE_FIXED_PWR, txpwr);
31338c2ecf20Sopenharmony_ci	if (ret) {
31348c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set tx power for station ret: %d\n",
31358c2ecf20Sopenharmony_ci			    ret);
31368c2ecf20Sopenharmony_ci		goto out;
31378c2ecf20Sopenharmony_ci	}
31388c2ecf20Sopenharmony_ci
31398c2ecf20Sopenharmony_ciout:
31408c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
31418c2ecf20Sopenharmony_ci	return ret;
31428c2ecf20Sopenharmony_ci}
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_cistatic void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw,
31458c2ecf20Sopenharmony_ci					struct ieee80211_vif *vif,
31468c2ecf20Sopenharmony_ci					struct ieee80211_sta *sta,
31478c2ecf20Sopenharmony_ci					u32 changed)
31488c2ecf20Sopenharmony_ci{
31498c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
31508c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
31518c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
31528c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
31538c2ecf20Sopenharmony_ci	u32 bw, smps;
31548c2ecf20Sopenharmony_ci
31558c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->ab->base_lock);
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	peer = ath11k_peer_find(ar->ab, arvif->vdev_id, sta->addr);
31588c2ecf20Sopenharmony_ci	if (!peer) {
31598c2ecf20Sopenharmony_ci		spin_unlock_bh(&ar->ab->base_lock);
31608c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "mac sta rc update failed to find peer %pM on vdev %i\n",
31618c2ecf20Sopenharmony_ci			    sta->addr, arvif->vdev_id);
31628c2ecf20Sopenharmony_ci		return;
31638c2ecf20Sopenharmony_ci	}
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->ab->base_lock);
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
31688c2ecf20Sopenharmony_ci		   "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
31698c2ecf20Sopenharmony_ci		   sta->addr, changed, sta->bandwidth, sta->rx_nss,
31708c2ecf20Sopenharmony_ci		   sta->smps_mode);
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_BW_CHANGED) {
31758c2ecf20Sopenharmony_ci		bw = WMI_PEER_CHWIDTH_20MHZ;
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci		switch (sta->bandwidth) {
31788c2ecf20Sopenharmony_ci		case IEEE80211_STA_RX_BW_20:
31798c2ecf20Sopenharmony_ci			bw = WMI_PEER_CHWIDTH_20MHZ;
31808c2ecf20Sopenharmony_ci			break;
31818c2ecf20Sopenharmony_ci		case IEEE80211_STA_RX_BW_40:
31828c2ecf20Sopenharmony_ci			bw = WMI_PEER_CHWIDTH_40MHZ;
31838c2ecf20Sopenharmony_ci			break;
31848c2ecf20Sopenharmony_ci		case IEEE80211_STA_RX_BW_80:
31858c2ecf20Sopenharmony_ci			bw = WMI_PEER_CHWIDTH_80MHZ;
31868c2ecf20Sopenharmony_ci			break;
31878c2ecf20Sopenharmony_ci		case IEEE80211_STA_RX_BW_160:
31888c2ecf20Sopenharmony_ci			bw = WMI_PEER_CHWIDTH_160MHZ;
31898c2ecf20Sopenharmony_ci			break;
31908c2ecf20Sopenharmony_ci		default:
31918c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n",
31928c2ecf20Sopenharmony_ci				    sta->bandwidth, sta->addr);
31938c2ecf20Sopenharmony_ci			bw = WMI_PEER_CHWIDTH_20MHZ;
31948c2ecf20Sopenharmony_ci			break;
31958c2ecf20Sopenharmony_ci		}
31968c2ecf20Sopenharmony_ci
31978c2ecf20Sopenharmony_ci		arsta->bw = bw;
31988c2ecf20Sopenharmony_ci	}
31998c2ecf20Sopenharmony_ci
32008c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_NSS_CHANGED)
32018c2ecf20Sopenharmony_ci		arsta->nss = sta->rx_nss;
32028c2ecf20Sopenharmony_ci
32038c2ecf20Sopenharmony_ci	if (changed & IEEE80211_RC_SMPS_CHANGED) {
32048c2ecf20Sopenharmony_ci		smps = WMI_PEER_SMPS_PS_NONE;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci		switch (sta->smps_mode) {
32078c2ecf20Sopenharmony_ci		case IEEE80211_SMPS_AUTOMATIC:
32088c2ecf20Sopenharmony_ci		case IEEE80211_SMPS_OFF:
32098c2ecf20Sopenharmony_ci			smps = WMI_PEER_SMPS_PS_NONE;
32108c2ecf20Sopenharmony_ci			break;
32118c2ecf20Sopenharmony_ci		case IEEE80211_SMPS_STATIC:
32128c2ecf20Sopenharmony_ci			smps = WMI_PEER_SMPS_STATIC;
32138c2ecf20Sopenharmony_ci			break;
32148c2ecf20Sopenharmony_ci		case IEEE80211_SMPS_DYNAMIC:
32158c2ecf20Sopenharmony_ci			smps = WMI_PEER_SMPS_DYNAMIC;
32168c2ecf20Sopenharmony_ci			break;
32178c2ecf20Sopenharmony_ci		default:
32188c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "Invalid smps %d in sta rc update for %pM\n",
32198c2ecf20Sopenharmony_ci				    sta->smps_mode, sta->addr);
32208c2ecf20Sopenharmony_ci			smps = WMI_PEER_SMPS_PS_NONE;
32218c2ecf20Sopenharmony_ci			break;
32228c2ecf20Sopenharmony_ci		}
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci		arsta->smps = smps;
32258c2ecf20Sopenharmony_ci	}
32268c2ecf20Sopenharmony_ci
32278c2ecf20Sopenharmony_ci	arsta->changed |= changed;
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci	ieee80211_queue_work(hw, &arsta->update_wk);
32328c2ecf20Sopenharmony_ci}
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_cistatic int ath11k_conf_tx_uapsd(struct ath11k *ar, struct ieee80211_vif *vif,
32358c2ecf20Sopenharmony_ci				u16 ac, bool enable)
32368c2ecf20Sopenharmony_ci{
32378c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
32388c2ecf20Sopenharmony_ci	u32 value = 0;
32398c2ecf20Sopenharmony_ci	int ret = 0;
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_ci	if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
32428c2ecf20Sopenharmony_ci		return 0;
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_ci	switch (ac) {
32458c2ecf20Sopenharmony_ci	case IEEE80211_AC_VO:
32468c2ecf20Sopenharmony_ci		value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
32478c2ecf20Sopenharmony_ci			WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
32488c2ecf20Sopenharmony_ci		break;
32498c2ecf20Sopenharmony_ci	case IEEE80211_AC_VI:
32508c2ecf20Sopenharmony_ci		value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
32518c2ecf20Sopenharmony_ci			WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
32528c2ecf20Sopenharmony_ci		break;
32538c2ecf20Sopenharmony_ci	case IEEE80211_AC_BE:
32548c2ecf20Sopenharmony_ci		value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
32558c2ecf20Sopenharmony_ci			WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
32568c2ecf20Sopenharmony_ci		break;
32578c2ecf20Sopenharmony_ci	case IEEE80211_AC_BK:
32588c2ecf20Sopenharmony_ci		value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
32598c2ecf20Sopenharmony_ci			WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
32608c2ecf20Sopenharmony_ci		break;
32618c2ecf20Sopenharmony_ci	}
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	if (enable)
32648c2ecf20Sopenharmony_ci		arvif->u.sta.uapsd |= value;
32658c2ecf20Sopenharmony_ci	else
32668c2ecf20Sopenharmony_ci		arvif->u.sta.uapsd &= ~value;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
32698c2ecf20Sopenharmony_ci					  WMI_STA_PS_PARAM_UAPSD,
32708c2ecf20Sopenharmony_ci					  arvif->u.sta.uapsd);
32718c2ecf20Sopenharmony_ci	if (ret) {
32728c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "could not set uapsd params %d\n", ret);
32738c2ecf20Sopenharmony_ci		goto exit;
32748c2ecf20Sopenharmony_ci	}
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci	if (arvif->u.sta.uapsd)
32778c2ecf20Sopenharmony_ci		value = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD;
32788c2ecf20Sopenharmony_ci	else
32798c2ecf20Sopenharmony_ci		value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
32828c2ecf20Sopenharmony_ci					  WMI_STA_PS_PARAM_RX_WAKE_POLICY,
32838c2ecf20Sopenharmony_ci					  value);
32848c2ecf20Sopenharmony_ci	if (ret)
32858c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "could not set rx wake param %d\n", ret);
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ciexit:
32888c2ecf20Sopenharmony_ci	return ret;
32898c2ecf20Sopenharmony_ci}
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_cistatic int ath11k_mac_op_conf_tx(struct ieee80211_hw *hw,
32928c2ecf20Sopenharmony_ci				 struct ieee80211_vif *vif, u16 ac,
32938c2ecf20Sopenharmony_ci				 const struct ieee80211_tx_queue_params *params)
32948c2ecf20Sopenharmony_ci{
32958c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
32968c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
32978c2ecf20Sopenharmony_ci	struct wmi_wmm_params_arg *p = NULL;
32988c2ecf20Sopenharmony_ci	int ret;
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
33018c2ecf20Sopenharmony_ci
33028c2ecf20Sopenharmony_ci	switch (ac) {
33038c2ecf20Sopenharmony_ci	case IEEE80211_AC_VO:
33048c2ecf20Sopenharmony_ci		p = &arvif->wmm_params.ac_vo;
33058c2ecf20Sopenharmony_ci		break;
33068c2ecf20Sopenharmony_ci	case IEEE80211_AC_VI:
33078c2ecf20Sopenharmony_ci		p = &arvif->wmm_params.ac_vi;
33088c2ecf20Sopenharmony_ci		break;
33098c2ecf20Sopenharmony_ci	case IEEE80211_AC_BE:
33108c2ecf20Sopenharmony_ci		p = &arvif->wmm_params.ac_be;
33118c2ecf20Sopenharmony_ci		break;
33128c2ecf20Sopenharmony_ci	case IEEE80211_AC_BK:
33138c2ecf20Sopenharmony_ci		p = &arvif->wmm_params.ac_bk;
33148c2ecf20Sopenharmony_ci		break;
33158c2ecf20Sopenharmony_ci	}
33168c2ecf20Sopenharmony_ci
33178c2ecf20Sopenharmony_ci	if (WARN_ON(!p)) {
33188c2ecf20Sopenharmony_ci		ret = -EINVAL;
33198c2ecf20Sopenharmony_ci		goto exit;
33208c2ecf20Sopenharmony_ci	}
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_ci	p->cwmin = params->cw_min;
33238c2ecf20Sopenharmony_ci	p->cwmax = params->cw_max;
33248c2ecf20Sopenharmony_ci	p->aifs = params->aifs;
33258c2ecf20Sopenharmony_ci	p->txop = params->txop;
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_wmm_update_cmd_tlv(ar, arvif->vdev_id,
33288c2ecf20Sopenharmony_ci						 &arvif->wmm_params);
33298c2ecf20Sopenharmony_ci	if (ret) {
33308c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set wmm params: %d\n", ret);
33318c2ecf20Sopenharmony_ci		goto exit;
33328c2ecf20Sopenharmony_ci	}
33338c2ecf20Sopenharmony_ci
33348c2ecf20Sopenharmony_ci	ret = ath11k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci	if (ret)
33378c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set sta uapsd: %d\n", ret);
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ciexit:
33408c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
33418c2ecf20Sopenharmony_ci	return ret;
33428c2ecf20Sopenharmony_ci}
33438c2ecf20Sopenharmony_ci
33448c2ecf20Sopenharmony_cistatic struct ieee80211_sta_ht_cap
33458c2ecf20Sopenharmony_ciath11k_create_ht_cap(struct ath11k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask)
33468c2ecf20Sopenharmony_ci{
33478c2ecf20Sopenharmony_ci	int i;
33488c2ecf20Sopenharmony_ci	struct ieee80211_sta_ht_cap ht_cap = {0};
33498c2ecf20Sopenharmony_ci	u32 ar_vht_cap = ar->pdev->cap.vht_cap;
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci	if (!(ar_ht_cap & WMI_HT_CAP_ENABLED))
33528c2ecf20Sopenharmony_ci		return ht_cap;
33538c2ecf20Sopenharmony_ci
33548c2ecf20Sopenharmony_ci	ht_cap.ht_supported = 1;
33558c2ecf20Sopenharmony_ci	ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
33568c2ecf20Sopenharmony_ci	ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
33578c2ecf20Sopenharmony_ci	ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
33588c2ecf20Sopenharmony_ci	ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
33598c2ecf20Sopenharmony_ci	ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT;
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_HT20_SGI)
33628c2ecf20Sopenharmony_ci		ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_HT40_SGI)
33658c2ecf20Sopenharmony_ci		ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_DYNAMIC_SMPS) {
33688c2ecf20Sopenharmony_ci		u32 smps;
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_ci		smps   = WLAN_HT_CAP_SM_PS_DYNAMIC;
33718c2ecf20Sopenharmony_ci		smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci		ht_cap.cap |= smps;
33748c2ecf20Sopenharmony_ci	}
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_TX_STBC)
33778c2ecf20Sopenharmony_ci		ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
33788c2ecf20Sopenharmony_ci
33798c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_RX_STBC) {
33808c2ecf20Sopenharmony_ci		u32 stbc;
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci		stbc   = ar_ht_cap;
33838c2ecf20Sopenharmony_ci		stbc  &= WMI_HT_CAP_RX_STBC;
33848c2ecf20Sopenharmony_ci		stbc >>= WMI_HT_CAP_RX_STBC_MASK_SHIFT;
33858c2ecf20Sopenharmony_ci		stbc <<= IEEE80211_HT_CAP_RX_STBC_SHIFT;
33868c2ecf20Sopenharmony_ci		stbc  &= IEEE80211_HT_CAP_RX_STBC;
33878c2ecf20Sopenharmony_ci
33888c2ecf20Sopenharmony_ci		ht_cap.cap |= stbc;
33898c2ecf20Sopenharmony_ci	}
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_RX_LDPC)
33928c2ecf20Sopenharmony_ci		ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
33938c2ecf20Sopenharmony_ci
33948c2ecf20Sopenharmony_ci	if (ar_ht_cap & WMI_HT_CAP_L_SIG_TXOP_PROT)
33958c2ecf20Sopenharmony_ci		ht_cap.cap |= IEEE80211_HT_CAP_LSIG_TXOP_PROT;
33968c2ecf20Sopenharmony_ci
33978c2ecf20Sopenharmony_ci	if (ar_vht_cap & WMI_VHT_CAP_MAX_MPDU_LEN_MASK)
33988c2ecf20Sopenharmony_ci		ht_cap.cap |= IEEE80211_HT_CAP_MAX_AMSDU;
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	for (i = 0; i < ar->num_rx_chains; i++) {
34018c2ecf20Sopenharmony_ci		if (rate_cap_rx_chainmask & BIT(i))
34028c2ecf20Sopenharmony_ci			ht_cap.mcs.rx_mask[i] = 0xFF;
34038c2ecf20Sopenharmony_ci	}
34048c2ecf20Sopenharmony_ci
34058c2ecf20Sopenharmony_ci	ht_cap.mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_ci	return ht_cap;
34088c2ecf20Sopenharmony_ci}
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_cistatic int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
34118c2ecf20Sopenharmony_ci{
34128c2ecf20Sopenharmony_ci	u32 value = 0;
34138c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
34148c2ecf20Sopenharmony_ci	int nsts;
34158c2ecf20Sopenharmony_ci	int sound_dim;
34168c2ecf20Sopenharmony_ci	u32 vht_cap = ar->pdev->cap.vht_cap;
34178c2ecf20Sopenharmony_ci	u32 vdev_param = WMI_VDEV_PARAM_TXBF;
34188c2ecf20Sopenharmony_ci
34198c2ecf20Sopenharmony_ci	if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) {
34208c2ecf20Sopenharmony_ci		nsts = vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
34218c2ecf20Sopenharmony_ci		nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
34228c2ecf20Sopenharmony_ci		if (nsts > (ar->num_rx_chains - 1))
34238c2ecf20Sopenharmony_ci			nsts = ar->num_rx_chains - 1;
34248c2ecf20Sopenharmony_ci		value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
34258c2ecf20Sopenharmony_ci	}
34268c2ecf20Sopenharmony_ci
34278c2ecf20Sopenharmony_ci	if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
34288c2ecf20Sopenharmony_ci		sound_dim = vht_cap &
34298c2ecf20Sopenharmony_ci			    IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
34308c2ecf20Sopenharmony_ci		sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
34318c2ecf20Sopenharmony_ci		if (sound_dim > (ar->num_tx_chains - 1))
34328c2ecf20Sopenharmony_ci			sound_dim = ar->num_tx_chains - 1;
34338c2ecf20Sopenharmony_ci		value |= SM(sound_dim, WMI_BF_SOUND_DIM_OFFSET);
34348c2ecf20Sopenharmony_ci	}
34358c2ecf20Sopenharmony_ci
34368c2ecf20Sopenharmony_ci	if (!value)
34378c2ecf20Sopenharmony_ci		return 0;
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci	if (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) {
34408c2ecf20Sopenharmony_ci		value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci		if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) &&
34438c2ecf20Sopenharmony_ci		    arvif->vdev_type == WMI_VDEV_TYPE_AP)
34448c2ecf20Sopenharmony_ci			value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
34458c2ecf20Sopenharmony_ci	}
34468c2ecf20Sopenharmony_ci
34478c2ecf20Sopenharmony_ci	/* TODO: SUBFEE not validated in HK, disable here until validated? */
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_ci	if (vht_cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
34508c2ecf20Sopenharmony_ci		value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
34518c2ecf20Sopenharmony_ci
34528c2ecf20Sopenharmony_ci		if ((vht_cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
34538c2ecf20Sopenharmony_ci		    arvif->vdev_type == WMI_VDEV_TYPE_STA)
34548c2ecf20Sopenharmony_ci			value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
34558c2ecf20Sopenharmony_ci	}
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	return ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
34588c2ecf20Sopenharmony_ci					     vdev_param, value);
34598c2ecf20Sopenharmony_ci}
34608c2ecf20Sopenharmony_ci
34618c2ecf20Sopenharmony_cistatic void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
34628c2ecf20Sopenharmony_ci{
34638c2ecf20Sopenharmony_ci	bool subfer, subfee;
34648c2ecf20Sopenharmony_ci	int sound_dim = 0, nsts = 0;
34658c2ecf20Sopenharmony_ci
34668c2ecf20Sopenharmony_ci	subfer = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE));
34678c2ecf20Sopenharmony_ci	subfee = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci	if (ar->num_tx_chains < 2) {
34708c2ecf20Sopenharmony_ci		*vht_cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
34718c2ecf20Sopenharmony_ci		subfer = false;
34728c2ecf20Sopenharmony_ci	}
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	if (ar->num_rx_chains < 2) {
34758c2ecf20Sopenharmony_ci		*vht_cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
34768c2ecf20Sopenharmony_ci		subfee = false;
34778c2ecf20Sopenharmony_ci	}
34788c2ecf20Sopenharmony_ci
34798c2ecf20Sopenharmony_ci	/* If SU Beaformer is not set, then disable MU Beamformer Capability */
34808c2ecf20Sopenharmony_ci	if (!subfer)
34818c2ecf20Sopenharmony_ci		*vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_ci	/* If SU Beaformee is not set, then disable MU Beamformee Capability */
34848c2ecf20Sopenharmony_ci	if (!subfee)
34858c2ecf20Sopenharmony_ci		*vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_ci	sound_dim = (*vht_cap & IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK);
34888c2ecf20Sopenharmony_ci	sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
34898c2ecf20Sopenharmony_ci	*vht_cap &= ~IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_ci	nsts = (*vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
34928c2ecf20Sopenharmony_ci	nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
34938c2ecf20Sopenharmony_ci	*vht_cap &= ~IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_ci	/* Enable Sounding Dimension Field only if SU BF is enabled */
34968c2ecf20Sopenharmony_ci	if (subfer) {
34978c2ecf20Sopenharmony_ci		if (sound_dim > (ar->num_tx_chains - 1))
34988c2ecf20Sopenharmony_ci			sound_dim = ar->num_tx_chains - 1;
34998c2ecf20Sopenharmony_ci
35008c2ecf20Sopenharmony_ci		sound_dim <<= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
35018c2ecf20Sopenharmony_ci		sound_dim &=  IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
35028c2ecf20Sopenharmony_ci		*vht_cap |= sound_dim;
35038c2ecf20Sopenharmony_ci	}
35048c2ecf20Sopenharmony_ci
35058c2ecf20Sopenharmony_ci	/* Enable Beamformee STS Field only if SU BF is enabled */
35068c2ecf20Sopenharmony_ci	if (subfee) {
35078c2ecf20Sopenharmony_ci		if (nsts > (ar->num_rx_chains - 1))
35088c2ecf20Sopenharmony_ci			nsts = ar->num_rx_chains - 1;
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci		nsts <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
35118c2ecf20Sopenharmony_ci		nsts &=  IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
35128c2ecf20Sopenharmony_ci		*vht_cap |= nsts;
35138c2ecf20Sopenharmony_ci	}
35148c2ecf20Sopenharmony_ci}
35158c2ecf20Sopenharmony_ci
35168c2ecf20Sopenharmony_cistatic struct ieee80211_sta_vht_cap
35178c2ecf20Sopenharmony_ciath11k_create_vht_cap(struct ath11k *ar, u32 rate_cap_tx_chainmask,
35188c2ecf20Sopenharmony_ci		      u32 rate_cap_rx_chainmask)
35198c2ecf20Sopenharmony_ci{
35208c2ecf20Sopenharmony_ci	struct ieee80211_sta_vht_cap vht_cap = {0};
35218c2ecf20Sopenharmony_ci	u16 txmcs_map, rxmcs_map;
35228c2ecf20Sopenharmony_ci	int i;
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	vht_cap.vht_supported = 1;
35258c2ecf20Sopenharmony_ci	vht_cap.cap = ar->pdev->cap.vht_cap;
35268c2ecf20Sopenharmony_ci
35278c2ecf20Sopenharmony_ci	ath11k_set_vht_txbf_cap(ar, &vht_cap.cap);
35288c2ecf20Sopenharmony_ci
35298c2ecf20Sopenharmony_ci	/* TODO: Enable back VHT160 mode once association issues are fixed */
35308c2ecf20Sopenharmony_ci	/* Disabling VHT160 and VHT80+80 modes */
35318c2ecf20Sopenharmony_ci	vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
35328c2ecf20Sopenharmony_ci	vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
35338c2ecf20Sopenharmony_ci
35348c2ecf20Sopenharmony_ci	rxmcs_map = 0;
35358c2ecf20Sopenharmony_ci	txmcs_map = 0;
35368c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
35378c2ecf20Sopenharmony_ci		if (i < ar->num_tx_chains && rate_cap_tx_chainmask & BIT(i))
35388c2ecf20Sopenharmony_ci			txmcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
35398c2ecf20Sopenharmony_ci		else
35408c2ecf20Sopenharmony_ci			txmcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
35418c2ecf20Sopenharmony_ci
35428c2ecf20Sopenharmony_ci		if (i < ar->num_rx_chains && rate_cap_rx_chainmask & BIT(i))
35438c2ecf20Sopenharmony_ci			rxmcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
35448c2ecf20Sopenharmony_ci		else
35458c2ecf20Sopenharmony_ci			rxmcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
35468c2ecf20Sopenharmony_ci	}
35478c2ecf20Sopenharmony_ci
35488c2ecf20Sopenharmony_ci	if (rate_cap_tx_chainmask <= 1)
35498c2ecf20Sopenharmony_ci		vht_cap.cap &= ~IEEE80211_VHT_CAP_TXSTBC;
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_map);
35528c2ecf20Sopenharmony_ci	vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_map);
35538c2ecf20Sopenharmony_ci
35548c2ecf20Sopenharmony_ci	return vht_cap;
35558c2ecf20Sopenharmony_ci}
35568c2ecf20Sopenharmony_ci
35578c2ecf20Sopenharmony_cistatic void ath11k_mac_setup_ht_vht_cap(struct ath11k *ar,
35588c2ecf20Sopenharmony_ci					struct ath11k_pdev_cap *cap,
35598c2ecf20Sopenharmony_ci					u32 *ht_cap_info)
35608c2ecf20Sopenharmony_ci{
35618c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *band;
35628c2ecf20Sopenharmony_ci	u32 rate_cap_tx_chainmask;
35638c2ecf20Sopenharmony_ci	u32 rate_cap_rx_chainmask;
35648c2ecf20Sopenharmony_ci	u32 ht_cap;
35658c2ecf20Sopenharmony_ci
35668c2ecf20Sopenharmony_ci	rate_cap_tx_chainmask = ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift;
35678c2ecf20Sopenharmony_ci	rate_cap_rx_chainmask = ar->cfg_rx_chainmask >> cap->rx_chain_mask_shift;
35688c2ecf20Sopenharmony_ci
35698c2ecf20Sopenharmony_ci	if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) {
35708c2ecf20Sopenharmony_ci		band = &ar->mac.sbands[NL80211_BAND_2GHZ];
35718c2ecf20Sopenharmony_ci		ht_cap = cap->band[NL80211_BAND_2GHZ].ht_cap_info;
35728c2ecf20Sopenharmony_ci		if (ht_cap_info)
35738c2ecf20Sopenharmony_ci			*ht_cap_info = ht_cap;
35748c2ecf20Sopenharmony_ci		band->ht_cap = ath11k_create_ht_cap(ar, ht_cap,
35758c2ecf20Sopenharmony_ci						    rate_cap_rx_chainmask);
35768c2ecf20Sopenharmony_ci	}
35778c2ecf20Sopenharmony_ci
35788c2ecf20Sopenharmony_ci	if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && !ar->supports_6ghz) {
35798c2ecf20Sopenharmony_ci		band = &ar->mac.sbands[NL80211_BAND_5GHZ];
35808c2ecf20Sopenharmony_ci		ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info;
35818c2ecf20Sopenharmony_ci		if (ht_cap_info)
35828c2ecf20Sopenharmony_ci			*ht_cap_info = ht_cap;
35838c2ecf20Sopenharmony_ci		band->ht_cap = ath11k_create_ht_cap(ar, ht_cap,
35848c2ecf20Sopenharmony_ci						    rate_cap_rx_chainmask);
35858c2ecf20Sopenharmony_ci		band->vht_cap = ath11k_create_vht_cap(ar, rate_cap_tx_chainmask,
35868c2ecf20Sopenharmony_ci						      rate_cap_rx_chainmask);
35878c2ecf20Sopenharmony_ci	}
35888c2ecf20Sopenharmony_ci}
35898c2ecf20Sopenharmony_ci
35908c2ecf20Sopenharmony_cistatic int ath11k_check_chain_mask(struct ath11k *ar, u32 ant, bool is_tx_ant)
35918c2ecf20Sopenharmony_ci{
35928c2ecf20Sopenharmony_ci	/* TODO: Check the request chainmask against the supported
35938c2ecf20Sopenharmony_ci	 * chainmask table which is advertised in extented_service_ready event
35948c2ecf20Sopenharmony_ci	 */
35958c2ecf20Sopenharmony_ci
35968c2ecf20Sopenharmony_ci	return 0;
35978c2ecf20Sopenharmony_ci}
35988c2ecf20Sopenharmony_ci
35998c2ecf20Sopenharmony_cistatic void ath11k_gen_ppe_thresh(struct ath11k_ppe_threshold *fw_ppet,
36008c2ecf20Sopenharmony_ci				  u8 *he_ppet)
36018c2ecf20Sopenharmony_ci{
36028c2ecf20Sopenharmony_ci	int nss, ru;
36038c2ecf20Sopenharmony_ci	u8 bit = 7;
36048c2ecf20Sopenharmony_ci
36058c2ecf20Sopenharmony_ci	he_ppet[0] = fw_ppet->numss_m1 & IEEE80211_PPE_THRES_NSS_MASK;
36068c2ecf20Sopenharmony_ci	he_ppet[0] |= (fw_ppet->ru_bit_mask <<
36078c2ecf20Sopenharmony_ci		       IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) &
36088c2ecf20Sopenharmony_ci		      IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK;
36098c2ecf20Sopenharmony_ci	for (nss = 0; nss <= fw_ppet->numss_m1; nss++) {
36108c2ecf20Sopenharmony_ci		for (ru = 0; ru < 4; ru++) {
36118c2ecf20Sopenharmony_ci			u8 val;
36128c2ecf20Sopenharmony_ci			int i;
36138c2ecf20Sopenharmony_ci
36148c2ecf20Sopenharmony_ci			if ((fw_ppet->ru_bit_mask & BIT(ru)) == 0)
36158c2ecf20Sopenharmony_ci				continue;
36168c2ecf20Sopenharmony_ci			val = (fw_ppet->ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) &
36178c2ecf20Sopenharmony_ci			       0x3f;
36188c2ecf20Sopenharmony_ci			val = ((val >> 3) & 0x7) | ((val & 0x7) << 3);
36198c2ecf20Sopenharmony_ci			for (i = 5; i >= 0; i--) {
36208c2ecf20Sopenharmony_ci				he_ppet[bit / 8] |=
36218c2ecf20Sopenharmony_ci					((val >> i) & 0x1) << ((bit % 8));
36228c2ecf20Sopenharmony_ci				bit++;
36238c2ecf20Sopenharmony_ci			}
36248c2ecf20Sopenharmony_ci		}
36258c2ecf20Sopenharmony_ci	}
36268c2ecf20Sopenharmony_ci}
36278c2ecf20Sopenharmony_ci
36288c2ecf20Sopenharmony_cistatic void
36298c2ecf20Sopenharmony_ciath11k_mac_filter_he_cap_mesh(struct ieee80211_he_cap_elem *he_cap_elem)
36308c2ecf20Sopenharmony_ci{
36318c2ecf20Sopenharmony_ci	u8 m;
36328c2ecf20Sopenharmony_ci
36338c2ecf20Sopenharmony_ci	m = IEEE80211_HE_MAC_CAP0_TWT_RES |
36348c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP0_TWT_REQ;
36358c2ecf20Sopenharmony_ci	he_cap_elem->mac_cap_info[0] &= ~m;
36368c2ecf20Sopenharmony_ci
36378c2ecf20Sopenharmony_ci	m = IEEE80211_HE_MAC_CAP2_TRS |
36388c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP2_BCAST_TWT |
36398c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP2_MU_CASCADING;
36408c2ecf20Sopenharmony_ci	he_cap_elem->mac_cap_info[2] &= ~m;
36418c2ecf20Sopenharmony_ci
36428c2ecf20Sopenharmony_ci	m = IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED |
36438c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP2_BCAST_TWT |
36448c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP2_MU_CASCADING;
36458c2ecf20Sopenharmony_ci	he_cap_elem->mac_cap_info[3] &= ~m;
36468c2ecf20Sopenharmony_ci
36478c2ecf20Sopenharmony_ci	m = IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG |
36488c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP4_BQR;
36498c2ecf20Sopenharmony_ci	he_cap_elem->mac_cap_info[4] &= ~m;
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci	m = IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION |
36528c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU |
36538c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING |
36548c2ecf20Sopenharmony_ci	    IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX;
36558c2ecf20Sopenharmony_ci	he_cap_elem->mac_cap_info[5] &= ~m;
36568c2ecf20Sopenharmony_ci
36578c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
36588c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
36598c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[2] &= ~m;
36608c2ecf20Sopenharmony_ci
36618c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA |
36628c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK |
36638c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK;
36648c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[3] &= ~m;
36658c2ecf20Sopenharmony_ci
36668c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
36678c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[4] &= ~m;
36688c2ecf20Sopenharmony_ci
36698c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
36708c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[5] &= ~m;
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
36738c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB |
36748c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
36758c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO;
36768c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[6] &= ~m;
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP7_SRP_BASED_SR |
36798c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR |
36808c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ |
36818c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ;
36828c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[7] &= ~m;
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
36858c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
36868c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
36878c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
36888c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[8] &= ~m;
36898c2ecf20Sopenharmony_ci
36908c2ecf20Sopenharmony_ci	m = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
36918c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
36928c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
36938c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
36948c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
36958c2ecf20Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB;
36968c2ecf20Sopenharmony_ci	he_cap_elem->phy_cap_info[9] &= ~m;
36978c2ecf20Sopenharmony_ci}
36988c2ecf20Sopenharmony_ci
36998c2ecf20Sopenharmony_cistatic __le16 ath11k_mac_setup_he_6ghz_cap(struct ath11k_pdev_cap *pcap,
37008c2ecf20Sopenharmony_ci					   struct ath11k_band_cap *bcap)
37018c2ecf20Sopenharmony_ci{
37028c2ecf20Sopenharmony_ci	u8 val;
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_ci	bcap->he_6ghz_capa = IEEE80211_HT_MPDU_DENSITY_NONE;
37058c2ecf20Sopenharmony_ci	if (bcap->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
37068c2ecf20Sopenharmony_ci		bcap->he_6ghz_capa |=
37078c2ecf20Sopenharmony_ci			FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS,
37088c2ecf20Sopenharmony_ci				   WLAN_HT_CAP_SM_PS_DYNAMIC);
37098c2ecf20Sopenharmony_ci	else
37108c2ecf20Sopenharmony_ci		bcap->he_6ghz_capa |=
37118c2ecf20Sopenharmony_ci			FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS,
37128c2ecf20Sopenharmony_ci				   WLAN_HT_CAP_SM_PS_DISABLED);
37138c2ecf20Sopenharmony_ci	val = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
37148c2ecf20Sopenharmony_ci			pcap->vht_cap);
37158c2ecf20Sopenharmony_ci	bcap->he_6ghz_capa |=
37168c2ecf20Sopenharmony_ci		FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP, val);
37178c2ecf20Sopenharmony_ci	val = FIELD_GET(IEEE80211_VHT_CAP_MAX_MPDU_MASK, pcap->vht_cap);
37188c2ecf20Sopenharmony_ci	bcap->he_6ghz_capa |=
37198c2ecf20Sopenharmony_ci		FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN, val);
37208c2ecf20Sopenharmony_ci	if (pcap->vht_cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN)
37218c2ecf20Sopenharmony_ci		bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
37228c2ecf20Sopenharmony_ci	if (pcap->vht_cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN)
37238c2ecf20Sopenharmony_ci		bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS;
37248c2ecf20Sopenharmony_ci
37258c2ecf20Sopenharmony_ci	return cpu_to_le16(bcap->he_6ghz_capa);
37268c2ecf20Sopenharmony_ci}
37278c2ecf20Sopenharmony_ci
37288c2ecf20Sopenharmony_cistatic int ath11k_mac_copy_he_cap(struct ath11k *ar,
37298c2ecf20Sopenharmony_ci				  struct ath11k_pdev_cap *cap,
37308c2ecf20Sopenharmony_ci				  struct ieee80211_sband_iftype_data *data,
37318c2ecf20Sopenharmony_ci				  int band)
37328c2ecf20Sopenharmony_ci{
37338c2ecf20Sopenharmony_ci	int i, idx = 0;
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci	for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
37368c2ecf20Sopenharmony_ci		struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
37378c2ecf20Sopenharmony_ci		struct ath11k_band_cap *band_cap = &cap->band[band];
37388c2ecf20Sopenharmony_ci		struct ieee80211_he_cap_elem *he_cap_elem =
37398c2ecf20Sopenharmony_ci				&he_cap->he_cap_elem;
37408c2ecf20Sopenharmony_ci
37418c2ecf20Sopenharmony_ci		switch (i) {
37428c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_STATION:
37438c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_AP:
37448c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_MESH_POINT:
37458c2ecf20Sopenharmony_ci			break;
37468c2ecf20Sopenharmony_ci
37478c2ecf20Sopenharmony_ci		default:
37488c2ecf20Sopenharmony_ci			continue;
37498c2ecf20Sopenharmony_ci		}
37508c2ecf20Sopenharmony_ci
37518c2ecf20Sopenharmony_ci		data[idx].types_mask = BIT(i);
37528c2ecf20Sopenharmony_ci		he_cap->has_he = true;
37538c2ecf20Sopenharmony_ci		memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info,
37548c2ecf20Sopenharmony_ci		       sizeof(he_cap_elem->mac_cap_info));
37558c2ecf20Sopenharmony_ci		memcpy(he_cap_elem->phy_cap_info, band_cap->he_cap_phy_info,
37568c2ecf20Sopenharmony_ci		       sizeof(he_cap_elem->phy_cap_info));
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci		he_cap_elem->mac_cap_info[1] &=
37598c2ecf20Sopenharmony_ci			IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK;
37608c2ecf20Sopenharmony_ci		he_cap_elem->phy_cap_info[4] &=
37618c2ecf20Sopenharmony_ci			~IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK;
37628c2ecf20Sopenharmony_ci		he_cap_elem->phy_cap_info[4] &=
37638c2ecf20Sopenharmony_ci			~IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK;
37648c2ecf20Sopenharmony_ci		he_cap_elem->phy_cap_info[4] |= (ar->num_tx_chains - 1) << 2;
37658c2ecf20Sopenharmony_ci
37668c2ecf20Sopenharmony_ci		he_cap_elem->phy_cap_info[5] &=
37678c2ecf20Sopenharmony_ci			~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK;
37688c2ecf20Sopenharmony_ci		he_cap_elem->phy_cap_info[5] &=
37698c2ecf20Sopenharmony_ci			~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK;
37708c2ecf20Sopenharmony_ci		he_cap_elem->phy_cap_info[5] |= ar->num_tx_chains - 1;
37718c2ecf20Sopenharmony_ci
37728c2ecf20Sopenharmony_ci		switch (i) {
37738c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_AP:
37748c2ecf20Sopenharmony_ci			he_cap_elem->phy_cap_info[3] &=
37758c2ecf20Sopenharmony_ci				~IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK;
37768c2ecf20Sopenharmony_ci			he_cap_elem->phy_cap_info[9] |=
37778c2ecf20Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
37788c2ecf20Sopenharmony_ci			break;
37798c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_STATION:
37808c2ecf20Sopenharmony_ci			he_cap_elem->mac_cap_info[0] &=
37818c2ecf20Sopenharmony_ci				~IEEE80211_HE_MAC_CAP0_TWT_RES;
37828c2ecf20Sopenharmony_ci			he_cap_elem->mac_cap_info[0] |=
37838c2ecf20Sopenharmony_ci				IEEE80211_HE_MAC_CAP0_TWT_REQ;
37848c2ecf20Sopenharmony_ci			he_cap_elem->phy_cap_info[9] |=
37858c2ecf20Sopenharmony_ci				IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
37868c2ecf20Sopenharmony_ci			break;
37878c2ecf20Sopenharmony_ci		case NL80211_IFTYPE_MESH_POINT:
37888c2ecf20Sopenharmony_ci			ath11k_mac_filter_he_cap_mesh(he_cap_elem);
37898c2ecf20Sopenharmony_ci			break;
37908c2ecf20Sopenharmony_ci		}
37918c2ecf20Sopenharmony_ci
37928c2ecf20Sopenharmony_ci		he_cap->he_mcs_nss_supp.rx_mcs_80 =
37938c2ecf20Sopenharmony_ci			cpu_to_le16(band_cap->he_mcs & 0xffff);
37948c2ecf20Sopenharmony_ci		he_cap->he_mcs_nss_supp.tx_mcs_80 =
37958c2ecf20Sopenharmony_ci			cpu_to_le16(band_cap->he_mcs & 0xffff);
37968c2ecf20Sopenharmony_ci		he_cap->he_mcs_nss_supp.rx_mcs_160 =
37978c2ecf20Sopenharmony_ci			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
37988c2ecf20Sopenharmony_ci		he_cap->he_mcs_nss_supp.tx_mcs_160 =
37998c2ecf20Sopenharmony_ci			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
38008c2ecf20Sopenharmony_ci		he_cap->he_mcs_nss_supp.rx_mcs_80p80 =
38018c2ecf20Sopenharmony_ci			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
38028c2ecf20Sopenharmony_ci		he_cap->he_mcs_nss_supp.tx_mcs_80p80 =
38038c2ecf20Sopenharmony_ci			cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff);
38048c2ecf20Sopenharmony_ci
38058c2ecf20Sopenharmony_ci		memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
38068c2ecf20Sopenharmony_ci		if (he_cap_elem->phy_cap_info[6] &
38078c2ecf20Sopenharmony_ci		    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
38088c2ecf20Sopenharmony_ci			ath11k_gen_ppe_thresh(&band_cap->he_ppet,
38098c2ecf20Sopenharmony_ci					      he_cap->ppe_thres);
38108c2ecf20Sopenharmony_ci
38118c2ecf20Sopenharmony_ci		if (band == NL80211_BAND_6GHZ) {
38128c2ecf20Sopenharmony_ci			data[idx].he_6ghz_capa.capa =
38138c2ecf20Sopenharmony_ci				ath11k_mac_setup_he_6ghz_cap(cap, band_cap);
38148c2ecf20Sopenharmony_ci		}
38158c2ecf20Sopenharmony_ci		idx++;
38168c2ecf20Sopenharmony_ci	}
38178c2ecf20Sopenharmony_ci
38188c2ecf20Sopenharmony_ci	return idx;
38198c2ecf20Sopenharmony_ci}
38208c2ecf20Sopenharmony_ci
38218c2ecf20Sopenharmony_cistatic void ath11k_mac_setup_he_cap(struct ath11k *ar,
38228c2ecf20Sopenharmony_ci				    struct ath11k_pdev_cap *cap)
38238c2ecf20Sopenharmony_ci{
38248c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *band;
38258c2ecf20Sopenharmony_ci	int count;
38268c2ecf20Sopenharmony_ci
38278c2ecf20Sopenharmony_ci	if (cap->supported_bands & WMI_HOST_WLAN_2G_CAP) {
38288c2ecf20Sopenharmony_ci		count = ath11k_mac_copy_he_cap(ar, cap,
38298c2ecf20Sopenharmony_ci					       ar->mac.iftype[NL80211_BAND_2GHZ],
38308c2ecf20Sopenharmony_ci					       NL80211_BAND_2GHZ);
38318c2ecf20Sopenharmony_ci		band = &ar->mac.sbands[NL80211_BAND_2GHZ];
38328c2ecf20Sopenharmony_ci		band->iftype_data = ar->mac.iftype[NL80211_BAND_2GHZ];
38338c2ecf20Sopenharmony_ci		band->n_iftype_data = count;
38348c2ecf20Sopenharmony_ci	}
38358c2ecf20Sopenharmony_ci
38368c2ecf20Sopenharmony_ci	if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) {
38378c2ecf20Sopenharmony_ci		count = ath11k_mac_copy_he_cap(ar, cap,
38388c2ecf20Sopenharmony_ci					       ar->mac.iftype[NL80211_BAND_5GHZ],
38398c2ecf20Sopenharmony_ci					       NL80211_BAND_5GHZ);
38408c2ecf20Sopenharmony_ci		band = &ar->mac.sbands[NL80211_BAND_5GHZ];
38418c2ecf20Sopenharmony_ci		band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ];
38428c2ecf20Sopenharmony_ci		band->n_iftype_data = count;
38438c2ecf20Sopenharmony_ci	}
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci	if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP &&
38468c2ecf20Sopenharmony_ci	    ar->supports_6ghz) {
38478c2ecf20Sopenharmony_ci		count = ath11k_mac_copy_he_cap(ar, cap,
38488c2ecf20Sopenharmony_ci					       ar->mac.iftype[NL80211_BAND_6GHZ],
38498c2ecf20Sopenharmony_ci					       NL80211_BAND_6GHZ);
38508c2ecf20Sopenharmony_ci		band = &ar->mac.sbands[NL80211_BAND_6GHZ];
38518c2ecf20Sopenharmony_ci		band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ];
38528c2ecf20Sopenharmony_ci		band->n_iftype_data = count;
38538c2ecf20Sopenharmony_ci	}
38548c2ecf20Sopenharmony_ci}
38558c2ecf20Sopenharmony_ci
38568c2ecf20Sopenharmony_cistatic int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
38578c2ecf20Sopenharmony_ci{
38588c2ecf20Sopenharmony_ci	int ret;
38598c2ecf20Sopenharmony_ci
38608c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
38618c2ecf20Sopenharmony_ci
38628c2ecf20Sopenharmony_ci	if (ath11k_check_chain_mask(ar, tx_ant, true))
38638c2ecf20Sopenharmony_ci		return -EINVAL;
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_ci	if (ath11k_check_chain_mask(ar, rx_ant, false))
38668c2ecf20Sopenharmony_ci		return -EINVAL;
38678c2ecf20Sopenharmony_ci
38688c2ecf20Sopenharmony_ci	ar->cfg_tx_chainmask = tx_ant;
38698c2ecf20Sopenharmony_ci	ar->cfg_rx_chainmask = rx_ant;
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci	if (ar->state != ATH11K_STATE_ON &&
38728c2ecf20Sopenharmony_ci	    ar->state != ATH11K_STATE_RESTARTED)
38738c2ecf20Sopenharmony_ci		return 0;
38748c2ecf20Sopenharmony_ci
38758c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_TX_CHAIN_MASK,
38768c2ecf20Sopenharmony_ci					tx_ant, ar->pdev->pdev_id);
38778c2ecf20Sopenharmony_ci	if (ret) {
38788c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set tx-chainmask: %d, req 0x%x\n",
38798c2ecf20Sopenharmony_ci			    ret, tx_ant);
38808c2ecf20Sopenharmony_ci		return ret;
38818c2ecf20Sopenharmony_ci	}
38828c2ecf20Sopenharmony_ci
38838c2ecf20Sopenharmony_ci	ar->num_tx_chains = get_num_chains(tx_ant);
38848c2ecf20Sopenharmony_ci
38858c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RX_CHAIN_MASK,
38868c2ecf20Sopenharmony_ci					rx_ant, ar->pdev->pdev_id);
38878c2ecf20Sopenharmony_ci	if (ret) {
38888c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set rx-chainmask: %d, req 0x%x\n",
38898c2ecf20Sopenharmony_ci			    ret, rx_ant);
38908c2ecf20Sopenharmony_ci		return ret;
38918c2ecf20Sopenharmony_ci	}
38928c2ecf20Sopenharmony_ci
38938c2ecf20Sopenharmony_ci	ar->num_rx_chains = get_num_chains(rx_ant);
38948c2ecf20Sopenharmony_ci
38958c2ecf20Sopenharmony_ci	/* Reload HT/VHT/HE capability */
38968c2ecf20Sopenharmony_ci	ath11k_mac_setup_ht_vht_cap(ar, &ar->pdev->cap, NULL);
38978c2ecf20Sopenharmony_ci	ath11k_mac_setup_he_cap(ar, &ar->pdev->cap);
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_ci	return 0;
39008c2ecf20Sopenharmony_ci}
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_cistatic void ath11k_mac_tx_mgmt_free(struct ath11k *ar, int buf_id)
39038c2ecf20Sopenharmony_ci{
39048c2ecf20Sopenharmony_ci	struct sk_buff *msdu;
39058c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info;
39068c2ecf20Sopenharmony_ci
39078c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->txmgmt_idr_lock);
39088c2ecf20Sopenharmony_ci	msdu = idr_remove(&ar->txmgmt_idr, buf_id);
39098c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->txmgmt_idr_lock);
39108c2ecf20Sopenharmony_ci
39118c2ecf20Sopenharmony_ci	if (!msdu)
39128c2ecf20Sopenharmony_ci		return;
39138c2ecf20Sopenharmony_ci
39148c2ecf20Sopenharmony_ci	dma_unmap_single(ar->ab->dev, ATH11K_SKB_CB(msdu)->paddr, msdu->len,
39158c2ecf20Sopenharmony_ci			 DMA_TO_DEVICE);
39168c2ecf20Sopenharmony_ci
39178c2ecf20Sopenharmony_ci	info = IEEE80211_SKB_CB(msdu);
39188c2ecf20Sopenharmony_ci	memset(&info->status, 0, sizeof(info->status));
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_ci	ieee80211_free_txskb(ar->hw, msdu);
39218c2ecf20Sopenharmony_ci}
39228c2ecf20Sopenharmony_ci
39238c2ecf20Sopenharmony_ciint ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
39248c2ecf20Sopenharmony_ci{
39258c2ecf20Sopenharmony_ci	struct ath11k *ar = ctx;
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci	ath11k_mac_tx_mgmt_free(ar, buf_id);
39288c2ecf20Sopenharmony_ci
39298c2ecf20Sopenharmony_ci	return 0;
39308c2ecf20Sopenharmony_ci}
39318c2ecf20Sopenharmony_ci
39328c2ecf20Sopenharmony_cistatic int ath11k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
39338c2ecf20Sopenharmony_ci{
39348c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = ctx;
39358c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
39368c2ecf20Sopenharmony_ci	struct ath11k *ar = skb_cb->ar;
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci	if (skb_cb->vif == vif)
39398c2ecf20Sopenharmony_ci		ath11k_mac_tx_mgmt_free(ar, buf_id);
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_ci	return 0;
39428c2ecf20Sopenharmony_ci}
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_cistatic int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
39458c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
39468c2ecf20Sopenharmony_ci{
39478c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
39488c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
39498c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info;
39508c2ecf20Sopenharmony_ci	dma_addr_t paddr;
39518c2ecf20Sopenharmony_ci	int buf_id;
39528c2ecf20Sopenharmony_ci	int ret;
39538c2ecf20Sopenharmony_ci
39548c2ecf20Sopenharmony_ci	ATH11K_SKB_CB(skb)->ar = ar;
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->txmgmt_idr_lock);
39578c2ecf20Sopenharmony_ci	buf_id = idr_alloc(&ar->txmgmt_idr, skb, 0,
39588c2ecf20Sopenharmony_ci			   ATH11K_TX_MGMT_NUM_PENDING_MAX, GFP_ATOMIC);
39598c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->txmgmt_idr_lock);
39608c2ecf20Sopenharmony_ci	if (buf_id < 0)
39618c2ecf20Sopenharmony_ci		return -ENOSPC;
39628c2ecf20Sopenharmony_ci
39638c2ecf20Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
39648c2ecf20Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) {
39658c2ecf20Sopenharmony_ci		if ((ieee80211_is_action(hdr->frame_control) ||
39668c2ecf20Sopenharmony_ci		     ieee80211_is_deauth(hdr->frame_control) ||
39678c2ecf20Sopenharmony_ci		     ieee80211_is_disassoc(hdr->frame_control)) &&
39688c2ecf20Sopenharmony_ci		     ieee80211_has_protected(hdr->frame_control)) {
39698c2ecf20Sopenharmony_ci			skb_put(skb, IEEE80211_CCMP_MIC_LEN);
39708c2ecf20Sopenharmony_ci		}
39718c2ecf20Sopenharmony_ci	}
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci	paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
39748c2ecf20Sopenharmony_ci	if (dma_mapping_error(ab->dev, paddr)) {
39758c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to DMA map mgmt Tx buffer\n");
39768c2ecf20Sopenharmony_ci		ret = -EIO;
39778c2ecf20Sopenharmony_ci		goto err_free_idr;
39788c2ecf20Sopenharmony_ci	}
39798c2ecf20Sopenharmony_ci
39808c2ecf20Sopenharmony_ci	ATH11K_SKB_CB(skb)->paddr = paddr;
39818c2ecf20Sopenharmony_ci
39828c2ecf20Sopenharmony_ci	ret = ath11k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb);
39838c2ecf20Sopenharmony_ci	if (ret) {
39848c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret);
39858c2ecf20Sopenharmony_ci		goto err_unmap_buf;
39868c2ecf20Sopenharmony_ci	}
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	return 0;
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_cierr_unmap_buf:
39918c2ecf20Sopenharmony_ci	dma_unmap_single(ab->dev, ATH11K_SKB_CB(skb)->paddr,
39928c2ecf20Sopenharmony_ci			 skb->len, DMA_TO_DEVICE);
39938c2ecf20Sopenharmony_cierr_free_idr:
39948c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->txmgmt_idr_lock);
39958c2ecf20Sopenharmony_ci	idr_remove(&ar->txmgmt_idr, buf_id);
39968c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->txmgmt_idr_lock);
39978c2ecf20Sopenharmony_ci
39988c2ecf20Sopenharmony_ci	return ret;
39998c2ecf20Sopenharmony_ci}
40008c2ecf20Sopenharmony_ci
40018c2ecf20Sopenharmony_cistatic void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar)
40028c2ecf20Sopenharmony_ci{
40038c2ecf20Sopenharmony_ci	struct sk_buff *skb;
40048c2ecf20Sopenharmony_ci
40058c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL)
40068c2ecf20Sopenharmony_ci		ieee80211_free_txskb(ar->hw, skb);
40078c2ecf20Sopenharmony_ci}
40088c2ecf20Sopenharmony_ci
40098c2ecf20Sopenharmony_cistatic void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work)
40108c2ecf20Sopenharmony_ci{
40118c2ecf20Sopenharmony_ci	struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work);
40128c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb;
40138c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif;
40148c2ecf20Sopenharmony_ci	struct sk_buff *skb;
40158c2ecf20Sopenharmony_ci	int ret;
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) {
40188c2ecf20Sopenharmony_ci		skb_cb = ATH11K_SKB_CB(skb);
40198c2ecf20Sopenharmony_ci		if (!skb_cb->vif) {
40208c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "no vif found for mgmt frame\n");
40218c2ecf20Sopenharmony_ci			ieee80211_free_txskb(ar->hw, skb);
40228c2ecf20Sopenharmony_ci			continue;
40238c2ecf20Sopenharmony_ci		}
40248c2ecf20Sopenharmony_ci
40258c2ecf20Sopenharmony_ci		arvif = ath11k_vif_to_arvif(skb_cb->vif);
40268c2ecf20Sopenharmony_ci		mutex_lock(&ar->conf_mutex);
40278c2ecf20Sopenharmony_ci		if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) {
40288c2ecf20Sopenharmony_ci			ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb);
40298c2ecf20Sopenharmony_ci			if (ret) {
40308c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n",
40318c2ecf20Sopenharmony_ci					    arvif->vdev_id, ret);
40328c2ecf20Sopenharmony_ci				ieee80211_free_txskb(ar->hw, skb);
40338c2ecf20Sopenharmony_ci			} else {
40348c2ecf20Sopenharmony_ci				atomic_inc(&ar->num_pending_mgmt_tx);
40358c2ecf20Sopenharmony_ci			}
40368c2ecf20Sopenharmony_ci		} else {
40378c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
40388c2ecf20Sopenharmony_ci				    "dropping mgmt frame for vdev %d, is_started %d\n",
40398c2ecf20Sopenharmony_ci				    arvif->vdev_id,
40408c2ecf20Sopenharmony_ci				    arvif->is_started);
40418c2ecf20Sopenharmony_ci			ieee80211_free_txskb(ar->hw, skb);
40428c2ecf20Sopenharmony_ci		}
40438c2ecf20Sopenharmony_ci		mutex_unlock(&ar->conf_mutex);
40448c2ecf20Sopenharmony_ci	}
40458c2ecf20Sopenharmony_ci}
40468c2ecf20Sopenharmony_ci
40478c2ecf20Sopenharmony_cistatic int ath11k_mac_mgmt_tx(struct ath11k *ar, struct sk_buff *skb,
40488c2ecf20Sopenharmony_ci			      bool is_prb_rsp)
40498c2ecf20Sopenharmony_ci{
40508c2ecf20Sopenharmony_ci	struct sk_buff_head *q = &ar->wmi_mgmt_tx_queue;
40518c2ecf20Sopenharmony_ci
40528c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
40538c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
40548c2ecf20Sopenharmony_ci
40558c2ecf20Sopenharmony_ci	/* Drop probe response packets when the pending management tx
40568c2ecf20Sopenharmony_ci	 * count has reached a certain threshold, so as to prioritize
40578c2ecf20Sopenharmony_ci	 * other mgmt packets like auth and assoc to be sent on time
40588c2ecf20Sopenharmony_ci	 * for establishing successful connections.
40598c2ecf20Sopenharmony_ci	 */
40608c2ecf20Sopenharmony_ci	if (is_prb_rsp &&
40618c2ecf20Sopenharmony_ci	    atomic_read(&ar->num_pending_mgmt_tx) > ATH11K_PRB_RSP_DROP_THRESHOLD) {
40628c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
40638c2ecf20Sopenharmony_ci			    "dropping probe response as pending queue is almost full\n");
40648c2ecf20Sopenharmony_ci		return -ENOSPC;
40658c2ecf20Sopenharmony_ci	}
40668c2ecf20Sopenharmony_ci
40678c2ecf20Sopenharmony_ci	if (skb_queue_len(q) == ATH11K_TX_MGMT_NUM_PENDING_MAX) {
40688c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "mgmt tx queue is full\n");
40698c2ecf20Sopenharmony_ci		return -ENOSPC;
40708c2ecf20Sopenharmony_ci	}
40718c2ecf20Sopenharmony_ci
40728c2ecf20Sopenharmony_ci	skb_queue_tail(q, skb);
40738c2ecf20Sopenharmony_ci	ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work);
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_ci	return 0;
40768c2ecf20Sopenharmony_ci}
40778c2ecf20Sopenharmony_ci
40788c2ecf20Sopenharmony_cistatic void ath11k_mac_op_tx(struct ieee80211_hw *hw,
40798c2ecf20Sopenharmony_ci			     struct ieee80211_tx_control *control,
40808c2ecf20Sopenharmony_ci			     struct sk_buff *skb)
40818c2ecf20Sopenharmony_ci{
40828c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
40838c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
40848c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
40858c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = info->control.vif;
40868c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
40878c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
40888c2ecf20Sopenharmony_ci	struct ieee80211_key_conf *key = info->control.hw_key;
40898c2ecf20Sopenharmony_ci	u32 info_flags = info->flags;
40908c2ecf20Sopenharmony_ci	bool is_prb_rsp;
40918c2ecf20Sopenharmony_ci	int ret;
40928c2ecf20Sopenharmony_ci
40938c2ecf20Sopenharmony_ci	memset(skb_cb, 0, sizeof(*skb_cb));
40948c2ecf20Sopenharmony_ci	skb_cb->vif = vif;
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci	if (key) {
40978c2ecf20Sopenharmony_ci		skb_cb->cipher = key->cipher;
40988c2ecf20Sopenharmony_ci		skb_cb->flags |= ATH11K_SKB_CIPHER_SET;
40998c2ecf20Sopenharmony_ci	}
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ci	if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
41028c2ecf20Sopenharmony_ci		skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
41038c2ecf20Sopenharmony_ci	} else if (ieee80211_is_mgmt(hdr->frame_control)) {
41048c2ecf20Sopenharmony_ci		is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
41058c2ecf20Sopenharmony_ci		ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp);
41068c2ecf20Sopenharmony_ci		if (ret) {
41078c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to queue management frame %d\n",
41088c2ecf20Sopenharmony_ci				    ret);
41098c2ecf20Sopenharmony_ci			ieee80211_free_txskb(ar->hw, skb);
41108c2ecf20Sopenharmony_ci		}
41118c2ecf20Sopenharmony_ci		return;
41128c2ecf20Sopenharmony_ci	}
41138c2ecf20Sopenharmony_ci
41148c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx(ar, arvif, skb);
41158c2ecf20Sopenharmony_ci	if (ret) {
41168c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to transmit frame %d\n", ret);
41178c2ecf20Sopenharmony_ci		ieee80211_free_txskb(ar->hw, skb);
41188c2ecf20Sopenharmony_ci	}
41198c2ecf20Sopenharmony_ci}
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_civoid ath11k_mac_drain_tx(struct ath11k *ar)
41228c2ecf20Sopenharmony_ci{
41238c2ecf20Sopenharmony_ci	/* make sure rcu-protected mac80211 tx path itself is drained */
41248c2ecf20Sopenharmony_ci	synchronize_net();
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_ci	cancel_work_sync(&ar->wmi_mgmt_tx_work);
41278c2ecf20Sopenharmony_ci	ath11k_mgmt_over_wmi_tx_purge(ar);
41288c2ecf20Sopenharmony_ci}
41298c2ecf20Sopenharmony_ci
41308c2ecf20Sopenharmony_cistatic int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
41318c2ecf20Sopenharmony_ci{
41328c2ecf20Sopenharmony_ci	struct htt_rx_ring_tlv_filter tlv_filter = {0};
41338c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
41348c2ecf20Sopenharmony_ci	int i, ret = 0;
41358c2ecf20Sopenharmony_ci	u32 ring_id;
41368c2ecf20Sopenharmony_ci
41378c2ecf20Sopenharmony_ci	if (enable) {
41388c2ecf20Sopenharmony_ci		tlv_filter = ath11k_mac_mon_status_filter_default;
41398c2ecf20Sopenharmony_ci		if (ath11k_debugfs_rx_filter(ar))
41408c2ecf20Sopenharmony_ci			tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);
41418c2ecf20Sopenharmony_ci	}
41428c2ecf20Sopenharmony_ci
41438c2ecf20Sopenharmony_ci	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
41448c2ecf20Sopenharmony_ci		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
41458c2ecf20Sopenharmony_ci		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id,
41468c2ecf20Sopenharmony_ci						       ar->dp.mac_id + i,
41478c2ecf20Sopenharmony_ci						       HAL_RXDMA_MONITOR_STATUS,
41488c2ecf20Sopenharmony_ci						       DP_RX_BUFFER_SIZE,
41498c2ecf20Sopenharmony_ci						       &tlv_filter);
41508c2ecf20Sopenharmony_ci	}
41518c2ecf20Sopenharmony_ci
41528c2ecf20Sopenharmony_ci	return ret;
41538c2ecf20Sopenharmony_ci}
41548c2ecf20Sopenharmony_ci
41558c2ecf20Sopenharmony_cistatic int ath11k_mac_op_start(struct ieee80211_hw *hw)
41568c2ecf20Sopenharmony_ci{
41578c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
41588c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
41598c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev = ar->pdev;
41608c2ecf20Sopenharmony_ci	int ret;
41618c2ecf20Sopenharmony_ci
41628c2ecf20Sopenharmony_ci	ath11k_mac_drain_tx(ar);
41638c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
41648c2ecf20Sopenharmony_ci
41658c2ecf20Sopenharmony_ci	switch (ar->state) {
41668c2ecf20Sopenharmony_ci	case ATH11K_STATE_OFF:
41678c2ecf20Sopenharmony_ci		ar->state = ATH11K_STATE_ON;
41688c2ecf20Sopenharmony_ci		break;
41698c2ecf20Sopenharmony_ci	case ATH11K_STATE_RESTARTING:
41708c2ecf20Sopenharmony_ci		ar->state = ATH11K_STATE_RESTARTED;
41718c2ecf20Sopenharmony_ci		break;
41728c2ecf20Sopenharmony_ci	case ATH11K_STATE_RESTARTED:
41738c2ecf20Sopenharmony_ci	case ATH11K_STATE_WEDGED:
41748c2ecf20Sopenharmony_ci	case ATH11K_STATE_ON:
41758c2ecf20Sopenharmony_ci		WARN_ON(1);
41768c2ecf20Sopenharmony_ci		ret = -EINVAL;
41778c2ecf20Sopenharmony_ci		goto err;
41788c2ecf20Sopenharmony_ci	}
41798c2ecf20Sopenharmony_ci
41808c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS,
41818c2ecf20Sopenharmony_ci					1, pdev->pdev_id);
41828c2ecf20Sopenharmony_ci
41838c2ecf20Sopenharmony_ci	if (ret) {
41848c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret);
41858c2ecf20Sopenharmony_ci		goto err;
41868c2ecf20Sopenharmony_ci	}
41878c2ecf20Sopenharmony_ci
41888c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1,
41898c2ecf20Sopenharmony_ci					pdev->pdev_id);
41908c2ecf20Sopenharmony_ci	if (ret) {
41918c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret);
41928c2ecf20Sopenharmony_ci		goto err;
41938c2ecf20Sopenharmony_ci	}
41948c2ecf20Sopenharmony_ci
41958c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_ARP_AC_OVERRIDE,
41968c2ecf20Sopenharmony_ci					0, pdev->pdev_id);
41978c2ecf20Sopenharmony_ci	if (ret) {
41988c2ecf20Sopenharmony_ci		ath11k_err(ab, "failed to set ac override for ARP: %d\n",
41998c2ecf20Sopenharmony_ci			   ret);
42008c2ecf20Sopenharmony_ci		goto err;
42018c2ecf20Sopenharmony_ci	}
42028c2ecf20Sopenharmony_ci
42038c2ecf20Sopenharmony_ci	ret = ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(ar, pdev->pdev_id);
42048c2ecf20Sopenharmony_ci	if (ret) {
42058c2ecf20Sopenharmony_ci		ath11k_err(ab, "failed to offload radar detection: %d\n",
42068c2ecf20Sopenharmony_ci			   ret);
42078c2ecf20Sopenharmony_ci		goto err;
42088c2ecf20Sopenharmony_ci	}
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
42118c2ecf20Sopenharmony_ci						  HTT_PPDU_STATS_TAG_DEFAULT);
42128c2ecf20Sopenharmony_ci	if (ret) {
42138c2ecf20Sopenharmony_ci		ath11k_err(ab, "failed to req ppdu stats: %d\n", ret);
42148c2ecf20Sopenharmony_ci		goto err;
42158c2ecf20Sopenharmony_ci	}
42168c2ecf20Sopenharmony_ci
42178c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_MESH_MCAST_ENABLE,
42188c2ecf20Sopenharmony_ci					1, pdev->pdev_id);
42198c2ecf20Sopenharmony_ci
42208c2ecf20Sopenharmony_ci	if (ret) {
42218c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret);
42228c2ecf20Sopenharmony_ci		goto err;
42238c2ecf20Sopenharmony_ci	}
42248c2ecf20Sopenharmony_ci
42258c2ecf20Sopenharmony_ci	__ath11k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
42268c2ecf20Sopenharmony_ci
42278c2ecf20Sopenharmony_ci	/* TODO: Do we need to enable ANI? */
42288c2ecf20Sopenharmony_ci
42298c2ecf20Sopenharmony_ci	ath11k_reg_update_chan_list(ar);
42308c2ecf20Sopenharmony_ci
42318c2ecf20Sopenharmony_ci	ar->num_started_vdevs = 0;
42328c2ecf20Sopenharmony_ci	ar->num_created_vdevs = 0;
42338c2ecf20Sopenharmony_ci	ar->num_peers = 0;
42348c2ecf20Sopenharmony_ci	ar->allocated_vdev_map = 0;
42358c2ecf20Sopenharmony_ci
42368c2ecf20Sopenharmony_ci	/* Configure monitor status ring with default rx_filter to get rx status
42378c2ecf20Sopenharmony_ci	 * such as rssi, rx_duration.
42388c2ecf20Sopenharmony_ci	 */
42398c2ecf20Sopenharmony_ci	ret = ath11k_mac_config_mon_status_default(ar, true);
42408c2ecf20Sopenharmony_ci	if (ret) {
42418c2ecf20Sopenharmony_ci		ath11k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n",
42428c2ecf20Sopenharmony_ci			   ret);
42438c2ecf20Sopenharmony_ci		goto err;
42448c2ecf20Sopenharmony_ci	}
42458c2ecf20Sopenharmony_ci
42468c2ecf20Sopenharmony_ci	/* Configure the hash seed for hash based reo dest ring selection */
42478c2ecf20Sopenharmony_ci	ath11k_wmi_pdev_lro_cfg(ar, ar->pdev->pdev_id);
42488c2ecf20Sopenharmony_ci
42498c2ecf20Sopenharmony_ci	/* allow device to enter IMPS */
42508c2ecf20Sopenharmony_ci	if (ab->hw_params.idle_ps) {
42518c2ecf20Sopenharmony_ci		ret = ath11k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_IDLE_PS_CONFIG,
42528c2ecf20Sopenharmony_ci						1, pdev->pdev_id);
42538c2ecf20Sopenharmony_ci		if (ret) {
42548c2ecf20Sopenharmony_ci			ath11k_err(ab, "failed to enable idle ps: %d\n", ret);
42558c2ecf20Sopenharmony_ci			goto err;
42568c2ecf20Sopenharmony_ci		}
42578c2ecf20Sopenharmony_ci	}
42588c2ecf20Sopenharmony_ci
42598c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
42608c2ecf20Sopenharmony_ci
42618c2ecf20Sopenharmony_ci	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx],
42628c2ecf20Sopenharmony_ci			   &ab->pdevs[ar->pdev_idx]);
42638c2ecf20Sopenharmony_ci
42648c2ecf20Sopenharmony_ci	return 0;
42658c2ecf20Sopenharmony_ci
42668c2ecf20Sopenharmony_cierr:
42678c2ecf20Sopenharmony_ci	ar->state = ATH11K_STATE_OFF;
42688c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
42698c2ecf20Sopenharmony_ci
42708c2ecf20Sopenharmony_ci	return ret;
42718c2ecf20Sopenharmony_ci}
42728c2ecf20Sopenharmony_ci
42738c2ecf20Sopenharmony_cistatic void ath11k_mac_op_stop(struct ieee80211_hw *hw)
42748c2ecf20Sopenharmony_ci{
42758c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
42768c2ecf20Sopenharmony_ci	struct htt_ppdu_stats_info *ppdu_stats, *tmp;
42778c2ecf20Sopenharmony_ci	int ret;
42788c2ecf20Sopenharmony_ci
42798c2ecf20Sopenharmony_ci	ath11k_mac_drain_tx(ar);
42808c2ecf20Sopenharmony_ci
42818c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
42828c2ecf20Sopenharmony_ci	ret = ath11k_mac_config_mon_status_default(ar, false);
42838c2ecf20Sopenharmony_ci	if (ret)
42848c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n",
42858c2ecf20Sopenharmony_ci			   ret);
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
42888c2ecf20Sopenharmony_ci	ar->state = ATH11K_STATE_OFF;
42898c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
42908c2ecf20Sopenharmony_ci
42918c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&ar->scan.timeout);
42928c2ecf20Sopenharmony_ci	cancel_work_sync(&ar->regd_update_work);
42938c2ecf20Sopenharmony_ci
42948c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
42958c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
42968c2ecf20Sopenharmony_ci		list_del(&ppdu_stats->list);
42978c2ecf20Sopenharmony_ci		kfree(ppdu_stats);
42988c2ecf20Sopenharmony_ci	}
42998c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
43008c2ecf20Sopenharmony_ci
43018c2ecf20Sopenharmony_ci	rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL);
43028c2ecf20Sopenharmony_ci
43038c2ecf20Sopenharmony_ci	synchronize_rcu();
43048c2ecf20Sopenharmony_ci
43058c2ecf20Sopenharmony_ci	atomic_set(&ar->num_pending_mgmt_tx, 0);
43068c2ecf20Sopenharmony_ci}
43078c2ecf20Sopenharmony_ci
43088c2ecf20Sopenharmony_cistatic void
43098c2ecf20Sopenharmony_ciath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif,
43108c2ecf20Sopenharmony_ci				    struct vdev_create_params *params)
43118c2ecf20Sopenharmony_ci{
43128c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
43138c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev = ar->pdev;
43148c2ecf20Sopenharmony_ci
43158c2ecf20Sopenharmony_ci	params->if_id = arvif->vdev_id;
43168c2ecf20Sopenharmony_ci	params->type = arvif->vdev_type;
43178c2ecf20Sopenharmony_ci	params->subtype = arvif->vdev_subtype;
43188c2ecf20Sopenharmony_ci	params->pdev_id = pdev->pdev_id;
43198c2ecf20Sopenharmony_ci
43208c2ecf20Sopenharmony_ci	if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP) {
43218c2ecf20Sopenharmony_ci		params->chains[NL80211_BAND_2GHZ].tx = ar->num_tx_chains;
43228c2ecf20Sopenharmony_ci		params->chains[NL80211_BAND_2GHZ].rx = ar->num_rx_chains;
43238c2ecf20Sopenharmony_ci	}
43248c2ecf20Sopenharmony_ci	if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP) {
43258c2ecf20Sopenharmony_ci		params->chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains;
43268c2ecf20Sopenharmony_ci		params->chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains;
43278c2ecf20Sopenharmony_ci	}
43288c2ecf20Sopenharmony_ci	if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP &&
43298c2ecf20Sopenharmony_ci	    ar->supports_6ghz) {
43308c2ecf20Sopenharmony_ci		params->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains;
43318c2ecf20Sopenharmony_ci		params->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains;
43328c2ecf20Sopenharmony_ci	}
43338c2ecf20Sopenharmony_ci}
43348c2ecf20Sopenharmony_ci
43358c2ecf20Sopenharmony_cistatic u32
43368c2ecf20Sopenharmony_ciath11k_mac_prepare_he_mode(struct ath11k_pdev *pdev, u32 viftype)
43378c2ecf20Sopenharmony_ci{
43388c2ecf20Sopenharmony_ci	struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
43398c2ecf20Sopenharmony_ci	struct ath11k_band_cap *cap_band = NULL;
43408c2ecf20Sopenharmony_ci	u32 *hecap_phy_ptr = NULL;
43418c2ecf20Sopenharmony_ci	u32 hemode = 0;
43428c2ecf20Sopenharmony_ci
43438c2ecf20Sopenharmony_ci	if (pdev->cap.supported_bands & WMI_HOST_WLAN_2G_CAP)
43448c2ecf20Sopenharmony_ci		cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];
43458c2ecf20Sopenharmony_ci	else
43468c2ecf20Sopenharmony_ci		cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];
43478c2ecf20Sopenharmony_ci
43488c2ecf20Sopenharmony_ci	hecap_phy_ptr = &cap_band->he_cap_phy_info[0];
43498c2ecf20Sopenharmony_ci
43508c2ecf20Sopenharmony_ci	hemode = FIELD_PREP(HE_MODE_SU_TX_BFEE, HE_SU_BFEE_ENABLE) |
43518c2ecf20Sopenharmony_ci		 FIELD_PREP(HE_MODE_SU_TX_BFER, HECAP_PHY_SUBFMR_GET(hecap_phy_ptr)) |
43528c2ecf20Sopenharmony_ci		 FIELD_PREP(HE_MODE_UL_MUMIMO, HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr));
43538c2ecf20Sopenharmony_ci
43548c2ecf20Sopenharmony_ci	/* TODO WDS and other modes */
43558c2ecf20Sopenharmony_ci	if (viftype == NL80211_IFTYPE_AP) {
43568c2ecf20Sopenharmony_ci		hemode |= FIELD_PREP(HE_MODE_MU_TX_BFER,
43578c2ecf20Sopenharmony_ci			  HECAP_PHY_MUBFMR_GET(hecap_phy_ptr)) |
43588c2ecf20Sopenharmony_ci			  FIELD_PREP(HE_MODE_DL_OFDMA, HE_DL_MUOFDMA_ENABLE) |
43598c2ecf20Sopenharmony_ci			  FIELD_PREP(HE_MODE_UL_OFDMA, HE_UL_MUOFDMA_ENABLE);
43608c2ecf20Sopenharmony_ci	} else {
43618c2ecf20Sopenharmony_ci		hemode |= FIELD_PREP(HE_MODE_MU_TX_BFEE, HE_MU_BFEE_ENABLE);
43628c2ecf20Sopenharmony_ci	}
43638c2ecf20Sopenharmony_ci
43648c2ecf20Sopenharmony_ci	return hemode;
43658c2ecf20Sopenharmony_ci}
43668c2ecf20Sopenharmony_ci
43678c2ecf20Sopenharmony_cistatic int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
43688c2ecf20Sopenharmony_ci					  struct ath11k_vif *arvif)
43698c2ecf20Sopenharmony_ci{
43708c2ecf20Sopenharmony_ci	u32 param_id, param_value;
43718c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
43728c2ecf20Sopenharmony_ci	int ret = 0;
43738c2ecf20Sopenharmony_ci
43748c2ecf20Sopenharmony_ci	param_id = WMI_VDEV_PARAM_SET_HEMU_MODE;
43758c2ecf20Sopenharmony_ci	param_value = ath11k_mac_prepare_he_mode(ar->pdev, arvif->vif->type);
43768c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
43778c2ecf20Sopenharmony_ci					    param_id, param_value);
43788c2ecf20Sopenharmony_ci	if (ret) {
43798c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n",
43808c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret, param_value);
43818c2ecf20Sopenharmony_ci		return ret;
43828c2ecf20Sopenharmony_ci	}
43838c2ecf20Sopenharmony_ci	param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE;
43848c2ecf20Sopenharmony_ci	param_value =
43858c2ecf20Sopenharmony_ci		FIELD_PREP(HE_VHT_SOUNDING_MODE, HE_VHT_SOUNDING_MODE_ENABLE) |
43868c2ecf20Sopenharmony_ci		FIELD_PREP(HE_TRIG_NONTRIG_SOUNDING_MODE,
43878c2ecf20Sopenharmony_ci			   HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE);
43888c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
43898c2ecf20Sopenharmony_ci					    param_id, param_value);
43908c2ecf20Sopenharmony_ci	if (ret) {
43918c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to set vdev %d HE MU mode: %d\n",
43928c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
43938c2ecf20Sopenharmony_ci		return ret;
43948c2ecf20Sopenharmony_ci	}
43958c2ecf20Sopenharmony_ci	return ret;
43968c2ecf20Sopenharmony_ci}
43978c2ecf20Sopenharmony_ci
43988c2ecf20Sopenharmony_cistatic void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
43998c2ecf20Sopenharmony_ci					     struct ieee80211_vif *vif)
44008c2ecf20Sopenharmony_ci{
44018c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
44028c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
44038c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
44048c2ecf20Sopenharmony_ci	u32 param_id, param_value;
44058c2ecf20Sopenharmony_ci	int ret;
44068c2ecf20Sopenharmony_ci
44078c2ecf20Sopenharmony_ci	param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
44088c2ecf20Sopenharmony_ci	if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET ||
44098c2ecf20Sopenharmony_ci	    (vif->type != NL80211_IFTYPE_STATION &&
44108c2ecf20Sopenharmony_ci	     vif->type != NL80211_IFTYPE_AP))
44118c2ecf20Sopenharmony_ci		vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
44128c2ecf20Sopenharmony_ci
44138c2ecf20Sopenharmony_ci	if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
44148c2ecf20Sopenharmony_ci		param_value = ATH11K_HW_TXRX_ETHERNET;
44158c2ecf20Sopenharmony_ci	else if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
44168c2ecf20Sopenharmony_ci		param_value = ATH11K_HW_TXRX_RAW;
44178c2ecf20Sopenharmony_ci	else
44188c2ecf20Sopenharmony_ci		param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
44198c2ecf20Sopenharmony_ci
44208c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
44218c2ecf20Sopenharmony_ci					    param_id, param_value);
44228c2ecf20Sopenharmony_ci	if (ret) {
44238c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
44248c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
44258c2ecf20Sopenharmony_ci		vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
44268c2ecf20Sopenharmony_ci	}
44278c2ecf20Sopenharmony_ci}
44288c2ecf20Sopenharmony_ci
44298c2ecf20Sopenharmony_cistatic int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
44308c2ecf20Sopenharmony_ci				       struct ieee80211_vif *vif)
44318c2ecf20Sopenharmony_ci{
44328c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
44338c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
44348c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
44358c2ecf20Sopenharmony_ci	struct vdev_create_params vdev_param = {0};
44368c2ecf20Sopenharmony_ci	struct peer_create_params peer_param;
44378c2ecf20Sopenharmony_ci	u32 param_id, param_value;
44388c2ecf20Sopenharmony_ci	u16 nss;
44398c2ecf20Sopenharmony_ci	int i;
44408c2ecf20Sopenharmony_ci	int ret;
44418c2ecf20Sopenharmony_ci	int bit;
44428c2ecf20Sopenharmony_ci
44438c2ecf20Sopenharmony_ci	vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
44448c2ecf20Sopenharmony_ci
44458c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
44468c2ecf20Sopenharmony_ci
44478c2ecf20Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_AP &&
44488c2ecf20Sopenharmony_ci	    ar->num_peers > (ar->max_num_peers - 1)) {
44498c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n");
44508c2ecf20Sopenharmony_ci		ret = -ENOBUFS;
44518c2ecf20Sopenharmony_ci		goto err;
44528c2ecf20Sopenharmony_ci	}
44538c2ecf20Sopenharmony_ci
44548c2ecf20Sopenharmony_ci	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
44558c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
44568c2ecf20Sopenharmony_ci			    TARGET_NUM_VDEVS);
44578c2ecf20Sopenharmony_ci		ret = -EBUSY;
44588c2ecf20Sopenharmony_ci		goto err;
44598c2ecf20Sopenharmony_ci	}
44608c2ecf20Sopenharmony_ci
44618c2ecf20Sopenharmony_ci	memset(arvif, 0, sizeof(*arvif));
44628c2ecf20Sopenharmony_ci
44638c2ecf20Sopenharmony_ci	arvif->ar = ar;
44648c2ecf20Sopenharmony_ci	arvif->vif = vif;
44658c2ecf20Sopenharmony_ci
44668c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&arvif->list);
44678c2ecf20Sopenharmony_ci
44688c2ecf20Sopenharmony_ci	/* Should we initialize any worker to handle connection loss indication
44698c2ecf20Sopenharmony_ci	 * from firmware in sta mode?
44708c2ecf20Sopenharmony_ci	 */
44718c2ecf20Sopenharmony_ci
44728c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) {
44738c2ecf20Sopenharmony_ci		arvif->bitrate_mask.control[i].legacy = 0xffffffff;
44748c2ecf20Sopenharmony_ci		memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff,
44758c2ecf20Sopenharmony_ci		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
44768c2ecf20Sopenharmony_ci		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
44778c2ecf20Sopenharmony_ci		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
44788c2ecf20Sopenharmony_ci	}
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci	bit = __ffs64(ab->free_vdev_map);
44818c2ecf20Sopenharmony_ci
44828c2ecf20Sopenharmony_ci	arvif->vdev_id = bit;
44838c2ecf20Sopenharmony_ci	arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
44848c2ecf20Sopenharmony_ci
44858c2ecf20Sopenharmony_ci	switch (vif->type) {
44868c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_UNSPECIFIED:
44878c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_STATION:
44888c2ecf20Sopenharmony_ci		arvif->vdev_type = WMI_VDEV_TYPE_STA;
44898c2ecf20Sopenharmony_ci		break;
44908c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
44918c2ecf20Sopenharmony_ci		arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S;
44928c2ecf20Sopenharmony_ci		fallthrough;
44938c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_AP:
44948c2ecf20Sopenharmony_ci		arvif->vdev_type = WMI_VDEV_TYPE_AP;
44958c2ecf20Sopenharmony_ci		break;
44968c2ecf20Sopenharmony_ci	case NL80211_IFTYPE_MONITOR:
44978c2ecf20Sopenharmony_ci		arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
44988c2ecf20Sopenharmony_ci		break;
44998c2ecf20Sopenharmony_ci	default:
45008c2ecf20Sopenharmony_ci		WARN_ON(1);
45018c2ecf20Sopenharmony_ci		break;
45028c2ecf20Sopenharmony_ci	}
45038c2ecf20Sopenharmony_ci
45048c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n",
45058c2ecf20Sopenharmony_ci		   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
45068c2ecf20Sopenharmony_ci		   ab->free_vdev_map);
45078c2ecf20Sopenharmony_ci
45088c2ecf20Sopenharmony_ci	vif->cab_queue = arvif->vdev_id % (ATH11K_HW_MAX_QUEUES - 1);
45098c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++)
45108c2ecf20Sopenharmony_ci		vif->hw_queue[i] = i % (ATH11K_HW_MAX_QUEUES - 1);
45118c2ecf20Sopenharmony_ci
45128c2ecf20Sopenharmony_ci	ath11k_mac_setup_vdev_create_params(arvif, &vdev_param);
45138c2ecf20Sopenharmony_ci
45148c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_create(ar, vif->addr, &vdev_param);
45158c2ecf20Sopenharmony_ci	if (ret) {
45168c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to create WMI vdev %d: %d\n",
45178c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
45188c2ecf20Sopenharmony_ci		goto err;
45198c2ecf20Sopenharmony_ci	}
45208c2ecf20Sopenharmony_ci
45218c2ecf20Sopenharmony_ci	ar->num_created_vdevs++;
45228c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM created, vdev_id %d\n",
45238c2ecf20Sopenharmony_ci		   vif->addr, arvif->vdev_id);
45248c2ecf20Sopenharmony_ci	ar->allocated_vdev_map |= 1LL << arvif->vdev_id;
45258c2ecf20Sopenharmony_ci	ab->free_vdev_map &= ~(1LL << arvif->vdev_id);
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
45288c2ecf20Sopenharmony_ci	list_add(&arvif->list, &ar->arvifs);
45298c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
45308c2ecf20Sopenharmony_ci
45318c2ecf20Sopenharmony_ci	ath11k_mac_op_update_vif_offload(hw, vif);
45328c2ecf20Sopenharmony_ci
45338c2ecf20Sopenharmony_ci	nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
45348c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
45358c2ecf20Sopenharmony_ci					    WMI_VDEV_PARAM_NSS, nss);
45368c2ecf20Sopenharmony_ci	if (ret) {
45378c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to set vdev %d chainmask 0x%x, nss %d :%d\n",
45388c2ecf20Sopenharmony_ci			    arvif->vdev_id, ar->cfg_tx_chainmask, nss, ret);
45398c2ecf20Sopenharmony_ci		goto err_vdev_del;
45408c2ecf20Sopenharmony_ci	}
45418c2ecf20Sopenharmony_ci
45428c2ecf20Sopenharmony_ci	switch (arvif->vdev_type) {
45438c2ecf20Sopenharmony_ci	case WMI_VDEV_TYPE_AP:
45448c2ecf20Sopenharmony_ci		peer_param.vdev_id = arvif->vdev_id;
45458c2ecf20Sopenharmony_ci		peer_param.peer_addr = vif->addr;
45468c2ecf20Sopenharmony_ci		peer_param.peer_type = WMI_PEER_TYPE_DEFAULT;
45478c2ecf20Sopenharmony_ci		ret = ath11k_peer_create(ar, arvif, NULL, &peer_param);
45488c2ecf20Sopenharmony_ci		if (ret) {
45498c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to vdev %d create peer for AP: %d\n",
45508c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
45518c2ecf20Sopenharmony_ci			goto err_vdev_del;
45528c2ecf20Sopenharmony_ci		}
45538c2ecf20Sopenharmony_ci
45548c2ecf20Sopenharmony_ci		ret = ath11k_mac_set_kickout(arvif);
45558c2ecf20Sopenharmony_ci		if (ret) {
45568c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to set vdev %i kickout parameters: %d\n",
45578c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
45588c2ecf20Sopenharmony_ci			goto err_peer_del;
45598c2ecf20Sopenharmony_ci		}
45608c2ecf20Sopenharmony_ci		break;
45618c2ecf20Sopenharmony_ci	case WMI_VDEV_TYPE_STA:
45628c2ecf20Sopenharmony_ci		param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
45638c2ecf20Sopenharmony_ci		param_value = WMI_STA_PS_RX_WAKE_POLICY_WAKE;
45648c2ecf20Sopenharmony_ci		ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
45658c2ecf20Sopenharmony_ci						  param_id, param_value);
45668c2ecf20Sopenharmony_ci		if (ret) {
45678c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to set vdev %d RX wake policy: %d\n",
45688c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
45698c2ecf20Sopenharmony_ci			goto err_peer_del;
45708c2ecf20Sopenharmony_ci		}
45718c2ecf20Sopenharmony_ci
45728c2ecf20Sopenharmony_ci		param_id = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
45738c2ecf20Sopenharmony_ci		param_value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
45748c2ecf20Sopenharmony_ci		ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
45758c2ecf20Sopenharmony_ci						  param_id, param_value);
45768c2ecf20Sopenharmony_ci		if (ret) {
45778c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to set vdev %d TX wake threshold: %d\n",
45788c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
45798c2ecf20Sopenharmony_ci			goto err_peer_del;
45808c2ecf20Sopenharmony_ci		}
45818c2ecf20Sopenharmony_ci
45828c2ecf20Sopenharmony_ci		param_id = WMI_STA_PS_PARAM_PSPOLL_COUNT;
45838c2ecf20Sopenharmony_ci		param_value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
45848c2ecf20Sopenharmony_ci		ret = ath11k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
45858c2ecf20Sopenharmony_ci						  param_id, param_value);
45868c2ecf20Sopenharmony_ci		if (ret) {
45878c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to set vdev %d pspoll count: %d\n",
45888c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
45898c2ecf20Sopenharmony_ci			goto err_peer_del;
45908c2ecf20Sopenharmony_ci		}
45918c2ecf20Sopenharmony_ci
45928c2ecf20Sopenharmony_ci		ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, false);
45938c2ecf20Sopenharmony_ci		if (ret) {
45948c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to disable vdev %d ps mode: %d\n",
45958c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
45968c2ecf20Sopenharmony_ci			goto err_peer_del;
45978c2ecf20Sopenharmony_ci		}
45988c2ecf20Sopenharmony_ci		break;
45998c2ecf20Sopenharmony_ci	default:
46008c2ecf20Sopenharmony_ci		break;
46018c2ecf20Sopenharmony_ci	}
46028c2ecf20Sopenharmony_ci
46038c2ecf20Sopenharmony_ci	arvif->txpower = vif->bss_conf.txpower;
46048c2ecf20Sopenharmony_ci	ret = ath11k_mac_txpower_recalc(ar);
46058c2ecf20Sopenharmony_ci	if (ret)
46068c2ecf20Sopenharmony_ci		goto err_peer_del;
46078c2ecf20Sopenharmony_ci
46088c2ecf20Sopenharmony_ci	param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
46098c2ecf20Sopenharmony_ci	param_value = ar->hw->wiphy->rts_threshold;
46108c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
46118c2ecf20Sopenharmony_ci					    param_id, param_value);
46128c2ecf20Sopenharmony_ci	if (ret) {
46138c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set rts threshold for vdev %d: %d\n",
46148c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
46158c2ecf20Sopenharmony_ci	}
46168c2ecf20Sopenharmony_ci
46178c2ecf20Sopenharmony_ci	ath11k_dp_vdev_tx_attach(ar, arvif);
46188c2ecf20Sopenharmony_ci
46198c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci	return 0;
46228c2ecf20Sopenharmony_ci
46238c2ecf20Sopenharmony_cierr_peer_del:
46248c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
46258c2ecf20Sopenharmony_ci		reinit_completion(&ar->peer_delete_done);
46268c2ecf20Sopenharmony_ci
46278c2ecf20Sopenharmony_ci		ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr,
46288c2ecf20Sopenharmony_ci						      arvif->vdev_id);
46298c2ecf20Sopenharmony_ci		if (ret) {
46308c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
46318c2ecf20Sopenharmony_ci				    arvif->vdev_id, vif->addr);
46328c2ecf20Sopenharmony_ci			goto err;
46338c2ecf20Sopenharmony_ci		}
46348c2ecf20Sopenharmony_ci
46358c2ecf20Sopenharmony_ci		ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id,
46368c2ecf20Sopenharmony_ci						       vif->addr);
46378c2ecf20Sopenharmony_ci		if (ret)
46388c2ecf20Sopenharmony_ci			goto err;
46398c2ecf20Sopenharmony_ci
46408c2ecf20Sopenharmony_ci		ar->num_peers--;
46418c2ecf20Sopenharmony_ci	}
46428c2ecf20Sopenharmony_ci
46438c2ecf20Sopenharmony_cierr_vdev_del:
46448c2ecf20Sopenharmony_ci	ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
46458c2ecf20Sopenharmony_ci	ar->num_created_vdevs--;
46468c2ecf20Sopenharmony_ci	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
46478c2ecf20Sopenharmony_ci	ab->free_vdev_map |= 1LL << arvif->vdev_id;
46488c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
46498c2ecf20Sopenharmony_ci	list_del(&arvif->list);
46508c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
46518c2ecf20Sopenharmony_ci
46528c2ecf20Sopenharmony_cierr:
46538c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
46548c2ecf20Sopenharmony_ci
46558c2ecf20Sopenharmony_ci	return ret;
46568c2ecf20Sopenharmony_ci}
46578c2ecf20Sopenharmony_ci
46588c2ecf20Sopenharmony_cistatic int ath11k_mac_vif_unref(int buf_id, void *skb, void *ctx)
46598c2ecf20Sopenharmony_ci{
46608c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = (struct ieee80211_vif *)ctx;
46618c2ecf20Sopenharmony_ci	struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB((struct sk_buff *)skb);
46628c2ecf20Sopenharmony_ci
46638c2ecf20Sopenharmony_ci	if (skb_cb->vif == vif)
46648c2ecf20Sopenharmony_ci		skb_cb->vif = NULL;
46658c2ecf20Sopenharmony_ci
46668c2ecf20Sopenharmony_ci	return 0;
46678c2ecf20Sopenharmony_ci}
46688c2ecf20Sopenharmony_ci
46698c2ecf20Sopenharmony_cistatic void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
46708c2ecf20Sopenharmony_ci					   struct ieee80211_vif *vif)
46718c2ecf20Sopenharmony_ci{
46728c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
46738c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
46748c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
46758c2ecf20Sopenharmony_ci	int ret;
46768c2ecf20Sopenharmony_ci	int i;
46778c2ecf20Sopenharmony_ci
46788c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
46798c2ecf20Sopenharmony_ci
46808c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n",
46818c2ecf20Sopenharmony_ci		   arvif->vdev_id);
46828c2ecf20Sopenharmony_ci
46838c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
46848c2ecf20Sopenharmony_ci	list_del(&arvif->list);
46858c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
46868c2ecf20Sopenharmony_ci
46878c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
46888c2ecf20Sopenharmony_ci		ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr);
46898c2ecf20Sopenharmony_ci		if (ret)
46908c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n",
46918c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
46928c2ecf20Sopenharmony_ci	}
46938c2ecf20Sopenharmony_ci
46948c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id);
46958c2ecf20Sopenharmony_ci	if (ret)
46968c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n",
46978c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
46988c2ecf20Sopenharmony_ci
46998c2ecf20Sopenharmony_ci	ar->num_created_vdevs--;
47008c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
47018c2ecf20Sopenharmony_ci		   vif->addr, arvif->vdev_id);
47028c2ecf20Sopenharmony_ci	ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
47038c2ecf20Sopenharmony_ci	ab->free_vdev_map |= 1LL << (arvif->vdev_id);
47048c2ecf20Sopenharmony_ci
47058c2ecf20Sopenharmony_ci	ath11k_peer_cleanup(ar, arvif->vdev_id);
47068c2ecf20Sopenharmony_ci
47078c2ecf20Sopenharmony_ci	idr_for_each(&ar->txmgmt_idr,
47088c2ecf20Sopenharmony_ci		     ath11k_mac_vif_txmgmt_idr_remove, vif);
47098c2ecf20Sopenharmony_ci
47108c2ecf20Sopenharmony_ci	for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) {
47118c2ecf20Sopenharmony_ci		spin_lock_bh(&ab->dp.tx_ring[i].tx_idr_lock);
47128c2ecf20Sopenharmony_ci		idr_for_each(&ab->dp.tx_ring[i].txbuf_idr,
47138c2ecf20Sopenharmony_ci			     ath11k_mac_vif_unref, vif);
47148c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->dp.tx_ring[i].tx_idr_lock);
47158c2ecf20Sopenharmony_ci	}
47168c2ecf20Sopenharmony_ci
47178c2ecf20Sopenharmony_ci	/* Recalc txpower for remaining vdev */
47188c2ecf20Sopenharmony_ci	ath11k_mac_txpower_recalc(ar);
47198c2ecf20Sopenharmony_ci	clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
47208c2ecf20Sopenharmony_ci
47218c2ecf20Sopenharmony_ci	/* TODO: recal traffic pause state based on the available vdevs */
47228c2ecf20Sopenharmony_ci
47238c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
47248c2ecf20Sopenharmony_ci}
47258c2ecf20Sopenharmony_ci
47268c2ecf20Sopenharmony_ci/* FIXME: Has to be verified. */
47278c2ecf20Sopenharmony_ci#define SUPPORTED_FILTERS			\
47288c2ecf20Sopenharmony_ci	(FIF_ALLMULTI |				\
47298c2ecf20Sopenharmony_ci	FIF_CONTROL |				\
47308c2ecf20Sopenharmony_ci	FIF_PSPOLL |				\
47318c2ecf20Sopenharmony_ci	FIF_OTHER_BSS |				\
47328c2ecf20Sopenharmony_ci	FIF_BCN_PRBRESP_PROMISC |		\
47338c2ecf20Sopenharmony_ci	FIF_PROBE_REQ |				\
47348c2ecf20Sopenharmony_ci	FIF_FCSFAIL)
47358c2ecf20Sopenharmony_ci
47368c2ecf20Sopenharmony_cistatic void ath11k_mac_op_configure_filter(struct ieee80211_hw *hw,
47378c2ecf20Sopenharmony_ci					   unsigned int changed_flags,
47388c2ecf20Sopenharmony_ci					   unsigned int *total_flags,
47398c2ecf20Sopenharmony_ci					   u64 multicast)
47408c2ecf20Sopenharmony_ci{
47418c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
47428c2ecf20Sopenharmony_ci	bool reset_flag = false;
47438c2ecf20Sopenharmony_ci	int ret = 0;
47448c2ecf20Sopenharmony_ci
47458c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci	changed_flags &= SUPPORTED_FILTERS;
47488c2ecf20Sopenharmony_ci	*total_flags &= SUPPORTED_FILTERS;
47498c2ecf20Sopenharmony_ci	ar->filter_flags = *total_flags;
47508c2ecf20Sopenharmony_ci
47518c2ecf20Sopenharmony_ci	/* For monitor mode */
47528c2ecf20Sopenharmony_ci	reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC);
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_ci	ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag);
47558c2ecf20Sopenharmony_ci	if (!ret) {
47568c2ecf20Sopenharmony_ci		if (!reset_flag)
47578c2ecf20Sopenharmony_ci			set_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
47588c2ecf20Sopenharmony_ci		else
47598c2ecf20Sopenharmony_ci			clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
47608c2ecf20Sopenharmony_ci	} else {
47618c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
47628c2ecf20Sopenharmony_ci			    "fail to set monitor filter: %d\n", ret);
47638c2ecf20Sopenharmony_ci	}
47648c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
47658c2ecf20Sopenharmony_ci		   "changed_flags:0x%x, total_flags:0x%x, reset_flag:%d\n",
47668c2ecf20Sopenharmony_ci		   changed_flags, *total_flags, reset_flag);
47678c2ecf20Sopenharmony_ci
47688c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
47698c2ecf20Sopenharmony_ci}
47708c2ecf20Sopenharmony_ci
47718c2ecf20Sopenharmony_cistatic int ath11k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
47728c2ecf20Sopenharmony_ci{
47738c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
47748c2ecf20Sopenharmony_ci
47758c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
47768c2ecf20Sopenharmony_ci
47778c2ecf20Sopenharmony_ci	*tx_ant = ar->cfg_tx_chainmask;
47788c2ecf20Sopenharmony_ci	*rx_ant = ar->cfg_rx_chainmask;
47798c2ecf20Sopenharmony_ci
47808c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
47818c2ecf20Sopenharmony_ci
47828c2ecf20Sopenharmony_ci	return 0;
47838c2ecf20Sopenharmony_ci}
47848c2ecf20Sopenharmony_ci
47858c2ecf20Sopenharmony_cistatic int ath11k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
47868c2ecf20Sopenharmony_ci{
47878c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
47888c2ecf20Sopenharmony_ci	int ret;
47898c2ecf20Sopenharmony_ci
47908c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
47918c2ecf20Sopenharmony_ci	ret = __ath11k_set_antenna(ar, tx_ant, rx_ant);
47928c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
47938c2ecf20Sopenharmony_ci
47948c2ecf20Sopenharmony_ci	return ret;
47958c2ecf20Sopenharmony_ci}
47968c2ecf20Sopenharmony_ci
47978c2ecf20Sopenharmony_cistatic int ath11k_mac_op_ampdu_action(struct ieee80211_hw *hw,
47988c2ecf20Sopenharmony_ci				      struct ieee80211_vif *vif,
47998c2ecf20Sopenharmony_ci				      struct ieee80211_ampdu_params *params)
48008c2ecf20Sopenharmony_ci{
48018c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
48028c2ecf20Sopenharmony_ci	int ret = -EINVAL;
48038c2ecf20Sopenharmony_ci
48048c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
48058c2ecf20Sopenharmony_ci
48068c2ecf20Sopenharmony_ci	switch (params->action) {
48078c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_RX_START:
48088c2ecf20Sopenharmony_ci		ret = ath11k_dp_rx_ampdu_start(ar, params);
48098c2ecf20Sopenharmony_ci		break;
48108c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_RX_STOP:
48118c2ecf20Sopenharmony_ci		ret = ath11k_dp_rx_ampdu_stop(ar, params);
48128c2ecf20Sopenharmony_ci		break;
48138c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_START:
48148c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_STOP_CONT:
48158c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_STOP_FLUSH:
48168c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
48178c2ecf20Sopenharmony_ci	case IEEE80211_AMPDU_TX_OPERATIONAL:
48188c2ecf20Sopenharmony_ci		/* Tx A-MPDU aggregation offloaded to hw/fw so deny mac80211
48198c2ecf20Sopenharmony_ci		 * Tx aggregation requests.
48208c2ecf20Sopenharmony_ci		 */
48218c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
48228c2ecf20Sopenharmony_ci		break;
48238c2ecf20Sopenharmony_ci	}
48248c2ecf20Sopenharmony_ci
48258c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
48268c2ecf20Sopenharmony_ci
48278c2ecf20Sopenharmony_ci	return ret;
48288c2ecf20Sopenharmony_ci}
48298c2ecf20Sopenharmony_ci
48308c2ecf20Sopenharmony_cistatic int ath11k_mac_op_add_chanctx(struct ieee80211_hw *hw,
48318c2ecf20Sopenharmony_ci				     struct ieee80211_chanctx_conf *ctx)
48328c2ecf20Sopenharmony_ci{
48338c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
48348c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
48358c2ecf20Sopenharmony_ci
48368c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,
48378c2ecf20Sopenharmony_ci		   "mac chanctx add freq %hu width %d ptr %pK\n",
48388c2ecf20Sopenharmony_ci		   ctx->def.chan->center_freq, ctx->def.width, ctx);
48398c2ecf20Sopenharmony_ci
48408c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
48418c2ecf20Sopenharmony_ci
48428c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
48438c2ecf20Sopenharmony_ci	/* TODO: In case of multiple channel context, populate rx_channel from
48448c2ecf20Sopenharmony_ci	 * Rx PPDU desc information.
48458c2ecf20Sopenharmony_ci	 */
48468c2ecf20Sopenharmony_ci	ar->rx_channel = ctx->def.chan;
48478c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
48488c2ecf20Sopenharmony_ci
48498c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
48508c2ecf20Sopenharmony_ci
48518c2ecf20Sopenharmony_ci	return 0;
48528c2ecf20Sopenharmony_ci}
48538c2ecf20Sopenharmony_ci
48548c2ecf20Sopenharmony_cistatic void ath11k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
48558c2ecf20Sopenharmony_ci					 struct ieee80211_chanctx_conf *ctx)
48568c2ecf20Sopenharmony_ci{
48578c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
48588c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
48598c2ecf20Sopenharmony_ci
48608c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,
48618c2ecf20Sopenharmony_ci		   "mac chanctx remove freq %hu width %d ptr %pK\n",
48628c2ecf20Sopenharmony_ci		   ctx->def.chan->center_freq, ctx->def.width, ctx);
48638c2ecf20Sopenharmony_ci
48648c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
48658c2ecf20Sopenharmony_ci
48668c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
48678c2ecf20Sopenharmony_ci	/* TODO: In case of there is one more channel context left, populate
48688c2ecf20Sopenharmony_ci	 * rx_channel with the channel of that remaining channel context.
48698c2ecf20Sopenharmony_ci	 */
48708c2ecf20Sopenharmony_ci	ar->rx_channel = NULL;
48718c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
48728c2ecf20Sopenharmony_ci
48738c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
48748c2ecf20Sopenharmony_ci}
48758c2ecf20Sopenharmony_ci
48768c2ecf20Sopenharmony_cistatic inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar)
48778c2ecf20Sopenharmony_ci{
48788c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
48798c2ecf20Sopenharmony_ci
48808c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
48818c2ecf20Sopenharmony_ci		return -ESHUTDOWN;
48828c2ecf20Sopenharmony_ci
48838c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&ar->vdev_setup_done,
48848c2ecf20Sopenharmony_ci					 ATH11K_VDEV_SETUP_TIMEOUT_HZ))
48858c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
48868c2ecf20Sopenharmony_ci
48878c2ecf20Sopenharmony_ci	return ar->last_wmi_vdev_start_status ? -EINVAL : 0;
48888c2ecf20Sopenharmony_ci}
48898c2ecf20Sopenharmony_ci
48908c2ecf20Sopenharmony_cistatic int
48918c2ecf20Sopenharmony_ciath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
48928c2ecf20Sopenharmony_ci			      const struct cfg80211_chan_def *chandef,
48938c2ecf20Sopenharmony_ci			      bool restart)
48948c2ecf20Sopenharmony_ci{
48958c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
48968c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
48978c2ecf20Sopenharmony_ci	struct wmi_vdev_start_req_arg arg = {};
48988c2ecf20Sopenharmony_ci	int he_support = arvif->vif->bss_conf.he_support;
48998c2ecf20Sopenharmony_ci	int ret = 0;
49008c2ecf20Sopenharmony_ci
49018c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
49028c2ecf20Sopenharmony_ci
49038c2ecf20Sopenharmony_ci	reinit_completion(&ar->vdev_setup_done);
49048c2ecf20Sopenharmony_ci
49058c2ecf20Sopenharmony_ci	arg.vdev_id = arvif->vdev_id;
49068c2ecf20Sopenharmony_ci	arg.dtim_period = arvif->dtim_period;
49078c2ecf20Sopenharmony_ci	arg.bcn_intval = arvif->beacon_interval;
49088c2ecf20Sopenharmony_ci
49098c2ecf20Sopenharmony_ci	arg.channel.freq = chandef->chan->center_freq;
49108c2ecf20Sopenharmony_ci	arg.channel.band_center_freq1 = chandef->center_freq1;
49118c2ecf20Sopenharmony_ci	arg.channel.band_center_freq2 = chandef->center_freq2;
49128c2ecf20Sopenharmony_ci	arg.channel.mode =
49138c2ecf20Sopenharmony_ci		ath11k_phymodes[chandef->chan->band][chandef->width];
49148c2ecf20Sopenharmony_ci
49158c2ecf20Sopenharmony_ci	arg.channel.min_power = 0;
49168c2ecf20Sopenharmony_ci	arg.channel.max_power = chandef->chan->max_power * 2;
49178c2ecf20Sopenharmony_ci	arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
49188c2ecf20Sopenharmony_ci	arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
49198c2ecf20Sopenharmony_ci
49208c2ecf20Sopenharmony_ci	arg.pref_tx_streams = ar->num_tx_chains;
49218c2ecf20Sopenharmony_ci	arg.pref_rx_streams = ar->num_rx_chains;
49228c2ecf20Sopenharmony_ci
49238c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
49248c2ecf20Sopenharmony_ci		arg.ssid = arvif->u.ap.ssid;
49258c2ecf20Sopenharmony_ci		arg.ssid_len = arvif->u.ap.ssid_len;
49268c2ecf20Sopenharmony_ci		arg.hidden_ssid = arvif->u.ap.hidden_ssid;
49278c2ecf20Sopenharmony_ci
49288c2ecf20Sopenharmony_ci		/* For now allow DFS for AP mode */
49298c2ecf20Sopenharmony_ci		arg.channel.chan_radar =
49308c2ecf20Sopenharmony_ci			!!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
49318c2ecf20Sopenharmony_ci
49328c2ecf20Sopenharmony_ci		arg.channel.passive = arg.channel.chan_radar;
49338c2ecf20Sopenharmony_ci
49348c2ecf20Sopenharmony_ci		spin_lock_bh(&ab->base_lock);
49358c2ecf20Sopenharmony_ci		arg.regdomain = ar->ab->dfs_region;
49368c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
49378c2ecf20Sopenharmony_ci
49388c2ecf20Sopenharmony_ci		/* TODO: Notify if secondary 80Mhz also needs radar detection */
49398c2ecf20Sopenharmony_ci		if (he_support) {
49408c2ecf20Sopenharmony_ci			ret = ath11k_set_he_mu_sounding_mode(ar, arvif);
49418c2ecf20Sopenharmony_ci			if (ret) {
49428c2ecf20Sopenharmony_ci				ath11k_warn(ar->ab, "failed to set he mode vdev %i\n",
49438c2ecf20Sopenharmony_ci					    arg.vdev_id);
49448c2ecf20Sopenharmony_ci				return ret;
49458c2ecf20Sopenharmony_ci			}
49468c2ecf20Sopenharmony_ci		}
49478c2ecf20Sopenharmony_ci	}
49488c2ecf20Sopenharmony_ci
49498c2ecf20Sopenharmony_ci	arg.channel.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR);
49508c2ecf20Sopenharmony_ci
49518c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,
49528c2ecf20Sopenharmony_ci		   "mac vdev %d start center_freq %d phymode %s\n",
49538c2ecf20Sopenharmony_ci		   arg.vdev_id, arg.channel.freq,
49548c2ecf20Sopenharmony_ci		   ath11k_wmi_phymode_str(arg.channel.mode));
49558c2ecf20Sopenharmony_ci
49568c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_start(ar, &arg, restart);
49578c2ecf20Sopenharmony_ci	if (ret) {
49588c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to %s WMI vdev %i\n",
49598c2ecf20Sopenharmony_ci			    restart ? "restart" : "start", arg.vdev_id);
49608c2ecf20Sopenharmony_ci		return ret;
49618c2ecf20Sopenharmony_ci	}
49628c2ecf20Sopenharmony_ci
49638c2ecf20Sopenharmony_ci	ret = ath11k_mac_vdev_setup_sync(ar);
49648c2ecf20Sopenharmony_ci	if (ret) {
49658c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to synchronize setup for vdev %i %s: %d\n",
49668c2ecf20Sopenharmony_ci			    arg.vdev_id, restart ? "restart" : "start", ret);
49678c2ecf20Sopenharmony_ci		return ret;
49688c2ecf20Sopenharmony_ci	}
49698c2ecf20Sopenharmony_ci
49708c2ecf20Sopenharmony_ci	ar->num_started_vdevs++;
49718c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,  "vdev %pM started, vdev_id %d\n",
49728c2ecf20Sopenharmony_ci		   arvif->vif->addr, arvif->vdev_id);
49738c2ecf20Sopenharmony_ci
49748c2ecf20Sopenharmony_ci	/* Enable CAC Flag in the driver by checking the channel DFS cac time,
49758c2ecf20Sopenharmony_ci	 * i.e dfs_cac_ms value which will be valid only for radar channels
49768c2ecf20Sopenharmony_ci	 * and state as NL80211_DFS_USABLE which indicates CAC needs to be
49778c2ecf20Sopenharmony_ci	 * done before channel usage. This flags is used to drop rx packets.
49788c2ecf20Sopenharmony_ci	 * during CAC.
49798c2ecf20Sopenharmony_ci	 */
49808c2ecf20Sopenharmony_ci	/* TODO Set the flag for other interface types as required */
49818c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_AP &&
49828c2ecf20Sopenharmony_ci	    chandef->chan->dfs_cac_ms &&
49838c2ecf20Sopenharmony_ci	    chandef->chan->dfs_state == NL80211_DFS_USABLE) {
49848c2ecf20Sopenharmony_ci		set_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
49858c2ecf20Sopenharmony_ci		ath11k_dbg(ab, ATH11K_DBG_MAC,
49868c2ecf20Sopenharmony_ci			   "CAC Started in chan_freq %d for vdev %d\n",
49878c2ecf20Sopenharmony_ci			   arg.channel.freq, arg.vdev_id);
49888c2ecf20Sopenharmony_ci	}
49898c2ecf20Sopenharmony_ci
49908c2ecf20Sopenharmony_ci	ret = ath11k_mac_set_txbf_conf(arvif);
49918c2ecf20Sopenharmony_ci	if (ret)
49928c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to set txbf conf for vdev %d: %d\n",
49938c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
49948c2ecf20Sopenharmony_ci
49958c2ecf20Sopenharmony_ci	return 0;
49968c2ecf20Sopenharmony_ci}
49978c2ecf20Sopenharmony_ci
49988c2ecf20Sopenharmony_cistatic int ath11k_mac_vdev_stop(struct ath11k_vif *arvif)
49998c2ecf20Sopenharmony_ci{
50008c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
50018c2ecf20Sopenharmony_ci	int ret;
50028c2ecf20Sopenharmony_ci
50038c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
50048c2ecf20Sopenharmony_ci
50058c2ecf20Sopenharmony_ci	reinit_completion(&ar->vdev_setup_done);
50068c2ecf20Sopenharmony_ci
50078c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
50088c2ecf20Sopenharmony_ci
50098c2ecf20Sopenharmony_ci	ar->vdev_stop_status.stop_in_progress = true;
50108c2ecf20Sopenharmony_ci	ar->vdev_stop_status.vdev_id = arvif->vdev_id;
50118c2ecf20Sopenharmony_ci
50128c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
50138c2ecf20Sopenharmony_ci
50148c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_stop(ar, arvif->vdev_id);
50158c2ecf20Sopenharmony_ci	if (ret) {
50168c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n",
50178c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
50188c2ecf20Sopenharmony_ci		goto err;
50198c2ecf20Sopenharmony_ci	}
50208c2ecf20Sopenharmony_ci
50218c2ecf20Sopenharmony_ci	ret = ath11k_mac_vdev_setup_sync(ar);
50228c2ecf20Sopenharmony_ci	if (ret) {
50238c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n",
50248c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
50258c2ecf20Sopenharmony_ci		goto err;
50268c2ecf20Sopenharmony_ci	}
50278c2ecf20Sopenharmony_ci
50288c2ecf20Sopenharmony_ci	WARN_ON(ar->num_started_vdevs == 0);
50298c2ecf20Sopenharmony_ci
50308c2ecf20Sopenharmony_ci	ar->num_started_vdevs--;
50318c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n",
50328c2ecf20Sopenharmony_ci		   arvif->vif->addr, arvif->vdev_id);
50338c2ecf20Sopenharmony_ci
50348c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) {
50358c2ecf20Sopenharmony_ci		clear_bit(ATH11K_CAC_RUNNING, &ar->dev_flags);
50368c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "CAC Stopped for vdev %d\n",
50378c2ecf20Sopenharmony_ci			   arvif->vdev_id);
50388c2ecf20Sopenharmony_ci	}
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci	return 0;
50418c2ecf20Sopenharmony_cierr:
50428c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
50438c2ecf20Sopenharmony_ci	ar->vdev_stop_status.stop_in_progress = false;
50448c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
50458c2ecf20Sopenharmony_ci
50468c2ecf20Sopenharmony_ci	return ret;
50478c2ecf20Sopenharmony_ci}
50488c2ecf20Sopenharmony_ci
50498c2ecf20Sopenharmony_cistatic int ath11k_mac_vdev_start(struct ath11k_vif *arvif,
50508c2ecf20Sopenharmony_ci				 const struct cfg80211_chan_def *chandef)
50518c2ecf20Sopenharmony_ci{
50528c2ecf20Sopenharmony_ci	return ath11k_mac_vdev_start_restart(arvif, chandef, false);
50538c2ecf20Sopenharmony_ci}
50548c2ecf20Sopenharmony_ci
50558c2ecf20Sopenharmony_cistatic int ath11k_mac_vdev_restart(struct ath11k_vif *arvif,
50568c2ecf20Sopenharmony_ci				   const struct cfg80211_chan_def *chandef)
50578c2ecf20Sopenharmony_ci{
50588c2ecf20Sopenharmony_ci	return ath11k_mac_vdev_start_restart(arvif, chandef, true);
50598c2ecf20Sopenharmony_ci}
50608c2ecf20Sopenharmony_ci
50618c2ecf20Sopenharmony_cistruct ath11k_mac_change_chanctx_arg {
50628c2ecf20Sopenharmony_ci	struct ieee80211_chanctx_conf *ctx;
50638c2ecf20Sopenharmony_ci	struct ieee80211_vif_chanctx_switch *vifs;
50648c2ecf20Sopenharmony_ci	int n_vifs;
50658c2ecf20Sopenharmony_ci	int next_vif;
50668c2ecf20Sopenharmony_ci};
50678c2ecf20Sopenharmony_ci
50688c2ecf20Sopenharmony_cistatic void
50698c2ecf20Sopenharmony_ciath11k_mac_change_chanctx_cnt_iter(void *data, u8 *mac,
50708c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif)
50718c2ecf20Sopenharmony_ci{
50728c2ecf20Sopenharmony_ci	struct ath11k_mac_change_chanctx_arg *arg = data;
50738c2ecf20Sopenharmony_ci
50748c2ecf20Sopenharmony_ci	if (rcu_access_pointer(vif->chanctx_conf) != arg->ctx)
50758c2ecf20Sopenharmony_ci		return;
50768c2ecf20Sopenharmony_ci
50778c2ecf20Sopenharmony_ci	arg->n_vifs++;
50788c2ecf20Sopenharmony_ci}
50798c2ecf20Sopenharmony_ci
50808c2ecf20Sopenharmony_cistatic void
50818c2ecf20Sopenharmony_ciath11k_mac_change_chanctx_fill_iter(void *data, u8 *mac,
50828c2ecf20Sopenharmony_ci				    struct ieee80211_vif *vif)
50838c2ecf20Sopenharmony_ci{
50848c2ecf20Sopenharmony_ci	struct ath11k_mac_change_chanctx_arg *arg = data;
50858c2ecf20Sopenharmony_ci	struct ieee80211_chanctx_conf *ctx;
50868c2ecf20Sopenharmony_ci
50878c2ecf20Sopenharmony_ci	ctx = rcu_access_pointer(vif->chanctx_conf);
50888c2ecf20Sopenharmony_ci	if (ctx != arg->ctx)
50898c2ecf20Sopenharmony_ci		return;
50908c2ecf20Sopenharmony_ci
50918c2ecf20Sopenharmony_ci	if (WARN_ON(arg->next_vif == arg->n_vifs))
50928c2ecf20Sopenharmony_ci		return;
50938c2ecf20Sopenharmony_ci
50948c2ecf20Sopenharmony_ci	arg->vifs[arg->next_vif].vif = vif;
50958c2ecf20Sopenharmony_ci	arg->vifs[arg->next_vif].old_ctx = ctx;
50968c2ecf20Sopenharmony_ci	arg->vifs[arg->next_vif].new_ctx = ctx;
50978c2ecf20Sopenharmony_ci	arg->next_vif++;
50988c2ecf20Sopenharmony_ci}
50998c2ecf20Sopenharmony_ci
51008c2ecf20Sopenharmony_cistatic void
51018c2ecf20Sopenharmony_ciath11k_mac_update_vif_chan(struct ath11k *ar,
51028c2ecf20Sopenharmony_ci			   struct ieee80211_vif_chanctx_switch *vifs,
51038c2ecf20Sopenharmony_ci			   int n_vifs)
51048c2ecf20Sopenharmony_ci{
51058c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
51068c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif;
51078c2ecf20Sopenharmony_ci	int ret;
51088c2ecf20Sopenharmony_ci	int i;
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
51118c2ecf20Sopenharmony_ci
51128c2ecf20Sopenharmony_ci	for (i = 0; i < n_vifs; i++) {
51138c2ecf20Sopenharmony_ci		arvif = (void *)vifs[i].vif->drv_priv;
51148c2ecf20Sopenharmony_ci
51158c2ecf20Sopenharmony_ci		ath11k_dbg(ab, ATH11K_DBG_MAC,
51168c2ecf20Sopenharmony_ci			   "mac chanctx switch vdev_id %i freq %hu->%hu width %d->%d\n",
51178c2ecf20Sopenharmony_ci			   arvif->vdev_id,
51188c2ecf20Sopenharmony_ci			   vifs[i].old_ctx->def.chan->center_freq,
51198c2ecf20Sopenharmony_ci			   vifs[i].new_ctx->def.chan->center_freq,
51208c2ecf20Sopenharmony_ci			   vifs[i].old_ctx->def.width,
51218c2ecf20Sopenharmony_ci			   vifs[i].new_ctx->def.width);
51228c2ecf20Sopenharmony_ci
51238c2ecf20Sopenharmony_ci		if (WARN_ON(!arvif->is_started))
51248c2ecf20Sopenharmony_ci			continue;
51258c2ecf20Sopenharmony_ci
51268c2ecf20Sopenharmony_ci		if (WARN_ON(!arvif->is_up))
51278c2ecf20Sopenharmony_ci			continue;
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_down(ar, arvif->vdev_id);
51308c2ecf20Sopenharmony_ci		if (ret) {
51318c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to down vdev %d: %d\n",
51328c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
51338c2ecf20Sopenharmony_ci			continue;
51348c2ecf20Sopenharmony_ci		}
51358c2ecf20Sopenharmony_ci	}
51368c2ecf20Sopenharmony_ci
51378c2ecf20Sopenharmony_ci	/* All relevant vdevs are downed and associated channel resources
51388c2ecf20Sopenharmony_ci	 * should be available for the channel switch now.
51398c2ecf20Sopenharmony_ci	 */
51408c2ecf20Sopenharmony_ci
51418c2ecf20Sopenharmony_ci	/* TODO: Update ar->rx_channel */
51428c2ecf20Sopenharmony_ci
51438c2ecf20Sopenharmony_ci	for (i = 0; i < n_vifs; i++) {
51448c2ecf20Sopenharmony_ci		arvif = (void *)vifs[i].vif->drv_priv;
51458c2ecf20Sopenharmony_ci
51468c2ecf20Sopenharmony_ci		if (WARN_ON(!arvif->is_started))
51478c2ecf20Sopenharmony_ci			continue;
51488c2ecf20Sopenharmony_ci
51498c2ecf20Sopenharmony_ci		if (WARN_ON(!arvif->is_up))
51508c2ecf20Sopenharmony_ci			continue;
51518c2ecf20Sopenharmony_ci
51528c2ecf20Sopenharmony_ci		ret = ath11k_mac_vdev_restart(arvif, &vifs[i].new_ctx->def);
51538c2ecf20Sopenharmony_ci		if (ret) {
51548c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to restart vdev %d: %d\n",
51558c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
51568c2ecf20Sopenharmony_ci			continue;
51578c2ecf20Sopenharmony_ci		}
51588c2ecf20Sopenharmony_ci
51598c2ecf20Sopenharmony_ci		ret = ath11k_mac_setup_bcn_tmpl(arvif);
51608c2ecf20Sopenharmony_ci		if (ret)
51618c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to update bcn tmpl during csa: %d\n",
51628c2ecf20Sopenharmony_ci				    ret);
51638c2ecf20Sopenharmony_ci
51648c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
51658c2ecf20Sopenharmony_ci					 arvif->bssid);
51668c2ecf20Sopenharmony_ci		if (ret) {
51678c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to bring vdev up %d: %d\n",
51688c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
51698c2ecf20Sopenharmony_ci			continue;
51708c2ecf20Sopenharmony_ci		}
51718c2ecf20Sopenharmony_ci	}
51728c2ecf20Sopenharmony_ci}
51738c2ecf20Sopenharmony_ci
51748c2ecf20Sopenharmony_cistatic void
51758c2ecf20Sopenharmony_ciath11k_mac_update_active_vif_chan(struct ath11k *ar,
51768c2ecf20Sopenharmony_ci				  struct ieee80211_chanctx_conf *ctx)
51778c2ecf20Sopenharmony_ci{
51788c2ecf20Sopenharmony_ci	struct ath11k_mac_change_chanctx_arg arg = { .ctx = ctx };
51798c2ecf20Sopenharmony_ci
51808c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
51818c2ecf20Sopenharmony_ci
51828c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(ar->hw,
51838c2ecf20Sopenharmony_ci						   IEEE80211_IFACE_ITER_NORMAL,
51848c2ecf20Sopenharmony_ci						   ath11k_mac_change_chanctx_cnt_iter,
51858c2ecf20Sopenharmony_ci						   &arg);
51868c2ecf20Sopenharmony_ci	if (arg.n_vifs == 0)
51878c2ecf20Sopenharmony_ci		return;
51888c2ecf20Sopenharmony_ci
51898c2ecf20Sopenharmony_ci	arg.vifs = kcalloc(arg.n_vifs, sizeof(arg.vifs[0]), GFP_KERNEL);
51908c2ecf20Sopenharmony_ci	if (!arg.vifs)
51918c2ecf20Sopenharmony_ci		return;
51928c2ecf20Sopenharmony_ci
51938c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(ar->hw,
51948c2ecf20Sopenharmony_ci						   IEEE80211_IFACE_ITER_NORMAL,
51958c2ecf20Sopenharmony_ci						   ath11k_mac_change_chanctx_fill_iter,
51968c2ecf20Sopenharmony_ci						   &arg);
51978c2ecf20Sopenharmony_ci
51988c2ecf20Sopenharmony_ci	ath11k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs);
51998c2ecf20Sopenharmony_ci
52008c2ecf20Sopenharmony_ci	kfree(arg.vifs);
52018c2ecf20Sopenharmony_ci}
52028c2ecf20Sopenharmony_ci
52038c2ecf20Sopenharmony_cistatic void ath11k_mac_op_change_chanctx(struct ieee80211_hw *hw,
52048c2ecf20Sopenharmony_ci					 struct ieee80211_chanctx_conf *ctx,
52058c2ecf20Sopenharmony_ci					 u32 changed)
52068c2ecf20Sopenharmony_ci{
52078c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
52088c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
52098c2ecf20Sopenharmony_ci
52108c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
52118c2ecf20Sopenharmony_ci
52128c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,
52138c2ecf20Sopenharmony_ci		   "mac chanctx change freq %hu width %d ptr %pK changed %x\n",
52148c2ecf20Sopenharmony_ci		   ctx->def.chan->center_freq, ctx->def.width, ctx, changed);
52158c2ecf20Sopenharmony_ci
52168c2ecf20Sopenharmony_ci	/* This shouldn't really happen because channel switching should use
52178c2ecf20Sopenharmony_ci	 * switch_vif_chanctx().
52188c2ecf20Sopenharmony_ci	 */
52198c2ecf20Sopenharmony_ci	if (WARN_ON(changed & IEEE80211_CHANCTX_CHANGE_CHANNEL))
52208c2ecf20Sopenharmony_ci		goto unlock;
52218c2ecf20Sopenharmony_ci
52228c2ecf20Sopenharmony_ci	if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH)
52238c2ecf20Sopenharmony_ci		ath11k_mac_update_active_vif_chan(ar, ctx);
52248c2ecf20Sopenharmony_ci
52258c2ecf20Sopenharmony_ci	/* TODO: Recalc radar detection */
52268c2ecf20Sopenharmony_ci
52278c2ecf20Sopenharmony_ciunlock:
52288c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
52298c2ecf20Sopenharmony_ci}
52308c2ecf20Sopenharmony_ci
52318c2ecf20Sopenharmony_cistatic int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
52328c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif)
52338c2ecf20Sopenharmony_ci{
52348c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
52358c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
52368c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
52378c2ecf20Sopenharmony_ci	int ret;
52388c2ecf20Sopenharmony_ci
52398c2ecf20Sopenharmony_ci	if (WARN_ON(arvif->is_started))
52408c2ecf20Sopenharmony_ci		return -EBUSY;
52418c2ecf20Sopenharmony_ci
52428c2ecf20Sopenharmony_ci	ret = ath11k_mac_vdev_start(arvif, &arvif->chanctx.def);
52438c2ecf20Sopenharmony_ci	if (ret) {
52448c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n",
52458c2ecf20Sopenharmony_ci			    arvif->vdev_id, vif->addr,
52468c2ecf20Sopenharmony_ci			    arvif->chanctx.def.chan->center_freq, ret);
52478c2ecf20Sopenharmony_ci		return ret;
52488c2ecf20Sopenharmony_ci	}
52498c2ecf20Sopenharmony_ci
52508c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
52518c2ecf20Sopenharmony_ci		ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id);
52528c2ecf20Sopenharmony_ci		if (ret) {
52538c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed put monitor up: %d\n", ret);
52548c2ecf20Sopenharmony_ci			return ret;
52558c2ecf20Sopenharmony_ci		}
52568c2ecf20Sopenharmony_ci	}
52578c2ecf20Sopenharmony_ci
52588c2ecf20Sopenharmony_ci	arvif->is_started = true;
52598c2ecf20Sopenharmony_ci
52608c2ecf20Sopenharmony_ci	/* TODO: Setup ps and cts/rts protection */
52618c2ecf20Sopenharmony_ci	return 0;
52628c2ecf20Sopenharmony_ci}
52638c2ecf20Sopenharmony_ci
52648c2ecf20Sopenharmony_cistatic int
52658c2ecf20Sopenharmony_ciath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
52668c2ecf20Sopenharmony_ci				 struct ieee80211_vif *vif,
52678c2ecf20Sopenharmony_ci				 struct ieee80211_chanctx_conf *ctx)
52688c2ecf20Sopenharmony_ci{
52698c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
52708c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
52718c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
52728c2ecf20Sopenharmony_ci	int ret;
52738c2ecf20Sopenharmony_ci	struct peer_create_params param;
52748c2ecf20Sopenharmony_ci
52758c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
52768c2ecf20Sopenharmony_ci
52778c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,
52788c2ecf20Sopenharmony_ci		   "mac chanctx assign ptr %pK vdev_id %i\n",
52798c2ecf20Sopenharmony_ci		   ctx, arvif->vdev_id);
52808c2ecf20Sopenharmony_ci
52818c2ecf20Sopenharmony_ci	/* for QCA6390 bss peer must be created before vdev_start */
52828c2ecf20Sopenharmony_ci	if (ab->hw_params.vdev_start_delay &&
52838c2ecf20Sopenharmony_ci	    arvif->vdev_type != WMI_VDEV_TYPE_AP &&
52848c2ecf20Sopenharmony_ci	    arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
52858c2ecf20Sopenharmony_ci	    !ath11k_peer_find_by_vdev_id(ab, arvif->vdev_id)) {
52868c2ecf20Sopenharmony_ci		memcpy(&arvif->chanctx, ctx, sizeof(*ctx));
52878c2ecf20Sopenharmony_ci		ret = 0;
52888c2ecf20Sopenharmony_ci		goto out;
52898c2ecf20Sopenharmony_ci	}
52908c2ecf20Sopenharmony_ci
52918c2ecf20Sopenharmony_ci	if (WARN_ON(arvif->is_started)) {
52928c2ecf20Sopenharmony_ci		ret = -EBUSY;
52938c2ecf20Sopenharmony_ci		goto out;
52948c2ecf20Sopenharmony_ci	}
52958c2ecf20Sopenharmony_ci
52968c2ecf20Sopenharmony_ci	if (ab->hw_params.vdev_start_delay &&
52978c2ecf20Sopenharmony_ci	    arvif->vdev_type != WMI_VDEV_TYPE_AP &&
52988c2ecf20Sopenharmony_ci	    arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
52998c2ecf20Sopenharmony_ci		param.vdev_id = arvif->vdev_id;
53008c2ecf20Sopenharmony_ci		param.peer_type = WMI_PEER_TYPE_DEFAULT;
53018c2ecf20Sopenharmony_ci		param.peer_addr = ar->mac_addr;
53028c2ecf20Sopenharmony_ci
53038c2ecf20Sopenharmony_ci		ret = ath11k_peer_create(ar, arvif, NULL, &param);
53048c2ecf20Sopenharmony_ci		if (ret) {
53058c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to create peer after vdev start delay: %d",
53068c2ecf20Sopenharmony_ci				    ret);
53078c2ecf20Sopenharmony_ci			goto out;
53088c2ecf20Sopenharmony_ci		}
53098c2ecf20Sopenharmony_ci	}
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci	ret = ath11k_mac_vdev_start(arvif, &ctx->def);
53128c2ecf20Sopenharmony_ci	if (ret) {
53138c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n",
53148c2ecf20Sopenharmony_ci			    arvif->vdev_id, vif->addr,
53158c2ecf20Sopenharmony_ci			    ctx->def.chan->center_freq, ret);
53168c2ecf20Sopenharmony_ci		goto out;
53178c2ecf20Sopenharmony_ci	}
53188c2ecf20Sopenharmony_ci	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
53198c2ecf20Sopenharmony_ci		ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id);
53208c2ecf20Sopenharmony_ci		if (ret)
53218c2ecf20Sopenharmony_ci			goto out;
53228c2ecf20Sopenharmony_ci	}
53238c2ecf20Sopenharmony_ci
53248c2ecf20Sopenharmony_ci	arvif->is_started = true;
53258c2ecf20Sopenharmony_ci
53268c2ecf20Sopenharmony_ci	/* TODO: Setup ps and cts/rts protection */
53278c2ecf20Sopenharmony_ci
53288c2ecf20Sopenharmony_ci	ret = 0;
53298c2ecf20Sopenharmony_ci
53308c2ecf20Sopenharmony_ciout:
53318c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
53328c2ecf20Sopenharmony_ci
53338c2ecf20Sopenharmony_ci	return ret;
53348c2ecf20Sopenharmony_ci}
53358c2ecf20Sopenharmony_ci
53368c2ecf20Sopenharmony_cistatic void
53378c2ecf20Sopenharmony_ciath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
53388c2ecf20Sopenharmony_ci				   struct ieee80211_vif *vif,
53398c2ecf20Sopenharmony_ci				   struct ieee80211_chanctx_conf *ctx)
53408c2ecf20Sopenharmony_ci{
53418c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
53428c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
53438c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
53448c2ecf20Sopenharmony_ci	struct ath11k_peer *peer;
53458c2ecf20Sopenharmony_ci	int ret;
53468c2ecf20Sopenharmony_ci
53478c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
53488c2ecf20Sopenharmony_ci
53498c2ecf20Sopenharmony_ci	ath11k_dbg(ab, ATH11K_DBG_MAC,
53508c2ecf20Sopenharmony_ci		   "mac chanctx unassign ptr %pK vdev_id %i\n",
53518c2ecf20Sopenharmony_ci		   ctx, arvif->vdev_id);
53528c2ecf20Sopenharmony_ci
53538c2ecf20Sopenharmony_ci	WARN_ON(!arvif->is_started);
53548c2ecf20Sopenharmony_ci
53558c2ecf20Sopenharmony_ci	if (ab->hw_params.vdev_start_delay &&
53568c2ecf20Sopenharmony_ci	    arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
53578c2ecf20Sopenharmony_ci		spin_lock_bh(&ab->base_lock);
53588c2ecf20Sopenharmony_ci		peer = ath11k_peer_find_by_addr(ab, ar->mac_addr);
53598c2ecf20Sopenharmony_ci		spin_unlock_bh(&ab->base_lock);
53608c2ecf20Sopenharmony_ci		if (peer)
53618c2ecf20Sopenharmony_ci			ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);
53628c2ecf20Sopenharmony_ci	}
53638c2ecf20Sopenharmony_ci
53648c2ecf20Sopenharmony_ci	ret = ath11k_mac_vdev_stop(arvif);
53658c2ecf20Sopenharmony_ci	if (ret)
53668c2ecf20Sopenharmony_ci		ath11k_warn(ab, "failed to stop vdev %i: %d\n",
53678c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
53688c2ecf20Sopenharmony_ci
53698c2ecf20Sopenharmony_ci	arvif->is_started = false;
53708c2ecf20Sopenharmony_ci
53718c2ecf20Sopenharmony_ci	if (ab->hw_params.vdev_start_delay &&
53728c2ecf20Sopenharmony_ci	    arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
53738c2ecf20Sopenharmony_ci		ath11k_wmi_vdev_down(ar, arvif->vdev_id);
53748c2ecf20Sopenharmony_ci
53758c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
53768c2ecf20Sopenharmony_ci}
53778c2ecf20Sopenharmony_ci
53788c2ecf20Sopenharmony_cistatic int
53798c2ecf20Sopenharmony_ciath11k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
53808c2ecf20Sopenharmony_ci				 struct ieee80211_vif_chanctx_switch *vifs,
53818c2ecf20Sopenharmony_ci				 int n_vifs,
53828c2ecf20Sopenharmony_ci				 enum ieee80211_chanctx_switch_mode mode)
53838c2ecf20Sopenharmony_ci{
53848c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
53858c2ecf20Sopenharmony_ci
53868c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
53878c2ecf20Sopenharmony_ci
53888c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
53898c2ecf20Sopenharmony_ci		   "mac chanctx switch n_vifs %d mode %d\n",
53908c2ecf20Sopenharmony_ci		   n_vifs, mode);
53918c2ecf20Sopenharmony_ci	ath11k_mac_update_vif_chan(ar, vifs, n_vifs);
53928c2ecf20Sopenharmony_ci
53938c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
53948c2ecf20Sopenharmony_ci
53958c2ecf20Sopenharmony_ci	return 0;
53968c2ecf20Sopenharmony_ci}
53978c2ecf20Sopenharmony_ci
53988c2ecf20Sopenharmony_cistatic int
53998c2ecf20Sopenharmony_ciath11k_set_vdev_param_to_all_vifs(struct ath11k *ar, int param, u32 value)
54008c2ecf20Sopenharmony_ci{
54018c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif;
54028c2ecf20Sopenharmony_ci	int ret = 0;
54038c2ecf20Sopenharmony_ci
54048c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
54058c2ecf20Sopenharmony_ci	list_for_each_entry(arvif, &ar->arvifs, list) {
54068c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "setting mac vdev %d param %d value %d\n",
54078c2ecf20Sopenharmony_ci			   param, arvif->vdev_id, value);
54088c2ecf20Sopenharmony_ci
54098c2ecf20Sopenharmony_ci		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
54108c2ecf20Sopenharmony_ci						    param, value);
54118c2ecf20Sopenharmony_ci		if (ret) {
54128c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to set param %d for vdev %d: %d\n",
54138c2ecf20Sopenharmony_ci				    param, arvif->vdev_id, ret);
54148c2ecf20Sopenharmony_ci			break;
54158c2ecf20Sopenharmony_ci		}
54168c2ecf20Sopenharmony_ci	}
54178c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
54188c2ecf20Sopenharmony_ci	return ret;
54198c2ecf20Sopenharmony_ci}
54208c2ecf20Sopenharmony_ci
54218c2ecf20Sopenharmony_ci/* mac80211 stores device specific RTS/Fragmentation threshold value,
54228c2ecf20Sopenharmony_ci * this is set interface specific to firmware from ath11k driver
54238c2ecf20Sopenharmony_ci */
54248c2ecf20Sopenharmony_cistatic int ath11k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
54258c2ecf20Sopenharmony_ci{
54268c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
54278c2ecf20Sopenharmony_ci	int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
54288c2ecf20Sopenharmony_ci
54298c2ecf20Sopenharmony_ci	return ath11k_set_vdev_param_to_all_vifs(ar, param_id, value);
54308c2ecf20Sopenharmony_ci}
54318c2ecf20Sopenharmony_ci
54328c2ecf20Sopenharmony_cistatic int ath11k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
54338c2ecf20Sopenharmony_ci{
54348c2ecf20Sopenharmony_ci	/* Even though there's a WMI vdev param for fragmentation threshold no
54358c2ecf20Sopenharmony_ci	 * known firmware actually implements it. Moreover it is not possible to
54368c2ecf20Sopenharmony_ci	 * rely frame fragmentation to mac80211 because firmware clears the
54378c2ecf20Sopenharmony_ci	 * "more fragments" bit in frame control making it impossible for remote
54388c2ecf20Sopenharmony_ci	 * devices to reassemble frames.
54398c2ecf20Sopenharmony_ci	 *
54408c2ecf20Sopenharmony_ci	 * Hence implement a dummy callback just to say fragmentation isn't
54418c2ecf20Sopenharmony_ci	 * supported. This effectively prevents mac80211 from doing frame
54428c2ecf20Sopenharmony_ci	 * fragmentation in software.
54438c2ecf20Sopenharmony_ci	 */
54448c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
54458c2ecf20Sopenharmony_ci}
54468c2ecf20Sopenharmony_ci
54478c2ecf20Sopenharmony_cistatic void ath11k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
54488c2ecf20Sopenharmony_ci				u32 queues, bool drop)
54498c2ecf20Sopenharmony_ci{
54508c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
54518c2ecf20Sopenharmony_ci	long time_left;
54528c2ecf20Sopenharmony_ci
54538c2ecf20Sopenharmony_ci	if (drop)
54548c2ecf20Sopenharmony_ci		return;
54558c2ecf20Sopenharmony_ci
54568c2ecf20Sopenharmony_ci	time_left = wait_event_timeout(ar->dp.tx_empty_waitq,
54578c2ecf20Sopenharmony_ci				       (atomic_read(&ar->dp.num_tx_pending) == 0),
54588c2ecf20Sopenharmony_ci				       ATH11K_FLUSH_TIMEOUT);
54598c2ecf20Sopenharmony_ci	if (time_left == 0)
54608c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left);
54618c2ecf20Sopenharmony_ci}
54628c2ecf20Sopenharmony_ci
54638c2ecf20Sopenharmony_cistatic int
54648c2ecf20Sopenharmony_ciath11k_mac_bitrate_mask_num_ht_rates(struct ath11k *ar,
54658c2ecf20Sopenharmony_ci				     enum nl80211_band band,
54668c2ecf20Sopenharmony_ci				     const struct cfg80211_bitrate_mask *mask)
54678c2ecf20Sopenharmony_ci{
54688c2ecf20Sopenharmony_ci	int num_rates = 0;
54698c2ecf20Sopenharmony_ci	int i;
54708c2ecf20Sopenharmony_ci
54718c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++)
54728c2ecf20Sopenharmony_ci		num_rates += hweight16(mask->control[band].ht_mcs[i]);
54738c2ecf20Sopenharmony_ci
54748c2ecf20Sopenharmony_ci	return num_rates;
54758c2ecf20Sopenharmony_ci}
54768c2ecf20Sopenharmony_ci
54778c2ecf20Sopenharmony_cistatic bool
54788c2ecf20Sopenharmony_ciath11k_mac_has_single_legacy_rate(struct ath11k *ar,
54798c2ecf20Sopenharmony_ci				  enum nl80211_band band,
54808c2ecf20Sopenharmony_ci				  const struct cfg80211_bitrate_mask *mask)
54818c2ecf20Sopenharmony_ci{
54828c2ecf20Sopenharmony_ci	int num_rates = 0;
54838c2ecf20Sopenharmony_ci
54848c2ecf20Sopenharmony_ci	num_rates = hweight32(mask->control[band].legacy);
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_ci	if (ath11k_mac_bitrate_mask_num_ht_rates(ar, band, mask))
54878c2ecf20Sopenharmony_ci		return false;
54888c2ecf20Sopenharmony_ci
54898c2ecf20Sopenharmony_ci	if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask))
54908c2ecf20Sopenharmony_ci		return false;
54918c2ecf20Sopenharmony_ci
54928c2ecf20Sopenharmony_ci	return num_rates == 1;
54938c2ecf20Sopenharmony_ci}
54948c2ecf20Sopenharmony_ci
54958c2ecf20Sopenharmony_cistatic bool
54968c2ecf20Sopenharmony_ciath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
54978c2ecf20Sopenharmony_ci				       enum nl80211_band band,
54988c2ecf20Sopenharmony_ci				       const struct cfg80211_bitrate_mask *mask,
54998c2ecf20Sopenharmony_ci				       int *nss)
55008c2ecf20Sopenharmony_ci{
55018c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
55028c2ecf20Sopenharmony_ci	u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
55038c2ecf20Sopenharmony_ci	u8 ht_nss_mask = 0;
55048c2ecf20Sopenharmony_ci	u8 vht_nss_mask = 0;
55058c2ecf20Sopenharmony_ci	int i;
55068c2ecf20Sopenharmony_ci
55078c2ecf20Sopenharmony_ci	/* No need to consider legacy here. Basic rates are always present
55088c2ecf20Sopenharmony_ci	 * in bitrate mask
55098c2ecf20Sopenharmony_ci	 */
55108c2ecf20Sopenharmony_ci
55118c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mask->control[band].ht_mcs); i++) {
55128c2ecf20Sopenharmony_ci		if (mask->control[band].ht_mcs[i] == 0)
55138c2ecf20Sopenharmony_ci			continue;
55148c2ecf20Sopenharmony_ci		else if (mask->control[band].ht_mcs[i] ==
55158c2ecf20Sopenharmony_ci			 sband->ht_cap.mcs.rx_mask[i])
55168c2ecf20Sopenharmony_ci			ht_nss_mask |= BIT(i);
55178c2ecf20Sopenharmony_ci		else
55188c2ecf20Sopenharmony_ci			return false;
55198c2ecf20Sopenharmony_ci	}
55208c2ecf20Sopenharmony_ci
55218c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mask->control[band].vht_mcs); i++) {
55228c2ecf20Sopenharmony_ci		if (mask->control[band].vht_mcs[i] == 0)
55238c2ecf20Sopenharmony_ci			continue;
55248c2ecf20Sopenharmony_ci		else if (mask->control[band].vht_mcs[i] ==
55258c2ecf20Sopenharmony_ci			 ath11k_mac_get_max_vht_mcs_map(vht_mcs_map, i))
55268c2ecf20Sopenharmony_ci			vht_nss_mask |= BIT(i);
55278c2ecf20Sopenharmony_ci		else
55288c2ecf20Sopenharmony_ci			return false;
55298c2ecf20Sopenharmony_ci	}
55308c2ecf20Sopenharmony_ci
55318c2ecf20Sopenharmony_ci	if (ht_nss_mask != vht_nss_mask)
55328c2ecf20Sopenharmony_ci		return false;
55338c2ecf20Sopenharmony_ci
55348c2ecf20Sopenharmony_ci	if (ht_nss_mask == 0)
55358c2ecf20Sopenharmony_ci		return false;
55368c2ecf20Sopenharmony_ci
55378c2ecf20Sopenharmony_ci	if (BIT(fls(ht_nss_mask)) - 1 != ht_nss_mask)
55388c2ecf20Sopenharmony_ci		return false;
55398c2ecf20Sopenharmony_ci
55408c2ecf20Sopenharmony_ci	*nss = fls(ht_nss_mask);
55418c2ecf20Sopenharmony_ci
55428c2ecf20Sopenharmony_ci	return true;
55438c2ecf20Sopenharmony_ci}
55448c2ecf20Sopenharmony_ci
55458c2ecf20Sopenharmony_cistatic int
55468c2ecf20Sopenharmony_ciath11k_mac_get_single_legacy_rate(struct ath11k *ar,
55478c2ecf20Sopenharmony_ci				  enum nl80211_band band,
55488c2ecf20Sopenharmony_ci				  const struct cfg80211_bitrate_mask *mask,
55498c2ecf20Sopenharmony_ci				  u32 *rate, u8 *nss)
55508c2ecf20Sopenharmony_ci{
55518c2ecf20Sopenharmony_ci	int rate_idx;
55528c2ecf20Sopenharmony_ci	u16 bitrate;
55538c2ecf20Sopenharmony_ci	u8 preamble;
55548c2ecf20Sopenharmony_ci	u8 hw_rate;
55558c2ecf20Sopenharmony_ci
55568c2ecf20Sopenharmony_ci	if (hweight32(mask->control[band].legacy) != 1)
55578c2ecf20Sopenharmony_ci		return -EINVAL;
55588c2ecf20Sopenharmony_ci
55598c2ecf20Sopenharmony_ci	rate_idx = ffs(mask->control[band].legacy) - 1;
55608c2ecf20Sopenharmony_ci
55618c2ecf20Sopenharmony_ci	if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ)
55628c2ecf20Sopenharmony_ci		rate_idx += ATH11K_MAC_FIRST_OFDM_RATE_IDX;
55638c2ecf20Sopenharmony_ci
55648c2ecf20Sopenharmony_ci	hw_rate = ath11k_legacy_rates[rate_idx].hw_value;
55658c2ecf20Sopenharmony_ci	bitrate = ath11k_legacy_rates[rate_idx].bitrate;
55668c2ecf20Sopenharmony_ci
55678c2ecf20Sopenharmony_ci	if (ath11k_mac_bitrate_is_cck(bitrate))
55688c2ecf20Sopenharmony_ci		preamble = WMI_RATE_PREAMBLE_CCK;
55698c2ecf20Sopenharmony_ci	else
55708c2ecf20Sopenharmony_ci		preamble = WMI_RATE_PREAMBLE_OFDM;
55718c2ecf20Sopenharmony_ci
55728c2ecf20Sopenharmony_ci	*nss = 1;
55738c2ecf20Sopenharmony_ci	*rate = ATH11K_HW_RATE_CODE(hw_rate, 0, preamble);
55748c2ecf20Sopenharmony_ci
55758c2ecf20Sopenharmony_ci	return 0;
55768c2ecf20Sopenharmony_ci}
55778c2ecf20Sopenharmony_ci
55788c2ecf20Sopenharmony_cistatic int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif,
55798c2ecf20Sopenharmony_ci					    u32 rate, u8 nss, u8 sgi, u8 ldpc)
55808c2ecf20Sopenharmony_ci{
55818c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
55828c2ecf20Sopenharmony_ci	u32 vdev_param;
55838c2ecf20Sopenharmony_ci	int ret;
55848c2ecf20Sopenharmony_ci
55858c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
55868c2ecf20Sopenharmony_ci
55878c2ecf20Sopenharmony_ci	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
55888c2ecf20Sopenharmony_ci		   arvif->vdev_id, rate, nss, sgi);
55898c2ecf20Sopenharmony_ci
55908c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_FIXED_RATE;
55918c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
55928c2ecf20Sopenharmony_ci					    vdev_param, rate);
55938c2ecf20Sopenharmony_ci	if (ret) {
55948c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n",
55958c2ecf20Sopenharmony_ci			    rate, ret);
55968c2ecf20Sopenharmony_ci		return ret;
55978c2ecf20Sopenharmony_ci	}
55988c2ecf20Sopenharmony_ci
55998c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_NSS;
56008c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
56018c2ecf20Sopenharmony_ci					    vdev_param, nss);
56028c2ecf20Sopenharmony_ci	if (ret) {
56038c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set nss param %d: %d\n",
56048c2ecf20Sopenharmony_ci			    nss, ret);
56058c2ecf20Sopenharmony_ci		return ret;
56068c2ecf20Sopenharmony_ci	}
56078c2ecf20Sopenharmony_ci
56088c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_SGI;
56098c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
56108c2ecf20Sopenharmony_ci					    vdev_param, sgi);
56118c2ecf20Sopenharmony_ci	if (ret) {
56128c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n",
56138c2ecf20Sopenharmony_ci			    sgi, ret);
56148c2ecf20Sopenharmony_ci		return ret;
56158c2ecf20Sopenharmony_ci	}
56168c2ecf20Sopenharmony_ci
56178c2ecf20Sopenharmony_ci	vdev_param = WMI_VDEV_PARAM_LDPC;
56188c2ecf20Sopenharmony_ci	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
56198c2ecf20Sopenharmony_ci					    vdev_param, ldpc);
56208c2ecf20Sopenharmony_ci	if (ret) {
56218c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set ldpc param %d: %d\n",
56228c2ecf20Sopenharmony_ci			    ldpc, ret);
56238c2ecf20Sopenharmony_ci		return ret;
56248c2ecf20Sopenharmony_ci	}
56258c2ecf20Sopenharmony_ci
56268c2ecf20Sopenharmony_ci	return 0;
56278c2ecf20Sopenharmony_ci}
56288c2ecf20Sopenharmony_ci
56298c2ecf20Sopenharmony_cistatic bool
56308c2ecf20Sopenharmony_ciath11k_mac_vht_mcs_range_present(struct ath11k *ar,
56318c2ecf20Sopenharmony_ci				 enum nl80211_band band,
56328c2ecf20Sopenharmony_ci				 const struct cfg80211_bitrate_mask *mask)
56338c2ecf20Sopenharmony_ci{
56348c2ecf20Sopenharmony_ci	int i;
56358c2ecf20Sopenharmony_ci	u16 vht_mcs;
56368c2ecf20Sopenharmony_ci
56378c2ecf20Sopenharmony_ci	for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
56388c2ecf20Sopenharmony_ci		vht_mcs = mask->control[band].vht_mcs[i];
56398c2ecf20Sopenharmony_ci
56408c2ecf20Sopenharmony_ci		switch (vht_mcs) {
56418c2ecf20Sopenharmony_ci		case 0:
56428c2ecf20Sopenharmony_ci		case BIT(8) - 1:
56438c2ecf20Sopenharmony_ci		case BIT(9) - 1:
56448c2ecf20Sopenharmony_ci		case BIT(10) - 1:
56458c2ecf20Sopenharmony_ci			break;
56468c2ecf20Sopenharmony_ci		default:
56478c2ecf20Sopenharmony_ci			return false;
56488c2ecf20Sopenharmony_ci		}
56498c2ecf20Sopenharmony_ci	}
56508c2ecf20Sopenharmony_ci
56518c2ecf20Sopenharmony_ci	return true;
56528c2ecf20Sopenharmony_ci}
56538c2ecf20Sopenharmony_ci
56548c2ecf20Sopenharmony_cistatic void ath11k_mac_set_bitrate_mask_iter(void *data,
56558c2ecf20Sopenharmony_ci					     struct ieee80211_sta *sta)
56568c2ecf20Sopenharmony_ci{
56578c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = data;
56588c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
56598c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
56608c2ecf20Sopenharmony_ci
56618c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
56628c2ecf20Sopenharmony_ci	arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED;
56638c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
56648c2ecf20Sopenharmony_ci
56658c2ecf20Sopenharmony_ci	ieee80211_queue_work(ar->hw, &arsta->update_wk);
56668c2ecf20Sopenharmony_ci}
56678c2ecf20Sopenharmony_ci
56688c2ecf20Sopenharmony_cistatic void ath11k_mac_disable_peer_fixed_rate(void *data,
56698c2ecf20Sopenharmony_ci					       struct ieee80211_sta *sta)
56708c2ecf20Sopenharmony_ci{
56718c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = data;
56728c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
56738c2ecf20Sopenharmony_ci	int ret;
56748c2ecf20Sopenharmony_ci
56758c2ecf20Sopenharmony_ci	ret = ath11k_wmi_set_peer_param(ar, sta->addr,
56768c2ecf20Sopenharmony_ci					arvif->vdev_id,
56778c2ecf20Sopenharmony_ci					WMI_PEER_PARAM_FIXED_RATE,
56788c2ecf20Sopenharmony_ci					WMI_FIXED_RATE_NONE);
56798c2ecf20Sopenharmony_ci	if (ret)
56808c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab,
56818c2ecf20Sopenharmony_ci			    "failed to disable peer fixed rate for STA %pM ret %d\n",
56828c2ecf20Sopenharmony_ci			    sta->addr, ret);
56838c2ecf20Sopenharmony_ci}
56848c2ecf20Sopenharmony_ci
56858c2ecf20Sopenharmony_cistatic int
56868c2ecf20Sopenharmony_ciath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
56878c2ecf20Sopenharmony_ci			       struct ieee80211_vif *vif,
56888c2ecf20Sopenharmony_ci			       const struct cfg80211_bitrate_mask *mask)
56898c2ecf20Sopenharmony_ci{
56908c2ecf20Sopenharmony_ci	struct ath11k_vif *arvif = (void *)vif->drv_priv;
56918c2ecf20Sopenharmony_ci	struct cfg80211_chan_def def;
56928c2ecf20Sopenharmony_ci	struct ath11k *ar = arvif->ar;
56938c2ecf20Sopenharmony_ci	enum nl80211_band band;
56948c2ecf20Sopenharmony_ci	const u8 *ht_mcs_mask;
56958c2ecf20Sopenharmony_ci	const u16 *vht_mcs_mask;
56968c2ecf20Sopenharmony_ci	u32 rate;
56978c2ecf20Sopenharmony_ci	u8 nss;
56988c2ecf20Sopenharmony_ci	u8 sgi;
56998c2ecf20Sopenharmony_ci	u8 ldpc;
57008c2ecf20Sopenharmony_ci	int single_nss;
57018c2ecf20Sopenharmony_ci	int ret;
57028c2ecf20Sopenharmony_ci	int num_rates;
57038c2ecf20Sopenharmony_ci
57048c2ecf20Sopenharmony_ci	if (ath11k_mac_vif_chan(vif, &def))
57058c2ecf20Sopenharmony_ci		return -EPERM;
57068c2ecf20Sopenharmony_ci
57078c2ecf20Sopenharmony_ci	band = def.chan->band;
57088c2ecf20Sopenharmony_ci	ht_mcs_mask = mask->control[band].ht_mcs;
57098c2ecf20Sopenharmony_ci	vht_mcs_mask = mask->control[band].vht_mcs;
57108c2ecf20Sopenharmony_ci	ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
57118c2ecf20Sopenharmony_ci
57128c2ecf20Sopenharmony_ci	sgi = mask->control[band].gi;
57138c2ecf20Sopenharmony_ci	if (sgi == NL80211_TXRATE_FORCE_LGI)
57148c2ecf20Sopenharmony_ci		return -EINVAL;
57158c2ecf20Sopenharmony_ci
57168c2ecf20Sopenharmony_ci	/* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it
57178c2ecf20Sopenharmony_ci	 * requires passing atleast one of used basic rates along with them.
57188c2ecf20Sopenharmony_ci	 * Fixed rate setting across different preambles(legacy, HT, VHT) is
57198c2ecf20Sopenharmony_ci	 * not supported by the FW. Hence use of FIXED_RATE vdev param is not
57208c2ecf20Sopenharmony_ci	 * suitable for setting single HT/VHT rates.
57218c2ecf20Sopenharmony_ci	 * But, there could be a single basic rate passed from userspace which
57228c2ecf20Sopenharmony_ci	 * can be done through the FIXED_RATE param.
57238c2ecf20Sopenharmony_ci	 */
57248c2ecf20Sopenharmony_ci	if (ath11k_mac_has_single_legacy_rate(ar, band, mask)) {
57258c2ecf20Sopenharmony_ci		ret = ath11k_mac_get_single_legacy_rate(ar, band, mask, &rate,
57268c2ecf20Sopenharmony_ci							&nss);
57278c2ecf20Sopenharmony_ci		if (ret) {
57288c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab, "failed to get single legacy rate for vdev %i: %d\n",
57298c2ecf20Sopenharmony_ci				    arvif->vdev_id, ret);
57308c2ecf20Sopenharmony_ci			return ret;
57318c2ecf20Sopenharmony_ci		}
57328c2ecf20Sopenharmony_ci		ieee80211_iterate_stations_atomic(ar->hw,
57338c2ecf20Sopenharmony_ci						  ath11k_mac_disable_peer_fixed_rate,
57348c2ecf20Sopenharmony_ci						  arvif);
57358c2ecf20Sopenharmony_ci	} else if (ath11k_mac_bitrate_mask_get_single_nss(ar, band, mask,
57368c2ecf20Sopenharmony_ci							  &single_nss)) {
57378c2ecf20Sopenharmony_ci		rate = WMI_FIXED_RATE_NONE;
57388c2ecf20Sopenharmony_ci		nss = single_nss;
57398c2ecf20Sopenharmony_ci	} else {
57408c2ecf20Sopenharmony_ci		rate = WMI_FIXED_RATE_NONE;
57418c2ecf20Sopenharmony_ci		nss = min_t(u32, ar->num_tx_chains,
57428c2ecf20Sopenharmony_ci			    max(ath11k_mac_max_ht_nss(ht_mcs_mask),
57438c2ecf20Sopenharmony_ci				ath11k_mac_max_vht_nss(vht_mcs_mask)));
57448c2ecf20Sopenharmony_ci
57458c2ecf20Sopenharmony_ci		/* If multiple rates across different preambles are given
57468c2ecf20Sopenharmony_ci		 * we can reconfigure this info with all peers using PEER_ASSOC
57478c2ecf20Sopenharmony_ci		 * command with the below exception cases.
57488c2ecf20Sopenharmony_ci		 * - Single VHT Rate : peer_assoc command accommodates only MCS
57498c2ecf20Sopenharmony_ci		 * range values i.e 0-7, 0-8, 0-9 for VHT. Though mac80211
57508c2ecf20Sopenharmony_ci		 * mandates passing basic rates along with HT/VHT rates, FW
57518c2ecf20Sopenharmony_ci		 * doesn't allow switching from VHT to Legacy. Hence instead of
57528c2ecf20Sopenharmony_ci		 * setting legacy and VHT rates using RATEMASK_CMD vdev cmd,
57538c2ecf20Sopenharmony_ci		 * we could set this VHT rate as peer fixed rate param, which
57548c2ecf20Sopenharmony_ci		 * will override FIXED rate and FW rate control algorithm.
57558c2ecf20Sopenharmony_ci		 * If single VHT rate is passed along with HT rates, we select
57568c2ecf20Sopenharmony_ci		 * the VHT rate as fixed rate for vht peers.
57578c2ecf20Sopenharmony_ci		 * - Multiple VHT Rates : When Multiple VHT rates are given,this
57588c2ecf20Sopenharmony_ci		 * can be set using RATEMASK CMD which uses FW rate-ctl alg.
57598c2ecf20Sopenharmony_ci		 * TODO: Setting multiple VHT MCS and replacing peer_assoc with
57608c2ecf20Sopenharmony_ci		 * RATEMASK_CMDID can cover all use cases of setting rates
57618c2ecf20Sopenharmony_ci		 * across multiple preambles and rates within same type.
57628c2ecf20Sopenharmony_ci		 * But requires more validation of the command at this point.
57638c2ecf20Sopenharmony_ci		 */
57648c2ecf20Sopenharmony_ci
57658c2ecf20Sopenharmony_ci		num_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
57668c2ecf20Sopenharmony_ci								  mask);
57678c2ecf20Sopenharmony_ci
57688c2ecf20Sopenharmony_ci		if (!ath11k_mac_vht_mcs_range_present(ar, band, mask) &&
57698c2ecf20Sopenharmony_ci		    num_rates > 1) {
57708c2ecf20Sopenharmony_ci			/* TODO: Handle multiple VHT MCS values setting using
57718c2ecf20Sopenharmony_ci			 * RATEMASK CMD
57728c2ecf20Sopenharmony_ci			 */
57738c2ecf20Sopenharmony_ci			ath11k_warn(ar->ab,
57748c2ecf20Sopenharmony_ci				    "Setting more than one MCS Value in bitrate mask not supported\n");
57758c2ecf20Sopenharmony_ci			return -EINVAL;
57768c2ecf20Sopenharmony_ci		}
57778c2ecf20Sopenharmony_ci
57788c2ecf20Sopenharmony_ci		ieee80211_iterate_stations_atomic(ar->hw,
57798c2ecf20Sopenharmony_ci						  ath11k_mac_disable_peer_fixed_rate,
57808c2ecf20Sopenharmony_ci						  arvif);
57818c2ecf20Sopenharmony_ci
57828c2ecf20Sopenharmony_ci		mutex_lock(&ar->conf_mutex);
57838c2ecf20Sopenharmony_ci
57848c2ecf20Sopenharmony_ci		arvif->bitrate_mask = *mask;
57858c2ecf20Sopenharmony_ci		ieee80211_iterate_stations_atomic(ar->hw,
57868c2ecf20Sopenharmony_ci						  ath11k_mac_set_bitrate_mask_iter,
57878c2ecf20Sopenharmony_ci						  arvif);
57888c2ecf20Sopenharmony_ci
57898c2ecf20Sopenharmony_ci		mutex_unlock(&ar->conf_mutex);
57908c2ecf20Sopenharmony_ci	}
57918c2ecf20Sopenharmony_ci
57928c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
57938c2ecf20Sopenharmony_ci
57948c2ecf20Sopenharmony_ci	ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
57958c2ecf20Sopenharmony_ci	if (ret) {
57968c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n",
57978c2ecf20Sopenharmony_ci			    arvif->vdev_id, ret);
57988c2ecf20Sopenharmony_ci	}
57998c2ecf20Sopenharmony_ci
58008c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
58018c2ecf20Sopenharmony_ci
58028c2ecf20Sopenharmony_ci	return ret;
58038c2ecf20Sopenharmony_ci}
58048c2ecf20Sopenharmony_ci
58058c2ecf20Sopenharmony_cistatic void
58068c2ecf20Sopenharmony_ciath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
58078c2ecf20Sopenharmony_ci				enum ieee80211_reconfig_type reconfig_type)
58088c2ecf20Sopenharmony_ci{
58098c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
58108c2ecf20Sopenharmony_ci
58118c2ecf20Sopenharmony_ci	if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
58128c2ecf20Sopenharmony_ci		return;
58138c2ecf20Sopenharmony_ci
58148c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
58158c2ecf20Sopenharmony_ci
58168c2ecf20Sopenharmony_ci	if (ar->state == ATH11K_STATE_RESTARTED) {
58178c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "pdev %d successfully recovered\n",
58188c2ecf20Sopenharmony_ci			    ar->pdev->pdev_id);
58198c2ecf20Sopenharmony_ci		ar->state = ATH11K_STATE_ON;
58208c2ecf20Sopenharmony_ci		ieee80211_wake_queues(ar->hw);
58218c2ecf20Sopenharmony_ci	}
58228c2ecf20Sopenharmony_ci
58238c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
58248c2ecf20Sopenharmony_ci}
58258c2ecf20Sopenharmony_ci
58268c2ecf20Sopenharmony_cistatic void
58278c2ecf20Sopenharmony_ciath11k_mac_update_bss_chan_survey(struct ath11k *ar,
58288c2ecf20Sopenharmony_ci				  struct ieee80211_channel *channel)
58298c2ecf20Sopenharmony_ci{
58308c2ecf20Sopenharmony_ci	int ret;
58318c2ecf20Sopenharmony_ci	enum wmi_bss_chan_info_req_type type = WMI_BSS_SURVEY_REQ_TYPE_READ;
58328c2ecf20Sopenharmony_ci
58338c2ecf20Sopenharmony_ci	lockdep_assert_held(&ar->conf_mutex);
58348c2ecf20Sopenharmony_ci
58358c2ecf20Sopenharmony_ci	if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_ab.svc_map) ||
58368c2ecf20Sopenharmony_ci	    ar->rx_channel != channel)
58378c2ecf20Sopenharmony_ci		return;
58388c2ecf20Sopenharmony_ci
58398c2ecf20Sopenharmony_ci	if (ar->scan.state != ATH11K_SCAN_IDLE) {
58408c2ecf20Sopenharmony_ci		ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
58418c2ecf20Sopenharmony_ci			   "ignoring bss chan info req while scanning..\n");
58428c2ecf20Sopenharmony_ci		return;
58438c2ecf20Sopenharmony_ci	}
58448c2ecf20Sopenharmony_ci
58458c2ecf20Sopenharmony_ci	reinit_completion(&ar->bss_survey_done);
58468c2ecf20Sopenharmony_ci
58478c2ecf20Sopenharmony_ci	ret = ath11k_wmi_pdev_bss_chan_info_request(ar, type);
58488c2ecf20Sopenharmony_ci	if (ret) {
58498c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "failed to send pdev bss chan info request\n");
58508c2ecf20Sopenharmony_ci		return;
58518c2ecf20Sopenharmony_ci	}
58528c2ecf20Sopenharmony_ci
58538c2ecf20Sopenharmony_ci	ret = wait_for_completion_timeout(&ar->bss_survey_done, 3 * HZ);
58548c2ecf20Sopenharmony_ci	if (ret == 0)
58558c2ecf20Sopenharmony_ci		ath11k_warn(ar->ab, "bss channel survey timed out\n");
58568c2ecf20Sopenharmony_ci}
58578c2ecf20Sopenharmony_ci
58588c2ecf20Sopenharmony_cistatic int ath11k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
58598c2ecf20Sopenharmony_ci				    struct survey_info *survey)
58608c2ecf20Sopenharmony_ci{
58618c2ecf20Sopenharmony_ci	struct ath11k *ar = hw->priv;
58628c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
58638c2ecf20Sopenharmony_ci	struct survey_info *ar_survey;
58648c2ecf20Sopenharmony_ci	int ret = 0;
58658c2ecf20Sopenharmony_ci
58668c2ecf20Sopenharmony_ci	if (idx >= ATH11K_NUM_CHANS)
58678c2ecf20Sopenharmony_ci		return -ENOENT;
58688c2ecf20Sopenharmony_ci
58698c2ecf20Sopenharmony_ci	ar_survey = &ar->survey[idx];
58708c2ecf20Sopenharmony_ci
58718c2ecf20Sopenharmony_ci	mutex_lock(&ar->conf_mutex);
58728c2ecf20Sopenharmony_ci
58738c2ecf20Sopenharmony_ci	sband = hw->wiphy->bands[NL80211_BAND_2GHZ];
58748c2ecf20Sopenharmony_ci	if (sband && idx >= sband->n_channels) {
58758c2ecf20Sopenharmony_ci		idx -= sband->n_channels;
58768c2ecf20Sopenharmony_ci		sband = NULL;
58778c2ecf20Sopenharmony_ci	}
58788c2ecf20Sopenharmony_ci
58798c2ecf20Sopenharmony_ci	if (!sband)
58808c2ecf20Sopenharmony_ci		sband = hw->wiphy->bands[NL80211_BAND_5GHZ];
58818c2ecf20Sopenharmony_ci
58828c2ecf20Sopenharmony_ci	if (!sband || idx >= sband->n_channels) {
58838c2ecf20Sopenharmony_ci		ret = -ENOENT;
58848c2ecf20Sopenharmony_ci		goto exit;
58858c2ecf20Sopenharmony_ci	}
58868c2ecf20Sopenharmony_ci
58878c2ecf20Sopenharmony_ci	ath11k_mac_update_bss_chan_survey(ar, &sband->channels[idx]);
58888c2ecf20Sopenharmony_ci
58898c2ecf20Sopenharmony_ci	spin_lock_bh(&ar->data_lock);
58908c2ecf20Sopenharmony_ci	memcpy(survey, ar_survey, sizeof(*survey));
58918c2ecf20Sopenharmony_ci	spin_unlock_bh(&ar->data_lock);
58928c2ecf20Sopenharmony_ci
58938c2ecf20Sopenharmony_ci	survey->channel = &sband->channels[idx];
58948c2ecf20Sopenharmony_ci
58958c2ecf20Sopenharmony_ci	if (ar->rx_channel == survey->channel)
58968c2ecf20Sopenharmony_ci		survey->filled |= SURVEY_INFO_IN_USE;
58978c2ecf20Sopenharmony_ci
58988c2ecf20Sopenharmony_ciexit:
58998c2ecf20Sopenharmony_ci	mutex_unlock(&ar->conf_mutex);
59008c2ecf20Sopenharmony_ci	return ret;
59018c2ecf20Sopenharmony_ci}
59028c2ecf20Sopenharmony_ci
59038c2ecf20Sopenharmony_cistatic void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw,
59048c2ecf20Sopenharmony_ci					 struct ieee80211_vif *vif,
59058c2ecf20Sopenharmony_ci					 struct ieee80211_sta *sta,
59068c2ecf20Sopenharmony_ci					 struct station_info *sinfo)
59078c2ecf20Sopenharmony_ci{
59088c2ecf20Sopenharmony_ci	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
59098c2ecf20Sopenharmony_ci
59108c2ecf20Sopenharmony_ci	sinfo->rx_duration = arsta->rx_duration;
59118c2ecf20Sopenharmony_ci	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
59128c2ecf20Sopenharmony_ci
59138c2ecf20Sopenharmony_ci	sinfo->tx_duration = arsta->tx_duration;
59148c2ecf20Sopenharmony_ci	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
59158c2ecf20Sopenharmony_ci
59168c2ecf20Sopenharmony_ci	if (!arsta->txrate.legacy && !arsta->txrate.nss)
59178c2ecf20Sopenharmony_ci		return;
59188c2ecf20Sopenharmony_ci
59198c2ecf20Sopenharmony_ci	if (arsta->txrate.legacy) {
59208c2ecf20Sopenharmony_ci		sinfo->txrate.legacy = arsta->txrate.legacy;
59218c2ecf20Sopenharmony_ci	} else {
59228c2ecf20Sopenharmony_ci		sinfo->txrate.mcs = arsta->txrate.mcs;
59238c2ecf20Sopenharmony_ci		sinfo->txrate.nss = arsta->txrate.nss;
59248c2ecf20Sopenharmony_ci		sinfo->txrate.bw = arsta->txrate.bw;
59258c2ecf20Sopenharmony_ci		sinfo->txrate.he_gi = arsta->txrate.he_gi;
59268c2ecf20Sopenharmony_ci		sinfo->txrate.he_dcm = arsta->txrate.he_dcm;
59278c2ecf20Sopenharmony_ci		sinfo->txrate.he_ru_alloc = arsta->txrate.he_ru_alloc;
59288c2ecf20Sopenharmony_ci	}
59298c2ecf20Sopenharmony_ci	sinfo->txrate.flags = arsta->txrate.flags;
59308c2ecf20Sopenharmony_ci	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
59318c2ecf20Sopenharmony_ci
59328c2ecf20Sopenharmony_ci	/* TODO: Use real NF instead of default one. */
59338c2ecf20Sopenharmony_ci	sinfo->signal = arsta->rssi_comb + ATH11K_DEFAULT_NOISE_FLOOR;
59348c2ecf20Sopenharmony_ci}
59358c2ecf20Sopenharmony_ci
59368c2ecf20Sopenharmony_cistatic const struct ieee80211_ops ath11k_ops = {
59378c2ecf20Sopenharmony_ci	.tx				= ath11k_mac_op_tx,
59388c2ecf20Sopenharmony_ci	.start                          = ath11k_mac_op_start,
59398c2ecf20Sopenharmony_ci	.stop                           = ath11k_mac_op_stop,
59408c2ecf20Sopenharmony_ci	.reconfig_complete              = ath11k_mac_op_reconfig_complete,
59418c2ecf20Sopenharmony_ci	.add_interface                  = ath11k_mac_op_add_interface,
59428c2ecf20Sopenharmony_ci	.remove_interface		= ath11k_mac_op_remove_interface,
59438c2ecf20Sopenharmony_ci	.update_vif_offload		= ath11k_mac_op_update_vif_offload,
59448c2ecf20Sopenharmony_ci	.config                         = ath11k_mac_op_config,
59458c2ecf20Sopenharmony_ci	.bss_info_changed               = ath11k_mac_op_bss_info_changed,
59468c2ecf20Sopenharmony_ci	.configure_filter		= ath11k_mac_op_configure_filter,
59478c2ecf20Sopenharmony_ci	.hw_scan                        = ath11k_mac_op_hw_scan,
59488c2ecf20Sopenharmony_ci	.cancel_hw_scan                 = ath11k_mac_op_cancel_hw_scan,
59498c2ecf20Sopenharmony_ci	.set_key                        = ath11k_mac_op_set_key,
59508c2ecf20Sopenharmony_ci	.sta_state                      = ath11k_mac_op_sta_state,
59518c2ecf20Sopenharmony_ci	.sta_set_txpwr			= ath11k_mac_op_sta_set_txpwr,
59528c2ecf20Sopenharmony_ci	.sta_rc_update			= ath11k_mac_op_sta_rc_update,
59538c2ecf20Sopenharmony_ci	.conf_tx                        = ath11k_mac_op_conf_tx,
59548c2ecf20Sopenharmony_ci	.set_antenna			= ath11k_mac_op_set_antenna,
59558c2ecf20Sopenharmony_ci	.get_antenna			= ath11k_mac_op_get_antenna,
59568c2ecf20Sopenharmony_ci	.ampdu_action			= ath11k_mac_op_ampdu_action,
59578c2ecf20Sopenharmony_ci	.add_chanctx			= ath11k_mac_op_add_chanctx,
59588c2ecf20Sopenharmony_ci	.remove_chanctx			= ath11k_mac_op_remove_chanctx,
59598c2ecf20Sopenharmony_ci	.change_chanctx			= ath11k_mac_op_change_chanctx,
59608c2ecf20Sopenharmony_ci	.assign_vif_chanctx		= ath11k_mac_op_assign_vif_chanctx,
59618c2ecf20Sopenharmony_ci	.unassign_vif_chanctx		= ath11k_mac_op_unassign_vif_chanctx,
59628c2ecf20Sopenharmony_ci	.switch_vif_chanctx		= ath11k_mac_op_switch_vif_chanctx,
59638c2ecf20Sopenharmony_ci	.set_rts_threshold		= ath11k_mac_op_set_rts_threshold,
59648c2ecf20Sopenharmony_ci	.set_frag_threshold		= ath11k_mac_op_set_frag_threshold,
59658c2ecf20Sopenharmony_ci	.set_bitrate_mask		= ath11k_mac_op_set_bitrate_mask,
59668c2ecf20Sopenharmony_ci	.get_survey			= ath11k_mac_op_get_survey,
59678c2ecf20Sopenharmony_ci	.flush				= ath11k_mac_op_flush,
59688c2ecf20Sopenharmony_ci	.sta_statistics			= ath11k_mac_op_sta_statistics,
59698c2ecf20Sopenharmony_ci	CFG80211_TESTMODE_CMD(ath11k_tm_cmd)
59708c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH11K_DEBUGFS
59718c2ecf20Sopenharmony_ci	.sta_add_debugfs		= ath11k_debugfs_sta_op_add,
59728c2ecf20Sopenharmony_ci#endif
59738c2ecf20Sopenharmony_ci};
59748c2ecf20Sopenharmony_ci
59758c2ecf20Sopenharmony_cistatic void ath11k_mac_update_ch_list(struct ath11k *ar,
59768c2ecf20Sopenharmony_ci				      struct ieee80211_supported_band *band,
59778c2ecf20Sopenharmony_ci				      u32 freq_low, u32 freq_high)
59788c2ecf20Sopenharmony_ci{
59798c2ecf20Sopenharmony_ci	int i;
59808c2ecf20Sopenharmony_ci
59818c2ecf20Sopenharmony_ci	if (!(freq_low && freq_high))
59828c2ecf20Sopenharmony_ci		return;
59838c2ecf20Sopenharmony_ci
59848c2ecf20Sopenharmony_ci	for (i = 0; i < band->n_channels; i++) {
59858c2ecf20Sopenharmony_ci		if (band->channels[i].center_freq < freq_low ||
59868c2ecf20Sopenharmony_ci		    band->channels[i].center_freq > freq_high)
59878c2ecf20Sopenharmony_ci			band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
59888c2ecf20Sopenharmony_ci	}
59898c2ecf20Sopenharmony_ci}
59908c2ecf20Sopenharmony_ci
59918c2ecf20Sopenharmony_cistatic u32 ath11k_get_phy_id(struct ath11k *ar, u32 band)
59928c2ecf20Sopenharmony_ci{
59938c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev = ar->pdev;
59948c2ecf20Sopenharmony_ci	struct ath11k_pdev_cap *pdev_cap = &pdev->cap;
59958c2ecf20Sopenharmony_ci
59968c2ecf20Sopenharmony_ci	if (band == WMI_HOST_WLAN_2G_CAP)
59978c2ecf20Sopenharmony_ci		return pdev_cap->band[NL80211_BAND_2GHZ].phy_id;
59988c2ecf20Sopenharmony_ci
59998c2ecf20Sopenharmony_ci	if (band == WMI_HOST_WLAN_5G_CAP)
60008c2ecf20Sopenharmony_ci		return pdev_cap->band[NL80211_BAND_5GHZ].phy_id;
60018c2ecf20Sopenharmony_ci
60028c2ecf20Sopenharmony_ci	ath11k_warn(ar->ab, "unsupported phy cap:%d\n", band);
60038c2ecf20Sopenharmony_ci
60048c2ecf20Sopenharmony_ci	return 0;
60058c2ecf20Sopenharmony_ci}
60068c2ecf20Sopenharmony_ci
60078c2ecf20Sopenharmony_cistatic int ath11k_mac_setup_channels_rates(struct ath11k *ar,
60088c2ecf20Sopenharmony_ci					   u32 supported_bands)
60098c2ecf20Sopenharmony_ci{
60108c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *band;
60118c2ecf20Sopenharmony_ci	struct ath11k_hal_reg_capabilities_ext *reg_cap;
60128c2ecf20Sopenharmony_ci	void *channels;
60138c2ecf20Sopenharmony_ci	u32 phy_id;
60148c2ecf20Sopenharmony_ci
60158c2ecf20Sopenharmony_ci	BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) +
60168c2ecf20Sopenharmony_ci		      ARRAY_SIZE(ath11k_5ghz_channels) +
60178c2ecf20Sopenharmony_ci		      ARRAY_SIZE(ath11k_6ghz_channels)) !=
60188c2ecf20Sopenharmony_ci		     ATH11K_NUM_CHANS);
60198c2ecf20Sopenharmony_ci
60208c2ecf20Sopenharmony_ci	reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx];
60218c2ecf20Sopenharmony_ci
60228c2ecf20Sopenharmony_ci	if (supported_bands & WMI_HOST_WLAN_2G_CAP) {
60238c2ecf20Sopenharmony_ci		channels = kmemdup(ath11k_2ghz_channels,
60248c2ecf20Sopenharmony_ci				   sizeof(ath11k_2ghz_channels),
60258c2ecf20Sopenharmony_ci				   GFP_KERNEL);
60268c2ecf20Sopenharmony_ci		if (!channels)
60278c2ecf20Sopenharmony_ci			return -ENOMEM;
60288c2ecf20Sopenharmony_ci
60298c2ecf20Sopenharmony_ci		band = &ar->mac.sbands[NL80211_BAND_2GHZ];
60308c2ecf20Sopenharmony_ci		band->band = NL80211_BAND_2GHZ;
60318c2ecf20Sopenharmony_ci		band->n_channels = ARRAY_SIZE(ath11k_2ghz_channels);
60328c2ecf20Sopenharmony_ci		band->channels = channels;
60338c2ecf20Sopenharmony_ci		band->n_bitrates = ath11k_g_rates_size;
60348c2ecf20Sopenharmony_ci		band->bitrates = ath11k_g_rates;
60358c2ecf20Sopenharmony_ci		ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band;
60368c2ecf20Sopenharmony_ci
60378c2ecf20Sopenharmony_ci		if (ar->ab->hw_params.single_pdev_only) {
60388c2ecf20Sopenharmony_ci			phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP);
60398c2ecf20Sopenharmony_ci			reg_cap = &ar->ab->hal_reg_cap[phy_id];
60408c2ecf20Sopenharmony_ci		}
60418c2ecf20Sopenharmony_ci		ath11k_mac_update_ch_list(ar, band,
60428c2ecf20Sopenharmony_ci					  reg_cap->low_2ghz_chan,
60438c2ecf20Sopenharmony_ci					  reg_cap->high_2ghz_chan);
60448c2ecf20Sopenharmony_ci	}
60458c2ecf20Sopenharmony_ci
60468c2ecf20Sopenharmony_ci	if (supported_bands & WMI_HOST_WLAN_5G_CAP) {
60478c2ecf20Sopenharmony_ci		if (reg_cap->high_5ghz_chan >= ATH11K_MIN_6G_FREQ) {
60488c2ecf20Sopenharmony_ci			channels = kmemdup(ath11k_6ghz_channels,
60498c2ecf20Sopenharmony_ci					   sizeof(ath11k_6ghz_channels), GFP_KERNEL);
60508c2ecf20Sopenharmony_ci			if (!channels) {
60518c2ecf20Sopenharmony_ci				kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
60528c2ecf20Sopenharmony_ci				return -ENOMEM;
60538c2ecf20Sopenharmony_ci			}
60548c2ecf20Sopenharmony_ci
60558c2ecf20Sopenharmony_ci			ar->supports_6ghz = true;
60568c2ecf20Sopenharmony_ci			band = &ar->mac.sbands[NL80211_BAND_6GHZ];
60578c2ecf20Sopenharmony_ci			band->band = NL80211_BAND_6GHZ;
60588c2ecf20Sopenharmony_ci			band->n_channels = ARRAY_SIZE(ath11k_6ghz_channels);
60598c2ecf20Sopenharmony_ci			band->channels = channels;
60608c2ecf20Sopenharmony_ci			band->n_bitrates = ath11k_a_rates_size;
60618c2ecf20Sopenharmony_ci			band->bitrates = ath11k_a_rates;
60628c2ecf20Sopenharmony_ci			ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band;
60638c2ecf20Sopenharmony_ci			ath11k_mac_update_ch_list(ar, band,
60648c2ecf20Sopenharmony_ci						  reg_cap->low_5ghz_chan,
60658c2ecf20Sopenharmony_ci						  reg_cap->high_5ghz_chan);
60668c2ecf20Sopenharmony_ci		}
60678c2ecf20Sopenharmony_ci
60688c2ecf20Sopenharmony_ci		if (reg_cap->low_5ghz_chan < ATH11K_MIN_6G_FREQ) {
60698c2ecf20Sopenharmony_ci			channels = kmemdup(ath11k_5ghz_channels,
60708c2ecf20Sopenharmony_ci					   sizeof(ath11k_5ghz_channels),
60718c2ecf20Sopenharmony_ci					   GFP_KERNEL);
60728c2ecf20Sopenharmony_ci			if (!channels) {
60738c2ecf20Sopenharmony_ci				kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
60748c2ecf20Sopenharmony_ci				kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
60758c2ecf20Sopenharmony_ci				return -ENOMEM;
60768c2ecf20Sopenharmony_ci			}
60778c2ecf20Sopenharmony_ci
60788c2ecf20Sopenharmony_ci			band = &ar->mac.sbands[NL80211_BAND_5GHZ];
60798c2ecf20Sopenharmony_ci			band->band = NL80211_BAND_5GHZ;
60808c2ecf20Sopenharmony_ci			band->n_channels = ARRAY_SIZE(ath11k_5ghz_channels);
60818c2ecf20Sopenharmony_ci			band->channels = channels;
60828c2ecf20Sopenharmony_ci			band->n_bitrates = ath11k_a_rates_size;
60838c2ecf20Sopenharmony_ci			band->bitrates = ath11k_a_rates;
60848c2ecf20Sopenharmony_ci			ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
60858c2ecf20Sopenharmony_ci
60868c2ecf20Sopenharmony_ci			if (ar->ab->hw_params.single_pdev_only) {
60878c2ecf20Sopenharmony_ci				phy_id = ath11k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP);
60888c2ecf20Sopenharmony_ci				reg_cap = &ar->ab->hal_reg_cap[phy_id];
60898c2ecf20Sopenharmony_ci			}
60908c2ecf20Sopenharmony_ci
60918c2ecf20Sopenharmony_ci			ath11k_mac_update_ch_list(ar, band,
60928c2ecf20Sopenharmony_ci						  reg_cap->low_5ghz_chan,
60938c2ecf20Sopenharmony_ci						  reg_cap->high_5ghz_chan);
60948c2ecf20Sopenharmony_ci		}
60958c2ecf20Sopenharmony_ci	}
60968c2ecf20Sopenharmony_ci
60978c2ecf20Sopenharmony_ci	return 0;
60988c2ecf20Sopenharmony_ci}
60998c2ecf20Sopenharmony_ci
61008c2ecf20Sopenharmony_cistatic int ath11k_mac_setup_iface_combinations(struct ath11k *ar)
61018c2ecf20Sopenharmony_ci{
61028c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
61038c2ecf20Sopenharmony_ci	struct ieee80211_iface_combination *combinations;
61048c2ecf20Sopenharmony_ci	struct ieee80211_iface_limit *limits;
61058c2ecf20Sopenharmony_ci	int n_limits;
61068c2ecf20Sopenharmony_ci
61078c2ecf20Sopenharmony_ci	combinations = kzalloc(sizeof(*combinations), GFP_KERNEL);
61088c2ecf20Sopenharmony_ci	if (!combinations)
61098c2ecf20Sopenharmony_ci		return -ENOMEM;
61108c2ecf20Sopenharmony_ci
61118c2ecf20Sopenharmony_ci	n_limits = 2;
61128c2ecf20Sopenharmony_ci
61138c2ecf20Sopenharmony_ci	limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL);
61148c2ecf20Sopenharmony_ci	if (!limits) {
61158c2ecf20Sopenharmony_ci		kfree(combinations);
61168c2ecf20Sopenharmony_ci		return -ENOMEM;
61178c2ecf20Sopenharmony_ci	}
61188c2ecf20Sopenharmony_ci
61198c2ecf20Sopenharmony_ci	limits[0].max = 1;
61208c2ecf20Sopenharmony_ci	limits[0].types |= BIT(NL80211_IFTYPE_STATION);
61218c2ecf20Sopenharmony_ci
61228c2ecf20Sopenharmony_ci	limits[1].max = 16;
61238c2ecf20Sopenharmony_ci	limits[1].types |= BIT(NL80211_IFTYPE_AP);
61248c2ecf20Sopenharmony_ci
61258c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_MAC80211_MESH) &&
61268c2ecf20Sopenharmony_ci	    ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT))
61278c2ecf20Sopenharmony_ci		limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT);
61288c2ecf20Sopenharmony_ci
61298c2ecf20Sopenharmony_ci	combinations[0].limits = limits;
61308c2ecf20Sopenharmony_ci	combinations[0].n_limits = n_limits;
61318c2ecf20Sopenharmony_ci	combinations[0].max_interfaces = 16;
61328c2ecf20Sopenharmony_ci	combinations[0].num_different_channels = 1;
61338c2ecf20Sopenharmony_ci	combinations[0].beacon_int_infra_match = true;
61348c2ecf20Sopenharmony_ci	combinations[0].beacon_int_min_gcd = 100;
61358c2ecf20Sopenharmony_ci	combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
61368c2ecf20Sopenharmony_ci						BIT(NL80211_CHAN_WIDTH_20) |
61378c2ecf20Sopenharmony_ci						BIT(NL80211_CHAN_WIDTH_40) |
61388c2ecf20Sopenharmony_ci						BIT(NL80211_CHAN_WIDTH_80);
61398c2ecf20Sopenharmony_ci
61408c2ecf20Sopenharmony_ci	ar->hw->wiphy->iface_combinations = combinations;
61418c2ecf20Sopenharmony_ci	ar->hw->wiphy->n_iface_combinations = 1;
61428c2ecf20Sopenharmony_ci
61438c2ecf20Sopenharmony_ci	return 0;
61448c2ecf20Sopenharmony_ci}
61458c2ecf20Sopenharmony_ci
61468c2ecf20Sopenharmony_cistatic const u8 ath11k_if_types_ext_capa[] = {
61478c2ecf20Sopenharmony_ci	[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
61488c2ecf20Sopenharmony_ci	[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
61498c2ecf20Sopenharmony_ci};
61508c2ecf20Sopenharmony_ci
61518c2ecf20Sopenharmony_cistatic const u8 ath11k_if_types_ext_capa_sta[] = {
61528c2ecf20Sopenharmony_ci	[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
61538c2ecf20Sopenharmony_ci	[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
61548c2ecf20Sopenharmony_ci	[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,
61558c2ecf20Sopenharmony_ci};
61568c2ecf20Sopenharmony_ci
61578c2ecf20Sopenharmony_cistatic const u8 ath11k_if_types_ext_capa_ap[] = {
61588c2ecf20Sopenharmony_ci	[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
61598c2ecf20Sopenharmony_ci	[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
61608c2ecf20Sopenharmony_ci	[9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT,
61618c2ecf20Sopenharmony_ci};
61628c2ecf20Sopenharmony_ci
61638c2ecf20Sopenharmony_cistatic const struct wiphy_iftype_ext_capab ath11k_iftypes_ext_capa[] = {
61648c2ecf20Sopenharmony_ci	{
61658c2ecf20Sopenharmony_ci		.extended_capabilities = ath11k_if_types_ext_capa,
61668c2ecf20Sopenharmony_ci		.extended_capabilities_mask = ath11k_if_types_ext_capa,
61678c2ecf20Sopenharmony_ci		.extended_capabilities_len = sizeof(ath11k_if_types_ext_capa),
61688c2ecf20Sopenharmony_ci	}, {
61698c2ecf20Sopenharmony_ci		.iftype = NL80211_IFTYPE_STATION,
61708c2ecf20Sopenharmony_ci		.extended_capabilities = ath11k_if_types_ext_capa_sta,
61718c2ecf20Sopenharmony_ci		.extended_capabilities_mask = ath11k_if_types_ext_capa_sta,
61728c2ecf20Sopenharmony_ci		.extended_capabilities_len =
61738c2ecf20Sopenharmony_ci				sizeof(ath11k_if_types_ext_capa_sta),
61748c2ecf20Sopenharmony_ci	}, {
61758c2ecf20Sopenharmony_ci		.iftype = NL80211_IFTYPE_AP,
61768c2ecf20Sopenharmony_ci		.extended_capabilities = ath11k_if_types_ext_capa_ap,
61778c2ecf20Sopenharmony_ci		.extended_capabilities_mask = ath11k_if_types_ext_capa_ap,
61788c2ecf20Sopenharmony_ci		.extended_capabilities_len =
61798c2ecf20Sopenharmony_ci				sizeof(ath11k_if_types_ext_capa_ap),
61808c2ecf20Sopenharmony_ci	},
61818c2ecf20Sopenharmony_ci};
61828c2ecf20Sopenharmony_ci
61838c2ecf20Sopenharmony_cistatic void __ath11k_mac_unregister(struct ath11k *ar)
61848c2ecf20Sopenharmony_ci{
61858c2ecf20Sopenharmony_ci	cancel_work_sync(&ar->regd_update_work);
61868c2ecf20Sopenharmony_ci
61878c2ecf20Sopenharmony_ci	ieee80211_unregister_hw(ar->hw);
61888c2ecf20Sopenharmony_ci
61898c2ecf20Sopenharmony_ci	idr_for_each(&ar->txmgmt_idr, ath11k_mac_tx_mgmt_pending_free, ar);
61908c2ecf20Sopenharmony_ci	idr_destroy(&ar->txmgmt_idr);
61918c2ecf20Sopenharmony_ci
61928c2ecf20Sopenharmony_ci	kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
61938c2ecf20Sopenharmony_ci	kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
61948c2ecf20Sopenharmony_ci	kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
61958c2ecf20Sopenharmony_ci
61968c2ecf20Sopenharmony_ci	kfree(ar->hw->wiphy->iface_combinations[0].limits);
61978c2ecf20Sopenharmony_ci	kfree(ar->hw->wiphy->iface_combinations);
61988c2ecf20Sopenharmony_ci
61998c2ecf20Sopenharmony_ci	SET_IEEE80211_DEV(ar->hw, NULL);
62008c2ecf20Sopenharmony_ci}
62018c2ecf20Sopenharmony_ci
62028c2ecf20Sopenharmony_civoid ath11k_mac_unregister(struct ath11k_base *ab)
62038c2ecf20Sopenharmony_ci{
62048c2ecf20Sopenharmony_ci	struct ath11k *ar;
62058c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
62068c2ecf20Sopenharmony_ci	int i;
62078c2ecf20Sopenharmony_ci
62088c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
62098c2ecf20Sopenharmony_ci		pdev = &ab->pdevs[i];
62108c2ecf20Sopenharmony_ci		ar = pdev->ar;
62118c2ecf20Sopenharmony_ci		if (!ar)
62128c2ecf20Sopenharmony_ci			continue;
62138c2ecf20Sopenharmony_ci
62148c2ecf20Sopenharmony_ci		__ath11k_mac_unregister(ar);
62158c2ecf20Sopenharmony_ci	}
62168c2ecf20Sopenharmony_ci}
62178c2ecf20Sopenharmony_ci
62188c2ecf20Sopenharmony_cistatic int __ath11k_mac_register(struct ath11k *ar)
62198c2ecf20Sopenharmony_ci{
62208c2ecf20Sopenharmony_ci	struct ath11k_base *ab = ar->ab;
62218c2ecf20Sopenharmony_ci	struct ath11k_pdev_cap *cap = &ar->pdev->cap;
62228c2ecf20Sopenharmony_ci	static const u32 cipher_suites[] = {
62238c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_TKIP,
62248c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_CCMP,
62258c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_AES_CMAC,
62268c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_BIP_CMAC_256,
62278c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_BIP_GMAC_128,
62288c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_BIP_GMAC_256,
62298c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_GCMP,
62308c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_GCMP_256,
62318c2ecf20Sopenharmony_ci		WLAN_CIPHER_SUITE_CCMP_256,
62328c2ecf20Sopenharmony_ci	};
62338c2ecf20Sopenharmony_ci	int ret;
62348c2ecf20Sopenharmony_ci	u32 ht_cap = 0;
62358c2ecf20Sopenharmony_ci
62368c2ecf20Sopenharmony_ci	ath11k_pdev_caps_update(ar);
62378c2ecf20Sopenharmony_ci
62388c2ecf20Sopenharmony_ci	SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr);
62398c2ecf20Sopenharmony_ci
62408c2ecf20Sopenharmony_ci	SET_IEEE80211_DEV(ar->hw, ab->dev);
62418c2ecf20Sopenharmony_ci
62428c2ecf20Sopenharmony_ci	ret = ath11k_mac_setup_channels_rates(ar,
62438c2ecf20Sopenharmony_ci					      cap->supported_bands);
62448c2ecf20Sopenharmony_ci	if (ret)
62458c2ecf20Sopenharmony_ci		goto err;
62468c2ecf20Sopenharmony_ci
62478c2ecf20Sopenharmony_ci	ath11k_mac_setup_ht_vht_cap(ar, cap, &ht_cap);
62488c2ecf20Sopenharmony_ci	ath11k_mac_setup_he_cap(ar, cap);
62498c2ecf20Sopenharmony_ci
62508c2ecf20Sopenharmony_ci	ret = ath11k_mac_setup_iface_combinations(ar);
62518c2ecf20Sopenharmony_ci	if (ret) {
62528c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "failed to setup interface combinations: %d\n", ret);
62538c2ecf20Sopenharmony_ci		goto err_free_channels;
62548c2ecf20Sopenharmony_ci	}
62558c2ecf20Sopenharmony_ci
62568c2ecf20Sopenharmony_ci	ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask;
62578c2ecf20Sopenharmony_ci	ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask;
62588c2ecf20Sopenharmony_ci
62598c2ecf20Sopenharmony_ci	ar->hw->wiphy->interface_modes = ab->hw_params.interface_modes;
62608c2ecf20Sopenharmony_ci
62618c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SIGNAL_DBM);
62628c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SUPPORTS_PS);
62638c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
62648c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, MFP_CAPABLE);
62658c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS);
62668c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL);
62678c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, AP_LINK_PS);
62688c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SPECTRUM_MGMT);
62698c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, CONNECTION_MONITOR);
62708c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK);
62718c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
62728c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
62738c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
62748c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
62758c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
62768c2ecf20Sopenharmony_ci	ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
62778c2ecf20Sopenharmony_ci	if (ht_cap & WMI_HT_CAP_ENABLED) {
62788c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
62798c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
62808c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER);
62818c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU);
62828c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, USES_RSS);
62838c2ecf20Sopenharmony_ci	}
62848c2ecf20Sopenharmony_ci
62858c2ecf20Sopenharmony_ci	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
62868c2ecf20Sopenharmony_ci	ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
62878c2ecf20Sopenharmony_ci
62888c2ecf20Sopenharmony_ci	/* TODO: Check if HT capability advertised from firmware is different
62898c2ecf20Sopenharmony_ci	 * for each band for a dual band capable radio. It will be tricky to
62908c2ecf20Sopenharmony_ci	 * handle it when the ht capability different for each band.
62918c2ecf20Sopenharmony_ci	 */
62928c2ecf20Sopenharmony_ci	if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS)
62938c2ecf20Sopenharmony_ci		ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
62948c2ecf20Sopenharmony_ci
62958c2ecf20Sopenharmony_ci	ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
62968c2ecf20Sopenharmony_ci	ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
62978c2ecf20Sopenharmony_ci
62988c2ecf20Sopenharmony_ci	ar->hw->max_listen_interval = ATH11K_MAX_HW_LISTEN_INTERVAL;
62998c2ecf20Sopenharmony_ci
63008c2ecf20Sopenharmony_ci	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
63018c2ecf20Sopenharmony_ci	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
63028c2ecf20Sopenharmony_ci	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
63038c2ecf20Sopenharmony_ci
63048c2ecf20Sopenharmony_ci	ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
63058c2ecf20Sopenharmony_ci	ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
63068c2ecf20Sopenharmony_ci				   NL80211_FEATURE_AP_SCAN;
63078c2ecf20Sopenharmony_ci
63088c2ecf20Sopenharmony_ci	ar->max_num_stations = TARGET_NUM_STATIONS;
63098c2ecf20Sopenharmony_ci	ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
63108c2ecf20Sopenharmony_ci
63118c2ecf20Sopenharmony_ci	ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
63128c2ecf20Sopenharmony_ci
63138c2ecf20Sopenharmony_ci	ar->hw->queues = ATH11K_HW_MAX_QUEUES;
63148c2ecf20Sopenharmony_ci	ar->hw->wiphy->tx_queue_len = ATH11K_QUEUE_LEN;
63158c2ecf20Sopenharmony_ci	ar->hw->offchannel_tx_hw_queue = ATH11K_HW_MAX_QUEUES - 1;
63168c2ecf20Sopenharmony_ci	ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
63178c2ecf20Sopenharmony_ci
63188c2ecf20Sopenharmony_ci	ar->hw->vif_data_size = sizeof(struct ath11k_vif);
63198c2ecf20Sopenharmony_ci	ar->hw->sta_data_size = sizeof(struct ath11k_sta);
63208c2ecf20Sopenharmony_ci
63218c2ecf20Sopenharmony_ci	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
63228c2ecf20Sopenharmony_ci	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
63238c2ecf20Sopenharmony_ci
63248c2ecf20Sopenharmony_ci	ar->hw->wiphy->cipher_suites = cipher_suites;
63258c2ecf20Sopenharmony_ci	ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
63268c2ecf20Sopenharmony_ci
63278c2ecf20Sopenharmony_ci	ar->hw->wiphy->iftype_ext_capab = ath11k_iftypes_ext_capa;
63288c2ecf20Sopenharmony_ci	ar->hw->wiphy->num_iftype_ext_capab =
63298c2ecf20Sopenharmony_ci		ARRAY_SIZE(ath11k_iftypes_ext_capa);
63308c2ecf20Sopenharmony_ci
63318c2ecf20Sopenharmony_ci	ath11k_reg_init(ar);
63328c2ecf20Sopenharmony_ci
63338c2ecf20Sopenharmony_ci	if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {
63348c2ecf20Sopenharmony_ci		ar->hw->netdev_features = NETIF_F_HW_CSUM;
63358c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
63368c2ecf20Sopenharmony_ci		ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
63378c2ecf20Sopenharmony_ci	}
63388c2ecf20Sopenharmony_ci
63398c2ecf20Sopenharmony_ci	ret = ieee80211_register_hw(ar->hw);
63408c2ecf20Sopenharmony_ci	if (ret) {
63418c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "ieee80211 registration failed: %d\n", ret);
63428c2ecf20Sopenharmony_ci		goto err_free_if_combs;
63438c2ecf20Sopenharmony_ci	}
63448c2ecf20Sopenharmony_ci
63458c2ecf20Sopenharmony_ci	if (!ab->hw_params.supports_monitor)
63468c2ecf20Sopenharmony_ci		/* There's a race between calling ieee80211_register_hw()
63478c2ecf20Sopenharmony_ci		 * and here where the monitor mode is enabled for a little
63488c2ecf20Sopenharmony_ci		 * while. But that time is so short and in practise it make
63498c2ecf20Sopenharmony_ci		 * a difference in real life.
63508c2ecf20Sopenharmony_ci		 */
63518c2ecf20Sopenharmony_ci		ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
63528c2ecf20Sopenharmony_ci
63538c2ecf20Sopenharmony_ci	/* Apply the regd received during initialization */
63548c2ecf20Sopenharmony_ci	ret = ath11k_regd_update(ar);
63558c2ecf20Sopenharmony_ci	if (ret) {
63568c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret);
63578c2ecf20Sopenharmony_ci		goto err_unregister_hw;
63588c2ecf20Sopenharmony_ci	}
63598c2ecf20Sopenharmony_ci
63608c2ecf20Sopenharmony_ci	ret = ath11k_debugfs_register(ar);
63618c2ecf20Sopenharmony_ci	if (ret) {
63628c2ecf20Sopenharmony_ci		ath11k_err(ar->ab, "debugfs registration failed: %d\n", ret);
63638c2ecf20Sopenharmony_ci		goto err_unregister_hw;
63648c2ecf20Sopenharmony_ci	}
63658c2ecf20Sopenharmony_ci
63668c2ecf20Sopenharmony_ci	return 0;
63678c2ecf20Sopenharmony_ci
63688c2ecf20Sopenharmony_cierr_unregister_hw:
63698c2ecf20Sopenharmony_ci	ieee80211_unregister_hw(ar->hw);
63708c2ecf20Sopenharmony_ci
63718c2ecf20Sopenharmony_cierr_free_if_combs:
63728c2ecf20Sopenharmony_ci	kfree(ar->hw->wiphy->iface_combinations[0].limits);
63738c2ecf20Sopenharmony_ci	kfree(ar->hw->wiphy->iface_combinations);
63748c2ecf20Sopenharmony_ci
63758c2ecf20Sopenharmony_cierr_free_channels:
63768c2ecf20Sopenharmony_ci	kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
63778c2ecf20Sopenharmony_ci	kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
63788c2ecf20Sopenharmony_ci	kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
63798c2ecf20Sopenharmony_ci
63808c2ecf20Sopenharmony_cierr:
63818c2ecf20Sopenharmony_ci	SET_IEEE80211_DEV(ar->hw, NULL);
63828c2ecf20Sopenharmony_ci	return ret;
63838c2ecf20Sopenharmony_ci}
63848c2ecf20Sopenharmony_ci
63858c2ecf20Sopenharmony_ciint ath11k_mac_register(struct ath11k_base *ab)
63868c2ecf20Sopenharmony_ci{
63878c2ecf20Sopenharmony_ci	struct ath11k *ar;
63888c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
63898c2ecf20Sopenharmony_ci	int i;
63908c2ecf20Sopenharmony_ci	int ret;
63918c2ecf20Sopenharmony_ci
63928c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
63938c2ecf20Sopenharmony_ci		return 0;
63948c2ecf20Sopenharmony_ci
63958c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
63968c2ecf20Sopenharmony_ci		pdev = &ab->pdevs[i];
63978c2ecf20Sopenharmony_ci		ar = pdev->ar;
63988c2ecf20Sopenharmony_ci		if (ab->pdevs_macaddr_valid) {
63998c2ecf20Sopenharmony_ci			ether_addr_copy(ar->mac_addr, pdev->mac_addr);
64008c2ecf20Sopenharmony_ci		} else {
64018c2ecf20Sopenharmony_ci			ether_addr_copy(ar->mac_addr, ab->mac_addr);
64028c2ecf20Sopenharmony_ci			ar->mac_addr[4] += i;
64038c2ecf20Sopenharmony_ci		}
64048c2ecf20Sopenharmony_ci
64058c2ecf20Sopenharmony_ci		ret = __ath11k_mac_register(ar);
64068c2ecf20Sopenharmony_ci		if (ret)
64078c2ecf20Sopenharmony_ci			goto err_cleanup;
64088c2ecf20Sopenharmony_ci
64098c2ecf20Sopenharmony_ci		idr_init(&ar->txmgmt_idr);
64108c2ecf20Sopenharmony_ci		spin_lock_init(&ar->txmgmt_idr_lock);
64118c2ecf20Sopenharmony_ci	}
64128c2ecf20Sopenharmony_ci
64138c2ecf20Sopenharmony_ci	/* Initialize channel counters frequency value in hertz */
64148c2ecf20Sopenharmony_ci	ab->cc_freq_hz = IPQ8074_CC_FREQ_HERTZ;
64158c2ecf20Sopenharmony_ci	ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1;
64168c2ecf20Sopenharmony_ci
64178c2ecf20Sopenharmony_ci	return 0;
64188c2ecf20Sopenharmony_ci
64198c2ecf20Sopenharmony_cierr_cleanup:
64208c2ecf20Sopenharmony_ci	for (i = i - 1; i >= 0; i--) {
64218c2ecf20Sopenharmony_ci		pdev = &ab->pdevs[i];
64228c2ecf20Sopenharmony_ci		ar = pdev->ar;
64238c2ecf20Sopenharmony_ci		__ath11k_mac_unregister(ar);
64248c2ecf20Sopenharmony_ci	}
64258c2ecf20Sopenharmony_ci
64268c2ecf20Sopenharmony_ci	return ret;
64278c2ecf20Sopenharmony_ci}
64288c2ecf20Sopenharmony_ci
64298c2ecf20Sopenharmony_ciint ath11k_mac_allocate(struct ath11k_base *ab)
64308c2ecf20Sopenharmony_ci{
64318c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw;
64328c2ecf20Sopenharmony_ci	struct ath11k *ar;
64338c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
64348c2ecf20Sopenharmony_ci	int ret;
64358c2ecf20Sopenharmony_ci	int i;
64368c2ecf20Sopenharmony_ci
64378c2ecf20Sopenharmony_ci	if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
64388c2ecf20Sopenharmony_ci		return 0;
64398c2ecf20Sopenharmony_ci
64408c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
64418c2ecf20Sopenharmony_ci		pdev = &ab->pdevs[i];
64428c2ecf20Sopenharmony_ci		hw = ieee80211_alloc_hw(sizeof(struct ath11k), &ath11k_ops);
64438c2ecf20Sopenharmony_ci		if (!hw) {
64448c2ecf20Sopenharmony_ci			ath11k_warn(ab, "failed to allocate mac80211 hw device\n");
64458c2ecf20Sopenharmony_ci			ret = -ENOMEM;
64468c2ecf20Sopenharmony_ci			goto err_free_mac;
64478c2ecf20Sopenharmony_ci		}
64488c2ecf20Sopenharmony_ci
64498c2ecf20Sopenharmony_ci		ar = hw->priv;
64508c2ecf20Sopenharmony_ci		ar->hw = hw;
64518c2ecf20Sopenharmony_ci		ar->ab = ab;
64528c2ecf20Sopenharmony_ci		ar->pdev = pdev;
64538c2ecf20Sopenharmony_ci		ar->pdev_idx = i;
64548c2ecf20Sopenharmony_ci		ar->lmac_id = ath11k_hw_get_mac_from_pdev_id(&ab->hw_params, i);
64558c2ecf20Sopenharmony_ci
64568c2ecf20Sopenharmony_ci		ar->wmi = &ab->wmi_ab.wmi[i];
64578c2ecf20Sopenharmony_ci		/* FIXME wmi[0] is already initialized during attach,
64588c2ecf20Sopenharmony_ci		 * Should we do this again?
64598c2ecf20Sopenharmony_ci		 */
64608c2ecf20Sopenharmony_ci		ath11k_wmi_pdev_attach(ab, i);
64618c2ecf20Sopenharmony_ci
64628c2ecf20Sopenharmony_ci		ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask;
64638c2ecf20Sopenharmony_ci		ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask;
64648c2ecf20Sopenharmony_ci		ar->num_tx_chains = get_num_chains(pdev->cap.tx_chain_mask);
64658c2ecf20Sopenharmony_ci		ar->num_rx_chains = get_num_chains(pdev->cap.rx_chain_mask);
64668c2ecf20Sopenharmony_ci
64678c2ecf20Sopenharmony_ci		pdev->ar = ar;
64688c2ecf20Sopenharmony_ci		spin_lock_init(&ar->data_lock);
64698c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ar->arvifs);
64708c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ar->ppdu_stats_info);
64718c2ecf20Sopenharmony_ci		mutex_init(&ar->conf_mutex);
64728c2ecf20Sopenharmony_ci		init_completion(&ar->vdev_setup_done);
64738c2ecf20Sopenharmony_ci		init_completion(&ar->peer_assoc_done);
64748c2ecf20Sopenharmony_ci		init_completion(&ar->peer_delete_done);
64758c2ecf20Sopenharmony_ci		init_completion(&ar->install_key_done);
64768c2ecf20Sopenharmony_ci		init_completion(&ar->bss_survey_done);
64778c2ecf20Sopenharmony_ci		init_completion(&ar->scan.started);
64788c2ecf20Sopenharmony_ci		init_completion(&ar->scan.completed);
64798c2ecf20Sopenharmony_ci		init_completion(&ar->thermal.wmi_sync);
64808c2ecf20Sopenharmony_ci
64818c2ecf20Sopenharmony_ci		INIT_DELAYED_WORK(&ar->scan.timeout, ath11k_scan_timeout_work);
64828c2ecf20Sopenharmony_ci		INIT_WORK(&ar->regd_update_work, ath11k_regd_update_work);
64838c2ecf20Sopenharmony_ci
64848c2ecf20Sopenharmony_ci		INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work);
64858c2ecf20Sopenharmony_ci		skb_queue_head_init(&ar->wmi_mgmt_tx_queue);
64868c2ecf20Sopenharmony_ci		clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
64878c2ecf20Sopenharmony_ci	}
64888c2ecf20Sopenharmony_ci
64898c2ecf20Sopenharmony_ci	return 0;
64908c2ecf20Sopenharmony_ci
64918c2ecf20Sopenharmony_cierr_free_mac:
64928c2ecf20Sopenharmony_ci	ath11k_mac_destroy(ab);
64938c2ecf20Sopenharmony_ci
64948c2ecf20Sopenharmony_ci	return ret;
64958c2ecf20Sopenharmony_ci}
64968c2ecf20Sopenharmony_ci
64978c2ecf20Sopenharmony_civoid ath11k_mac_destroy(struct ath11k_base *ab)
64988c2ecf20Sopenharmony_ci{
64998c2ecf20Sopenharmony_ci	struct ath11k *ar;
65008c2ecf20Sopenharmony_ci	struct ath11k_pdev *pdev;
65018c2ecf20Sopenharmony_ci	int i;
65028c2ecf20Sopenharmony_ci
65038c2ecf20Sopenharmony_ci	for (i = 0; i < ab->num_radios; i++) {
65048c2ecf20Sopenharmony_ci		pdev = &ab->pdevs[i];
65058c2ecf20Sopenharmony_ci		ar = pdev->ar;
65068c2ecf20Sopenharmony_ci		if (!ar)
65078c2ecf20Sopenharmony_ci			continue;
65088c2ecf20Sopenharmony_ci
65098c2ecf20Sopenharmony_ci		ieee80211_free_hw(ar->hw);
65108c2ecf20Sopenharmony_ci		pdev->ar = NULL;
65118c2ecf20Sopenharmony_ci	}
65128c2ecf20Sopenharmony_ci}
6513