18e93258fSBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
28e93258fSBjoern A. Zeeb /* Copyright(c) 2019-2020 Realtek Corporation
38e93258fSBjoern A. Zeeb */
48e93258fSBjoern A. Zeeb
58e93258fSBjoern A. Zeeb #if defined(__FreeBSD__)
68e93258fSBjoern A. Zeeb #define LINUXKPI_PARAM_PREFIX rtw89_
78e93258fSBjoern A. Zeeb #endif
88e93258fSBjoern A. Zeeb
98e93258fSBjoern A. Zeeb #include <linux/ip.h>
108e93258fSBjoern A. Zeeb #include <linux/udp.h>
118e93258fSBjoern A. Zeeb
128e93258fSBjoern A. Zeeb #include "cam.h"
138e93258fSBjoern A. Zeeb #include "chan.h"
148e93258fSBjoern A. Zeeb #include "coex.h"
158e93258fSBjoern A. Zeeb #include "core.h"
168e93258fSBjoern A. Zeeb #include "efuse.h"
178e93258fSBjoern A. Zeeb #include "fw.h"
188e93258fSBjoern A. Zeeb #include "mac.h"
198e93258fSBjoern A. Zeeb #include "phy.h"
208e93258fSBjoern A. Zeeb #include "ps.h"
218e93258fSBjoern A. Zeeb #include "reg.h"
228e93258fSBjoern A. Zeeb #include "sar.h"
238e93258fSBjoern A. Zeeb #include "ser.h"
248e93258fSBjoern A. Zeeb #include "txrx.h"
258e93258fSBjoern A. Zeeb #include "util.h"
266d67aabdSBjoern A. Zeeb #include "wow.h"
278e93258fSBjoern A. Zeeb
288e93258fSBjoern A. Zeeb static bool rtw89_disable_ps_mode;
298e93258fSBjoern A. Zeeb module_param_named(disable_ps_mode, rtw89_disable_ps_mode, bool, 0644);
308e93258fSBjoern A. Zeeb MODULE_PARM_DESC(disable_ps_mode, "Set Y to disable low power mode");
318e93258fSBjoern A. Zeeb
32*7a5b55e3SBjoern A. Zeeb #if defined(__FreeBSD__)
33*7a5b55e3SBjoern A. Zeeb static bool rtw_ht_support = false;
34*7a5b55e3SBjoern A. Zeeb module_param_named(support_ht, rtw_ht_support, bool, 0644);
35*7a5b55e3SBjoern A. Zeeb MODULE_PARM_DESC(support_ht, "Set to Y to enable HT support");
36*7a5b55e3SBjoern A. Zeeb
37*7a5b55e3SBjoern A. Zeeb static bool rtw_vht_support = false;
38*7a5b55e3SBjoern A. Zeeb module_param_named(support_vht, rtw_vht_support, bool, 0644);
39*7a5b55e3SBjoern A. Zeeb MODULE_PARM_DESC(support_vht, "Set to Y to enable VHT support");
40*7a5b55e3SBjoern A. Zeeb
41*7a5b55e3SBjoern A. Zeeb static bool rtw_eht_support = false;
42*7a5b55e3SBjoern A. Zeeb module_param_named(support_eht, rtw_eht_support, bool, 0644);
43*7a5b55e3SBjoern A. Zeeb MODULE_PARM_DESC(support_eht, "Set to Y to enable EHT support");
44*7a5b55e3SBjoern A. Zeeb #endif
45*7a5b55e3SBjoern A. Zeeb
46*7a5b55e3SBjoern A. Zeeb
478e93258fSBjoern A. Zeeb #define RTW89_DEF_CHAN(_freq, _hw_val, _flags, _band) \
488e93258fSBjoern A. Zeeb { .center_freq = _freq, .hw_value = _hw_val, .flags = _flags, .band = _band, }
498e93258fSBjoern A. Zeeb #define RTW89_DEF_CHAN_2G(_freq, _hw_val) \
508e93258fSBjoern A. Zeeb RTW89_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_2GHZ)
518e93258fSBjoern A. Zeeb #define RTW89_DEF_CHAN_5G(_freq, _hw_val) \
528e93258fSBjoern A. Zeeb RTW89_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_5GHZ)
538e93258fSBjoern A. Zeeb #define RTW89_DEF_CHAN_5G_NO_HT40MINUS(_freq, _hw_val) \
548e93258fSBjoern A. Zeeb RTW89_DEF_CHAN(_freq, _hw_val, IEEE80211_CHAN_NO_HT40MINUS, NL80211_BAND_5GHZ)
558e93258fSBjoern A. Zeeb #define RTW89_DEF_CHAN_6G(_freq, _hw_val) \
568e93258fSBjoern A. Zeeb RTW89_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_6GHZ)
578e93258fSBjoern A. Zeeb
588e93258fSBjoern A. Zeeb static struct ieee80211_channel rtw89_channels_2ghz[] = {
598e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2412, 1),
608e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2417, 2),
618e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2422, 3),
628e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2427, 4),
638e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2432, 5),
648e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2437, 6),
658e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2442, 7),
668e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2447, 8),
678e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2452, 9),
688e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2457, 10),
698e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2462, 11),
708e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2467, 12),
718e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2472, 13),
728e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_2G(2484, 14),
738e93258fSBjoern A. Zeeb };
748e93258fSBjoern A. Zeeb
758e93258fSBjoern A. Zeeb static struct ieee80211_channel rtw89_channels_5ghz[] = {
768e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5180, 36),
778e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5200, 40),
788e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5220, 44),
798e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5240, 48),
808e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5260, 52),
818e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5280, 56),
828e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5300, 60),
838e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5320, 64),
848e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5500, 100),
858e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5520, 104),
868e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5540, 108),
878e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5560, 112),
888e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5580, 116),
898e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5600, 120),
908e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5620, 124),
918e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5640, 128),
928e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5660, 132),
938e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5680, 136),
948e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5700, 140),
958e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5720, 144),
968e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5745, 149),
978e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5765, 153),
988e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5785, 157),
998e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G(5805, 161),
1008e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_5G_NO_HT40MINUS(5825, 165),
101e2340276SBjoern A. Zeeb RTW89_DEF_CHAN_5G(5845, 169),
102e2340276SBjoern A. Zeeb RTW89_DEF_CHAN_5G(5865, 173),
103e2340276SBjoern A. Zeeb RTW89_DEF_CHAN_5G(5885, 177),
1048e93258fSBjoern A. Zeeb };
1058e93258fSBjoern A. Zeeb
1066d67aabdSBjoern A. Zeeb static_assert(RTW89_5GHZ_UNII4_START_INDEX + RTW89_5GHZ_UNII4_CHANNEL_NUM ==
1076d67aabdSBjoern A. Zeeb ARRAY_SIZE(rtw89_channels_5ghz));
1086d67aabdSBjoern A. Zeeb
1098e93258fSBjoern A. Zeeb static struct ieee80211_channel rtw89_channels_6ghz[] = {
1108e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(5955, 1),
1118e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(5975, 5),
1128e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(5995, 9),
1138e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6015, 13),
1148e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6035, 17),
1158e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6055, 21),
1168e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6075, 25),
1178e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6095, 29),
1188e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6115, 33),
1198e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6135, 37),
1208e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6155, 41),
1218e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6175, 45),
1228e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6195, 49),
1238e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6215, 53),
1248e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6235, 57),
1258e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6255, 61),
1268e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6275, 65),
1278e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6295, 69),
1288e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6315, 73),
1298e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6335, 77),
1308e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6355, 81),
1318e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6375, 85),
1328e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6395, 89),
1338e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6415, 93),
1348e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6435, 97),
1358e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6455, 101),
1368e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6475, 105),
1378e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6495, 109),
1388e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6515, 113),
1398e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6535, 117),
1408e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6555, 121),
1418e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6575, 125),
1428e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6595, 129),
1438e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6615, 133),
1448e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6635, 137),
1458e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6655, 141),
1468e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6675, 145),
1478e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6695, 149),
1488e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6715, 153),
1498e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6735, 157),
1508e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6755, 161),
1518e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6775, 165),
1528e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6795, 169),
1538e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6815, 173),
1548e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6835, 177),
1558e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6855, 181),
1568e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6875, 185),
1578e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6895, 189),
1588e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6915, 193),
1598e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6935, 197),
1608e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6955, 201),
1618e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6975, 205),
1628e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(6995, 209),
1638e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(7015, 213),
1648e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(7035, 217),
1658e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(7055, 221),
1668e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(7075, 225),
1678e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(7095, 229),
1688e93258fSBjoern A. Zeeb RTW89_DEF_CHAN_6G(7115, 233),
1698e93258fSBjoern A. Zeeb };
1708e93258fSBjoern A. Zeeb
1718e93258fSBjoern A. Zeeb static struct ieee80211_rate rtw89_bitrates[] = {
1728e93258fSBjoern A. Zeeb { .bitrate = 10, .hw_value = 0x00, },
1738e93258fSBjoern A. Zeeb { .bitrate = 20, .hw_value = 0x01, },
1748e93258fSBjoern A. Zeeb { .bitrate = 55, .hw_value = 0x02, },
1758e93258fSBjoern A. Zeeb { .bitrate = 110, .hw_value = 0x03, },
1768e93258fSBjoern A. Zeeb { .bitrate = 60, .hw_value = 0x04, },
1778e93258fSBjoern A. Zeeb { .bitrate = 90, .hw_value = 0x05, },
1788e93258fSBjoern A. Zeeb { .bitrate = 120, .hw_value = 0x06, },
1798e93258fSBjoern A. Zeeb { .bitrate = 180, .hw_value = 0x07, },
1808e93258fSBjoern A. Zeeb { .bitrate = 240, .hw_value = 0x08, },
1818e93258fSBjoern A. Zeeb { .bitrate = 360, .hw_value = 0x09, },
1828e93258fSBjoern A. Zeeb { .bitrate = 480, .hw_value = 0x0a, },
1838e93258fSBjoern A. Zeeb { .bitrate = 540, .hw_value = 0x0b, },
1848e93258fSBjoern A. Zeeb };
1858e93258fSBjoern A. Zeeb
186e2340276SBjoern A. Zeeb static const struct ieee80211_iface_limit rtw89_iface_limits[] = {
187e2340276SBjoern A. Zeeb {
188e2340276SBjoern A. Zeeb .max = 1,
189e2340276SBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION),
190e2340276SBjoern A. Zeeb },
191e2340276SBjoern A. Zeeb {
192e2340276SBjoern A. Zeeb .max = 1,
193e2340276SBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
194e2340276SBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) |
195e2340276SBjoern A. Zeeb BIT(NL80211_IFTYPE_AP),
196e2340276SBjoern A. Zeeb },
197e2340276SBjoern A. Zeeb };
198e2340276SBjoern A. Zeeb
1996d67aabdSBjoern A. Zeeb static const struct ieee80211_iface_limit rtw89_iface_limits_mcc[] = {
2006d67aabdSBjoern A. Zeeb {
2016d67aabdSBjoern A. Zeeb .max = 1,
2026d67aabdSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_STATION),
2036d67aabdSBjoern A. Zeeb },
2046d67aabdSBjoern A. Zeeb {
2056d67aabdSBjoern A. Zeeb .max = 1,
2066d67aabdSBjoern A. Zeeb .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
2076d67aabdSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO),
2086d67aabdSBjoern A. Zeeb },
2096d67aabdSBjoern A. Zeeb };
2106d67aabdSBjoern A. Zeeb
211e2340276SBjoern A. Zeeb static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
212e2340276SBjoern A. Zeeb {
213e2340276SBjoern A. Zeeb .limits = rtw89_iface_limits,
214e2340276SBjoern A. Zeeb .n_limits = ARRAY_SIZE(rtw89_iface_limits),
215e2340276SBjoern A. Zeeb .max_interfaces = 2,
216e2340276SBjoern A. Zeeb .num_different_channels = 1,
2176d67aabdSBjoern A. Zeeb },
2186d67aabdSBjoern A. Zeeb {
2196d67aabdSBjoern A. Zeeb .limits = rtw89_iface_limits_mcc,
2206d67aabdSBjoern A. Zeeb .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc),
2216d67aabdSBjoern A. Zeeb .max_interfaces = 2,
2226d67aabdSBjoern A. Zeeb .num_different_channels = 2,
2236d67aabdSBjoern A. Zeeb },
224e2340276SBjoern A. Zeeb };
225e2340276SBjoern A. Zeeb
rtw89_ra_report_to_bitrate(struct rtw89_dev * rtwdev,u8 rpt_rate,u16 * bitrate)2268e93258fSBjoern A. Zeeb bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate)
2278e93258fSBjoern A. Zeeb {
2288e93258fSBjoern A. Zeeb struct ieee80211_rate rate;
2298e93258fSBjoern A. Zeeb
2308e93258fSBjoern A. Zeeb if (unlikely(rpt_rate >= ARRAY_SIZE(rtw89_bitrates))) {
2318e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rpt rate %d\n", rpt_rate);
2328e93258fSBjoern A. Zeeb return false;
2338e93258fSBjoern A. Zeeb }
2348e93258fSBjoern A. Zeeb
2358e93258fSBjoern A. Zeeb rate = rtw89_bitrates[rpt_rate];
2368e93258fSBjoern A. Zeeb *bitrate = rate.bitrate;
2378e93258fSBjoern A. Zeeb
2388e93258fSBjoern A. Zeeb return true;
2398e93258fSBjoern A. Zeeb }
2408e93258fSBjoern A. Zeeb
241e2340276SBjoern A. Zeeb static const struct ieee80211_supported_band rtw89_sband_2ghz = {
2428e93258fSBjoern A. Zeeb .band = NL80211_BAND_2GHZ,
2438e93258fSBjoern A. Zeeb .channels = rtw89_channels_2ghz,
2448e93258fSBjoern A. Zeeb .n_channels = ARRAY_SIZE(rtw89_channels_2ghz),
2458e93258fSBjoern A. Zeeb .bitrates = rtw89_bitrates,
2468e93258fSBjoern A. Zeeb .n_bitrates = ARRAY_SIZE(rtw89_bitrates),
2478e93258fSBjoern A. Zeeb .ht_cap = {0},
2488e93258fSBjoern A. Zeeb .vht_cap = {0},
2498e93258fSBjoern A. Zeeb };
2508e93258fSBjoern A. Zeeb
251e2340276SBjoern A. Zeeb static const struct ieee80211_supported_band rtw89_sband_5ghz = {
2528e93258fSBjoern A. Zeeb .band = NL80211_BAND_5GHZ,
2538e93258fSBjoern A. Zeeb .channels = rtw89_channels_5ghz,
2548e93258fSBjoern A. Zeeb .n_channels = ARRAY_SIZE(rtw89_channels_5ghz),
2558e93258fSBjoern A. Zeeb
2568e93258fSBjoern A. Zeeb /* 5G has no CCK rates, 1M/2M/5.5M/11M */
2578e93258fSBjoern A. Zeeb .bitrates = rtw89_bitrates + 4,
2588e93258fSBjoern A. Zeeb .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4,
2598e93258fSBjoern A. Zeeb .ht_cap = {0},
2608e93258fSBjoern A. Zeeb .vht_cap = {0},
2618e93258fSBjoern A. Zeeb };
2628e93258fSBjoern A. Zeeb
263e2340276SBjoern A. Zeeb static const struct ieee80211_supported_band rtw89_sband_6ghz = {
2648e93258fSBjoern A. Zeeb .band = NL80211_BAND_6GHZ,
2658e93258fSBjoern A. Zeeb .channels = rtw89_channels_6ghz,
2668e93258fSBjoern A. Zeeb .n_channels = ARRAY_SIZE(rtw89_channels_6ghz),
2678e93258fSBjoern A. Zeeb
2688e93258fSBjoern A. Zeeb /* 6G has no CCK rates, 1M/2M/5.5M/11M */
2698e93258fSBjoern A. Zeeb .bitrates = rtw89_bitrates + 4,
2708e93258fSBjoern A. Zeeb .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4,
2718e93258fSBjoern A. Zeeb };
2728e93258fSBjoern A. Zeeb
rtw89_traffic_stats_accu(struct rtw89_dev * rtwdev,struct rtw89_traffic_stats * stats,struct sk_buff * skb,bool tx)2738e93258fSBjoern A. Zeeb static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev,
2748e93258fSBjoern A. Zeeb struct rtw89_traffic_stats *stats,
2758e93258fSBjoern A. Zeeb struct sk_buff *skb, bool tx)
2768e93258fSBjoern A. Zeeb {
2778e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
2788e93258fSBjoern A. Zeeb
2796d67aabdSBjoern A. Zeeb if (tx && ieee80211_is_assoc_req(hdr->frame_control))
2806d67aabdSBjoern A. Zeeb rtw89_wow_parse_akm(rtwdev, skb);
2816d67aabdSBjoern A. Zeeb
2828e93258fSBjoern A. Zeeb if (!ieee80211_is_data(hdr->frame_control))
2838e93258fSBjoern A. Zeeb return;
2848e93258fSBjoern A. Zeeb
2858e93258fSBjoern A. Zeeb if (is_broadcast_ether_addr(hdr->addr1) ||
2868e93258fSBjoern A. Zeeb is_multicast_ether_addr(hdr->addr1))
2878e93258fSBjoern A. Zeeb return;
2888e93258fSBjoern A. Zeeb
2898e93258fSBjoern A. Zeeb if (tx) {
2908e93258fSBjoern A. Zeeb stats->tx_cnt++;
2918e93258fSBjoern A. Zeeb stats->tx_unicast += skb->len;
2928e93258fSBjoern A. Zeeb } else {
2938e93258fSBjoern A. Zeeb stats->rx_cnt++;
2948e93258fSBjoern A. Zeeb stats->rx_unicast += skb->len;
2958e93258fSBjoern A. Zeeb }
2968e93258fSBjoern A. Zeeb }
2978e93258fSBjoern A. Zeeb
rtw89_get_default_chandef(struct cfg80211_chan_def * chandef)2988e93258fSBjoern A. Zeeb void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef)
2998e93258fSBjoern A. Zeeb {
3008e93258fSBjoern A. Zeeb cfg80211_chandef_create(chandef, &rtw89_channels_2ghz[0],
3018e93258fSBjoern A. Zeeb NL80211_CHAN_NO_HT);
3028e93258fSBjoern A. Zeeb }
3038e93258fSBjoern A. Zeeb
rtw89_get_channel_params(const struct cfg80211_chan_def * chandef,struct rtw89_chan * chan)3046d67aabdSBjoern A. Zeeb void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
3058e93258fSBjoern A. Zeeb struct rtw89_chan *chan)
3068e93258fSBjoern A. Zeeb {
3078e93258fSBjoern A. Zeeb struct ieee80211_channel *channel = chandef->chan;
3088e93258fSBjoern A. Zeeb enum nl80211_chan_width width = chandef->width;
3098e93258fSBjoern A. Zeeb u32 primary_freq, center_freq;
3108e93258fSBjoern A. Zeeb u8 center_chan;
3118e93258fSBjoern A. Zeeb u8 bandwidth = RTW89_CHANNEL_WIDTH_20;
3128e93258fSBjoern A. Zeeb u32 offset;
3138e93258fSBjoern A. Zeeb u8 band;
3148e93258fSBjoern A. Zeeb
3158e93258fSBjoern A. Zeeb center_chan = channel->hw_value;
3168e93258fSBjoern A. Zeeb primary_freq = channel->center_freq;
3178e93258fSBjoern A. Zeeb center_freq = chandef->center_freq1;
3188e93258fSBjoern A. Zeeb
3198e93258fSBjoern A. Zeeb switch (width) {
3208e93258fSBjoern A. Zeeb case NL80211_CHAN_WIDTH_20_NOHT:
3218e93258fSBjoern A. Zeeb case NL80211_CHAN_WIDTH_20:
3228e93258fSBjoern A. Zeeb bandwidth = RTW89_CHANNEL_WIDTH_20;
3238e93258fSBjoern A. Zeeb break;
3248e93258fSBjoern A. Zeeb case NL80211_CHAN_WIDTH_40:
3258e93258fSBjoern A. Zeeb bandwidth = RTW89_CHANNEL_WIDTH_40;
3268e93258fSBjoern A. Zeeb if (primary_freq > center_freq) {
3278e93258fSBjoern A. Zeeb center_chan -= 2;
3288e93258fSBjoern A. Zeeb } else {
3298e93258fSBjoern A. Zeeb center_chan += 2;
3308e93258fSBjoern A. Zeeb }
3318e93258fSBjoern A. Zeeb break;
3328e93258fSBjoern A. Zeeb case NL80211_CHAN_WIDTH_80:
3338e93258fSBjoern A. Zeeb case NL80211_CHAN_WIDTH_160:
3348e93258fSBjoern A. Zeeb bandwidth = nl_to_rtw89_bandwidth(width);
3358e93258fSBjoern A. Zeeb if (primary_freq > center_freq) {
3368e93258fSBjoern A. Zeeb offset = (primary_freq - center_freq - 10) / 20;
3378e93258fSBjoern A. Zeeb center_chan -= 2 + offset * 4;
3388e93258fSBjoern A. Zeeb } else {
3398e93258fSBjoern A. Zeeb offset = (center_freq - primary_freq - 10) / 20;
3408e93258fSBjoern A. Zeeb center_chan += 2 + offset * 4;
3418e93258fSBjoern A. Zeeb }
3428e93258fSBjoern A. Zeeb break;
3438e93258fSBjoern A. Zeeb default:
3448e93258fSBjoern A. Zeeb center_chan = 0;
3458e93258fSBjoern A. Zeeb break;
3468e93258fSBjoern A. Zeeb }
3478e93258fSBjoern A. Zeeb
3488e93258fSBjoern A. Zeeb switch (channel->band) {
3498e93258fSBjoern A. Zeeb default:
3508e93258fSBjoern A. Zeeb case NL80211_BAND_2GHZ:
3518e93258fSBjoern A. Zeeb band = RTW89_BAND_2G;
3528e93258fSBjoern A. Zeeb break;
3538e93258fSBjoern A. Zeeb case NL80211_BAND_5GHZ:
3548e93258fSBjoern A. Zeeb band = RTW89_BAND_5G;
3558e93258fSBjoern A. Zeeb break;
3568e93258fSBjoern A. Zeeb case NL80211_BAND_6GHZ:
3578e93258fSBjoern A. Zeeb band = RTW89_BAND_6G;
3588e93258fSBjoern A. Zeeb break;
3598e93258fSBjoern A. Zeeb }
3608e93258fSBjoern A. Zeeb
3618e93258fSBjoern A. Zeeb rtw89_chan_create(chan, center_chan, channel->hw_value, band, bandwidth);
3628e93258fSBjoern A. Zeeb }
3638e93258fSBjoern A. Zeeb
rtw89_core_set_chip_txpwr(struct rtw89_dev * rtwdev)3648e93258fSBjoern A. Zeeb void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
3658e93258fSBjoern A. Zeeb {
3666d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
3678e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
3688e93258fSBjoern A. Zeeb const struct rtw89_chan *chan;
3698e93258fSBjoern A. Zeeb enum rtw89_sub_entity_idx sub_entity_idx;
3706d67aabdSBjoern A. Zeeb enum rtw89_sub_entity_idx roc_idx;
3718e93258fSBjoern A. Zeeb enum rtw89_phy_idx phy_idx;
3728e93258fSBjoern A. Zeeb enum rtw89_entity_mode mode;
3738e93258fSBjoern A. Zeeb bool entity_active;
3748e93258fSBjoern A. Zeeb
3758e93258fSBjoern A. Zeeb entity_active = rtw89_get_entity_state(rtwdev);
3768e93258fSBjoern A. Zeeb if (!entity_active)
3778e93258fSBjoern A. Zeeb return;
3788e93258fSBjoern A. Zeeb
3798e93258fSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
3806d67aabdSBjoern A. Zeeb switch (mode) {
3816d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_SCC:
3826d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
3838e93258fSBjoern A. Zeeb sub_entity_idx = RTW89_SUB_ENTITY_0;
3846d67aabdSBjoern A. Zeeb break;
3856d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC_PREPARE:
3866d67aabdSBjoern A. Zeeb sub_entity_idx = RTW89_SUB_ENTITY_1;
3876d67aabdSBjoern A. Zeeb break;
3886d67aabdSBjoern A. Zeeb default:
3896d67aabdSBjoern A. Zeeb WARN(1, "Invalid ent mode: %d\n", mode);
3906d67aabdSBjoern A. Zeeb return;
3916d67aabdSBjoern A. Zeeb }
3926d67aabdSBjoern A. Zeeb
3936d67aabdSBjoern A. Zeeb roc_idx = atomic_read(&hal->roc_entity_idx);
3946d67aabdSBjoern A. Zeeb if (roc_idx != RTW89_SUB_ENTITY_IDLE)
3956d67aabdSBjoern A. Zeeb sub_entity_idx = roc_idx;
3966d67aabdSBjoern A. Zeeb
3978e93258fSBjoern A. Zeeb phy_idx = RTW89_PHY_0;
3988e93258fSBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, sub_entity_idx);
3998e93258fSBjoern A. Zeeb chip->ops->set_txpwr(rtwdev, chan, phy_idx);
4008e93258fSBjoern A. Zeeb }
4018e93258fSBjoern A. Zeeb
rtw89_set_channel(struct rtw89_dev * rtwdev)4026d67aabdSBjoern A. Zeeb int rtw89_set_channel(struct rtw89_dev *rtwdev)
4038e93258fSBjoern A. Zeeb {
4046d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
4058e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
4066d67aabdSBjoern A. Zeeb const struct rtw89_chan_rcd *chan_rcd;
4076d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan;
4088e93258fSBjoern A. Zeeb enum rtw89_sub_entity_idx sub_entity_idx;
4096d67aabdSBjoern A. Zeeb enum rtw89_sub_entity_idx roc_idx;
4108e93258fSBjoern A. Zeeb enum rtw89_mac_idx mac_idx;
4118e93258fSBjoern A. Zeeb enum rtw89_phy_idx phy_idx;
4128e93258fSBjoern A. Zeeb struct rtw89_channel_help_params bak;
4138e93258fSBjoern A. Zeeb enum rtw89_entity_mode mode;
4148e93258fSBjoern A. Zeeb bool entity_active;
4158e93258fSBjoern A. Zeeb
4168e93258fSBjoern A. Zeeb entity_active = rtw89_get_entity_state(rtwdev);
4178e93258fSBjoern A. Zeeb
4188e93258fSBjoern A. Zeeb mode = rtw89_entity_recalc(rtwdev);
4196d67aabdSBjoern A. Zeeb switch (mode) {
4206d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_SCC:
4216d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC:
4228e93258fSBjoern A. Zeeb sub_entity_idx = RTW89_SUB_ENTITY_0;
4236d67aabdSBjoern A. Zeeb break;
4246d67aabdSBjoern A. Zeeb case RTW89_ENTITY_MODE_MCC_PREPARE:
4256d67aabdSBjoern A. Zeeb sub_entity_idx = RTW89_SUB_ENTITY_1;
4266d67aabdSBjoern A. Zeeb break;
4276d67aabdSBjoern A. Zeeb default:
4286d67aabdSBjoern A. Zeeb WARN(1, "Invalid ent mode: %d\n", mode);
4296d67aabdSBjoern A. Zeeb return -EINVAL;
4306d67aabdSBjoern A. Zeeb }
4316d67aabdSBjoern A. Zeeb
4326d67aabdSBjoern A. Zeeb roc_idx = atomic_read(&hal->roc_entity_idx);
4336d67aabdSBjoern A. Zeeb if (roc_idx != RTW89_SUB_ENTITY_IDLE)
4346d67aabdSBjoern A. Zeeb sub_entity_idx = roc_idx;
4356d67aabdSBjoern A. Zeeb
4368e93258fSBjoern A. Zeeb mac_idx = RTW89_MAC_0;
4378e93258fSBjoern A. Zeeb phy_idx = RTW89_PHY_0;
4388e93258fSBjoern A. Zeeb
4396d67aabdSBjoern A. Zeeb chan = rtw89_chan_get(rtwdev, sub_entity_idx);
4406d67aabdSBjoern A. Zeeb chan_rcd = rtw89_chan_rcd_get(rtwdev, sub_entity_idx);
4418e93258fSBjoern A. Zeeb
4426d67aabdSBjoern A. Zeeb rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx);
4438e93258fSBjoern A. Zeeb
4446d67aabdSBjoern A. Zeeb chip->ops->set_channel(rtwdev, chan, mac_idx, phy_idx);
4458e93258fSBjoern A. Zeeb
4466d67aabdSBjoern A. Zeeb chip->ops->set_txpwr(rtwdev, chan, phy_idx);
4478e93258fSBjoern A. Zeeb
4486d67aabdSBjoern A. Zeeb rtw89_chip_set_channel_done(rtwdev, &bak, chan, mac_idx, phy_idx);
4498e93258fSBjoern A. Zeeb
4506d67aabdSBjoern A. Zeeb if (!entity_active || chan_rcd->band_changed) {
4516d67aabdSBjoern A. Zeeb rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan->band_type);
4528e93258fSBjoern A. Zeeb rtw89_chip_rfk_band_changed(rtwdev, phy_idx);
4538e93258fSBjoern A. Zeeb }
4548e93258fSBjoern A. Zeeb
4558e93258fSBjoern A. Zeeb rtw89_set_entity_state(rtwdev, true);
4566d67aabdSBjoern A. Zeeb return 0;
4578e93258fSBjoern A. Zeeb }
4588e93258fSBjoern A. Zeeb
rtw89_get_channel(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,struct rtw89_chan * chan)459e2340276SBjoern A. Zeeb void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
460e2340276SBjoern A. Zeeb struct rtw89_chan *chan)
461e2340276SBjoern A. Zeeb {
462e2340276SBjoern A. Zeeb const struct cfg80211_chan_def *chandef;
463e2340276SBjoern A. Zeeb
464e2340276SBjoern A. Zeeb chandef = rtw89_chandef_get(rtwdev, rtwvif->sub_entity_idx);
465e2340276SBjoern A. Zeeb rtw89_get_channel_params(chandef, chan);
466e2340276SBjoern A. Zeeb }
467e2340276SBjoern A. Zeeb
4688e93258fSBjoern A. Zeeb static enum rtw89_core_tx_type
rtw89_core_get_tx_type(struct rtw89_dev * rtwdev,struct sk_buff * skb)4698e93258fSBjoern A. Zeeb rtw89_core_get_tx_type(struct rtw89_dev *rtwdev,
4708e93258fSBjoern A. Zeeb struct sk_buff *skb)
4718e93258fSBjoern A. Zeeb {
4728e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (void *)skb->data;
4738e93258fSBjoern A. Zeeb __le16 fc = hdr->frame_control;
4748e93258fSBjoern A. Zeeb
4758e93258fSBjoern A. Zeeb if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc))
4768e93258fSBjoern A. Zeeb return RTW89_CORE_TX_TYPE_MGMT;
4778e93258fSBjoern A. Zeeb
4788e93258fSBjoern A. Zeeb return RTW89_CORE_TX_TYPE_DATA;
4798e93258fSBjoern A. Zeeb }
4808e93258fSBjoern A. Zeeb
4818e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_ampdu_info(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req,enum btc_pkt_type pkt_type)4828e93258fSBjoern A. Zeeb rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev,
4838e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req,
4848e93258fSBjoern A. Zeeb enum btc_pkt_type pkt_type)
4858e93258fSBjoern A. Zeeb {
4868e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = tx_req->sta;
4878e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
4888e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
4898e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta;
4908e93258fSBjoern A. Zeeb u8 ampdu_num;
4918e93258fSBjoern A. Zeeb u8 tid;
4928e93258fSBjoern A. Zeeb
4938e93258fSBjoern A. Zeeb if (pkt_type == PACKET_EAPOL) {
4948e93258fSBjoern A. Zeeb desc_info->bk = true;
4958e93258fSBjoern A. Zeeb return;
4968e93258fSBjoern A. Zeeb }
4978e93258fSBjoern A. Zeeb
4988e93258fSBjoern A. Zeeb if (!(IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU))
4998e93258fSBjoern A. Zeeb return;
5008e93258fSBjoern A. Zeeb
5018e93258fSBjoern A. Zeeb if (!sta) {
5028e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "cannot set ampdu info without sta\n");
5038e93258fSBjoern A. Zeeb return;
5048e93258fSBjoern A. Zeeb }
5058e93258fSBjoern A. Zeeb
5068e93258fSBjoern A. Zeeb tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
5078e93258fSBjoern A. Zeeb rtwsta = (struct rtw89_sta *)sta->drv_priv;
5088e93258fSBjoern A. Zeeb
5098e93258fSBjoern A. Zeeb ampdu_num = (u8)((rtwsta->ampdu_params[tid].agg_num ?
5108e93258fSBjoern A. Zeeb rtwsta->ampdu_params[tid].agg_num :
5118e93258fSBjoern A. Zeeb 4 << sta->deflink.ht_cap.ampdu_factor) - 1);
5128e93258fSBjoern A. Zeeb
5138e93258fSBjoern A. Zeeb desc_info->agg_en = true;
5148e93258fSBjoern A. Zeeb desc_info->ampdu_density = sta->deflink.ht_cap.ampdu_density;
5158e93258fSBjoern A. Zeeb desc_info->ampdu_num = ampdu_num;
5168e93258fSBjoern A. Zeeb }
5178e93258fSBjoern A. Zeeb
5188e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_sec_key(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)5198e93258fSBjoern A. Zeeb rtw89_core_tx_update_sec_key(struct rtw89_dev *rtwdev,
5208e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
5218e93258fSBjoern A. Zeeb {
5226d67aabdSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
5238e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
5246d67aabdSBjoern A. Zeeb const struct rtw89_sec_cam_entry *sec_cam;
5258e93258fSBjoern A. Zeeb struct ieee80211_tx_info *info;
5268e93258fSBjoern A. Zeeb struct ieee80211_key_conf *key;
5278e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
5288e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
5298e93258fSBjoern A. Zeeb u8 sec_type = RTW89_SEC_KEY_TYPE_NONE;
5306d67aabdSBjoern A. Zeeb u8 sec_cam_idx;
5318e93258fSBjoern A. Zeeb u64 pn64;
5328e93258fSBjoern A. Zeeb
5338e93258fSBjoern A. Zeeb info = IEEE80211_SKB_CB(skb);
5348e93258fSBjoern A. Zeeb key = info->control.hw_key;
5356d67aabdSBjoern A. Zeeb sec_cam_idx = key->hw_key_idx;
5366d67aabdSBjoern A. Zeeb sec_cam = cam_info->sec_entries[sec_cam_idx];
5378e93258fSBjoern A. Zeeb if (!sec_cam) {
5388e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "sec cam entry is empty\n");
5398e93258fSBjoern A. Zeeb return;
5408e93258fSBjoern A. Zeeb }
5418e93258fSBjoern A. Zeeb
5428e93258fSBjoern A. Zeeb switch (key->cipher) {
5438e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP40:
5448e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_WEP40;
5458e93258fSBjoern A. Zeeb break;
5468e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_WEP104:
5478e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_WEP104;
5488e93258fSBjoern A. Zeeb break;
5498e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_TKIP:
5508e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_TKIP;
5518e93258fSBjoern A. Zeeb break;
5528e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP:
5538e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_CCMP128;
5548e93258fSBjoern A. Zeeb break;
5558e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_CCMP_256:
5568e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_CCMP256;
5578e93258fSBjoern A. Zeeb break;
5588e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP:
5598e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_GCMP128;
5608e93258fSBjoern A. Zeeb break;
5618e93258fSBjoern A. Zeeb case WLAN_CIPHER_SUITE_GCMP_256:
5628e93258fSBjoern A. Zeeb sec_type = RTW89_SEC_KEY_TYPE_GCMP256;
5638e93258fSBjoern A. Zeeb break;
5648e93258fSBjoern A. Zeeb default:
5658e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "key cipher not supported %d\n", key->cipher);
5668e93258fSBjoern A. Zeeb return;
5678e93258fSBjoern A. Zeeb }
5688e93258fSBjoern A. Zeeb
5698e93258fSBjoern A. Zeeb desc_info->sec_en = true;
5708e93258fSBjoern A. Zeeb desc_info->sec_keyid = key->keyidx;
5718e93258fSBjoern A. Zeeb desc_info->sec_type = sec_type;
5728e93258fSBjoern A. Zeeb desc_info->sec_cam_idx = sec_cam->sec_cam_idx;
5738e93258fSBjoern A. Zeeb
5748e93258fSBjoern A. Zeeb if (!chip->hw_sec_hdr)
5758e93258fSBjoern A. Zeeb return;
5768e93258fSBjoern A. Zeeb
5778e93258fSBjoern A. Zeeb pn64 = atomic64_inc_return(&key->tx_pn);
5788e93258fSBjoern A. Zeeb desc_info->sec_seq[0] = pn64;
5798e93258fSBjoern A. Zeeb desc_info->sec_seq[1] = pn64 >> 8;
5808e93258fSBjoern A. Zeeb desc_info->sec_seq[2] = pn64 >> 16;
5818e93258fSBjoern A. Zeeb desc_info->sec_seq[3] = pn64 >> 24;
5828e93258fSBjoern A. Zeeb desc_info->sec_seq[4] = pn64 >> 32;
5838e93258fSBjoern A. Zeeb desc_info->sec_seq[5] = pn64 >> 40;
5848e93258fSBjoern A. Zeeb desc_info->wp_offset = 1; /* in unit of 8 bytes for security header */
5858e93258fSBjoern A. Zeeb }
5868e93258fSBjoern A. Zeeb
rtw89_core_get_mgmt_rate(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req,const struct rtw89_chan * chan)5878e93258fSBjoern A. Zeeb static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
5886d67aabdSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req,
5896d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan)
5908e93258fSBjoern A. Zeeb {
5918e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
5928e93258fSBjoern A. Zeeb struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
5938e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = tx_info->control.vif;
594e2340276SBjoern A. Zeeb u16 lowest_rate;
595e2340276SBjoern A. Zeeb
596e2340276SBjoern A. Zeeb if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE ||
597e2340276SBjoern A. Zeeb (vif && vif->p2p))
598e2340276SBjoern A. Zeeb lowest_rate = RTW89_HW_RATE_OFDM6;
599e2340276SBjoern A. Zeeb else if (chan->band_type == RTW89_BAND_2G)
600e2340276SBjoern A. Zeeb lowest_rate = RTW89_HW_RATE_CCK1;
601e2340276SBjoern A. Zeeb else
602e2340276SBjoern A. Zeeb lowest_rate = RTW89_HW_RATE_OFDM6;
6038e93258fSBjoern A. Zeeb
6048e93258fSBjoern A. Zeeb if (!vif || !vif->bss_conf.basic_rates || !tx_req->sta)
6058e93258fSBjoern A. Zeeb return lowest_rate;
6068e93258fSBjoern A. Zeeb
6078e93258fSBjoern A. Zeeb return __ffs(vif->bss_conf.basic_rates) + lowest_rate;
6088e93258fSBjoern A. Zeeb }
6098e93258fSBjoern A. Zeeb
rtw89_core_tx_get_mac_id(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)610e2340276SBjoern A. Zeeb static u8 rtw89_core_tx_get_mac_id(struct rtw89_dev *rtwdev,
611e2340276SBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
612e2340276SBjoern A. Zeeb {
613e2340276SBjoern A. Zeeb struct ieee80211_vif *vif = tx_req->vif;
614e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
615e2340276SBjoern A. Zeeb struct ieee80211_sta *sta = tx_req->sta;
616e2340276SBjoern A. Zeeb struct rtw89_sta *rtwsta;
617e2340276SBjoern A. Zeeb
618e2340276SBjoern A. Zeeb if (!sta)
619e2340276SBjoern A. Zeeb return rtwvif->mac_id;
620e2340276SBjoern A. Zeeb
621e2340276SBjoern A. Zeeb rtwsta = (struct rtw89_sta *)sta->drv_priv;
622e2340276SBjoern A. Zeeb return rtwsta->mac_id;
623e2340276SBjoern A. Zeeb }
624e2340276SBjoern A. Zeeb
6258e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_mgmt_info(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)6268e93258fSBjoern A. Zeeb rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
6278e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
6288e93258fSBjoern A. Zeeb {
6298e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = tx_req->vif;
6308e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
6318e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
6326d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
6336d67aabdSBjoern A. Zeeb rtwvif->sub_entity_idx);
6348e93258fSBjoern A. Zeeb u8 qsel, ch_dma;
6358e93258fSBjoern A. Zeeb
6368e93258fSBjoern A. Zeeb qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : RTW89_TX_QSEL_B0_MGMT;
6378e93258fSBjoern A. Zeeb ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
6388e93258fSBjoern A. Zeeb
6398e93258fSBjoern A. Zeeb desc_info->qsel = qsel;
6408e93258fSBjoern A. Zeeb desc_info->ch_dma = ch_dma;
6418e93258fSBjoern A. Zeeb desc_info->port = desc_info->hiq ? rtwvif->port : 0;
642e2340276SBjoern A. Zeeb desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req);
6438e93258fSBjoern A. Zeeb desc_info->hw_ssn_sel = RTW89_MGMT_HW_SSN_SEL;
6448e93258fSBjoern A. Zeeb desc_info->hw_seq_mode = RTW89_MGMT_HW_SEQ_MODE;
6458e93258fSBjoern A. Zeeb
6468e93258fSBjoern A. Zeeb /* fixed data rate for mgmt frames */
6478e93258fSBjoern A. Zeeb desc_info->en_wd_info = true;
6488e93258fSBjoern A. Zeeb desc_info->use_rate = true;
6498e93258fSBjoern A. Zeeb desc_info->dis_data_fb = true;
6506d67aabdSBjoern A. Zeeb desc_info->data_rate = rtw89_core_get_mgmt_rate(rtwdev, tx_req, chan);
6518e93258fSBjoern A. Zeeb
6528e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
6538e93258fSBjoern A. Zeeb "tx mgmt frame with rate 0x%x on channel %d (band %d, bw %d)\n",
6548e93258fSBjoern A. Zeeb desc_info->data_rate, chan->channel, chan->band_type,
6558e93258fSBjoern A. Zeeb chan->band_width);
6568e93258fSBjoern A. Zeeb }
6578e93258fSBjoern A. Zeeb
6588e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_h2c_info(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)6598e93258fSBjoern A. Zeeb rtw89_core_tx_update_h2c_info(struct rtw89_dev *rtwdev,
6608e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
6618e93258fSBjoern A. Zeeb {
6628e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
6638e93258fSBjoern A. Zeeb
6648e93258fSBjoern A. Zeeb desc_info->is_bmc = false;
6658e93258fSBjoern A. Zeeb desc_info->wd_page = false;
6668e93258fSBjoern A. Zeeb desc_info->ch_dma = RTW89_DMA_H2C;
6678e93258fSBjoern A. Zeeb }
6688e93258fSBjoern A. Zeeb
rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev * rtwdev,__le32 * htc,const struct rtw89_chan * chan)6696d67aabdSBjoern A. Zeeb static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc,
6706d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan)
6718e93258fSBjoern A. Zeeb {
6728e93258fSBjoern A. Zeeb static const u8 rtw89_bandwidth_to_om[] = {
6738e93258fSBjoern A. Zeeb [RTW89_CHANNEL_WIDTH_20] = HTC_OM_CHANNEL_WIDTH_20,
6748e93258fSBjoern A. Zeeb [RTW89_CHANNEL_WIDTH_40] = HTC_OM_CHANNEL_WIDTH_40,
6758e93258fSBjoern A. Zeeb [RTW89_CHANNEL_WIDTH_80] = HTC_OM_CHANNEL_WIDTH_80,
6768e93258fSBjoern A. Zeeb [RTW89_CHANNEL_WIDTH_160] = HTC_OM_CHANNEL_WIDTH_160_OR_80_80,
6778e93258fSBjoern A. Zeeb [RTW89_CHANNEL_WIDTH_80_80] = HTC_OM_CHANNEL_WIDTH_160_OR_80_80,
6788e93258fSBjoern A. Zeeb };
6798e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
6808e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
6818e93258fSBjoern A. Zeeb u8 om_bandwidth;
6828e93258fSBjoern A. Zeeb
6838e93258fSBjoern A. Zeeb if (!chip->dis_2g_40m_ul_ofdma ||
6848e93258fSBjoern A. Zeeb chan->band_type != RTW89_BAND_2G ||
6858e93258fSBjoern A. Zeeb chan->band_width != RTW89_CHANNEL_WIDTH_40)
6868e93258fSBjoern A. Zeeb return;
6878e93258fSBjoern A. Zeeb
6888e93258fSBjoern A. Zeeb om_bandwidth = chan->band_width < ARRAY_SIZE(rtw89_bandwidth_to_om) ?
6898e93258fSBjoern A. Zeeb rtw89_bandwidth_to_om[chan->band_width] : 0;
6908e93258fSBjoern A. Zeeb *htc = le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) |
6918e93258fSBjoern A. Zeeb le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_OM, RTW89_HTC_MASK_CTL_ID) |
6928e93258fSBjoern A. Zeeb le32_encode_bits(hal->rx_nss - 1, RTW89_HTC_MASK_HTC_OM_RX_NSS) |
6938e93258fSBjoern A. Zeeb le32_encode_bits(om_bandwidth, RTW89_HTC_MASK_HTC_OM_CH_WIDTH) |
6948e93258fSBjoern A. Zeeb le32_encode_bits(1, RTW89_HTC_MASK_HTC_OM_UL_MU_DIS) |
6958e93258fSBjoern A. Zeeb le32_encode_bits(hal->tx_nss - 1, RTW89_HTC_MASK_HTC_OM_TX_NSTS) |
6968e93258fSBjoern A. Zeeb le32_encode_bits(0, RTW89_HTC_MASK_HTC_OM_ER_SU_DIS) |
6978e93258fSBjoern A. Zeeb le32_encode_bits(0, RTW89_HTC_MASK_HTC_OM_DL_MU_MIMO_RR) |
6988e93258fSBjoern A. Zeeb le32_encode_bits(0, RTW89_HTC_MASK_HTC_OM_UL_MU_DATA_DIS);
6998e93258fSBjoern A. Zeeb }
7008e93258fSBjoern A. Zeeb
7018e93258fSBjoern A. Zeeb static bool
__rtw89_core_tx_check_he_qos_htc(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req,enum btc_pkt_type pkt_type)7028e93258fSBjoern A. Zeeb __rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev,
7038e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req,
7048e93258fSBjoern A. Zeeb enum btc_pkt_type pkt_type)
7058e93258fSBjoern A. Zeeb {
7068e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = tx_req->sta;
7078e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
7088e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
7098e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (void *)skb->data;
7108e93258fSBjoern A. Zeeb __le16 fc = hdr->frame_control;
7118e93258fSBjoern A. Zeeb
7128e93258fSBjoern A. Zeeb /* AP IOT issue with EAPoL, ARP and DHCP */
7138e93258fSBjoern A. Zeeb if (pkt_type < PACKET_MAX)
7148e93258fSBjoern A. Zeeb return false;
7158e93258fSBjoern A. Zeeb
7168e93258fSBjoern A. Zeeb if (!sta || !sta->deflink.he_cap.has_he)
7178e93258fSBjoern A. Zeeb return false;
7188e93258fSBjoern A. Zeeb
7198e93258fSBjoern A. Zeeb if (!ieee80211_is_data_qos(fc))
7208e93258fSBjoern A. Zeeb return false;
7218e93258fSBjoern A. Zeeb
7228e93258fSBjoern A. Zeeb if (skb_headroom(skb) < IEEE80211_HT_CTL_LEN)
7238e93258fSBjoern A. Zeeb return false;
7248e93258fSBjoern A. Zeeb
7258e93258fSBjoern A. Zeeb if (rtwsta && rtwsta->ra_report.might_fallback_legacy)
7268e93258fSBjoern A. Zeeb return false;
7278e93258fSBjoern A. Zeeb
7288e93258fSBjoern A. Zeeb return true;
7298e93258fSBjoern A. Zeeb }
7308e93258fSBjoern A. Zeeb
7318e93258fSBjoern A. Zeeb static void
__rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)7328e93258fSBjoern A. Zeeb __rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev,
7338e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
7348e93258fSBjoern A. Zeeb {
7358e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = tx_req->sta;
7368e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
7378e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
7388e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (void *)skb->data;
7398e93258fSBjoern A. Zeeb __le16 fc = hdr->frame_control;
7408e93258fSBjoern A. Zeeb void *data;
7418e93258fSBjoern A. Zeeb __le32 *htc;
7428e93258fSBjoern A. Zeeb u8 *qc;
7438e93258fSBjoern A. Zeeb int hdr_len;
7448e93258fSBjoern A. Zeeb
7458e93258fSBjoern A. Zeeb hdr_len = ieee80211_has_a4(fc) ? 32 : 26;
7468e93258fSBjoern A. Zeeb data = skb_push(skb, IEEE80211_HT_CTL_LEN);
7478e93258fSBjoern A. Zeeb #if defined(__linux__)
7488e93258fSBjoern A. Zeeb memmove(data, data + IEEE80211_HT_CTL_LEN, hdr_len);
7498e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
7508e93258fSBjoern A. Zeeb memmove(data, (u8 *)data + IEEE80211_HT_CTL_LEN, hdr_len);
7518e93258fSBjoern A. Zeeb #endif
7528e93258fSBjoern A. Zeeb
7538e93258fSBjoern A. Zeeb hdr = data;
7548e93258fSBjoern A. Zeeb #if defined(__linux__)
7558e93258fSBjoern A. Zeeb htc = data + hdr_len;
7568e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
7578e93258fSBjoern A. Zeeb htc = (__le32 *)((u8 *)data + hdr_len);
7588e93258fSBjoern A. Zeeb #endif
7598e93258fSBjoern A. Zeeb hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER);
7608e93258fSBjoern A. Zeeb *htc = rtwsta->htc_template ? rtwsta->htc_template :
7618e93258fSBjoern A. Zeeb le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) |
7628e93258fSBjoern A. Zeeb le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_CAS, RTW89_HTC_MASK_CTL_ID);
7638e93258fSBjoern A. Zeeb
7648e93258fSBjoern A. Zeeb #if defined(__linux__)
7658e93258fSBjoern A. Zeeb qc = data + hdr_len - IEEE80211_QOS_CTL_LEN;
7668e93258fSBjoern A. Zeeb #elif defined(__FreeBSD__)
7678e93258fSBjoern A. Zeeb qc = (u8 *)data + hdr_len - IEEE80211_QOS_CTL_LEN;
7688e93258fSBjoern A. Zeeb #endif
7698e93258fSBjoern A. Zeeb qc[0] |= IEEE80211_QOS_CTL_EOSP;
7708e93258fSBjoern A. Zeeb }
7718e93258fSBjoern A. Zeeb
7728e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_he_qos_htc(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req,enum btc_pkt_type pkt_type)7738e93258fSBjoern A. Zeeb rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev,
7748e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req,
7758e93258fSBjoern A. Zeeb enum btc_pkt_type pkt_type)
7768e93258fSBjoern A. Zeeb {
7778e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
7788e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = tx_req->vif;
7798e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
7808e93258fSBjoern A. Zeeb
7818e93258fSBjoern A. Zeeb if (!__rtw89_core_tx_check_he_qos_htc(rtwdev, tx_req, pkt_type))
7828e93258fSBjoern A. Zeeb goto desc_bk;
7838e93258fSBjoern A. Zeeb
7848e93258fSBjoern A. Zeeb __rtw89_core_tx_adjust_he_qos_htc(rtwdev, tx_req);
7858e93258fSBjoern A. Zeeb
7868e93258fSBjoern A. Zeeb desc_info->pkt_size += IEEE80211_HT_CTL_LEN;
7878e93258fSBjoern A. Zeeb desc_info->a_ctrl_bsr = true;
7888e93258fSBjoern A. Zeeb
7898e93258fSBjoern A. Zeeb desc_bk:
7908e93258fSBjoern A. Zeeb if (!rtwvif || rtwvif->last_a_ctrl == desc_info->a_ctrl_bsr)
7918e93258fSBjoern A. Zeeb return;
7928e93258fSBjoern A. Zeeb
7938e93258fSBjoern A. Zeeb rtwvif->last_a_ctrl = desc_info->a_ctrl_bsr;
7948e93258fSBjoern A. Zeeb desc_info->bk = true;
7958e93258fSBjoern A. Zeeb }
7968e93258fSBjoern A. Zeeb
rtw89_core_get_data_rate(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)797e2340276SBjoern A. Zeeb static u16 rtw89_core_get_data_rate(struct rtw89_dev *rtwdev,
7988e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
7998e93258fSBjoern A. Zeeb {
8008e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = tx_req->vif;
8018e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = tx_req->sta;
802e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
803e2340276SBjoern A. Zeeb struct rtw89_phy_rate_pattern *rate_pattern = &rtwvif->rate_pattern;
804e2340276SBjoern A. Zeeb enum rtw89_sub_entity_idx idx = rtwvif->sub_entity_idx;
805e2340276SBjoern A. Zeeb const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, idx);
806e2340276SBjoern A. Zeeb u16 lowest_rate;
8078e93258fSBjoern A. Zeeb
808e2340276SBjoern A. Zeeb if (rate_pattern->enable)
809e2340276SBjoern A. Zeeb return rate_pattern->rate;
8108e93258fSBjoern A. Zeeb
811e2340276SBjoern A. Zeeb if (vif->p2p)
812e2340276SBjoern A. Zeeb lowest_rate = RTW89_HW_RATE_OFDM6;
813e2340276SBjoern A. Zeeb else if (chan->band_type == RTW89_BAND_2G)
814e2340276SBjoern A. Zeeb lowest_rate = RTW89_HW_RATE_CCK1;
815e2340276SBjoern A. Zeeb else
816e2340276SBjoern A. Zeeb lowest_rate = RTW89_HW_RATE_OFDM6;
817e2340276SBjoern A. Zeeb
818e2340276SBjoern A. Zeeb if (!sta || !sta->deflink.supp_rates[chan->band_type])
819e2340276SBjoern A. Zeeb return lowest_rate;
820e2340276SBjoern A. Zeeb
821e2340276SBjoern A. Zeeb return __ffs(sta->deflink.supp_rates[chan->band_type]) + lowest_rate;
8228e93258fSBjoern A. Zeeb }
8238e93258fSBjoern A. Zeeb
8248e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_data_info(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)8258e93258fSBjoern A. Zeeb rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev,
8268e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
8278e93258fSBjoern A. Zeeb {
8288e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = tx_req->vif;
829e2340276SBjoern A. Zeeb struct ieee80211_sta *sta = tx_req->sta;
8308e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
831e2340276SBjoern A. Zeeb struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
8328e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
8338e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
8348e93258fSBjoern A. Zeeb u8 tid, tid_indicate;
8358e93258fSBjoern A. Zeeb u8 qsel, ch_dma;
8368e93258fSBjoern A. Zeeb
8378e93258fSBjoern A. Zeeb tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
8388e93258fSBjoern A. Zeeb tid_indicate = rtw89_core_get_tid_indicate(rtwdev, tid);
8398e93258fSBjoern A. Zeeb qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : rtw89_core_get_qsel(rtwdev, tid);
8408e93258fSBjoern A. Zeeb ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
8418e93258fSBjoern A. Zeeb
8428e93258fSBjoern A. Zeeb desc_info->ch_dma = ch_dma;
8438e93258fSBjoern A. Zeeb desc_info->tid_indicate = tid_indicate;
8448e93258fSBjoern A. Zeeb desc_info->qsel = qsel;
8458e93258fSBjoern A. Zeeb desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req);
8468e93258fSBjoern A. Zeeb desc_info->port = desc_info->hiq ? rtwvif->port : 0;
847e2340276SBjoern A. Zeeb desc_info->er_cap = rtwsta ? rtwsta->er_cap : false;
8486d67aabdSBjoern A. Zeeb desc_info->stbc = rtwsta ? rtwsta->ra.stbc_cap : false;
8496d67aabdSBjoern A. Zeeb desc_info->ldpc = rtwsta ? rtwsta->ra.ldpc_cap : false;
8508e93258fSBjoern A. Zeeb
8518e93258fSBjoern A. Zeeb /* enable wd_info for AMPDU */
8528e93258fSBjoern A. Zeeb desc_info->en_wd_info = true;
8538e93258fSBjoern A. Zeeb
8548e93258fSBjoern A. Zeeb if (IEEE80211_SKB_CB(skb)->control.hw_key)
8558e93258fSBjoern A. Zeeb rtw89_core_tx_update_sec_key(rtwdev, tx_req);
8568e93258fSBjoern A. Zeeb
857e2340276SBjoern A. Zeeb desc_info->data_retry_lowest_rate = rtw89_core_get_data_rate(rtwdev, tx_req);
8588e93258fSBjoern A. Zeeb }
8598e93258fSBjoern A. Zeeb
8608e93258fSBjoern A. Zeeb static enum btc_pkt_type
rtw89_core_tx_btc_spec_pkt_notify(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)8618e93258fSBjoern A. Zeeb rtw89_core_tx_btc_spec_pkt_notify(struct rtw89_dev *rtwdev,
8628e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
8638e93258fSBjoern A. Zeeb {
8648e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
8658e93258fSBjoern A. Zeeb struct udphdr *udphdr;
8668e93258fSBjoern A. Zeeb
8678e93258fSBjoern A. Zeeb if (IEEE80211_SKB_CB(skb)->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) {
8688e93258fSBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.eapol_notify_work);
8698e93258fSBjoern A. Zeeb return PACKET_EAPOL;
8708e93258fSBjoern A. Zeeb }
8718e93258fSBjoern A. Zeeb
8728e93258fSBjoern A. Zeeb if (skb->protocol == htons(ETH_P_ARP)) {
8738e93258fSBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.arp_notify_work);
8748e93258fSBjoern A. Zeeb return PACKET_ARP;
8758e93258fSBjoern A. Zeeb }
8768e93258fSBjoern A. Zeeb
8778e93258fSBjoern A. Zeeb if (skb->protocol == htons(ETH_P_IP) &&
8788e93258fSBjoern A. Zeeb ip_hdr(skb)->protocol == IPPROTO_UDP) {
8798e93258fSBjoern A. Zeeb udphdr = udp_hdr(skb);
8808e93258fSBjoern A. Zeeb if (((udphdr->source == htons(67) && udphdr->dest == htons(68)) ||
8818e93258fSBjoern A. Zeeb (udphdr->source == htons(68) && udphdr->dest == htons(67))) &&
8828e93258fSBjoern A. Zeeb skb->len > 282) {
8838e93258fSBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.dhcp_notify_work);
8848e93258fSBjoern A. Zeeb return PACKET_DHCP;
8858e93258fSBjoern A. Zeeb }
8868e93258fSBjoern A. Zeeb }
8878e93258fSBjoern A. Zeeb
8888e93258fSBjoern A. Zeeb if (skb->protocol == htons(ETH_P_IP) &&
8898e93258fSBjoern A. Zeeb ip_hdr(skb)->protocol == IPPROTO_ICMP) {
8908e93258fSBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.icmp_notify_work);
8918e93258fSBjoern A. Zeeb return PACKET_ICMP;
8928e93258fSBjoern A. Zeeb }
8938e93258fSBjoern A. Zeeb
8948e93258fSBjoern A. Zeeb return PACKET_MAX;
8958e93258fSBjoern A. Zeeb }
8968e93258fSBjoern A. Zeeb
rtw89_core_tx_update_llc_hdr(struct rtw89_dev * rtwdev,struct rtw89_tx_desc_info * desc_info,struct sk_buff * skb)8978e93258fSBjoern A. Zeeb static void rtw89_core_tx_update_llc_hdr(struct rtw89_dev *rtwdev,
8988e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info,
8998e93258fSBjoern A. Zeeb struct sk_buff *skb)
9008e93258fSBjoern A. Zeeb {
9018e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (void *)skb->data;
9028e93258fSBjoern A. Zeeb __le16 fc = hdr->frame_control;
9038e93258fSBjoern A. Zeeb
9048e93258fSBjoern A. Zeeb desc_info->hdr_llc_len = ieee80211_hdrlen(fc);
9058e93258fSBjoern A. Zeeb desc_info->hdr_llc_len >>= 1; /* in unit of 2 bytes */
9068e93258fSBjoern A. Zeeb }
9078e93258fSBjoern A. Zeeb
9088e93258fSBjoern A. Zeeb static void
rtw89_core_tx_wake(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)9098e93258fSBjoern A. Zeeb rtw89_core_tx_wake(struct rtw89_dev *rtwdev,
9108e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
9118e93258fSBjoern A. Zeeb {
912e2340276SBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
913e2340276SBjoern A. Zeeb
9148e93258fSBjoern A. Zeeb if (!RTW89_CHK_FW_FEATURE(TX_WAKE, &rtwdev->fw))
9158e93258fSBjoern A. Zeeb return;
9168e93258fSBjoern A. Zeeb
9178e93258fSBjoern A. Zeeb if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
9188e93258fSBjoern A. Zeeb return;
9198e93258fSBjoern A. Zeeb
920e2340276SBjoern A. Zeeb if (chip->chip_id != RTL8852C &&
921e2340276SBjoern A. Zeeb tx_req->tx_type != RTW89_CORE_TX_TYPE_MGMT)
9228e93258fSBjoern A. Zeeb return;
9238e93258fSBjoern A. Zeeb
9248e93258fSBjoern A. Zeeb rtw89_mac_notify_wake(rtwdev);
9258e93258fSBjoern A. Zeeb }
9268e93258fSBjoern A. Zeeb
9278e93258fSBjoern A. Zeeb static void
rtw89_core_tx_update_desc_info(struct rtw89_dev * rtwdev,struct rtw89_core_tx_request * tx_req)9288e93258fSBjoern A. Zeeb rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
9298e93258fSBjoern A. Zeeb struct rtw89_core_tx_request *tx_req)
9308e93258fSBjoern A. Zeeb {
9318e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
9328e93258fSBjoern A. Zeeb struct sk_buff *skb = tx_req->skb;
9338e93258fSBjoern A. Zeeb struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
9348e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (void *)skb->data;
9358e93258fSBjoern A. Zeeb enum rtw89_core_tx_type tx_type;
9368e93258fSBjoern A. Zeeb enum btc_pkt_type pkt_type;
9378e93258fSBjoern A. Zeeb bool is_bmc;
9388e93258fSBjoern A. Zeeb u16 seq;
9398e93258fSBjoern A. Zeeb
9408e93258fSBjoern A. Zeeb seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
9418e93258fSBjoern A. Zeeb if (tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD) {
9428e93258fSBjoern A. Zeeb tx_type = rtw89_core_get_tx_type(rtwdev, skb);
9438e93258fSBjoern A. Zeeb tx_req->tx_type = tx_type;
9448e93258fSBjoern A. Zeeb }
9458e93258fSBjoern A. Zeeb is_bmc = (is_broadcast_ether_addr(hdr->addr1) ||
9468e93258fSBjoern A. Zeeb is_multicast_ether_addr(hdr->addr1));
9478e93258fSBjoern A. Zeeb
9488e93258fSBjoern A. Zeeb desc_info->seq = seq;
9498e93258fSBjoern A. Zeeb desc_info->pkt_size = skb->len;
9508e93258fSBjoern A. Zeeb desc_info->is_bmc = is_bmc;
9518e93258fSBjoern A. Zeeb desc_info->wd_page = true;
9528e93258fSBjoern A. Zeeb desc_info->hiq = info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM;
9538e93258fSBjoern A. Zeeb
9548e93258fSBjoern A. Zeeb switch (tx_req->tx_type) {
9558e93258fSBjoern A. Zeeb case RTW89_CORE_TX_TYPE_MGMT:
9568e93258fSBjoern A. Zeeb rtw89_core_tx_update_mgmt_info(rtwdev, tx_req);
9578e93258fSBjoern A. Zeeb break;
9588e93258fSBjoern A. Zeeb case RTW89_CORE_TX_TYPE_DATA:
9598e93258fSBjoern A. Zeeb rtw89_core_tx_update_data_info(rtwdev, tx_req);
9608e93258fSBjoern A. Zeeb pkt_type = rtw89_core_tx_btc_spec_pkt_notify(rtwdev, tx_req);
9618e93258fSBjoern A. Zeeb rtw89_core_tx_update_he_qos_htc(rtwdev, tx_req, pkt_type);
9628e93258fSBjoern A. Zeeb rtw89_core_tx_update_ampdu_info(rtwdev, tx_req, pkt_type);
9638e93258fSBjoern A. Zeeb rtw89_core_tx_update_llc_hdr(rtwdev, desc_info, skb);
9648e93258fSBjoern A. Zeeb break;
9658e93258fSBjoern A. Zeeb case RTW89_CORE_TX_TYPE_FWCMD:
9668e93258fSBjoern A. Zeeb rtw89_core_tx_update_h2c_info(rtwdev, tx_req);
9678e93258fSBjoern A. Zeeb break;
9688e93258fSBjoern A. Zeeb }
9698e93258fSBjoern A. Zeeb }
9708e93258fSBjoern A. Zeeb
rtw89_core_tx_kick_off(struct rtw89_dev * rtwdev,u8 qsel)9718e93258fSBjoern A. Zeeb void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel)
9728e93258fSBjoern A. Zeeb {
9738e93258fSBjoern A. Zeeb u8 ch_dma;
9748e93258fSBjoern A. Zeeb
9758e93258fSBjoern A. Zeeb ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
9768e93258fSBjoern A. Zeeb
9778e93258fSBjoern A. Zeeb rtw89_hci_tx_kick_off(rtwdev, ch_dma);
9788e93258fSBjoern A. Zeeb }
9798e93258fSBjoern A. Zeeb
rtw89_core_tx_kick_off_and_wait(struct rtw89_dev * rtwdev,struct sk_buff * skb,int qsel,unsigned int timeout)980e2340276SBjoern A. Zeeb int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb,
981e2340276SBjoern A. Zeeb int qsel, unsigned int timeout)
982e2340276SBjoern A. Zeeb {
983e2340276SBjoern A. Zeeb struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb);
984e2340276SBjoern A. Zeeb struct rtw89_tx_wait_info *wait;
985e2340276SBjoern A. Zeeb unsigned long time_left;
986e2340276SBjoern A. Zeeb int ret = 0;
987e2340276SBjoern A. Zeeb
988e2340276SBjoern A. Zeeb wait = kzalloc(sizeof(*wait), GFP_KERNEL);
989e2340276SBjoern A. Zeeb if (!wait) {
990e2340276SBjoern A. Zeeb rtw89_core_tx_kick_off(rtwdev, qsel);
991e2340276SBjoern A. Zeeb return 0;
992e2340276SBjoern A. Zeeb }
993e2340276SBjoern A. Zeeb
994e2340276SBjoern A. Zeeb init_completion(&wait->completion);
995e2340276SBjoern A. Zeeb rcu_assign_pointer(skb_data->wait, wait);
996e2340276SBjoern A. Zeeb
997e2340276SBjoern A. Zeeb rtw89_core_tx_kick_off(rtwdev, qsel);
998e2340276SBjoern A. Zeeb time_left = wait_for_completion_timeout(&wait->completion,
999e2340276SBjoern A. Zeeb msecs_to_jiffies(timeout));
1000e2340276SBjoern A. Zeeb if (time_left == 0)
1001e2340276SBjoern A. Zeeb ret = -ETIMEDOUT;
1002e2340276SBjoern A. Zeeb else if (!wait->tx_done)
1003e2340276SBjoern A. Zeeb ret = -EAGAIN;
1004e2340276SBjoern A. Zeeb
1005e2340276SBjoern A. Zeeb rcu_assign_pointer(skb_data->wait, NULL);
1006e2340276SBjoern A. Zeeb kfree_rcu(wait, rcu_head);
1007e2340276SBjoern A. Zeeb
1008e2340276SBjoern A. Zeeb return ret;
1009e2340276SBjoern A. Zeeb }
1010e2340276SBjoern A. Zeeb
rtw89_h2c_tx(struct rtw89_dev * rtwdev,struct sk_buff * skb,bool fwdl)10118e93258fSBjoern A. Zeeb int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
10128e93258fSBjoern A. Zeeb struct sk_buff *skb, bool fwdl)
10138e93258fSBjoern A. Zeeb {
10148e93258fSBjoern A. Zeeb struct rtw89_core_tx_request tx_req = {0};
10158e93258fSBjoern A. Zeeb u32 cnt;
10168e93258fSBjoern A. Zeeb int ret;
10178e93258fSBjoern A. Zeeb
10188e93258fSBjoern A. Zeeb if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) {
10198e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_FW,
10208e93258fSBjoern A. Zeeb "ignore h2c due to power is off with firmware state=%d\n",
10218e93258fSBjoern A. Zeeb test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags));
1022e2340276SBjoern A. Zeeb dev_kfree_skb(skb);
10238e93258fSBjoern A. Zeeb return 0;
10248e93258fSBjoern A. Zeeb }
10258e93258fSBjoern A. Zeeb
10268e93258fSBjoern A. Zeeb tx_req.skb = skb;
10278e93258fSBjoern A. Zeeb tx_req.tx_type = RTW89_CORE_TX_TYPE_FWCMD;
10288e93258fSBjoern A. Zeeb if (fwdl)
10298e93258fSBjoern A. Zeeb tx_req.desc_info.fw_dl = true;
10308e93258fSBjoern A. Zeeb
10318e93258fSBjoern A. Zeeb rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
10328e93258fSBjoern A. Zeeb
10338e93258fSBjoern A. Zeeb if (!fwdl)
10348e93258fSBjoern A. Zeeb rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "H2C: ", skb->data, skb->len);
10358e93258fSBjoern A. Zeeb
10368e93258fSBjoern A. Zeeb cnt = rtw89_hci_check_and_reclaim_tx_resource(rtwdev, RTW89_TXCH_CH12);
10378e93258fSBjoern A. Zeeb if (cnt == 0) {
10388e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "no tx fwcmd resource\n");
10398e93258fSBjoern A. Zeeb return -ENOSPC;
10408e93258fSBjoern A. Zeeb }
10418e93258fSBjoern A. Zeeb
10428e93258fSBjoern A. Zeeb ret = rtw89_hci_tx_write(rtwdev, &tx_req);
10438e93258fSBjoern A. Zeeb if (ret) {
10448e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
10458e93258fSBjoern A. Zeeb return ret;
10468e93258fSBjoern A. Zeeb }
10478e93258fSBjoern A. Zeeb rtw89_hci_tx_kick_off(rtwdev, RTW89_TXCH_CH12);
10488e93258fSBjoern A. Zeeb
10498e93258fSBjoern A. Zeeb return 0;
10508e93258fSBjoern A. Zeeb }
10518e93258fSBjoern A. Zeeb
rtw89_core_tx_write(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct sk_buff * skb,int * qsel)10528e93258fSBjoern A. Zeeb int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
10538e93258fSBjoern A. Zeeb struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
10548e93258fSBjoern A. Zeeb {
10558e93258fSBjoern A. Zeeb struct rtw89_core_tx_request tx_req = {0};
10568e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
10578e93258fSBjoern A. Zeeb int ret;
10588e93258fSBjoern A. Zeeb
10598e93258fSBjoern A. Zeeb tx_req.skb = skb;
10608e93258fSBjoern A. Zeeb tx_req.sta = sta;
10618e93258fSBjoern A. Zeeb tx_req.vif = vif;
10628e93258fSBjoern A. Zeeb
10638e93258fSBjoern A. Zeeb rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
10648e93258fSBjoern A. Zeeb rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
10658e93258fSBjoern A. Zeeb rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
10668e93258fSBjoern A. Zeeb rtw89_core_tx_wake(rtwdev, &tx_req);
10678e93258fSBjoern A. Zeeb
10688e93258fSBjoern A. Zeeb ret = rtw89_hci_tx_write(rtwdev, &tx_req);
10698e93258fSBjoern A. Zeeb if (ret) {
10708e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
10718e93258fSBjoern A. Zeeb return ret;
10728e93258fSBjoern A. Zeeb }
10738e93258fSBjoern A. Zeeb
10748e93258fSBjoern A. Zeeb if (qsel)
10758e93258fSBjoern A. Zeeb *qsel = tx_req.desc_info.qsel;
10768e93258fSBjoern A. Zeeb
10778e93258fSBjoern A. Zeeb return 0;
10788e93258fSBjoern A. Zeeb }
10798e93258fSBjoern A. Zeeb
rtw89_build_txwd_body0(struct rtw89_tx_desc_info * desc_info)10808e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info)
10818e93258fSBjoern A. Zeeb {
10828e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY0_WP_OFFSET, desc_info->wp_offset) |
10838e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_WD_INFO_EN, desc_info->en_wd_info) |
10848e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_CHANNEL_DMA, desc_info->ch_dma) |
10858e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_HDR_LLC_LEN, desc_info->hdr_llc_len) |
10868e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_WD_PAGE, desc_info->wd_page) |
10878e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_FW_DL, desc_info->fw_dl) |
10888e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_HW_SSN_SEL, desc_info->hw_ssn_sel) |
10898e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_HW_SSN_MODE, desc_info->hw_seq_mode);
10908e93258fSBjoern A. Zeeb
10918e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
10928e93258fSBjoern A. Zeeb }
10938e93258fSBjoern A. Zeeb
rtw89_build_txwd_body0_v1(struct rtw89_tx_desc_info * desc_info)10948e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body0_v1(struct rtw89_tx_desc_info *desc_info)
10958e93258fSBjoern A. Zeeb {
10968e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY0_WP_OFFSET_V1, desc_info->wp_offset) |
10978e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_WD_INFO_EN, desc_info->en_wd_info) |
10988e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_CHANNEL_DMA, desc_info->ch_dma) |
10998e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_HDR_LLC_LEN, desc_info->hdr_llc_len) |
11008e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_WD_PAGE, desc_info->wd_page) |
11018e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY0_FW_DL, desc_info->fw_dl);
11028e93258fSBjoern A. Zeeb
11038e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11048e93258fSBjoern A. Zeeb }
11058e93258fSBjoern A. Zeeb
rtw89_build_txwd_body1_v1(struct rtw89_tx_desc_info * desc_info)11068e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body1_v1(struct rtw89_tx_desc_info *desc_info)
11078e93258fSBjoern A. Zeeb {
11088e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY1_ADDR_INFO_NUM, desc_info->addr_info_nr) |
11098e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY1_SEC_KEYID, desc_info->sec_keyid) |
11108e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY1_SEC_TYPE, desc_info->sec_type);
11118e93258fSBjoern A. Zeeb
11128e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11138e93258fSBjoern A. Zeeb }
11148e93258fSBjoern A. Zeeb
rtw89_build_txwd_body2(struct rtw89_tx_desc_info * desc_info)11158e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body2(struct rtw89_tx_desc_info *desc_info)
11168e93258fSBjoern A. Zeeb {
11178e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY2_TID_INDICATE, desc_info->tid_indicate) |
11188e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY2_QSEL, desc_info->qsel) |
11198e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY2_TXPKT_SIZE, desc_info->pkt_size) |
11208e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY2_MACID, desc_info->mac_id);
11218e93258fSBjoern A. Zeeb
11228e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11238e93258fSBjoern A. Zeeb }
11248e93258fSBjoern A. Zeeb
rtw89_build_txwd_body3(struct rtw89_tx_desc_info * desc_info)11258e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body3(struct rtw89_tx_desc_info *desc_info)
11268e93258fSBjoern A. Zeeb {
11278e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY3_SW_SEQ, desc_info->seq) |
11288e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY3_AGG_EN, desc_info->agg_en) |
11298e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY3_BK, desc_info->bk);
11308e93258fSBjoern A. Zeeb
11318e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11328e93258fSBjoern A. Zeeb }
11338e93258fSBjoern A. Zeeb
rtw89_build_txwd_body4(struct rtw89_tx_desc_info * desc_info)11348e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body4(struct rtw89_tx_desc_info *desc_info)
11358e93258fSBjoern A. Zeeb {
11368e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY4_SEC_IV_L0, desc_info->sec_seq[0]) |
11378e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY4_SEC_IV_L1, desc_info->sec_seq[1]);
11388e93258fSBjoern A. Zeeb
11398e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11408e93258fSBjoern A. Zeeb }
11418e93258fSBjoern A. Zeeb
rtw89_build_txwd_body5(struct rtw89_tx_desc_info * desc_info)11428e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body5(struct rtw89_tx_desc_info *desc_info)
11438e93258fSBjoern A. Zeeb {
11448e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY5_SEC_IV_H2, desc_info->sec_seq[2]) |
11458e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY5_SEC_IV_H3, desc_info->sec_seq[3]) |
11468e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY5_SEC_IV_H4, desc_info->sec_seq[4]) |
11478e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY5_SEC_IV_H5, desc_info->sec_seq[5]);
11488e93258fSBjoern A. Zeeb
11498e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11508e93258fSBjoern A. Zeeb }
11518e93258fSBjoern A. Zeeb
rtw89_build_txwd_body7_v1(struct rtw89_tx_desc_info * desc_info)11528e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_body7_v1(struct rtw89_tx_desc_info *desc_info)
11538e93258fSBjoern A. Zeeb {
11548e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_BODY7_USE_RATE_V1, desc_info->use_rate) |
11558e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_BODY7_DATA_RATE, desc_info->data_rate);
11568e93258fSBjoern A. Zeeb
11578e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11588e93258fSBjoern A. Zeeb }
11598e93258fSBjoern A. Zeeb
rtw89_build_txwd_info0(struct rtw89_tx_desc_info * desc_info)11608e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_info0(struct rtw89_tx_desc_info *desc_info)
11618e93258fSBjoern A. Zeeb {
11628e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_USE_RATE, desc_info->use_rate) |
11638e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DATA_RATE, desc_info->data_rate) |
11646d67aabdSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DATA_STBC, desc_info->stbc) |
11656d67aabdSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DATA_LDPC, desc_info->ldpc) |
11668e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
11678e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port);
11688e93258fSBjoern A. Zeeb
11698e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11708e93258fSBjoern A. Zeeb }
11718e93258fSBjoern A. Zeeb
rtw89_build_txwd_info0_v1(struct rtw89_tx_desc_info * desc_info)11728e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_info0_v1(struct rtw89_tx_desc_info *desc_info)
11738e93258fSBjoern A. Zeeb {
11746d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_DATA_STBC, desc_info->stbc) |
11756d67aabdSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DATA_LDPC, desc_info->ldpc) |
11766d67aabdSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
1177e2340276SBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port) |
1178e2340276SBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DATA_ER, desc_info->er_cap) |
1179e2340276SBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO0_DATA_BW_ER, 0);
11808e93258fSBjoern A. Zeeb
11818e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11828e93258fSBjoern A. Zeeb }
11838e93258fSBjoern A. Zeeb
rtw89_build_txwd_info1(struct rtw89_tx_desc_info * desc_info)11848e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_info1(struct rtw89_tx_desc_info *desc_info)
11858e93258fSBjoern A. Zeeb {
11868e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_INFO1_MAX_AGGNUM, desc_info->ampdu_num) |
11878e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO1_A_CTRL_BSR, desc_info->a_ctrl_bsr) |
11888e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO1_DATA_RTY_LOWEST_RATE,
11898e93258fSBjoern A. Zeeb desc_info->data_retry_lowest_rate);
11908e93258fSBjoern A. Zeeb
11918e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
11928e93258fSBjoern A. Zeeb }
11938e93258fSBjoern A. Zeeb
rtw89_build_txwd_info2(struct rtw89_tx_desc_info * desc_info)11948e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_info2(struct rtw89_tx_desc_info *desc_info)
11958e93258fSBjoern A. Zeeb {
11968e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_INFO2_AMPDU_DENSITY, desc_info->ampdu_density) |
11978e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO2_SEC_TYPE, desc_info->sec_type) |
11988e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO2_SEC_HW_ENC, desc_info->sec_en) |
11998e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO2_SEC_CAM_IDX, desc_info->sec_cam_idx);
12008e93258fSBjoern A. Zeeb
12018e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
12028e93258fSBjoern A. Zeeb }
12038e93258fSBjoern A. Zeeb
rtw89_build_txwd_info2_v1(struct rtw89_tx_desc_info * desc_info)12048e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_info2_v1(struct rtw89_tx_desc_info *desc_info)
12058e93258fSBjoern A. Zeeb {
12068e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_INFO2_AMPDU_DENSITY, desc_info->ampdu_density) |
12078e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO2_FORCE_KEY_EN, desc_info->sec_en) |
12088e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO2_SEC_CAM_IDX, desc_info->sec_cam_idx);
12098e93258fSBjoern A. Zeeb
12108e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
12118e93258fSBjoern A. Zeeb }
12128e93258fSBjoern A. Zeeb
rtw89_build_txwd_info4(struct rtw89_tx_desc_info * desc_info)12138e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_info4(struct rtw89_tx_desc_info *desc_info)
12148e93258fSBjoern A. Zeeb {
12156d67aabdSBjoern A. Zeeb bool rts_en = !desc_info->is_bmc;
12166d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, rts_en) |
12178e93258fSBjoern A. Zeeb FIELD_PREP(RTW89_TXWD_INFO4_HW_RTS_EN, 1);
12188e93258fSBjoern A. Zeeb
12198e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
12208e93258fSBjoern A. Zeeb }
12218e93258fSBjoern A. Zeeb
rtw89_core_fill_txdesc(struct rtw89_dev * rtwdev,struct rtw89_tx_desc_info * desc_info,void * txdesc)12228e93258fSBjoern A. Zeeb void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
12238e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info,
12248e93258fSBjoern A. Zeeb void *txdesc)
12258e93258fSBjoern A. Zeeb {
12268e93258fSBjoern A. Zeeb struct rtw89_txwd_body *txwd_body = (struct rtw89_txwd_body *)txdesc;
12278e93258fSBjoern A. Zeeb struct rtw89_txwd_info *txwd_info;
12288e93258fSBjoern A. Zeeb
12298e93258fSBjoern A. Zeeb txwd_body->dword0 = rtw89_build_txwd_body0(desc_info);
12308e93258fSBjoern A. Zeeb txwd_body->dword2 = rtw89_build_txwd_body2(desc_info);
12318e93258fSBjoern A. Zeeb txwd_body->dword3 = rtw89_build_txwd_body3(desc_info);
12328e93258fSBjoern A. Zeeb
12338e93258fSBjoern A. Zeeb if (!desc_info->en_wd_info)
12348e93258fSBjoern A. Zeeb return;
12358e93258fSBjoern A. Zeeb
12368e93258fSBjoern A. Zeeb txwd_info = (struct rtw89_txwd_info *)(txwd_body + 1);
12378e93258fSBjoern A. Zeeb txwd_info->dword0 = rtw89_build_txwd_info0(desc_info);
12388e93258fSBjoern A. Zeeb txwd_info->dword1 = rtw89_build_txwd_info1(desc_info);
12398e93258fSBjoern A. Zeeb txwd_info->dword2 = rtw89_build_txwd_info2(desc_info);
12408e93258fSBjoern A. Zeeb txwd_info->dword4 = rtw89_build_txwd_info4(desc_info);
12418e93258fSBjoern A. Zeeb
12428e93258fSBjoern A. Zeeb }
12438e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_fill_txdesc);
12448e93258fSBjoern A. Zeeb
rtw89_core_fill_txdesc_v1(struct rtw89_dev * rtwdev,struct rtw89_tx_desc_info * desc_info,void * txdesc)12458e93258fSBjoern A. Zeeb void rtw89_core_fill_txdesc_v1(struct rtw89_dev *rtwdev,
12468e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info,
12478e93258fSBjoern A. Zeeb void *txdesc)
12488e93258fSBjoern A. Zeeb {
12498e93258fSBjoern A. Zeeb struct rtw89_txwd_body_v1 *txwd_body = (struct rtw89_txwd_body_v1 *)txdesc;
12508e93258fSBjoern A. Zeeb struct rtw89_txwd_info *txwd_info;
12518e93258fSBjoern A. Zeeb
12528e93258fSBjoern A. Zeeb txwd_body->dword0 = rtw89_build_txwd_body0_v1(desc_info);
12538e93258fSBjoern A. Zeeb txwd_body->dword1 = rtw89_build_txwd_body1_v1(desc_info);
12548e93258fSBjoern A. Zeeb txwd_body->dword2 = rtw89_build_txwd_body2(desc_info);
12558e93258fSBjoern A. Zeeb txwd_body->dword3 = rtw89_build_txwd_body3(desc_info);
12568e93258fSBjoern A. Zeeb if (desc_info->sec_en) {
12578e93258fSBjoern A. Zeeb txwd_body->dword4 = rtw89_build_txwd_body4(desc_info);
12588e93258fSBjoern A. Zeeb txwd_body->dword5 = rtw89_build_txwd_body5(desc_info);
12598e93258fSBjoern A. Zeeb }
12608e93258fSBjoern A. Zeeb txwd_body->dword7 = rtw89_build_txwd_body7_v1(desc_info);
12618e93258fSBjoern A. Zeeb
12628e93258fSBjoern A. Zeeb if (!desc_info->en_wd_info)
12638e93258fSBjoern A. Zeeb return;
12648e93258fSBjoern A. Zeeb
12658e93258fSBjoern A. Zeeb txwd_info = (struct rtw89_txwd_info *)(txwd_body + 1);
12668e93258fSBjoern A. Zeeb txwd_info->dword0 = rtw89_build_txwd_info0_v1(desc_info);
12678e93258fSBjoern A. Zeeb txwd_info->dword1 = rtw89_build_txwd_info1(desc_info);
12688e93258fSBjoern A. Zeeb txwd_info->dword2 = rtw89_build_txwd_info2_v1(desc_info);
12698e93258fSBjoern A. Zeeb txwd_info->dword4 = rtw89_build_txwd_info4(desc_info);
12708e93258fSBjoern A. Zeeb }
12718e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_fill_txdesc_v1);
12728e93258fSBjoern A. Zeeb
rtw89_build_txwd_body0_v2(struct rtw89_tx_desc_info * desc_info)12736d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body0_v2(struct rtw89_tx_desc_info *desc_info)
12746d67aabdSBjoern A. Zeeb {
12756d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY0_WP_OFFSET_V1, desc_info->wp_offset) |
12766d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY0_WDINFO_EN, desc_info->en_wd_info) |
12776d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY0_CH_DMA, desc_info->ch_dma) |
12786d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY0_HDR_LLC_LEN, desc_info->hdr_llc_len) |
12796d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY0_WD_PAGE, desc_info->wd_page);
12806d67aabdSBjoern A. Zeeb
12816d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
12826d67aabdSBjoern A. Zeeb }
12836d67aabdSBjoern A. Zeeb
rtw89_build_txwd_body1_v2(struct rtw89_tx_desc_info * desc_info)12846d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body1_v2(struct rtw89_tx_desc_info *desc_info)
12856d67aabdSBjoern A. Zeeb {
12866d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY1_ADDR_INFO_NUM, desc_info->addr_info_nr) |
12876d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY1_SEC_KEYID, desc_info->sec_keyid) |
12886d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY1_SEC_TYPE, desc_info->sec_type);
12896d67aabdSBjoern A. Zeeb
12906d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
12916d67aabdSBjoern A. Zeeb }
12926d67aabdSBjoern A. Zeeb
rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info * desc_info)12936d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info *desc_info)
12946d67aabdSBjoern A. Zeeb {
12956d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY2_TID_IND, desc_info->tid_indicate) |
12966d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY2_QSEL, desc_info->qsel) |
12976d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY2_TXPKTSIZE, desc_info->pkt_size) |
12986d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY2_AGG_EN, desc_info->agg_en) |
12996d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY2_BK, desc_info->bk) |
13006d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY2_MACID, desc_info->mac_id);
13016d67aabdSBjoern A. Zeeb
13026d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13036d67aabdSBjoern A. Zeeb }
13046d67aabdSBjoern A. Zeeb
rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info * desc_info)13056d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info)
13066d67aabdSBjoern A. Zeeb {
13076d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq);
13086d67aabdSBjoern A. Zeeb
13096d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13106d67aabdSBjoern A. Zeeb }
13116d67aabdSBjoern A. Zeeb
rtw89_build_txwd_body4_v2(struct rtw89_tx_desc_info * desc_info)13126d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body4_v2(struct rtw89_tx_desc_info *desc_info)
13136d67aabdSBjoern A. Zeeb {
13146d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY4_SEC_IV_L0, desc_info->sec_seq[0]) |
13156d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY4_SEC_IV_L1, desc_info->sec_seq[1]);
13166d67aabdSBjoern A. Zeeb
13176d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13186d67aabdSBjoern A. Zeeb }
13196d67aabdSBjoern A. Zeeb
rtw89_build_txwd_body5_v2(struct rtw89_tx_desc_info * desc_info)13206d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body5_v2(struct rtw89_tx_desc_info *desc_info)
13216d67aabdSBjoern A. Zeeb {
13226d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY5_SEC_IV_H2, desc_info->sec_seq[2]) |
13236d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY5_SEC_IV_H3, desc_info->sec_seq[3]) |
13246d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY5_SEC_IV_H4, desc_info->sec_seq[4]) |
13256d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY5_SEC_IV_H5, desc_info->sec_seq[5]);
13266d67aabdSBjoern A. Zeeb
13276d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13286d67aabdSBjoern A. Zeeb }
13296d67aabdSBjoern A. Zeeb
rtw89_build_txwd_body7_v2(struct rtw89_tx_desc_info * desc_info)13306d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_body7_v2(struct rtw89_tx_desc_info *desc_info)
13316d67aabdSBjoern A. Zeeb {
13326d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_BODY7_USERATE_SEL, desc_info->use_rate) |
13336d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY7_DATA_ER, desc_info->er_cap) |
13346d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY7_DATA_BW_ER, 0) |
13356d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_BODY7_DATARATE, desc_info->data_rate);
13366d67aabdSBjoern A. Zeeb
13376d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13386d67aabdSBjoern A. Zeeb }
13396d67aabdSBjoern A. Zeeb
rtw89_build_txwd_info0_v2(struct rtw89_tx_desc_info * desc_info)13406d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_info0_v2(struct rtw89_tx_desc_info *desc_info)
13416d67aabdSBjoern A. Zeeb {
13426d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_INFO0_DATA_STBC, desc_info->stbc) |
13436d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO0_DATA_LDPC, desc_info->ldpc) |
13446d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
13456d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO0_MULTIPORT_ID, desc_info->port);
13466d67aabdSBjoern A. Zeeb
13476d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13486d67aabdSBjoern A. Zeeb }
13496d67aabdSBjoern A. Zeeb
rtw89_build_txwd_info1_v2(struct rtw89_tx_desc_info * desc_info)13506d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_info1_v2(struct rtw89_tx_desc_info *desc_info)
13516d67aabdSBjoern A. Zeeb {
13526d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_INFO1_MAX_AGG_NUM, desc_info->ampdu_num) |
13536d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO1_A_CTRL_BSR, desc_info->a_ctrl_bsr) |
13546d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO1_DATA_RTY_LOWEST_RATE,
13556d67aabdSBjoern A. Zeeb desc_info->data_retry_lowest_rate);
13566d67aabdSBjoern A. Zeeb
13576d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13586d67aabdSBjoern A. Zeeb }
13596d67aabdSBjoern A. Zeeb
rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info * desc_info)13606d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info *desc_info)
13616d67aabdSBjoern A. Zeeb {
13626d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_INFO2_AMPDU_DENSITY, desc_info->ampdu_density) |
13636d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO2_FORCE_KEY_EN, desc_info->sec_en) |
13646d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO2_SEC_CAM_IDX, desc_info->sec_cam_idx);
13656d67aabdSBjoern A. Zeeb
13666d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13676d67aabdSBjoern A. Zeeb }
13686d67aabdSBjoern A. Zeeb
rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info * desc_info)13696d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info *desc_info)
13706d67aabdSBjoern A. Zeeb {
13716d67aabdSBjoern A. Zeeb bool rts_en = !desc_info->is_bmc;
13726d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_TXD_INFO4_RTS_EN, rts_en) |
13736d67aabdSBjoern A. Zeeb FIELD_PREP(BE_TXD_INFO4_HW_RTS_EN, 1);
13746d67aabdSBjoern A. Zeeb
13756d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
13766d67aabdSBjoern A. Zeeb }
13776d67aabdSBjoern A. Zeeb
rtw89_core_fill_txdesc_v2(struct rtw89_dev * rtwdev,struct rtw89_tx_desc_info * desc_info,void * txdesc)13786d67aabdSBjoern A. Zeeb void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev,
13796d67aabdSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info,
13806d67aabdSBjoern A. Zeeb void *txdesc)
13816d67aabdSBjoern A. Zeeb {
13826d67aabdSBjoern A. Zeeb struct rtw89_txwd_body_v2 *txwd_body = txdesc;
13836d67aabdSBjoern A. Zeeb struct rtw89_txwd_info_v2 *txwd_info;
13846d67aabdSBjoern A. Zeeb
13856d67aabdSBjoern A. Zeeb txwd_body->dword0 = rtw89_build_txwd_body0_v2(desc_info);
13866d67aabdSBjoern A. Zeeb txwd_body->dword1 = rtw89_build_txwd_body1_v2(desc_info);
13876d67aabdSBjoern A. Zeeb txwd_body->dword2 = rtw89_build_txwd_body2_v2(desc_info);
13886d67aabdSBjoern A. Zeeb txwd_body->dword3 = rtw89_build_txwd_body3_v2(desc_info);
13896d67aabdSBjoern A. Zeeb if (desc_info->sec_en) {
13906d67aabdSBjoern A. Zeeb txwd_body->dword4 = rtw89_build_txwd_body4_v2(desc_info);
13916d67aabdSBjoern A. Zeeb txwd_body->dword5 = rtw89_build_txwd_body5_v2(desc_info);
13926d67aabdSBjoern A. Zeeb }
13936d67aabdSBjoern A. Zeeb txwd_body->dword7 = rtw89_build_txwd_body7_v2(desc_info);
13946d67aabdSBjoern A. Zeeb
13956d67aabdSBjoern A. Zeeb if (!desc_info->en_wd_info)
13966d67aabdSBjoern A. Zeeb return;
13976d67aabdSBjoern A. Zeeb
13986d67aabdSBjoern A. Zeeb txwd_info = (struct rtw89_txwd_info_v2 *)(txwd_body + 1);
13996d67aabdSBjoern A. Zeeb txwd_info->dword0 = rtw89_build_txwd_info0_v2(desc_info);
14006d67aabdSBjoern A. Zeeb txwd_info->dword1 = rtw89_build_txwd_info1_v2(desc_info);
14016d67aabdSBjoern A. Zeeb txwd_info->dword2 = rtw89_build_txwd_info2_v2(desc_info);
14026d67aabdSBjoern A. Zeeb txwd_info->dword4 = rtw89_build_txwd_info4_v2(desc_info);
14036d67aabdSBjoern A. Zeeb }
14046d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_fill_txdesc_v2);
14056d67aabdSBjoern A. Zeeb
rtw89_build_txwd_fwcmd0_v1(struct rtw89_tx_desc_info * desc_info)14068e93258fSBjoern A. Zeeb static __le32 rtw89_build_txwd_fwcmd0_v1(struct rtw89_tx_desc_info *desc_info)
14078e93258fSBjoern A. Zeeb {
14088e93258fSBjoern A. Zeeb u32 dword = FIELD_PREP(AX_RXD_RPKT_LEN_MASK, desc_info->pkt_size) |
14098e93258fSBjoern A. Zeeb FIELD_PREP(AX_RXD_RPKT_TYPE_MASK, desc_info->fw_dl ?
14108e93258fSBjoern A. Zeeb RTW89_CORE_RX_TYPE_FWDL :
14118e93258fSBjoern A. Zeeb RTW89_CORE_RX_TYPE_H2C);
14128e93258fSBjoern A. Zeeb
14138e93258fSBjoern A. Zeeb return cpu_to_le32(dword);
14148e93258fSBjoern A. Zeeb }
14158e93258fSBjoern A. Zeeb
rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev * rtwdev,struct rtw89_tx_desc_info * desc_info,void * txdesc)14168e93258fSBjoern A. Zeeb void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev,
14178e93258fSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info,
14188e93258fSBjoern A. Zeeb void *txdesc)
14198e93258fSBjoern A. Zeeb {
14208e93258fSBjoern A. Zeeb struct rtw89_rxdesc_short *txwd_v1 = (struct rtw89_rxdesc_short *)txdesc;
14218e93258fSBjoern A. Zeeb
14228e93258fSBjoern A. Zeeb txwd_v1->dword0 = rtw89_build_txwd_fwcmd0_v1(desc_info);
14238e93258fSBjoern A. Zeeb }
14248e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_fill_txdesc_fwcmd_v1);
14258e93258fSBjoern A. Zeeb
rtw89_build_txwd_fwcmd0_v2(struct rtw89_tx_desc_info * desc_info)14266d67aabdSBjoern A. Zeeb static __le32 rtw89_build_txwd_fwcmd0_v2(struct rtw89_tx_desc_info *desc_info)
14276d67aabdSBjoern A. Zeeb {
14286d67aabdSBjoern A. Zeeb u32 dword = FIELD_PREP(BE_RXD_RPKT_LEN_MASK, desc_info->pkt_size) |
14296d67aabdSBjoern A. Zeeb FIELD_PREP(BE_RXD_RPKT_TYPE_MASK, desc_info->fw_dl ?
14306d67aabdSBjoern A. Zeeb RTW89_CORE_RX_TYPE_FWDL :
14316d67aabdSBjoern A. Zeeb RTW89_CORE_RX_TYPE_H2C);
14326d67aabdSBjoern A. Zeeb
14336d67aabdSBjoern A. Zeeb return cpu_to_le32(dword);
14346d67aabdSBjoern A. Zeeb }
14356d67aabdSBjoern A. Zeeb
rtw89_core_fill_txdesc_fwcmd_v2(struct rtw89_dev * rtwdev,struct rtw89_tx_desc_info * desc_info,void * txdesc)14366d67aabdSBjoern A. Zeeb void rtw89_core_fill_txdesc_fwcmd_v2(struct rtw89_dev *rtwdev,
14376d67aabdSBjoern A. Zeeb struct rtw89_tx_desc_info *desc_info,
14386d67aabdSBjoern A. Zeeb void *txdesc)
14396d67aabdSBjoern A. Zeeb {
14406d67aabdSBjoern A. Zeeb struct rtw89_rxdesc_short_v2 *txwd_v2 = (struct rtw89_rxdesc_short_v2 *)txdesc;
14416d67aabdSBjoern A. Zeeb
14426d67aabdSBjoern A. Zeeb txwd_v2->dword0 = rtw89_build_txwd_fwcmd0_v2(desc_info);
14436d67aabdSBjoern A. Zeeb }
14446d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_fill_txdesc_fwcmd_v2);
14456d67aabdSBjoern A. Zeeb
rtw89_core_rx_process_mac_ppdu(struct rtw89_dev * rtwdev,struct sk_buff * skb,struct rtw89_rx_phy_ppdu * phy_ppdu)14468e93258fSBjoern A. Zeeb static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev,
14478e93258fSBjoern A. Zeeb struct sk_buff *skb,
14488e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
14498e93258fSBjoern A. Zeeb {
14506d67aabdSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
1451e2340276SBjoern A. Zeeb const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data;
14526d67aabdSBjoern A. Zeeb const struct rtw89_rxinfo_user *user;
14536d67aabdSBjoern A. Zeeb enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
14546d67aabdSBjoern A. Zeeb int rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE;
14558e93258fSBjoern A. Zeeb bool rx_cnt_valid = false;
14566d67aabdSBjoern A. Zeeb bool invalid = false;
14578e93258fSBjoern A. Zeeb u8 plcp_size = 0;
14588e93258fSBjoern A. Zeeb u8 *phy_sts;
14596d67aabdSBjoern A. Zeeb u8 usr_num;
14606d67aabdSBjoern A. Zeeb int i;
14616d67aabdSBjoern A. Zeeb
14626d67aabdSBjoern A. Zeeb if (chip_gen == RTW89_CHIP_BE) {
14636d67aabdSBjoern A. Zeeb invalid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_INVALID_V1);
14646d67aabdSBjoern A. Zeeb rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE_V1;
14656d67aabdSBjoern A. Zeeb }
14666d67aabdSBjoern A. Zeeb
14676d67aabdSBjoern A. Zeeb if (invalid)
14686d67aabdSBjoern A. Zeeb return -EINVAL;
14698e93258fSBjoern A. Zeeb
1470e2340276SBjoern A. Zeeb rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD);
14716d67aabdSBjoern A. Zeeb if (chip_gen == RTW89_CHIP_BE) {
14726d67aabdSBjoern A. Zeeb plcp_size = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_PLCP_LEN_V1) << 3;
14736d67aabdSBjoern A. Zeeb usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM_V1);
14746d67aabdSBjoern A. Zeeb } else {
1475e2340276SBjoern A. Zeeb plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3;
1476e2340276SBjoern A. Zeeb usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM);
14776d67aabdSBjoern A. Zeeb }
14786d67aabdSBjoern A. Zeeb if (usr_num > chip->ppdu_max_usr) {
14796d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n",
14806d67aabdSBjoern A. Zeeb usr_num);
14818e93258fSBjoern A. Zeeb return -EINVAL;
14828e93258fSBjoern A. Zeeb }
14838e93258fSBjoern A. Zeeb
14846d67aabdSBjoern A. Zeeb /* For WiFi 7 chips, RXWD.mac_id of PPDU status is not set by hardware,
14856d67aabdSBjoern A. Zeeb * so update mac_id by rxinfo_user[].mac_id.
14866d67aabdSBjoern A. Zeeb */
14876d67aabdSBjoern A. Zeeb for (i = 0; i < usr_num && chip_gen == RTW89_CHIP_BE; i++) {
14886d67aabdSBjoern A. Zeeb user = &rxinfo->user[i];
14896d67aabdSBjoern A. Zeeb if (!le32_get_bits(user->w0, RTW89_RXINFO_USER_MAC_ID_VALID))
14906d67aabdSBjoern A. Zeeb continue;
14916d67aabdSBjoern A. Zeeb
14926d67aabdSBjoern A. Zeeb phy_ppdu->mac_id =
14936d67aabdSBjoern A. Zeeb le32_get_bits(user->w0, RTW89_RXINFO_USER_MACID);
14946d67aabdSBjoern A. Zeeb break;
14956d67aabdSBjoern A. Zeeb }
14966d67aabdSBjoern A. Zeeb
14978e93258fSBjoern A. Zeeb phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE;
14988e93258fSBjoern A. Zeeb phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE;
14998e93258fSBjoern A. Zeeb /* 8-byte alignment */
15008e93258fSBjoern A. Zeeb if (usr_num & BIT(0))
15018e93258fSBjoern A. Zeeb phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE;
15028e93258fSBjoern A. Zeeb if (rx_cnt_valid)
15036d67aabdSBjoern A. Zeeb phy_sts += rx_cnt_size;
15048e93258fSBjoern A. Zeeb phy_sts += plcp_size;
15058e93258fSBjoern A. Zeeb
15066d67aabdSBjoern A. Zeeb if (phy_sts > skb->data + skb->len)
15076d67aabdSBjoern A. Zeeb return -EINVAL;
15086d67aabdSBjoern A. Zeeb
15098e93258fSBjoern A. Zeeb phy_ppdu->buf = phy_sts;
15108e93258fSBjoern A. Zeeb phy_ppdu->len = skb->data + skb->len - phy_sts;
15118e93258fSBjoern A. Zeeb
15128e93258fSBjoern A. Zeeb return 0;
15138e93258fSBjoern A. Zeeb }
15148e93258fSBjoern A. Zeeb
rtw89_core_rx_process_phy_ppdu_iter(void * data,struct ieee80211_sta * sta)15158e93258fSBjoern A. Zeeb static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
15168e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
15178e93258fSBjoern A. Zeeb {
15188e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
15198e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu = (struct rtw89_rx_phy_ppdu *)data;
1520e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = rtwsta->rtwdev;
1521e2340276SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
1522e2340276SBjoern A. Zeeb u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num;
1523e2340276SBjoern A. Zeeb u8 ant_pos = U8_MAX;
1524e2340276SBjoern A. Zeeb u8 evm_pos = 0;
1525e2340276SBjoern A. Zeeb int i;
15268e93258fSBjoern A. Zeeb
1527e2340276SBjoern A. Zeeb if (rtwsta->mac_id != phy_ppdu->mac_id || !phy_ppdu->to_self)
1528e2340276SBjoern A. Zeeb return;
1529e2340276SBjoern A. Zeeb
1530e2340276SBjoern A. Zeeb if (hal->ant_diversity && hal->antenna_rx) {
1531e2340276SBjoern A. Zeeb ant_pos = __ffs(hal->antenna_rx);
1532e2340276SBjoern A. Zeeb evm_pos = ant_pos;
1533e2340276SBjoern A. Zeeb }
1534e2340276SBjoern A. Zeeb
15358e93258fSBjoern A. Zeeb ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg);
1536e2340276SBjoern A. Zeeb
1537e2340276SBjoern A. Zeeb if (ant_pos < ant_num) {
1538e2340276SBjoern A. Zeeb ewma_rssi_add(&rtwsta->rssi[ant_pos], phy_ppdu->rssi[0]);
1539e2340276SBjoern A. Zeeb } else {
1540e2340276SBjoern A. Zeeb for (i = 0; i < rtwdev->chip->rf_path_num; i++)
1541e2340276SBjoern A. Zeeb ewma_rssi_add(&rtwsta->rssi[i], phy_ppdu->rssi[i]);
1542e2340276SBjoern A. Zeeb }
1543e2340276SBjoern A. Zeeb
1544e2340276SBjoern A. Zeeb if (phy_ppdu->ofdm.has) {
1545e2340276SBjoern A. Zeeb ewma_snr_add(&rtwsta->avg_snr, phy_ppdu->ofdm.avg_snr);
1546e2340276SBjoern A. Zeeb ewma_evm_add(&rtwsta->evm_min[evm_pos], phy_ppdu->ofdm.evm_min);
1547e2340276SBjoern A. Zeeb ewma_evm_add(&rtwsta->evm_max[evm_pos], phy_ppdu->ofdm.evm_max);
1548e2340276SBjoern A. Zeeb }
15498e93258fSBjoern A. Zeeb }
15508e93258fSBjoern A. Zeeb
15518e93258fSBjoern A. Zeeb #define VAR_LEN 0xff
15528e93258fSBjoern A. Zeeb #define VAR_LEN_UNIT 8
rtw89_core_get_phy_status_ie_len(struct rtw89_dev * rtwdev,const struct rtw89_phy_sts_iehdr * iehdr)1553e2340276SBjoern A. Zeeb static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev,
1554e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_iehdr *iehdr)
15558e93258fSBjoern A. Zeeb {
15566d67aabdSBjoern A. Zeeb static const u8 physts_ie_len_tabs[RTW89_CHIP_GEN_NUM][32] = {
15576d67aabdSBjoern A. Zeeb [RTW89_CHIP_AX] = {
15588e93258fSBjoern A. Zeeb 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
15598e93258fSBjoern A. Zeeb VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
15608e93258fSBjoern A. Zeeb VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
15616d67aabdSBjoern A. Zeeb },
15626d67aabdSBjoern A. Zeeb [RTW89_CHIP_BE] = {
15636d67aabdSBjoern A. Zeeb 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
15646d67aabdSBjoern A. Zeeb VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
15656d67aabdSBjoern A. Zeeb VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
15666d67aabdSBjoern A. Zeeb },
15678e93258fSBjoern A. Zeeb };
15686d67aabdSBjoern A. Zeeb const u8 *physts_ie_len_tab;
15698e93258fSBjoern A. Zeeb u16 ie_len;
15708e93258fSBjoern A. Zeeb u8 ie;
15718e93258fSBjoern A. Zeeb
15726d67aabdSBjoern A. Zeeb physts_ie_len_tab = physts_ie_len_tabs[rtwdev->chip->chip_gen];
15736d67aabdSBjoern A. Zeeb
1574e2340276SBjoern A. Zeeb ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE);
15758e93258fSBjoern A. Zeeb if (physts_ie_len_tab[ie] != VAR_LEN)
15768e93258fSBjoern A. Zeeb ie_len = physts_ie_len_tab[ie];
15778e93258fSBjoern A. Zeeb else
1578e2340276SBjoern A. Zeeb ie_len = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_LEN) * VAR_LEN_UNIT;
15798e93258fSBjoern A. Zeeb
15808e93258fSBjoern A. Zeeb return ie_len;
15818e93258fSBjoern A. Zeeb }
15828e93258fSBjoern A. Zeeb
rtw89_core_parse_phy_status_ie01(struct rtw89_dev * rtwdev,const struct rtw89_phy_sts_iehdr * iehdr,struct rtw89_rx_phy_ppdu * phy_ppdu)1583e2340276SBjoern A. Zeeb static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev,
1584e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_iehdr *iehdr,
15858e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
15868e93258fSBjoern A. Zeeb {
1587e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_ie0 *ie = (const struct rtw89_phy_sts_ie0 *)iehdr;
15888e93258fSBjoern A. Zeeb s16 cfo;
1589e2340276SBjoern A. Zeeb u32 t;
15908e93258fSBjoern A. Zeeb
1591e2340276SBjoern A. Zeeb phy_ppdu->chan_idx = le32_get_bits(ie->w0, RTW89_PHY_STS_IE01_W0_CH_IDX);
15926d67aabdSBjoern A. Zeeb
15936d67aabdSBjoern A. Zeeb if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) {
15946d67aabdSBjoern A. Zeeb phy_ppdu->ldpc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_LDPC);
15956d67aabdSBjoern A. Zeeb phy_ppdu->stbc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_STBC);
15966d67aabdSBjoern A. Zeeb }
15976d67aabdSBjoern A. Zeeb
15988e93258fSBjoern A. Zeeb if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6)
15998e93258fSBjoern A. Zeeb return;
1600e2340276SBjoern A. Zeeb
1601e2340276SBjoern A. Zeeb if (!phy_ppdu->to_self)
1602e2340276SBjoern A. Zeeb return;
1603e2340276SBjoern A. Zeeb
1604e2340276SBjoern A. Zeeb phy_ppdu->ofdm.avg_snr = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_AVG_SNR);
1605e2340276SBjoern A. Zeeb phy_ppdu->ofdm.evm_max = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_EVM_MAX);
1606e2340276SBjoern A. Zeeb phy_ppdu->ofdm.evm_min = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_EVM_MIN);
1607e2340276SBjoern A. Zeeb phy_ppdu->ofdm.has = true;
1608e2340276SBjoern A. Zeeb
16098e93258fSBjoern A. Zeeb /* sign conversion for S(12,2) */
1610e2340276SBjoern A. Zeeb if (rtwdev->chip->cfo_src_fd) {
1611e2340276SBjoern A. Zeeb t = le32_get_bits(ie->w1, RTW89_PHY_STS_IE01_W1_FD_CFO);
1612e2340276SBjoern A. Zeeb cfo = sign_extend32(t, 11);
1613e2340276SBjoern A. Zeeb } else {
1614e2340276SBjoern A. Zeeb t = le32_get_bits(ie->w1, RTW89_PHY_STS_IE01_W1_PREMB_CFO);
1615e2340276SBjoern A. Zeeb cfo = sign_extend32(t, 11);
1616e2340276SBjoern A. Zeeb }
1617e2340276SBjoern A. Zeeb
16188e93258fSBjoern A. Zeeb rtw89_phy_cfo_parse(rtwdev, cfo, phy_ppdu);
16198e93258fSBjoern A. Zeeb }
16208e93258fSBjoern A. Zeeb
rtw89_core_process_phy_status_ie(struct rtw89_dev * rtwdev,const struct rtw89_phy_sts_iehdr * iehdr,struct rtw89_rx_phy_ppdu * phy_ppdu)1621e2340276SBjoern A. Zeeb static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev,
1622e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_iehdr *iehdr,
16238e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
16248e93258fSBjoern A. Zeeb {
16258e93258fSBjoern A. Zeeb u8 ie;
16268e93258fSBjoern A. Zeeb
1627e2340276SBjoern A. Zeeb ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE);
1628e2340276SBjoern A. Zeeb
16298e93258fSBjoern A. Zeeb switch (ie) {
16308e93258fSBjoern A. Zeeb case RTW89_PHYSTS_IE01_CMN_OFDM:
1631e2340276SBjoern A. Zeeb rtw89_core_parse_phy_status_ie01(rtwdev, iehdr, phy_ppdu);
16328e93258fSBjoern A. Zeeb break;
16338e93258fSBjoern A. Zeeb default:
16348e93258fSBjoern A. Zeeb break;
16358e93258fSBjoern A. Zeeb }
16368e93258fSBjoern A. Zeeb
16378e93258fSBjoern A. Zeeb return 0;
16388e93258fSBjoern A. Zeeb }
16398e93258fSBjoern A. Zeeb
rtw89_core_update_phy_ppdu(struct rtw89_rx_phy_ppdu * phy_ppdu)16408e93258fSBjoern A. Zeeb static void rtw89_core_update_phy_ppdu(struct rtw89_rx_phy_ppdu *phy_ppdu)
16418e93258fSBjoern A. Zeeb {
1642e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf;
1643e2340276SBjoern A. Zeeb u8 *rssi = phy_ppdu->rssi;
16448e93258fSBjoern A. Zeeb
1645e2340276SBjoern A. Zeeb phy_ppdu->ie = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_IE_MAP);
1646e2340276SBjoern A. Zeeb phy_ppdu->rssi_avg = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_RSSI_AVG);
1647e2340276SBjoern A. Zeeb rssi[RF_PATH_A] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_A);
1648e2340276SBjoern A. Zeeb rssi[RF_PATH_B] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_B);
1649e2340276SBjoern A. Zeeb rssi[RF_PATH_C] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_C);
1650e2340276SBjoern A. Zeeb rssi[RF_PATH_D] = le32_get_bits(hdr->w1, RTW89_PHY_STS_HDR_W1_RSSI_D);
16518e93258fSBjoern A. Zeeb }
16528e93258fSBjoern A. Zeeb
rtw89_core_rx_process_phy_ppdu(struct rtw89_dev * rtwdev,struct rtw89_rx_phy_ppdu * phy_ppdu)16538e93258fSBjoern A. Zeeb static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev,
16548e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
16558e93258fSBjoern A. Zeeb {
1656e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf;
1657e2340276SBjoern A. Zeeb u32 len_from_header;
16586d67aabdSBjoern A. Zeeb bool physts_valid;
16596d67aabdSBjoern A. Zeeb
16606d67aabdSBjoern A. Zeeb physts_valid = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_VALID);
16616d67aabdSBjoern A. Zeeb if (!physts_valid)
16626d67aabdSBjoern A. Zeeb return -EINVAL;
1663e2340276SBjoern A. Zeeb
1664e2340276SBjoern A. Zeeb len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3;
1665e2340276SBjoern A. Zeeb
16666d67aabdSBjoern A. Zeeb if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
16676d67aabdSBjoern A. Zeeb len_from_header += PHY_STS_HDR_LEN;
16686d67aabdSBjoern A. Zeeb
1669e2340276SBjoern A. Zeeb if (len_from_header != phy_ppdu->len) {
16708e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n");
16718e93258fSBjoern A. Zeeb return -EINVAL;
16728e93258fSBjoern A. Zeeb }
16738e93258fSBjoern A. Zeeb rtw89_core_update_phy_ppdu(phy_ppdu);
16748e93258fSBjoern A. Zeeb
16758e93258fSBjoern A. Zeeb return 0;
16768e93258fSBjoern A. Zeeb }
16778e93258fSBjoern A. Zeeb
rtw89_core_rx_parse_phy_sts(struct rtw89_dev * rtwdev,struct rtw89_rx_phy_ppdu * phy_ppdu)16788e93258fSBjoern A. Zeeb static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev,
16798e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
16808e93258fSBjoern A. Zeeb {
16818e93258fSBjoern A. Zeeb u16 ie_len;
1682e2340276SBjoern A. Zeeb #if defined(__linux__)
1683e2340276SBjoern A. Zeeb void *pos, *end;
1684e2340276SBjoern A. Zeeb #elif defined(__FreeBSD__)
16858e93258fSBjoern A. Zeeb u8 *pos, *end;
1686e2340276SBjoern A. Zeeb #endif
16878e93258fSBjoern A. Zeeb
16888e93258fSBjoern A. Zeeb /* mark invalid reports and bypass them */
16898e93258fSBjoern A. Zeeb if (phy_ppdu->ie < RTW89_CCK_PKT)
16908e93258fSBjoern A. Zeeb return -EINVAL;
16918e93258fSBjoern A. Zeeb
1692e2340276SBjoern A. Zeeb #if defined(__linux__)
1693e2340276SBjoern A. Zeeb pos = phy_ppdu->buf + PHY_STS_HDR_LEN;
1694e2340276SBjoern A. Zeeb end = phy_ppdu->buf + phy_ppdu->len;
1695e2340276SBjoern A. Zeeb #elif defined(__FreeBSD__)
16968e93258fSBjoern A. Zeeb pos = (u8 *)phy_ppdu->buf + PHY_STS_HDR_LEN;
16978e93258fSBjoern A. Zeeb end = (u8 *)phy_ppdu->buf + phy_ppdu->len;
1698e2340276SBjoern A. Zeeb #endif
16998e93258fSBjoern A. Zeeb while (pos < end) {
1700e2340276SBjoern A. Zeeb #if defined(__linux__)
1701e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_iehdr *iehdr = pos;
1702e2340276SBjoern A. Zeeb #elif defined(__FreeBSD__)
1703e2340276SBjoern A. Zeeb const struct rtw89_phy_sts_iehdr *iehdr = (void *)pos;
1704e2340276SBjoern A. Zeeb #endif
1705e2340276SBjoern A. Zeeb
1706e2340276SBjoern A. Zeeb ie_len = rtw89_core_get_phy_status_ie_len(rtwdev, iehdr);
1707e2340276SBjoern A. Zeeb rtw89_core_process_phy_status_ie(rtwdev, iehdr, phy_ppdu);
17088e93258fSBjoern A. Zeeb pos += ie_len;
17098e93258fSBjoern A. Zeeb if (pos > end || ie_len == 0) {
17108e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
17118e93258fSBjoern A. Zeeb "phy status parse failed\n");
17128e93258fSBjoern A. Zeeb return -EINVAL;
17138e93258fSBjoern A. Zeeb }
17148e93258fSBjoern A. Zeeb }
17158e93258fSBjoern A. Zeeb
1716e2340276SBjoern A. Zeeb rtw89_phy_antdiv_parse(rtwdev, phy_ppdu);
1717e2340276SBjoern A. Zeeb
17188e93258fSBjoern A. Zeeb return 0;
17198e93258fSBjoern A. Zeeb }
17208e93258fSBjoern A. Zeeb
rtw89_core_rx_process_phy_sts(struct rtw89_dev * rtwdev,struct rtw89_rx_phy_ppdu * phy_ppdu)17218e93258fSBjoern A. Zeeb static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev,
17228e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
17238e93258fSBjoern A. Zeeb {
17248e93258fSBjoern A. Zeeb int ret;
17258e93258fSBjoern A. Zeeb
17268e93258fSBjoern A. Zeeb ret = rtw89_core_rx_parse_phy_sts(rtwdev, phy_ppdu);
17278e93258fSBjoern A. Zeeb if (ret)
17288e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX, "parse phy sts failed\n");
17298e93258fSBjoern A. Zeeb else
17308e93258fSBjoern A. Zeeb phy_ppdu->valid = true;
1731e2340276SBjoern A. Zeeb
1732e2340276SBjoern A. Zeeb ieee80211_iterate_stations_atomic(rtwdev->hw,
1733e2340276SBjoern A. Zeeb rtw89_core_rx_process_phy_ppdu_iter,
1734e2340276SBjoern A. Zeeb phy_ppdu);
17358e93258fSBjoern A. Zeeb }
17368e93258fSBjoern A. Zeeb
rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev * rtwdev,u8 desc_info_gi,bool rx_status,bool eht)17376d67aabdSBjoern A. Zeeb static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev,
17386d67aabdSBjoern A. Zeeb u8 desc_info_gi,
17396d67aabdSBjoern A. Zeeb bool rx_status, bool eht)
17408e93258fSBjoern A. Zeeb {
17416d67aabdSBjoern A. Zeeb switch (desc_info_gi) {
17428e93258fSBjoern A. Zeeb case RTW89_GILTF_SGI_4XHE08:
17438e93258fSBjoern A. Zeeb case RTW89_GILTF_2XHE08:
17448e93258fSBjoern A. Zeeb case RTW89_GILTF_1XHE08:
17456d67aabdSBjoern A. Zeeb return eht ? NL80211_RATE_INFO_EHT_GI_0_8 :
17466d67aabdSBjoern A. Zeeb NL80211_RATE_INFO_HE_GI_0_8;
17478e93258fSBjoern A. Zeeb case RTW89_GILTF_2XHE16:
17488e93258fSBjoern A. Zeeb case RTW89_GILTF_1XHE16:
17496d67aabdSBjoern A. Zeeb return eht ? NL80211_RATE_INFO_EHT_GI_1_6 :
17506d67aabdSBjoern A. Zeeb NL80211_RATE_INFO_HE_GI_1_6;
17518e93258fSBjoern A. Zeeb case RTW89_GILTF_LGI_4XHE32:
17526d67aabdSBjoern A. Zeeb return eht ? NL80211_RATE_INFO_EHT_GI_3_2 :
17536d67aabdSBjoern A. Zeeb NL80211_RATE_INFO_HE_GI_3_2;
17548e93258fSBjoern A. Zeeb default:
17556d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi);
17566d67aabdSBjoern A. Zeeb if (rx_status)
17576d67aabdSBjoern A. Zeeb return eht ? NL80211_RATE_INFO_EHT_GI_3_2 :
17586d67aabdSBjoern A. Zeeb NL80211_RATE_INFO_HE_GI_3_2;
17596d67aabdSBjoern A. Zeeb return U8_MAX;
17608e93258fSBjoern A. Zeeb }
17618e93258fSBjoern A. Zeeb }
17628e93258fSBjoern A. Zeeb
17636d67aabdSBjoern A. Zeeb static
rtw89_check_rx_statu_gi_match(struct ieee80211_rx_status * status,u8 gi_ltf,bool eht)17646d67aabdSBjoern A. Zeeb bool rtw89_check_rx_statu_gi_match(struct ieee80211_rx_status *status, u8 gi_ltf,
17656d67aabdSBjoern A. Zeeb bool eht)
17666d67aabdSBjoern A. Zeeb {
17676d67aabdSBjoern A. Zeeb if (eht)
17686d67aabdSBjoern A. Zeeb return status->eht.gi == gi_ltf;
17696d67aabdSBjoern A. Zeeb
17706d67aabdSBjoern A. Zeeb return status->he_gi == gi_ltf;
17716d67aabdSBjoern A. Zeeb }
17726d67aabdSBjoern A. Zeeb
rtw89_core_rx_ppdu_match(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,struct ieee80211_rx_status * status)17738e93258fSBjoern A. Zeeb static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev,
17748e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
17758e93258fSBjoern A. Zeeb struct ieee80211_rx_status *status)
17768e93258fSBjoern A. Zeeb {
17778e93258fSBjoern A. Zeeb u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
17788e93258fSBjoern A. Zeeb u8 data_rate_mode, bw, rate_idx = MASKBYTE0, gi_ltf;
17796d67aabdSBjoern A. Zeeb bool eht = false;
17808e93258fSBjoern A. Zeeb u16 data_rate;
17818e93258fSBjoern A. Zeeb bool ret;
17828e93258fSBjoern A. Zeeb
17838e93258fSBjoern A. Zeeb data_rate = desc_info->data_rate;
1784e2340276SBjoern A. Zeeb data_rate_mode = rtw89_get_data_rate_mode(rtwdev, data_rate);
17858e93258fSBjoern A. Zeeb if (data_rate_mode == DATA_RATE_MODE_NON_HT) {
1786e2340276SBjoern A. Zeeb rate_idx = rtw89_get_data_not_ht_idx(rtwdev, data_rate);
17878e93258fSBjoern A. Zeeb /* rate_idx is still hardware value here */
17888e93258fSBjoern A. Zeeb } else if (data_rate_mode == DATA_RATE_MODE_HT) {
1789e2340276SBjoern A. Zeeb rate_idx = rtw89_get_data_ht_mcs(rtwdev, data_rate);
17906d67aabdSBjoern A. Zeeb } else if (data_rate_mode == DATA_RATE_MODE_VHT ||
17916d67aabdSBjoern A. Zeeb data_rate_mode == DATA_RATE_MODE_HE ||
17926d67aabdSBjoern A. Zeeb data_rate_mode == DATA_RATE_MODE_EHT) {
1793e2340276SBjoern A. Zeeb rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
17948e93258fSBjoern A. Zeeb } else {
17958e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
17968e93258fSBjoern A. Zeeb }
17978e93258fSBjoern A. Zeeb
17986d67aabdSBjoern A. Zeeb eht = data_rate_mode == DATA_RATE_MODE_EHT;
17998e93258fSBjoern A. Zeeb bw = rtw89_hw_to_rate_info_bw(desc_info->bw);
18006d67aabdSBjoern A. Zeeb gi_ltf = rtw89_rxdesc_to_nl_he_eht_gi(rtwdev, desc_info->gi_ltf, false, eht);
18018e93258fSBjoern A. Zeeb ret = rtwdev->ppdu_sts.curr_rx_ppdu_cnt[band] == desc_info->ppdu_cnt &&
18028e93258fSBjoern A. Zeeb status->rate_idx == rate_idx &&
18036d67aabdSBjoern A. Zeeb rtw89_check_rx_statu_gi_match(status, gi_ltf, eht) &&
18048e93258fSBjoern A. Zeeb status->bw == bw;
18058e93258fSBjoern A. Zeeb
18068e93258fSBjoern A. Zeeb return ret;
18078e93258fSBjoern A. Zeeb }
18088e93258fSBjoern A. Zeeb
18098e93258fSBjoern A. Zeeb struct rtw89_vif_rx_stats_iter_data {
18108e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev;
18118e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu;
18128e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info;
18138e93258fSBjoern A. Zeeb struct sk_buff *skb;
18148e93258fSBjoern A. Zeeb const u8 *bssid;
18158e93258fSBjoern A. Zeeb };
18168e93258fSBjoern A. Zeeb
rtw89_stats_trigger_frame(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct sk_buff * skb)18178e93258fSBjoern A. Zeeb static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
18188e93258fSBjoern A. Zeeb struct ieee80211_vif *vif,
18198e93258fSBjoern A. Zeeb struct sk_buff *skb)
18208e93258fSBjoern A. Zeeb {
18218e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
18228e93258fSBjoern A. Zeeb struct ieee80211_trigger *tf = (struct ieee80211_trigger *)skb->data;
18236d67aabdSBjoern A. Zeeb u8 *pos, *end, type, tf_bw;
18246d67aabdSBjoern A. Zeeb u16 aid, tf_rua;
18258e93258fSBjoern A. Zeeb
18268e93258fSBjoern A. Zeeb if (!ether_addr_equal(vif->bss_conf.bssid, tf->ta) ||
18278e93258fSBjoern A. Zeeb rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION ||
18288e93258fSBjoern A. Zeeb rtwvif->net_type == RTW89_NET_TYPE_NO_LINK)
18298e93258fSBjoern A. Zeeb return;
18308e93258fSBjoern A. Zeeb
18318e93258fSBjoern A. Zeeb type = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_TYPE_MASK);
18326d67aabdSBjoern A. Zeeb if (type != IEEE80211_TRIGGER_TYPE_BASIC && type != IEEE80211_TRIGGER_TYPE_MU_BAR)
18338e93258fSBjoern A. Zeeb return;
18348e93258fSBjoern A. Zeeb
18358e93258fSBjoern A. Zeeb end = (u8 *)tf + skb->len;
18368e93258fSBjoern A. Zeeb pos = tf->variable;
18378e93258fSBjoern A. Zeeb
18388e93258fSBjoern A. Zeeb while (end - pos >= RTW89_TF_BASIC_USER_INFO_SZ) {
18398e93258fSBjoern A. Zeeb aid = RTW89_GET_TF_USER_INFO_AID12(pos);
18406d67aabdSBjoern A. Zeeb tf_rua = RTW89_GET_TF_USER_INFO_RUA(pos);
18416d67aabdSBjoern A. Zeeb tf_bw = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_ULBW_MASK);
18428e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
18436d67aabdSBjoern A. Zeeb "[TF] aid: %d, ul_mcs: %d, rua: %d, bw: %d\n",
18448e93258fSBjoern A. Zeeb aid, RTW89_GET_TF_USER_INFO_UL_MCS(pos),
18456d67aabdSBjoern A. Zeeb tf_rua, tf_bw);
18468e93258fSBjoern A. Zeeb
18478e93258fSBjoern A. Zeeb if (aid == RTW89_TF_PAD)
18488e93258fSBjoern A. Zeeb break;
18498e93258fSBjoern A. Zeeb
18508e93258fSBjoern A. Zeeb if (aid == vif->cfg.aid) {
18516d67aabdSBjoern A. Zeeb enum nl80211_he_ru_alloc rua = rtw89_he_rua_to_ru_alloc(tf_rua >> 1);
18526d67aabdSBjoern A. Zeeb
18538e93258fSBjoern A. Zeeb rtwvif->stats.rx_tf_acc++;
18548e93258fSBjoern A. Zeeb rtwdev->stats.rx_tf_acc++;
18556d67aabdSBjoern A. Zeeb if (tf_bw == IEEE80211_TRIGGER_ULBW_160_80P80MHZ &&
18566d67aabdSBjoern A. Zeeb rua <= NL80211_RATE_INFO_HE_RU_ALLOC_106)
18576d67aabdSBjoern A. Zeeb rtwvif->pwr_diff_en = true;
18588e93258fSBjoern A. Zeeb break;
18598e93258fSBjoern A. Zeeb }
18608e93258fSBjoern A. Zeeb
18618e93258fSBjoern A. Zeeb pos += RTW89_TF_BASIC_USER_INFO_SZ;
18628e93258fSBjoern A. Zeeb }
18638e93258fSBjoern A. Zeeb }
18648e93258fSBjoern A. Zeeb
rtw89_cancel_6ghz_probe_work(struct work_struct * work)1865e2340276SBjoern A. Zeeb static void rtw89_cancel_6ghz_probe_work(struct work_struct *work)
1866e2340276SBjoern A. Zeeb {
1867e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
1868e2340276SBjoern A. Zeeb cancel_6ghz_probe_work);
1869e2340276SBjoern A. Zeeb struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
1870e2340276SBjoern A. Zeeb struct rtw89_pktofld_info *info;
1871e2340276SBjoern A. Zeeb
1872e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
1873e2340276SBjoern A. Zeeb
1874e2340276SBjoern A. Zeeb if (!rtwdev->scanning)
1875e2340276SBjoern A. Zeeb goto out;
1876e2340276SBjoern A. Zeeb
1877e2340276SBjoern A. Zeeb list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) {
1878e2340276SBjoern A. Zeeb if (!info->cancel || !test_bit(info->id, rtwdev->pkt_offload))
1879e2340276SBjoern A. Zeeb continue;
1880e2340276SBjoern A. Zeeb
1881e2340276SBjoern A. Zeeb rtw89_fw_h2c_del_pkt_offload(rtwdev, info->id);
1882e2340276SBjoern A. Zeeb
1883e2340276SBjoern A. Zeeb /* Don't delete/free info from pkt_list at this moment. Let it
1884e2340276SBjoern A. Zeeb * be deleted/freed in rtw89_release_pkt_list() after scanning,
1885e2340276SBjoern A. Zeeb * since if during scanning, pkt_list is accessed in bottom half.
1886e2340276SBjoern A. Zeeb */
1887e2340276SBjoern A. Zeeb }
1888e2340276SBjoern A. Zeeb
1889e2340276SBjoern A. Zeeb out:
1890e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
1891e2340276SBjoern A. Zeeb }
1892e2340276SBjoern A. Zeeb
rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev * rtwdev,struct sk_buff * skb)1893e2340276SBjoern A. Zeeb static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
1894e2340276SBjoern A. Zeeb struct sk_buff *skb)
1895e2340276SBjoern A. Zeeb {
1896e2340276SBjoern A. Zeeb struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
1897e2340276SBjoern A. Zeeb struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
1898e2340276SBjoern A. Zeeb struct list_head *pkt_list = rtwdev->scan_info.pkt_list;
1899e2340276SBjoern A. Zeeb struct rtw89_pktofld_info *info;
1900e2340276SBjoern A. Zeeb const u8 *ies = mgmt->u.beacon.variable, *ssid_ie;
1901e2340276SBjoern A. Zeeb bool queue_work = false;
1902e2340276SBjoern A. Zeeb
1903e2340276SBjoern A. Zeeb if (rx_status->band != NL80211_BAND_6GHZ)
1904e2340276SBjoern A. Zeeb return;
1905e2340276SBjoern A. Zeeb
1906e2340276SBjoern A. Zeeb ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len);
1907e2340276SBjoern A. Zeeb
1908e2340276SBjoern A. Zeeb list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) {
1909e2340276SBjoern A. Zeeb if (ether_addr_equal(info->bssid, mgmt->bssid)) {
1910e2340276SBjoern A. Zeeb info->cancel = true;
1911e2340276SBjoern A. Zeeb queue_work = true;
1912e2340276SBjoern A. Zeeb continue;
1913e2340276SBjoern A. Zeeb }
1914e2340276SBjoern A. Zeeb
1915e2340276SBjoern A. Zeeb if (!ssid_ie || ssid_ie[1] != info->ssid_len || info->ssid_len == 0)
1916e2340276SBjoern A. Zeeb continue;
1917e2340276SBjoern A. Zeeb
1918e2340276SBjoern A. Zeeb if (memcmp(&ssid_ie[2], info->ssid, info->ssid_len) == 0) {
1919e2340276SBjoern A. Zeeb info->cancel = true;
1920e2340276SBjoern A. Zeeb queue_work = true;
1921e2340276SBjoern A. Zeeb }
1922e2340276SBjoern A. Zeeb }
1923e2340276SBjoern A. Zeeb
1924e2340276SBjoern A. Zeeb if (queue_work)
1925e2340276SBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work);
1926e2340276SBjoern A. Zeeb }
1927e2340276SBjoern A. Zeeb
rtw89_vif_sync_bcn_tsf(struct rtw89_vif * rtwvif,struct ieee80211_hdr * hdr,size_t len)19286d67aabdSBjoern A. Zeeb static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif,
19296d67aabdSBjoern A. Zeeb struct ieee80211_hdr *hdr, size_t len)
19306d67aabdSBjoern A. Zeeb {
19316d67aabdSBjoern A. Zeeb struct ieee80211_mgmt *mgmt = (typeof(mgmt))hdr;
19326d67aabdSBjoern A. Zeeb
19336d67aabdSBjoern A. Zeeb if (len < offsetof(typeof(*mgmt), u.beacon.variable))
19346d67aabdSBjoern A. Zeeb return;
19356d67aabdSBjoern A. Zeeb
19366d67aabdSBjoern A. Zeeb WRITE_ONCE(rtwvif->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp));
19376d67aabdSBjoern A. Zeeb }
19386d67aabdSBjoern A. Zeeb
rtw89_vif_rx_stats_iter(void * data,u8 * mac,struct ieee80211_vif * vif)19398e93258fSBjoern A. Zeeb static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
19408e93258fSBjoern A. Zeeb struct ieee80211_vif *vif)
19418e93258fSBjoern A. Zeeb {
19428e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
19438e93258fSBjoern A. Zeeb struct rtw89_vif_rx_stats_iter_data *iter_data = data;
19448e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = iter_data->rtwdev;
19458e93258fSBjoern A. Zeeb struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
19468e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
19478e93258fSBjoern A. Zeeb struct sk_buff *skb = iter_data->skb;
19488e93258fSBjoern A. Zeeb struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1949e2340276SBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu = iter_data->phy_ppdu;
19508e93258fSBjoern A. Zeeb const u8 *bssid = iter_data->bssid;
19518e93258fSBjoern A. Zeeb
1952e2340276SBjoern A. Zeeb if (rtwdev->scanning &&
1953e2340276SBjoern A. Zeeb (ieee80211_is_beacon(hdr->frame_control) ||
1954e2340276SBjoern A. Zeeb ieee80211_is_probe_resp(hdr->frame_control)))
1955e2340276SBjoern A. Zeeb rtw89_core_cancel_6ghz_probe_tx(rtwdev, skb);
1956e2340276SBjoern A. Zeeb
1957e2340276SBjoern A. Zeeb if (!vif->bss_conf.bssid)
1958e2340276SBjoern A. Zeeb return;
1959e2340276SBjoern A. Zeeb
19608e93258fSBjoern A. Zeeb if (ieee80211_is_trigger(hdr->frame_control)) {
19618e93258fSBjoern A. Zeeb rtw89_stats_trigger_frame(rtwdev, vif, skb);
19628e93258fSBjoern A. Zeeb return;
19638e93258fSBjoern A. Zeeb }
19648e93258fSBjoern A. Zeeb
19658e93258fSBjoern A. Zeeb if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
19668e93258fSBjoern A. Zeeb return;
19678e93258fSBjoern A. Zeeb
1968e2340276SBjoern A. Zeeb if (ieee80211_is_beacon(hdr->frame_control)) {
19696d67aabdSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION &&
19706d67aabdSBjoern A. Zeeb !test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
19716d67aabdSBjoern A. Zeeb rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len);
1972e2340276SBjoern A. Zeeb rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu);
19736d67aabdSBjoern A. Zeeb }
19748e93258fSBjoern A. Zeeb pkt_stat->beacon_nr++;
1975e2340276SBjoern A. Zeeb }
19768e93258fSBjoern A. Zeeb
19778e93258fSBjoern A. Zeeb if (!ether_addr_equal(vif->addr, hdr->addr1))
19788e93258fSBjoern A. Zeeb return;
19798e93258fSBjoern A. Zeeb
19808e93258fSBjoern A. Zeeb if (desc_info->data_rate < RTW89_HW_RATE_NR)
19818e93258fSBjoern A. Zeeb pkt_stat->rx_rate_cnt[desc_info->data_rate]++;
19828e93258fSBjoern A. Zeeb
19838e93258fSBjoern A. Zeeb rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false);
19848e93258fSBjoern A. Zeeb }
19858e93258fSBjoern A. Zeeb
rtw89_core_rx_stats(struct rtw89_dev * rtwdev,struct rtw89_rx_phy_ppdu * phy_ppdu,struct rtw89_rx_desc_info * desc_info,struct sk_buff * skb)19868e93258fSBjoern A. Zeeb static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev,
19878e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu,
19888e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
19898e93258fSBjoern A. Zeeb struct sk_buff *skb)
19908e93258fSBjoern A. Zeeb {
19918e93258fSBjoern A. Zeeb struct rtw89_vif_rx_stats_iter_data iter_data;
19928e93258fSBjoern A. Zeeb
19938e93258fSBjoern A. Zeeb rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, false);
19948e93258fSBjoern A. Zeeb
19958e93258fSBjoern A. Zeeb iter_data.rtwdev = rtwdev;
19968e93258fSBjoern A. Zeeb iter_data.phy_ppdu = phy_ppdu;
19978e93258fSBjoern A. Zeeb iter_data.desc_info = desc_info;
19988e93258fSBjoern A. Zeeb iter_data.skb = skb;
19998e93258fSBjoern A. Zeeb iter_data.bssid = get_hdr_bssid((struct ieee80211_hdr *)skb->data);
20008e93258fSBjoern A. Zeeb rtw89_iterate_vifs_bh(rtwdev, rtw89_vif_rx_stats_iter, &iter_data);
20018e93258fSBjoern A. Zeeb }
20028e93258fSBjoern A. Zeeb
rtw89_correct_cck_chan(struct rtw89_dev * rtwdev,struct ieee80211_rx_status * status)20038e93258fSBjoern A. Zeeb static void rtw89_correct_cck_chan(struct rtw89_dev *rtwdev,
20048e93258fSBjoern A. Zeeb struct ieee80211_rx_status *status)
20058e93258fSBjoern A. Zeeb {
20068e93258fSBjoern A. Zeeb const struct rtw89_chan_rcd *rcd =
20078e93258fSBjoern A. Zeeb rtw89_chan_rcd_get(rtwdev, RTW89_SUB_ENTITY_0);
20088e93258fSBjoern A. Zeeb u16 chan = rcd->prev_primary_channel;
20096d67aabdSBjoern A. Zeeb u8 band = rtw89_hw_to_nl80211_band(rcd->prev_band_type);
20108e93258fSBjoern A. Zeeb
20118e93258fSBjoern A. Zeeb if (status->band != NL80211_BAND_2GHZ &&
20128e93258fSBjoern A. Zeeb status->encoding == RX_ENC_LEGACY &&
20138e93258fSBjoern A. Zeeb status->rate_idx < RTW89_HW_RATE_OFDM6) {
20148e93258fSBjoern A. Zeeb status->freq = ieee80211_channel_to_frequency(chan, band);
20158e93258fSBjoern A. Zeeb status->band = band;
20168e93258fSBjoern A. Zeeb }
20178e93258fSBjoern A. Zeeb }
20188e93258fSBjoern A. Zeeb
rtw89_core_hw_to_sband_rate(struct ieee80211_rx_status * rx_status)20198e93258fSBjoern A. Zeeb static void rtw89_core_hw_to_sband_rate(struct ieee80211_rx_status *rx_status)
20208e93258fSBjoern A. Zeeb {
20218e93258fSBjoern A. Zeeb if (rx_status->band == NL80211_BAND_2GHZ ||
20228e93258fSBjoern A. Zeeb rx_status->encoding != RX_ENC_LEGACY)
20238e93258fSBjoern A. Zeeb return;
20248e93258fSBjoern A. Zeeb
20258e93258fSBjoern A. Zeeb /* Some control frames' freq(ACKs in this case) are reported wrong due
20268e93258fSBjoern A. Zeeb * to FW notify timing, set to lowest rate to prevent overflow.
20278e93258fSBjoern A. Zeeb */
20288e93258fSBjoern A. Zeeb if (rx_status->rate_idx < RTW89_HW_RATE_OFDM6) {
20298e93258fSBjoern A. Zeeb rx_status->rate_idx = 0;
20308e93258fSBjoern A. Zeeb return;
20318e93258fSBjoern A. Zeeb }
20328e93258fSBjoern A. Zeeb
20338e93258fSBjoern A. Zeeb /* No 4 CCK rates for non-2G */
20348e93258fSBjoern A. Zeeb rx_status->rate_idx -= 4;
20358e93258fSBjoern A. Zeeb }
20368e93258fSBjoern A. Zeeb
20376d67aabdSBjoern A. Zeeb static
rtw89_core_update_rx_status_by_ppdu(struct rtw89_dev * rtwdev,struct ieee80211_rx_status * rx_status,struct rtw89_rx_phy_ppdu * phy_ppdu)20386d67aabdSBjoern A. Zeeb void rtw89_core_update_rx_status_by_ppdu(struct rtw89_dev *rtwdev,
20396d67aabdSBjoern A. Zeeb struct ieee80211_rx_status *rx_status,
20406d67aabdSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu)
20416d67aabdSBjoern A. Zeeb {
20426d67aabdSBjoern A. Zeeb if (!(rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR))
20436d67aabdSBjoern A. Zeeb return;
20446d67aabdSBjoern A. Zeeb
20456d67aabdSBjoern A. Zeeb if (!phy_ppdu)
20466d67aabdSBjoern A. Zeeb return;
20476d67aabdSBjoern A. Zeeb
20486d67aabdSBjoern A. Zeeb if (phy_ppdu->ldpc)
20496d67aabdSBjoern A. Zeeb rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
20506d67aabdSBjoern A. Zeeb if (phy_ppdu->stbc)
20516d67aabdSBjoern A. Zeeb rx_status->enc_flags |= u8_encode_bits(1, RX_ENC_FLAG_STBC_MASK);
20526d67aabdSBjoern A. Zeeb }
20536d67aabdSBjoern A. Zeeb
20546d67aabdSBjoern A. Zeeb static const u8 rx_status_bw_to_radiotap_eht_usig[] = {
20556d67aabdSBjoern A. Zeeb [RATE_INFO_BW_20] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_20MHZ,
20566d67aabdSBjoern A. Zeeb [RATE_INFO_BW_5] = U8_MAX,
20576d67aabdSBjoern A. Zeeb [RATE_INFO_BW_10] = U8_MAX,
20586d67aabdSBjoern A. Zeeb [RATE_INFO_BW_40] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_40MHZ,
20596d67aabdSBjoern A. Zeeb [RATE_INFO_BW_80] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_80MHZ,
20606d67aabdSBjoern A. Zeeb [RATE_INFO_BW_160] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_160MHZ,
20616d67aabdSBjoern A. Zeeb [RATE_INFO_BW_HE_RU] = U8_MAX,
20626d67aabdSBjoern A. Zeeb [RATE_INFO_BW_320] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_320MHZ_1,
20636d67aabdSBjoern A. Zeeb [RATE_INFO_BW_EHT_RU] = U8_MAX,
20646d67aabdSBjoern A. Zeeb };
20656d67aabdSBjoern A. Zeeb
rtw89_core_update_radiotap_eht(struct rtw89_dev * rtwdev,struct sk_buff * skb,struct ieee80211_rx_status * rx_status)20666d67aabdSBjoern A. Zeeb static void rtw89_core_update_radiotap_eht(struct rtw89_dev *rtwdev,
20676d67aabdSBjoern A. Zeeb struct sk_buff *skb,
20686d67aabdSBjoern A. Zeeb struct ieee80211_rx_status *rx_status)
20696d67aabdSBjoern A. Zeeb {
20706d67aabdSBjoern A. Zeeb struct ieee80211_radiotap_eht_usig *usig;
20716d67aabdSBjoern A. Zeeb struct ieee80211_radiotap_eht *eht;
20726d67aabdSBjoern A. Zeeb struct ieee80211_radiotap_tlv *tlv;
20736d67aabdSBjoern A. Zeeb int eht_len = struct_size(eht, user_info, 1);
20746d67aabdSBjoern A. Zeeb int usig_len = sizeof(*usig);
20756d67aabdSBjoern A. Zeeb int len;
20766d67aabdSBjoern A. Zeeb u8 bw;
20776d67aabdSBjoern A. Zeeb
20786d67aabdSBjoern A. Zeeb len = sizeof(*tlv) + ALIGN(eht_len, 4) +
20796d67aabdSBjoern A. Zeeb sizeof(*tlv) + ALIGN(usig_len, 4);
20806d67aabdSBjoern A. Zeeb
20816d67aabdSBjoern A. Zeeb rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END;
20826d67aabdSBjoern A. Zeeb skb_reset_mac_header(skb);
20836d67aabdSBjoern A. Zeeb
20846d67aabdSBjoern A. Zeeb /* EHT */
20856d67aabdSBjoern A. Zeeb tlv = skb_push(skb, len);
20866d67aabdSBjoern A. Zeeb memset(tlv, 0, len);
20876d67aabdSBjoern A. Zeeb tlv->type = cpu_to_le16(IEEE80211_RADIOTAP_EHT);
20886d67aabdSBjoern A. Zeeb tlv->len = cpu_to_le16(eht_len);
20896d67aabdSBjoern A. Zeeb
20906d67aabdSBjoern A. Zeeb eht = (struct ieee80211_radiotap_eht *)tlv->data;
20916d67aabdSBjoern A. Zeeb eht->known = cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI);
20926d67aabdSBjoern A. Zeeb eht->data[0] =
20936d67aabdSBjoern A. Zeeb le32_encode_bits(rx_status->eht.gi, IEEE80211_RADIOTAP_EHT_DATA0_GI);
20946d67aabdSBjoern A. Zeeb
20956d67aabdSBjoern A. Zeeb eht->user_info[0] =
20966d67aabdSBjoern A. Zeeb cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN |
20976d67aabdSBjoern A. Zeeb IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_KNOWN_O |
20986d67aabdSBjoern A. Zeeb IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN);
20996d67aabdSBjoern A. Zeeb eht->user_info[0] |=
21006d67aabdSBjoern A. Zeeb le32_encode_bits(rx_status->rate_idx, IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) |
21016d67aabdSBjoern A. Zeeb le32_encode_bits(rx_status->nss, IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O);
21026d67aabdSBjoern A. Zeeb if (rx_status->enc_flags & RX_ENC_FLAG_LDPC)
21036d67aabdSBjoern A. Zeeb eht->user_info[0] |=
21046d67aabdSBjoern A. Zeeb cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_CODING);
21056d67aabdSBjoern A. Zeeb
21066d67aabdSBjoern A. Zeeb /* U-SIG */
21076d67aabdSBjoern A. Zeeb #if defined(__linux__)
21086d67aabdSBjoern A. Zeeb tlv = (void *)tlv + sizeof(*tlv) + ALIGN(eht_len, 4);
21096d67aabdSBjoern A. Zeeb #elif defined(__FreeBSD__)
21106d67aabdSBjoern A. Zeeb tlv = (void *)((u8 *)tlv + sizeof(*tlv) + ALIGN(eht_len, 4));
21116d67aabdSBjoern A. Zeeb #endif
21126d67aabdSBjoern A. Zeeb tlv->type = cpu_to_le16(IEEE80211_RADIOTAP_EHT_USIG);
21136d67aabdSBjoern A. Zeeb tlv->len = cpu_to_le16(usig_len);
21146d67aabdSBjoern A. Zeeb
21156d67aabdSBjoern A. Zeeb if (rx_status->bw >= ARRAY_SIZE(rx_status_bw_to_radiotap_eht_usig))
21166d67aabdSBjoern A. Zeeb return;
21176d67aabdSBjoern A. Zeeb
21186d67aabdSBjoern A. Zeeb bw = rx_status_bw_to_radiotap_eht_usig[rx_status->bw];
21196d67aabdSBjoern A. Zeeb if (bw == U8_MAX)
21206d67aabdSBjoern A. Zeeb return;
21216d67aabdSBjoern A. Zeeb
21226d67aabdSBjoern A. Zeeb usig = (struct ieee80211_radiotap_eht_usig *)tlv->data;
21236d67aabdSBjoern A. Zeeb usig->common =
21246d67aabdSBjoern A. Zeeb le32_encode_bits(1, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN) |
21256d67aabdSBjoern A. Zeeb le32_encode_bits(bw, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW);
21266d67aabdSBjoern A. Zeeb }
21276d67aabdSBjoern A. Zeeb
rtw89_core_update_radiotap(struct rtw89_dev * rtwdev,struct sk_buff * skb,struct ieee80211_rx_status * rx_status)2128e2340276SBjoern A. Zeeb static void rtw89_core_update_radiotap(struct rtw89_dev *rtwdev,
2129e2340276SBjoern A. Zeeb struct sk_buff *skb,
2130e2340276SBjoern A. Zeeb struct ieee80211_rx_status *rx_status)
2131e2340276SBjoern A. Zeeb {
2132e2340276SBjoern A. Zeeb static const struct ieee80211_radiotap_he known_he = {
2133e2340276SBjoern A. Zeeb .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
21346d67aabdSBjoern A. Zeeb IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN |
21356d67aabdSBjoern A. Zeeb IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN |
2136e2340276SBjoern A. Zeeb IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN),
2137e2340276SBjoern A. Zeeb .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN),
2138e2340276SBjoern A. Zeeb };
2139e2340276SBjoern A. Zeeb struct ieee80211_radiotap_he *he;
2140e2340276SBjoern A. Zeeb
2141e2340276SBjoern A. Zeeb if (!(rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR))
2142e2340276SBjoern A. Zeeb return;
2143e2340276SBjoern A. Zeeb
2144e2340276SBjoern A. Zeeb if (rx_status->encoding == RX_ENC_HE) {
2145e2340276SBjoern A. Zeeb rx_status->flag |= RX_FLAG_RADIOTAP_HE;
2146e2340276SBjoern A. Zeeb he = skb_push(skb, sizeof(*he));
2147e2340276SBjoern A. Zeeb *he = known_he;
21486d67aabdSBjoern A. Zeeb } else if (rx_status->encoding == RX_ENC_EHT) {
21496d67aabdSBjoern A. Zeeb rtw89_core_update_radiotap_eht(rtwdev, skb, rx_status);
2150e2340276SBjoern A. Zeeb }
2151e2340276SBjoern A. Zeeb }
2152e2340276SBjoern A. Zeeb
rtw89_core_rx_to_mac80211(struct rtw89_dev * rtwdev,struct rtw89_rx_phy_ppdu * phy_ppdu,struct rtw89_rx_desc_info * desc_info,struct sk_buff * skb_ppdu,struct ieee80211_rx_status * rx_status)21538e93258fSBjoern A. Zeeb static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
21548e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu,
21558e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
21568e93258fSBjoern A. Zeeb struct sk_buff *skb_ppdu,
21578e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status)
21588e93258fSBjoern A. Zeeb {
21598e93258fSBjoern A. Zeeb struct napi_struct *napi = &rtwdev->napi;
21608e93258fSBjoern A. Zeeb
21618e93258fSBjoern A. Zeeb /* In low power mode, napi isn't scheduled. Receive it to netif. */
21626d67aabdSBjoern A. Zeeb if (unlikely(!napi_is_scheduled(napi)))
21638e93258fSBjoern A. Zeeb napi = NULL;
21648e93258fSBjoern A. Zeeb
21658e93258fSBjoern A. Zeeb rtw89_core_hw_to_sband_rate(rx_status);
21668e93258fSBjoern A. Zeeb rtw89_core_rx_stats(rtwdev, phy_ppdu, desc_info, skb_ppdu);
21676d67aabdSBjoern A. Zeeb rtw89_core_update_rx_status_by_ppdu(rtwdev, rx_status, phy_ppdu);
2168e2340276SBjoern A. Zeeb rtw89_core_update_radiotap(rtwdev, skb_ppdu, rx_status);
21698e93258fSBjoern A. Zeeb /* In low power mode, it does RX in thread context. */
21708e93258fSBjoern A. Zeeb local_bh_disable();
21718e93258fSBjoern A. Zeeb ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, napi);
21728e93258fSBjoern A. Zeeb local_bh_enable();
21738e93258fSBjoern A. Zeeb rtwdev->napi_budget_countdown--;
21748e93258fSBjoern A. Zeeb }
21758e93258fSBjoern A. Zeeb
rtw89_core_rx_pending_skb(struct rtw89_dev * rtwdev,struct rtw89_rx_phy_ppdu * phy_ppdu,struct rtw89_rx_desc_info * desc_info,struct sk_buff * skb)21768e93258fSBjoern A. Zeeb static void rtw89_core_rx_pending_skb(struct rtw89_dev *rtwdev,
21778e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu *phy_ppdu,
21788e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
21798e93258fSBjoern A. Zeeb struct sk_buff *skb)
21808e93258fSBjoern A. Zeeb {
21818e93258fSBjoern A. Zeeb u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
21828e93258fSBjoern A. Zeeb int curr = rtwdev->ppdu_sts.curr_rx_ppdu_cnt[band];
21838e93258fSBjoern A. Zeeb struct sk_buff *skb_ppdu = NULL, *tmp;
21848e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status;
21858e93258fSBjoern A. Zeeb
21868e93258fSBjoern A. Zeeb if (curr > RTW89_MAX_PPDU_CNT)
21878e93258fSBjoern A. Zeeb return;
21888e93258fSBjoern A. Zeeb
21898e93258fSBjoern A. Zeeb skb_queue_walk_safe(&rtwdev->ppdu_sts.rx_queue[band], skb_ppdu, tmp) {
21908e93258fSBjoern A. Zeeb skb_unlink(skb_ppdu, &rtwdev->ppdu_sts.rx_queue[band]);
21918e93258fSBjoern A. Zeeb rx_status = IEEE80211_SKB_RXCB(skb_ppdu);
21928e93258fSBjoern A. Zeeb if (rtw89_core_rx_ppdu_match(rtwdev, desc_info, rx_status))
21938e93258fSBjoern A. Zeeb rtw89_chip_query_ppdu(rtwdev, phy_ppdu, rx_status);
21948e93258fSBjoern A. Zeeb rtw89_correct_cck_chan(rtwdev, rx_status);
21958e93258fSBjoern A. Zeeb rtw89_core_rx_to_mac80211(rtwdev, phy_ppdu, desc_info, skb_ppdu, rx_status);
21968e93258fSBjoern A. Zeeb }
21978e93258fSBjoern A. Zeeb }
21988e93258fSBjoern A. Zeeb
rtw89_core_rx_process_ppdu_sts(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,struct sk_buff * skb)21998e93258fSBjoern A. Zeeb static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev,
22008e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
22018e93258fSBjoern A. Zeeb struct sk_buff *skb)
22028e93258fSBjoern A. Zeeb {
22038e93258fSBjoern A. Zeeb struct rtw89_rx_phy_ppdu phy_ppdu = {.buf = skb->data, .valid = false,
22048e93258fSBjoern A. Zeeb .len = skb->len,
22058e93258fSBjoern A. Zeeb .to_self = desc_info->addr1_match,
22068e93258fSBjoern A. Zeeb .rate = desc_info->data_rate,
22078e93258fSBjoern A. Zeeb .mac_id = desc_info->mac_id};
22088e93258fSBjoern A. Zeeb int ret;
22098e93258fSBjoern A. Zeeb
22106d67aabdSBjoern A. Zeeb if (desc_info->mac_info_valid) {
22116d67aabdSBjoern A. Zeeb ret = rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu);
22126d67aabdSBjoern A. Zeeb if (ret)
22136d67aabdSBjoern A. Zeeb goto out;
22146d67aabdSBjoern A. Zeeb }
22156d67aabdSBjoern A. Zeeb
22168e93258fSBjoern A. Zeeb ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu);
22178e93258fSBjoern A. Zeeb if (ret)
22186d67aabdSBjoern A. Zeeb goto out;
22198e93258fSBjoern A. Zeeb
22208e93258fSBjoern A. Zeeb rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu);
22216d67aabdSBjoern A. Zeeb
22226d67aabdSBjoern A. Zeeb out:
22238e93258fSBjoern A. Zeeb rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb);
22248e93258fSBjoern A. Zeeb dev_kfree_skb_any(skb);
22258e93258fSBjoern A. Zeeb }
22268e93258fSBjoern A. Zeeb
rtw89_core_rx_process_report(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,struct sk_buff * skb)22278e93258fSBjoern A. Zeeb static void rtw89_core_rx_process_report(struct rtw89_dev *rtwdev,
22288e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
22298e93258fSBjoern A. Zeeb struct sk_buff *skb)
22308e93258fSBjoern A. Zeeb {
22318e93258fSBjoern A. Zeeb switch (desc_info->pkt_type) {
22328e93258fSBjoern A. Zeeb case RTW89_CORE_RX_TYPE_C2H:
22338e93258fSBjoern A. Zeeb rtw89_fw_c2h_irqsafe(rtwdev, skb);
22348e93258fSBjoern A. Zeeb break;
22358e93258fSBjoern A. Zeeb case RTW89_CORE_RX_TYPE_PPDU_STAT:
22368e93258fSBjoern A. Zeeb rtw89_core_rx_process_ppdu_sts(rtwdev, desc_info, skb);
22378e93258fSBjoern A. Zeeb break;
22388e93258fSBjoern A. Zeeb default:
22398e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX, "unhandled pkt_type=%d\n",
22408e93258fSBjoern A. Zeeb desc_info->pkt_type);
22418e93258fSBjoern A. Zeeb dev_kfree_skb_any(skb);
22428e93258fSBjoern A. Zeeb break;
22438e93258fSBjoern A. Zeeb }
22448e93258fSBjoern A. Zeeb }
22458e93258fSBjoern A. Zeeb
rtw89_core_query_rxdesc(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,u8 * data,u32 data_offset)22468e93258fSBjoern A. Zeeb void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev,
22478e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
22488e93258fSBjoern A. Zeeb u8 *data, u32 data_offset)
22498e93258fSBjoern A. Zeeb {
22508e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
22518e93258fSBjoern A. Zeeb struct rtw89_rxdesc_short *rxd_s;
22528e93258fSBjoern A. Zeeb struct rtw89_rxdesc_long *rxd_l;
22538e93258fSBjoern A. Zeeb u8 shift_len, drv_info_len;
22548e93258fSBjoern A. Zeeb
22558e93258fSBjoern A. Zeeb rxd_s = (struct rtw89_rxdesc_short *)(data + data_offset);
2256e2340276SBjoern A. Zeeb desc_info->pkt_size = le32_get_bits(rxd_s->dword0, AX_RXD_RPKT_LEN_MASK);
2257e2340276SBjoern A. Zeeb desc_info->drv_info_size = le32_get_bits(rxd_s->dword0, AX_RXD_DRV_INFO_SIZE_MASK);
2258e2340276SBjoern A. Zeeb desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, AX_RXD_LONG_RXD);
2259e2340276SBjoern A. Zeeb desc_info->pkt_type = le32_get_bits(rxd_s->dword0, AX_RXD_RPKT_TYPE_MASK);
2260e2340276SBjoern A. Zeeb desc_info->mac_info_valid = le32_get_bits(rxd_s->dword0, AX_RXD_MAC_INFO_VLD);
22618e93258fSBjoern A. Zeeb if (chip->chip_id == RTL8852C)
2262e2340276SBjoern A. Zeeb desc_info->bw = le32_get_bits(rxd_s->dword1, AX_RXD_BW_v1_MASK);
22638e93258fSBjoern A. Zeeb else
2264e2340276SBjoern A. Zeeb desc_info->bw = le32_get_bits(rxd_s->dword1, AX_RXD_BW_MASK);
2265e2340276SBjoern A. Zeeb desc_info->data_rate = le32_get_bits(rxd_s->dword1, AX_RXD_RX_DATARATE_MASK);
2266e2340276SBjoern A. Zeeb desc_info->gi_ltf = le32_get_bits(rxd_s->dword1, AX_RXD_RX_GI_LTF_MASK);
2267e2340276SBjoern A. Zeeb desc_info->user_id = le32_get_bits(rxd_s->dword1, AX_RXD_USER_ID_MASK);
2268e2340276SBjoern A. Zeeb desc_info->sr_en = le32_get_bits(rxd_s->dword1, AX_RXD_SR_EN);
2269e2340276SBjoern A. Zeeb desc_info->ppdu_cnt = le32_get_bits(rxd_s->dword1, AX_RXD_PPDU_CNT_MASK);
2270e2340276SBjoern A. Zeeb desc_info->ppdu_type = le32_get_bits(rxd_s->dword1, AX_RXD_PPDU_TYPE_MASK);
2271e2340276SBjoern A. Zeeb desc_info->free_run_cnt = le32_get_bits(rxd_s->dword2, AX_RXD_FREERUN_CNT_MASK);
2272e2340276SBjoern A. Zeeb desc_info->icv_err = le32_get_bits(rxd_s->dword3, AX_RXD_ICV_ERR);
2273e2340276SBjoern A. Zeeb desc_info->crc32_err = le32_get_bits(rxd_s->dword3, AX_RXD_CRC32_ERR);
2274e2340276SBjoern A. Zeeb desc_info->hw_dec = le32_get_bits(rxd_s->dword3, AX_RXD_HW_DEC);
2275e2340276SBjoern A. Zeeb desc_info->sw_dec = le32_get_bits(rxd_s->dword3, AX_RXD_SW_DEC);
2276e2340276SBjoern A. Zeeb desc_info->addr1_match = le32_get_bits(rxd_s->dword3, AX_RXD_A1_MATCH);
22778e93258fSBjoern A. Zeeb
22788e93258fSBjoern A. Zeeb shift_len = desc_info->shift << 1; /* 2-byte unit */
22798e93258fSBjoern A. Zeeb drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */
22808e93258fSBjoern A. Zeeb desc_info->offset = data_offset + shift_len + drv_info_len;
2281e2340276SBjoern A. Zeeb if (desc_info->long_rxdesc)
2282e2340276SBjoern A. Zeeb desc_info->rxd_len = sizeof(struct rtw89_rxdesc_long);
2283e2340276SBjoern A. Zeeb else
2284e2340276SBjoern A. Zeeb desc_info->rxd_len = sizeof(struct rtw89_rxdesc_short);
22858e93258fSBjoern A. Zeeb desc_info->ready = true;
22868e93258fSBjoern A. Zeeb
22878e93258fSBjoern A. Zeeb if (!desc_info->long_rxdesc)
22888e93258fSBjoern A. Zeeb return;
22898e93258fSBjoern A. Zeeb
22908e93258fSBjoern A. Zeeb rxd_l = (struct rtw89_rxdesc_long *)(data + data_offset);
2291e2340276SBjoern A. Zeeb desc_info->frame_type = le32_get_bits(rxd_l->dword4, AX_RXD_TYPE_MASK);
2292e2340276SBjoern A. Zeeb desc_info->addr_cam_valid = le32_get_bits(rxd_l->dword5, AX_RXD_ADDR_CAM_VLD);
2293e2340276SBjoern A. Zeeb desc_info->addr_cam_id = le32_get_bits(rxd_l->dword5, AX_RXD_ADDR_CAM_MASK);
2294e2340276SBjoern A. Zeeb desc_info->sec_cam_id = le32_get_bits(rxd_l->dword5, AX_RXD_SEC_CAM_IDX_MASK);
2295e2340276SBjoern A. Zeeb desc_info->mac_id = le32_get_bits(rxd_l->dword5, AX_RXD_MAC_ID_MASK);
2296e2340276SBjoern A. Zeeb desc_info->rx_pl_id = le32_get_bits(rxd_l->dword5, AX_RXD_RX_PL_ID_MASK);
22978e93258fSBjoern A. Zeeb }
22988e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_query_rxdesc);
22998e93258fSBjoern A. Zeeb
rtw89_core_query_rxdesc_v2(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,u8 * data,u32 data_offset)23006d67aabdSBjoern A. Zeeb void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev,
23016d67aabdSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
23026d67aabdSBjoern A. Zeeb u8 *data, u32 data_offset)
23036d67aabdSBjoern A. Zeeb {
23046d67aabdSBjoern A. Zeeb struct rtw89_rxdesc_short_v2 *rxd_s;
23056d67aabdSBjoern A. Zeeb struct rtw89_rxdesc_long_v2 *rxd_l;
23066d67aabdSBjoern A. Zeeb u16 shift_len, drv_info_len, phy_rtp_len, hdr_cnv_len;
23076d67aabdSBjoern A. Zeeb
23086d67aabdSBjoern A. Zeeb rxd_s = (struct rtw89_rxdesc_short_v2 *)(data + data_offset);
23096d67aabdSBjoern A. Zeeb
23106d67aabdSBjoern A. Zeeb desc_info->pkt_size = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_LEN_MASK);
23116d67aabdSBjoern A. Zeeb desc_info->drv_info_size = le32_get_bits(rxd_s->dword0, BE_RXD_DRV_INFO_SZ_MASK);
23126d67aabdSBjoern A. Zeeb desc_info->phy_rpt_size = le32_get_bits(rxd_s->dword0, BE_RXD_PHY_RPT_SZ_MASK);
23136d67aabdSBjoern A. Zeeb desc_info->hdr_cnv_size = le32_get_bits(rxd_s->dword0, BE_RXD_HDR_CNV_SZ_MASK);
23146d67aabdSBjoern A. Zeeb desc_info->shift = le32_get_bits(rxd_s->dword0, BE_RXD_SHIFT_MASK);
23156d67aabdSBjoern A. Zeeb desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, BE_RXD_LONG_RXD);
23166d67aabdSBjoern A. Zeeb desc_info->pkt_type = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_TYPE_MASK);
23176d67aabdSBjoern A. Zeeb if (desc_info->pkt_type == RTW89_CORE_RX_TYPE_PPDU_STAT)
23186d67aabdSBjoern A. Zeeb desc_info->mac_info_valid = true;
23196d67aabdSBjoern A. Zeeb
23206d67aabdSBjoern A. Zeeb desc_info->frame_type = le32_get_bits(rxd_s->dword2, BE_RXD_TYPE_MASK);
23216d67aabdSBjoern A. Zeeb desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_MASK);
23226d67aabdSBjoern A. Zeeb desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD);
23236d67aabdSBjoern A. Zeeb
23246d67aabdSBjoern A. Zeeb desc_info->icv_err = le32_get_bits(rxd_s->dword3, BE_RXD_ICV_ERR);
23256d67aabdSBjoern A. Zeeb desc_info->crc32_err = le32_get_bits(rxd_s->dword3, BE_RXD_CRC32_ERR);
23266d67aabdSBjoern A. Zeeb desc_info->hw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_HW_DEC);
23276d67aabdSBjoern A. Zeeb desc_info->sw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_SW_DEC);
23286d67aabdSBjoern A. Zeeb desc_info->addr1_match = le32_get_bits(rxd_s->dword3, BE_RXD_A1_MATCH);
23296d67aabdSBjoern A. Zeeb
23306d67aabdSBjoern A. Zeeb desc_info->bw = le32_get_bits(rxd_s->dword4, BE_RXD_BW_MASK);
23316d67aabdSBjoern A. Zeeb desc_info->data_rate = le32_get_bits(rxd_s->dword4, BE_RXD_RX_DATARATE_MASK);
23326d67aabdSBjoern A. Zeeb desc_info->gi_ltf = le32_get_bits(rxd_s->dword4, BE_RXD_RX_GI_LTF_MASK);
23336d67aabdSBjoern A. Zeeb desc_info->ppdu_cnt = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_CNT_MASK);
23346d67aabdSBjoern A. Zeeb desc_info->ppdu_type = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_TYPE_MASK);
23356d67aabdSBjoern A. Zeeb
23366d67aabdSBjoern A. Zeeb desc_info->free_run_cnt = le32_to_cpu(rxd_s->dword5);
23376d67aabdSBjoern A. Zeeb
23386d67aabdSBjoern A. Zeeb shift_len = desc_info->shift << 1; /* 2-byte unit */
23396d67aabdSBjoern A. Zeeb drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */
23406d67aabdSBjoern A. Zeeb phy_rtp_len = desc_info->phy_rpt_size << 3; /* 8-byte unit */
23416d67aabdSBjoern A. Zeeb hdr_cnv_len = desc_info->hdr_cnv_size << 4; /* 16-byte unit */
23426d67aabdSBjoern A. Zeeb desc_info->offset = data_offset + shift_len + drv_info_len +
23436d67aabdSBjoern A. Zeeb phy_rtp_len + hdr_cnv_len;
23446d67aabdSBjoern A. Zeeb
23456d67aabdSBjoern A. Zeeb if (desc_info->long_rxdesc)
23466d67aabdSBjoern A. Zeeb desc_info->rxd_len = sizeof(struct rtw89_rxdesc_long_v2);
23476d67aabdSBjoern A. Zeeb else
23486d67aabdSBjoern A. Zeeb desc_info->rxd_len = sizeof(struct rtw89_rxdesc_short_v2);
23496d67aabdSBjoern A. Zeeb desc_info->ready = true;
23506d67aabdSBjoern A. Zeeb
23516d67aabdSBjoern A. Zeeb if (!desc_info->long_rxdesc)
23526d67aabdSBjoern A. Zeeb return;
23536d67aabdSBjoern A. Zeeb
23546d67aabdSBjoern A. Zeeb rxd_l = (struct rtw89_rxdesc_long_v2 *)(data + data_offset);
23556d67aabdSBjoern A. Zeeb
23566d67aabdSBjoern A. Zeeb desc_info->sr_en = le32_get_bits(rxd_l->dword6, BE_RXD_SR_EN);
23576d67aabdSBjoern A. Zeeb desc_info->user_id = le32_get_bits(rxd_l->dword6, BE_RXD_USER_ID_MASK);
23586d67aabdSBjoern A. Zeeb desc_info->addr_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_ADDR_CAM_MASK);
23596d67aabdSBjoern A. Zeeb desc_info->sec_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_SEC_CAM_IDX_MASK);
23606d67aabdSBjoern A. Zeeb
23616d67aabdSBjoern A. Zeeb desc_info->rx_pl_id = le32_get_bits(rxd_l->dword7, BE_RXD_RX_PL_ID_MASK);
23626d67aabdSBjoern A. Zeeb }
23636d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_query_rxdesc_v2);
23646d67aabdSBjoern A. Zeeb
23658e93258fSBjoern A. Zeeb struct rtw89_core_iter_rx_status {
23668e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev;
23678e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status;
23688e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info;
23698e93258fSBjoern A. Zeeb u8 mac_id;
23708e93258fSBjoern A. Zeeb };
23718e93258fSBjoern A. Zeeb
23728e93258fSBjoern A. Zeeb static
rtw89_core_stats_sta_rx_status_iter(void * data,struct ieee80211_sta * sta)23738e93258fSBjoern A. Zeeb void rtw89_core_stats_sta_rx_status_iter(void *data, struct ieee80211_sta *sta)
23748e93258fSBjoern A. Zeeb {
23758e93258fSBjoern A. Zeeb struct rtw89_core_iter_rx_status *iter_data =
23768e93258fSBjoern A. Zeeb (struct rtw89_core_iter_rx_status *)data;
23778e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status = iter_data->rx_status;
23788e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
23798e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
23808e93258fSBjoern A. Zeeb u8 mac_id = iter_data->mac_id;
23818e93258fSBjoern A. Zeeb
23828e93258fSBjoern A. Zeeb if (mac_id != rtwsta->mac_id)
23838e93258fSBjoern A. Zeeb return;
23848e93258fSBjoern A. Zeeb
23858e93258fSBjoern A. Zeeb rtwsta->rx_status = *rx_status;
23868e93258fSBjoern A. Zeeb rtwsta->rx_hw_rate = desc_info->data_rate;
23878e93258fSBjoern A. Zeeb }
23888e93258fSBjoern A. Zeeb
rtw89_core_stats_sta_rx_status(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,struct ieee80211_rx_status * rx_status)23898e93258fSBjoern A. Zeeb static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev,
23908e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
23918e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status)
23928e93258fSBjoern A. Zeeb {
23938e93258fSBjoern A. Zeeb struct rtw89_core_iter_rx_status iter_data;
23948e93258fSBjoern A. Zeeb
23958e93258fSBjoern A. Zeeb if (!desc_info->addr1_match || !desc_info->long_rxdesc)
23968e93258fSBjoern A. Zeeb return;
23978e93258fSBjoern A. Zeeb
23988e93258fSBjoern A. Zeeb if (desc_info->frame_type != RTW89_RX_TYPE_DATA)
23998e93258fSBjoern A. Zeeb return;
24008e93258fSBjoern A. Zeeb
24018e93258fSBjoern A. Zeeb iter_data.rtwdev = rtwdev;
24028e93258fSBjoern A. Zeeb iter_data.rx_status = rx_status;
24038e93258fSBjoern A. Zeeb iter_data.desc_info = desc_info;
24048e93258fSBjoern A. Zeeb iter_data.mac_id = desc_info->mac_id;
24058e93258fSBjoern A. Zeeb ieee80211_iterate_stations_atomic(rtwdev->hw,
24068e93258fSBjoern A. Zeeb rtw89_core_stats_sta_rx_status_iter,
24078e93258fSBjoern A. Zeeb &iter_data);
24088e93258fSBjoern A. Zeeb }
24098e93258fSBjoern A. Zeeb
rtw89_core_update_rx_status(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,struct ieee80211_rx_status * rx_status)24108e93258fSBjoern A. Zeeb static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
24118e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
24128e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status)
24138e93258fSBjoern A. Zeeb {
24148e93258fSBjoern A. Zeeb const struct cfg80211_chan_def *chandef =
24158e93258fSBjoern A. Zeeb rtw89_chandef_get(rtwdev, RTW89_SUB_ENTITY_0);
24168e93258fSBjoern A. Zeeb u16 data_rate;
24178e93258fSBjoern A. Zeeb u8 data_rate_mode;
24186d67aabdSBjoern A. Zeeb bool eht = false;
24196d67aabdSBjoern A. Zeeb u8 gi;
24208e93258fSBjoern A. Zeeb
24218e93258fSBjoern A. Zeeb /* currently using single PHY */
24228e93258fSBjoern A. Zeeb rx_status->freq = chandef->chan->center_freq;
24238e93258fSBjoern A. Zeeb rx_status->band = chandef->chan->band;
24248e93258fSBjoern A. Zeeb
24258e93258fSBjoern A. Zeeb if (rtwdev->scanning &&
24268e93258fSBjoern A. Zeeb RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
24276d67aabdSBjoern A. Zeeb const struct rtw89_chan *cur = rtw89_scan_chan_get(rtwdev);
24288e93258fSBjoern A. Zeeb u8 chan = cur->primary_channel;
24298e93258fSBjoern A. Zeeb u8 band = cur->band_type;
24308e93258fSBjoern A. Zeeb enum nl80211_band nl_band;
24318e93258fSBjoern A. Zeeb
24328e93258fSBjoern A. Zeeb nl_band = rtw89_hw_to_nl80211_band(band);
24338e93258fSBjoern A. Zeeb rx_status->freq = ieee80211_channel_to_frequency(chan, nl_band);
24348e93258fSBjoern A. Zeeb rx_status->band = nl_band;
24358e93258fSBjoern A. Zeeb }
24368e93258fSBjoern A. Zeeb
24378e93258fSBjoern A. Zeeb if (desc_info->icv_err || desc_info->crc32_err)
24388e93258fSBjoern A. Zeeb rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
24398e93258fSBjoern A. Zeeb
24408e93258fSBjoern A. Zeeb if (desc_info->hw_dec &&
24418e93258fSBjoern A. Zeeb !(desc_info->sw_dec || desc_info->icv_err))
24428e93258fSBjoern A. Zeeb rx_status->flag |= RX_FLAG_DECRYPTED;
24438e93258fSBjoern A. Zeeb
24448e93258fSBjoern A. Zeeb rx_status->bw = rtw89_hw_to_rate_info_bw(desc_info->bw);
24458e93258fSBjoern A. Zeeb
24468e93258fSBjoern A. Zeeb data_rate = desc_info->data_rate;
2447e2340276SBjoern A. Zeeb data_rate_mode = rtw89_get_data_rate_mode(rtwdev, data_rate);
24488e93258fSBjoern A. Zeeb if (data_rate_mode == DATA_RATE_MODE_NON_HT) {
24498e93258fSBjoern A. Zeeb rx_status->encoding = RX_ENC_LEGACY;
2450e2340276SBjoern A. Zeeb rx_status->rate_idx = rtw89_get_data_not_ht_idx(rtwdev, data_rate);
24518e93258fSBjoern A. Zeeb /* convert rate_idx after we get the correct band */
24528e93258fSBjoern A. Zeeb } else if (data_rate_mode == DATA_RATE_MODE_HT) {
24538e93258fSBjoern A. Zeeb rx_status->encoding = RX_ENC_HT;
2454e2340276SBjoern A. Zeeb rx_status->rate_idx = rtw89_get_data_ht_mcs(rtwdev, data_rate);
24558e93258fSBjoern A. Zeeb if (desc_info->gi_ltf)
24568e93258fSBjoern A. Zeeb rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
24578e93258fSBjoern A. Zeeb } else if (data_rate_mode == DATA_RATE_MODE_VHT) {
24588e93258fSBjoern A. Zeeb rx_status->encoding = RX_ENC_VHT;
2459e2340276SBjoern A. Zeeb rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
2460e2340276SBjoern A. Zeeb rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
24618e93258fSBjoern A. Zeeb if (desc_info->gi_ltf)
24628e93258fSBjoern A. Zeeb rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
24638e93258fSBjoern A. Zeeb } else if (data_rate_mode == DATA_RATE_MODE_HE) {
24648e93258fSBjoern A. Zeeb rx_status->encoding = RX_ENC_HE;
2465e2340276SBjoern A. Zeeb rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
2466e2340276SBjoern A. Zeeb rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
24676d67aabdSBjoern A. Zeeb } else if (data_rate_mode == DATA_RATE_MODE_EHT) {
24686d67aabdSBjoern A. Zeeb rx_status->encoding = RX_ENC_EHT;
24696d67aabdSBjoern A. Zeeb rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
24706d67aabdSBjoern A. Zeeb rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
24716d67aabdSBjoern A. Zeeb eht = true;
24728e93258fSBjoern A. Zeeb } else {
24738e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
24748e93258fSBjoern A. Zeeb }
24758e93258fSBjoern A. Zeeb
24768e93258fSBjoern A. Zeeb /* he_gi is used to match ppdu, so we always fill it. */
24776d67aabdSBjoern A. Zeeb gi = rtw89_rxdesc_to_nl_he_eht_gi(rtwdev, desc_info->gi_ltf, true, eht);
24786d67aabdSBjoern A. Zeeb if (eht)
24796d67aabdSBjoern A. Zeeb rx_status->eht.gi = gi;
24806d67aabdSBjoern A. Zeeb else
24816d67aabdSBjoern A. Zeeb rx_status->he_gi = gi;
24828e93258fSBjoern A. Zeeb rx_status->flag |= RX_FLAG_MACTIME_START;
24838e93258fSBjoern A. Zeeb rx_status->mactime = desc_info->free_run_cnt;
24848e93258fSBjoern A. Zeeb
24858e93258fSBjoern A. Zeeb rtw89_core_stats_sta_rx_status(rtwdev, desc_info, rx_status);
24868e93258fSBjoern A. Zeeb }
24878e93258fSBjoern A. Zeeb
rtw89_update_ps_mode(struct rtw89_dev * rtwdev)24888e93258fSBjoern A. Zeeb static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev)
24898e93258fSBjoern A. Zeeb {
24908e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
24918e93258fSBjoern A. Zeeb
2492e2340276SBjoern A. Zeeb if (rtw89_disable_ps_mode || !chip->ps_mode_supported ||
2493e2340276SBjoern A. Zeeb RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw))
24948e93258fSBjoern A. Zeeb return RTW89_PS_MODE_NONE;
24958e93258fSBjoern A. Zeeb
2496e2340276SBjoern A. Zeeb if ((chip->ps_mode_supported & BIT(RTW89_PS_MODE_PWR_GATED)) &&
2497e2340276SBjoern A. Zeeb !RTW89_CHK_FW_FEATURE(NO_LPS_PG, &rtwdev->fw))
24988e93258fSBjoern A. Zeeb return RTW89_PS_MODE_PWR_GATED;
24998e93258fSBjoern A. Zeeb
25008e93258fSBjoern A. Zeeb if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_CLK_GATED))
25018e93258fSBjoern A. Zeeb return RTW89_PS_MODE_CLK_GATED;
25028e93258fSBjoern A. Zeeb
25038e93258fSBjoern A. Zeeb if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_RFOFF))
25048e93258fSBjoern A. Zeeb return RTW89_PS_MODE_RFOFF;
25058e93258fSBjoern A. Zeeb
25068e93258fSBjoern A. Zeeb return RTW89_PS_MODE_NONE;
25078e93258fSBjoern A. Zeeb }
25088e93258fSBjoern A. Zeeb
rtw89_core_flush_ppdu_rx_queue(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info)25098e93258fSBjoern A. Zeeb static void rtw89_core_flush_ppdu_rx_queue(struct rtw89_dev *rtwdev,
25108e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info)
25118e93258fSBjoern A. Zeeb {
25128e93258fSBjoern A. Zeeb struct rtw89_ppdu_sts_info *ppdu_sts = &rtwdev->ppdu_sts;
25138e93258fSBjoern A. Zeeb u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
25148e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status;
25158e93258fSBjoern A. Zeeb struct sk_buff *skb_ppdu, *tmp;
25168e93258fSBjoern A. Zeeb
25178e93258fSBjoern A. Zeeb skb_queue_walk_safe(&ppdu_sts->rx_queue[band], skb_ppdu, tmp) {
25188e93258fSBjoern A. Zeeb skb_unlink(skb_ppdu, &ppdu_sts->rx_queue[band]);
25198e93258fSBjoern A. Zeeb rx_status = IEEE80211_SKB_RXCB(skb_ppdu);
25208e93258fSBjoern A. Zeeb rtw89_core_rx_to_mac80211(rtwdev, NULL, desc_info, skb_ppdu, rx_status);
25218e93258fSBjoern A. Zeeb }
25228e93258fSBjoern A. Zeeb }
25238e93258fSBjoern A. Zeeb
rtw89_core_rx(struct rtw89_dev * rtwdev,struct rtw89_rx_desc_info * desc_info,struct sk_buff * skb)25248e93258fSBjoern A. Zeeb void rtw89_core_rx(struct rtw89_dev *rtwdev,
25258e93258fSBjoern A. Zeeb struct rtw89_rx_desc_info *desc_info,
25268e93258fSBjoern A. Zeeb struct sk_buff *skb)
25278e93258fSBjoern A. Zeeb {
25288e93258fSBjoern A. Zeeb struct ieee80211_rx_status *rx_status;
25298e93258fSBjoern A. Zeeb struct rtw89_ppdu_sts_info *ppdu_sts = &rtwdev->ppdu_sts;
25308e93258fSBjoern A. Zeeb u8 ppdu_cnt = desc_info->ppdu_cnt;
25318e93258fSBjoern A. Zeeb u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
25328e93258fSBjoern A. Zeeb
25338e93258fSBjoern A. Zeeb if (desc_info->pkt_type != RTW89_CORE_RX_TYPE_WIFI) {
25348e93258fSBjoern A. Zeeb rtw89_core_rx_process_report(rtwdev, desc_info, skb);
25358e93258fSBjoern A. Zeeb return;
25368e93258fSBjoern A. Zeeb }
25378e93258fSBjoern A. Zeeb
25388e93258fSBjoern A. Zeeb if (ppdu_sts->curr_rx_ppdu_cnt[band] != ppdu_cnt) {
25398e93258fSBjoern A. Zeeb rtw89_core_flush_ppdu_rx_queue(rtwdev, desc_info);
25408e93258fSBjoern A. Zeeb ppdu_sts->curr_rx_ppdu_cnt[band] = ppdu_cnt;
25418e93258fSBjoern A. Zeeb }
25428e93258fSBjoern A. Zeeb
25438e93258fSBjoern A. Zeeb rx_status = IEEE80211_SKB_RXCB(skb);
25448e93258fSBjoern A. Zeeb memset(rx_status, 0, sizeof(*rx_status));
25458e93258fSBjoern A. Zeeb rtw89_core_update_rx_status(rtwdev, desc_info, rx_status);
25468e93258fSBjoern A. Zeeb if (desc_info->long_rxdesc &&
25478e93258fSBjoern A. Zeeb BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP)
25488e93258fSBjoern A. Zeeb skb_queue_tail(&ppdu_sts->rx_queue[band], skb);
25498e93258fSBjoern A. Zeeb else
25508e93258fSBjoern A. Zeeb rtw89_core_rx_to_mac80211(rtwdev, NULL, desc_info, skb, rx_status);
25518e93258fSBjoern A. Zeeb }
25528e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_rx);
25538e93258fSBjoern A. Zeeb
rtw89_core_napi_start(struct rtw89_dev * rtwdev)25548e93258fSBjoern A. Zeeb void rtw89_core_napi_start(struct rtw89_dev *rtwdev)
25558e93258fSBjoern A. Zeeb {
25568e93258fSBjoern A. Zeeb if (test_and_set_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
25578e93258fSBjoern A. Zeeb return;
25588e93258fSBjoern A. Zeeb
25598e93258fSBjoern A. Zeeb napi_enable(&rtwdev->napi);
25608e93258fSBjoern A. Zeeb }
25618e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_napi_start);
25628e93258fSBjoern A. Zeeb
rtw89_core_napi_stop(struct rtw89_dev * rtwdev)25638e93258fSBjoern A. Zeeb void rtw89_core_napi_stop(struct rtw89_dev *rtwdev)
25648e93258fSBjoern A. Zeeb {
25658e93258fSBjoern A. Zeeb if (!test_and_clear_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
25668e93258fSBjoern A. Zeeb return;
25678e93258fSBjoern A. Zeeb
25688e93258fSBjoern A. Zeeb napi_synchronize(&rtwdev->napi);
25698e93258fSBjoern A. Zeeb napi_disable(&rtwdev->napi);
25708e93258fSBjoern A. Zeeb }
25718e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_napi_stop);
25728e93258fSBjoern A. Zeeb
rtw89_core_napi_init(struct rtw89_dev * rtwdev)25736d67aabdSBjoern A. Zeeb int rtw89_core_napi_init(struct rtw89_dev *rtwdev)
25748e93258fSBjoern A. Zeeb {
25756d67aabdSBjoern A. Zeeb rtwdev->netdev = alloc_netdev_dummy(0);
25766d67aabdSBjoern A. Zeeb if (!rtwdev->netdev)
25776d67aabdSBjoern A. Zeeb return -ENOMEM;
25786d67aabdSBjoern A. Zeeb
25796d67aabdSBjoern A. Zeeb netif_napi_add(rtwdev->netdev, &rtwdev->napi,
258023c73dbaSBjoern A. Zeeb rtwdev->hci.ops->napi_poll);
25816d67aabdSBjoern A. Zeeb return 0;
25828e93258fSBjoern A. Zeeb }
25838e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_napi_init);
25848e93258fSBjoern A. Zeeb
rtw89_core_napi_deinit(struct rtw89_dev * rtwdev)25858e93258fSBjoern A. Zeeb void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev)
25868e93258fSBjoern A. Zeeb {
25878e93258fSBjoern A. Zeeb rtw89_core_napi_stop(rtwdev);
25888e93258fSBjoern A. Zeeb netif_napi_del(&rtwdev->napi);
25896d67aabdSBjoern A. Zeeb free_netdev(rtwdev->netdev);
25908e93258fSBjoern A. Zeeb }
25918e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_napi_deinit);
25928e93258fSBjoern A. Zeeb
rtw89_core_ba_work(struct work_struct * work)25938e93258fSBjoern A. Zeeb static void rtw89_core_ba_work(struct work_struct *work)
25948e93258fSBjoern A. Zeeb {
25958e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev =
25968e93258fSBjoern A. Zeeb container_of(work, struct rtw89_dev, ba_work);
25978e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq, *tmp;
25988e93258fSBjoern A. Zeeb int ret;
25998e93258fSBjoern A. Zeeb
26008e93258fSBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
26018e93258fSBjoern A. Zeeb list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) {
26028e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
26038e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = txq->sta;
26048e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
26058e93258fSBjoern A. Zeeb u8 tid = txq->tid;
26068e93258fSBjoern A. Zeeb
26078e93258fSBjoern A. Zeeb if (!sta) {
26088e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "cannot start BA without sta\n");
26098e93258fSBjoern A. Zeeb goto skip_ba_work;
26108e93258fSBjoern A. Zeeb }
26118e93258fSBjoern A. Zeeb
26128e93258fSBjoern A. Zeeb if (rtwsta->disassoc) {
26138e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
26148e93258fSBjoern A. Zeeb "cannot start BA with disassoc sta\n");
26158e93258fSBjoern A. Zeeb goto skip_ba_work;
26168e93258fSBjoern A. Zeeb }
26178e93258fSBjoern A. Zeeb
26188e93258fSBjoern A. Zeeb ret = ieee80211_start_tx_ba_session(sta, tid, 0);
26198e93258fSBjoern A. Zeeb if (ret) {
26208e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
26218e93258fSBjoern A. Zeeb "failed to setup BA session for %pM:%2d: %d\n",
26228e93258fSBjoern A. Zeeb sta->addr, tid, ret);
26238e93258fSBjoern A. Zeeb if (ret == -EINVAL)
26248e93258fSBjoern A. Zeeb set_bit(RTW89_TXQ_F_BLOCK_BA, &rtwtxq->flags);
26258e93258fSBjoern A. Zeeb }
26268e93258fSBjoern A. Zeeb skip_ba_work:
26278e93258fSBjoern A. Zeeb list_del_init(&rtwtxq->list);
26288e93258fSBjoern A. Zeeb }
26298e93258fSBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
26308e93258fSBjoern A. Zeeb }
26318e93258fSBjoern A. Zeeb
rtw89_core_free_sta_pending_ba(struct rtw89_dev * rtwdev,struct ieee80211_sta * sta)26328e93258fSBjoern A. Zeeb static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev,
26338e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
26348e93258fSBjoern A. Zeeb {
26358e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq, *tmp;
26368e93258fSBjoern A. Zeeb
26378e93258fSBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
26388e93258fSBjoern A. Zeeb list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) {
26398e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
26408e93258fSBjoern A. Zeeb
26418e93258fSBjoern A. Zeeb if (sta == txq->sta)
26428e93258fSBjoern A. Zeeb list_del_init(&rtwtxq->list);
26438e93258fSBjoern A. Zeeb }
26448e93258fSBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
26458e93258fSBjoern A. Zeeb }
26468e93258fSBjoern A. Zeeb
rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev * rtwdev,struct ieee80211_sta * sta)26478e93258fSBjoern A. Zeeb static void rtw89_core_free_sta_pending_forbid_ba(struct rtw89_dev *rtwdev,
26488e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
26498e93258fSBjoern A. Zeeb {
26508e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq, *tmp;
26518e93258fSBjoern A. Zeeb
26528e93258fSBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
26538e93258fSBjoern A. Zeeb list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->forbid_ba_list, list) {
26548e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
26558e93258fSBjoern A. Zeeb
26568e93258fSBjoern A. Zeeb if (sta == txq->sta) {
26578e93258fSBjoern A. Zeeb clear_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags);
26588e93258fSBjoern A. Zeeb list_del_init(&rtwtxq->list);
26598e93258fSBjoern A. Zeeb }
26608e93258fSBjoern A. Zeeb }
26618e93258fSBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
26628e93258fSBjoern A. Zeeb }
26638e93258fSBjoern A. Zeeb
rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev * rtwdev,struct ieee80211_sta * sta)2664e2340276SBjoern A. Zeeb static void rtw89_core_free_sta_pending_roc_tx(struct rtw89_dev *rtwdev,
2665e2340276SBjoern A. Zeeb struct ieee80211_sta *sta)
2666e2340276SBjoern A. Zeeb {
2667e2340276SBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
2668e2340276SBjoern A. Zeeb struct sk_buff *skb, *tmp;
2669e2340276SBjoern A. Zeeb
2670e2340276SBjoern A. Zeeb skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) {
2671e2340276SBjoern A. Zeeb skb_unlink(skb, &rtwsta->roc_queue);
2672e2340276SBjoern A. Zeeb dev_kfree_skb_any(skb);
2673e2340276SBjoern A. Zeeb }
2674e2340276SBjoern A. Zeeb }
2675e2340276SBjoern A. Zeeb
rtw89_core_stop_tx_ba_session(struct rtw89_dev * rtwdev,struct rtw89_txq * rtwtxq)26768e93258fSBjoern A. Zeeb static void rtw89_core_stop_tx_ba_session(struct rtw89_dev *rtwdev,
26778e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq)
26788e93258fSBjoern A. Zeeb {
26798e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
26808e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = txq->sta;
26818e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
26828e93258fSBjoern A. Zeeb
26838e93258fSBjoern A. Zeeb if (unlikely(!rtwsta) || unlikely(rtwsta->disassoc))
26848e93258fSBjoern A. Zeeb return;
26858e93258fSBjoern A. Zeeb
26868e93258fSBjoern A. Zeeb if (!test_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags) ||
26878e93258fSBjoern A. Zeeb test_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags))
26888e93258fSBjoern A. Zeeb return;
26898e93258fSBjoern A. Zeeb
26908e93258fSBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
2691e2340276SBjoern A. Zeeb if (!test_and_set_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags))
26928e93258fSBjoern A. Zeeb list_add_tail(&rtwtxq->list, &rtwdev->forbid_ba_list);
2693e2340276SBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
2694e2340276SBjoern A. Zeeb
26958e93258fSBjoern A. Zeeb ieee80211_stop_tx_ba_session(sta, txq->tid);
26968e93258fSBjoern A. Zeeb cancel_delayed_work(&rtwdev->forbid_ba_work);
26978e93258fSBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->forbid_ba_work,
26988e93258fSBjoern A. Zeeb RTW89_FORBID_BA_TIMER);
26998e93258fSBjoern A. Zeeb }
27008e93258fSBjoern A. Zeeb
rtw89_core_txq_check_agg(struct rtw89_dev * rtwdev,struct rtw89_txq * rtwtxq,struct sk_buff * skb)27018e93258fSBjoern A. Zeeb static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev,
27028e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq,
27038e93258fSBjoern A. Zeeb struct sk_buff *skb)
27048e93258fSBjoern A. Zeeb {
27058e93258fSBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
27068e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
27078e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = txq->sta;
27088e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
27098e93258fSBjoern A. Zeeb
2710e2340276SBjoern A. Zeeb if (test_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags))
2711e2340276SBjoern A. Zeeb return;
2712e2340276SBjoern A. Zeeb
27138e93258fSBjoern A. Zeeb if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
27148e93258fSBjoern A. Zeeb rtw89_core_stop_tx_ba_session(rtwdev, rtwtxq);
27158e93258fSBjoern A. Zeeb return;
27168e93258fSBjoern A. Zeeb }
27178e93258fSBjoern A. Zeeb
27188e93258fSBjoern A. Zeeb if (unlikely(!sta))
27198e93258fSBjoern A. Zeeb return;
27208e93258fSBjoern A. Zeeb
27218e93258fSBjoern A. Zeeb if (unlikely(test_bit(RTW89_TXQ_F_BLOCK_BA, &rtwtxq->flags)))
27228e93258fSBjoern A. Zeeb return;
27238e93258fSBjoern A. Zeeb
27248e93258fSBjoern A. Zeeb if (test_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags)) {
27258e93258fSBjoern A. Zeeb IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_AMPDU;
27268e93258fSBjoern A. Zeeb return;
27278e93258fSBjoern A. Zeeb }
27288e93258fSBjoern A. Zeeb
27298e93258fSBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
27308e93258fSBjoern A. Zeeb if (!rtwsta->disassoc && list_empty(&rtwtxq->list)) {
27318e93258fSBjoern A. Zeeb list_add_tail(&rtwtxq->list, &rtwdev->ba_list);
27328e93258fSBjoern A. Zeeb ieee80211_queue_work(hw, &rtwdev->ba_work);
27338e93258fSBjoern A. Zeeb }
27348e93258fSBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
27358e93258fSBjoern A. Zeeb }
27368e93258fSBjoern A. Zeeb
rtw89_core_txq_push(struct rtw89_dev * rtwdev,struct rtw89_txq * rtwtxq,unsigned long frame_cnt,unsigned long byte_cnt)27378e93258fSBjoern A. Zeeb static void rtw89_core_txq_push(struct rtw89_dev *rtwdev,
27388e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq,
27398e93258fSBjoern A. Zeeb unsigned long frame_cnt,
27408e93258fSBjoern A. Zeeb unsigned long byte_cnt)
27418e93258fSBjoern A. Zeeb {
27428e93258fSBjoern A. Zeeb struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
27438e93258fSBjoern A. Zeeb struct ieee80211_vif *vif = txq->vif;
27448e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = txq->sta;
27458e93258fSBjoern A. Zeeb struct sk_buff *skb;
27468e93258fSBjoern A. Zeeb unsigned long i;
27478e93258fSBjoern A. Zeeb int ret;
27488e93258fSBjoern A. Zeeb
27498e93258fSBjoern A. Zeeb rcu_read_lock();
27508e93258fSBjoern A. Zeeb for (i = 0; i < frame_cnt; i++) {
27518e93258fSBjoern A. Zeeb skb = ieee80211_tx_dequeue_ni(rtwdev->hw, txq);
27528e93258fSBjoern A. Zeeb if (!skb) {
27538e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX, "dequeue a NULL skb\n");
27548e93258fSBjoern A. Zeeb goto out;
27558e93258fSBjoern A. Zeeb }
27568e93258fSBjoern A. Zeeb rtw89_core_txq_check_agg(rtwdev, rtwtxq, skb);
27578e93258fSBjoern A. Zeeb ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, NULL);
27588e93258fSBjoern A. Zeeb if (ret) {
27598e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to push txq: %d\n", ret);
27608e93258fSBjoern A. Zeeb ieee80211_free_txskb(rtwdev->hw, skb);
27618e93258fSBjoern A. Zeeb break;
27628e93258fSBjoern A. Zeeb }
27638e93258fSBjoern A. Zeeb }
27648e93258fSBjoern A. Zeeb out:
27658e93258fSBjoern A. Zeeb rcu_read_unlock();
27668e93258fSBjoern A. Zeeb }
27678e93258fSBjoern A. Zeeb
rtw89_check_and_reclaim_tx_resource(struct rtw89_dev * rtwdev,u8 tid)27688e93258fSBjoern A. Zeeb static u32 rtw89_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 tid)
27698e93258fSBjoern A. Zeeb {
27708e93258fSBjoern A. Zeeb u8 qsel, ch_dma;
27718e93258fSBjoern A. Zeeb
27728e93258fSBjoern A. Zeeb qsel = rtw89_core_get_qsel(rtwdev, tid);
27738e93258fSBjoern A. Zeeb ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
27748e93258fSBjoern A. Zeeb
27758e93258fSBjoern A. Zeeb return rtw89_hci_check_and_reclaim_tx_resource(rtwdev, ch_dma);
27768e93258fSBjoern A. Zeeb }
27778e93258fSBjoern A. Zeeb
rtw89_core_txq_agg_wait(struct rtw89_dev * rtwdev,struct ieee80211_txq * txq,unsigned long * frame_cnt,bool * sched_txq,bool * reinvoke)27788e93258fSBjoern A. Zeeb static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev,
27798e93258fSBjoern A. Zeeb struct ieee80211_txq *txq,
27808e93258fSBjoern A. Zeeb unsigned long *frame_cnt,
27818e93258fSBjoern A. Zeeb bool *sched_txq, bool *reinvoke)
27828e93258fSBjoern A. Zeeb {
27838e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv;
27848e93258fSBjoern A. Zeeb struct ieee80211_sta *sta = txq->sta;
27858e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = sta ? (struct rtw89_sta *)sta->drv_priv : NULL;
27868e93258fSBjoern A. Zeeb
27878e93258fSBjoern A. Zeeb if (!sta || rtwsta->max_agg_wait <= 0)
27888e93258fSBjoern A. Zeeb return false;
27898e93258fSBjoern A. Zeeb
27908e93258fSBjoern A. Zeeb if (rtwdev->stats.tx_tfc_lv <= RTW89_TFC_MID)
27918e93258fSBjoern A. Zeeb return false;
27928e93258fSBjoern A. Zeeb
27938e93258fSBjoern A. Zeeb if (*frame_cnt > 1) {
27948e93258fSBjoern A. Zeeb *frame_cnt -= 1;
27958e93258fSBjoern A. Zeeb *sched_txq = true;
27968e93258fSBjoern A. Zeeb *reinvoke = true;
27978e93258fSBjoern A. Zeeb rtwtxq->wait_cnt = 1;
27988e93258fSBjoern A. Zeeb return false;
27998e93258fSBjoern A. Zeeb }
28008e93258fSBjoern A. Zeeb
28018e93258fSBjoern A. Zeeb if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta->max_agg_wait) {
28028e93258fSBjoern A. Zeeb *reinvoke = true;
28038e93258fSBjoern A. Zeeb rtwtxq->wait_cnt++;
28048e93258fSBjoern A. Zeeb return true;
28058e93258fSBjoern A. Zeeb }
28068e93258fSBjoern A. Zeeb
28078e93258fSBjoern A. Zeeb rtwtxq->wait_cnt = 0;
28088e93258fSBjoern A. Zeeb return false;
28098e93258fSBjoern A. Zeeb }
28108e93258fSBjoern A. Zeeb
rtw89_core_txq_schedule(struct rtw89_dev * rtwdev,u8 ac,bool * reinvoke)28118e93258fSBjoern A. Zeeb static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinvoke)
28128e93258fSBjoern A. Zeeb {
28138e93258fSBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
28148e93258fSBjoern A. Zeeb struct ieee80211_txq *txq;
2815e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif;
28168e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq;
28178e93258fSBjoern A. Zeeb unsigned long frame_cnt;
28188e93258fSBjoern A. Zeeb unsigned long byte_cnt;
28198e93258fSBjoern A. Zeeb u32 tx_resource;
28208e93258fSBjoern A. Zeeb bool sched_txq;
28218e93258fSBjoern A. Zeeb
28228e93258fSBjoern A. Zeeb ieee80211_txq_schedule_start(hw, ac);
28238e93258fSBjoern A. Zeeb while ((txq = ieee80211_next_txq(hw, ac))) {
28248e93258fSBjoern A. Zeeb rtwtxq = (struct rtw89_txq *)txq->drv_priv;
2825e2340276SBjoern A. Zeeb rtwvif = (struct rtw89_vif *)txq->vif->drv_priv;
2826e2340276SBjoern A. Zeeb
2827e2340276SBjoern A. Zeeb if (rtwvif->offchan) {
2828e2340276SBjoern A. Zeeb ieee80211_return_txq(hw, txq, true);
2829e2340276SBjoern A. Zeeb continue;
2830e2340276SBjoern A. Zeeb }
28318e93258fSBjoern A. Zeeb tx_resource = rtw89_check_and_reclaim_tx_resource(rtwdev, txq->tid);
28328e93258fSBjoern A. Zeeb sched_txq = false;
28338e93258fSBjoern A. Zeeb
28348e93258fSBjoern A. Zeeb ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt);
28358e93258fSBjoern A. Zeeb if (rtw89_core_txq_agg_wait(rtwdev, txq, &frame_cnt, &sched_txq, reinvoke)) {
28368e93258fSBjoern A. Zeeb ieee80211_return_txq(hw, txq, true);
28378e93258fSBjoern A. Zeeb continue;
28388e93258fSBjoern A. Zeeb }
28398e93258fSBjoern A. Zeeb frame_cnt = min_t(unsigned long, frame_cnt, tx_resource);
28408e93258fSBjoern A. Zeeb rtw89_core_txq_push(rtwdev, rtwtxq, frame_cnt, byte_cnt);
28418e93258fSBjoern A. Zeeb ieee80211_return_txq(hw, txq, sched_txq);
28428e93258fSBjoern A. Zeeb if (frame_cnt != 0)
28438e93258fSBjoern A. Zeeb rtw89_core_tx_kick_off(rtwdev, rtw89_core_get_qsel(rtwdev, txq->tid));
28448e93258fSBjoern A. Zeeb
28458e93258fSBjoern A. Zeeb /* bound of tx_resource could get stuck due to burst traffic */
28468e93258fSBjoern A. Zeeb if (frame_cnt == tx_resource)
28478e93258fSBjoern A. Zeeb *reinvoke = true;
28488e93258fSBjoern A. Zeeb }
28498e93258fSBjoern A. Zeeb ieee80211_txq_schedule_end(hw, ac);
28508e93258fSBjoern A. Zeeb }
28518e93258fSBjoern A. Zeeb
rtw89_ips_work(struct work_struct * work)28528e93258fSBjoern A. Zeeb static void rtw89_ips_work(struct work_struct *work)
28538e93258fSBjoern A. Zeeb {
28548e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
28558e93258fSBjoern A. Zeeb ips_work);
28568e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
2857e2340276SBjoern A. Zeeb rtw89_enter_ips_by_hwflags(rtwdev);
28588e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
28598e93258fSBjoern A. Zeeb }
28608e93258fSBjoern A. Zeeb
rtw89_core_txq_work(struct work_struct * w)28618e93258fSBjoern A. Zeeb static void rtw89_core_txq_work(struct work_struct *w)
28628e93258fSBjoern A. Zeeb {
28638e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev, txq_work);
28648e93258fSBjoern A. Zeeb bool reinvoke = false;
28658e93258fSBjoern A. Zeeb u8 ac;
28668e93258fSBjoern A. Zeeb
28678e93258fSBjoern A. Zeeb for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
28688e93258fSBjoern A. Zeeb rtw89_core_txq_schedule(rtwdev, ac, &reinvoke);
28698e93258fSBjoern A. Zeeb
28708e93258fSBjoern A. Zeeb if (reinvoke) {
28718e93258fSBjoern A. Zeeb /* reinvoke to process the last frame */
28728e93258fSBjoern A. Zeeb mod_delayed_work(rtwdev->txq_wq, &rtwdev->txq_reinvoke_work, 1);
28738e93258fSBjoern A. Zeeb }
28748e93258fSBjoern A. Zeeb }
28758e93258fSBjoern A. Zeeb
rtw89_core_txq_reinvoke_work(struct work_struct * w)28768e93258fSBjoern A. Zeeb static void rtw89_core_txq_reinvoke_work(struct work_struct *w)
28778e93258fSBjoern A. Zeeb {
28788e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev,
28798e93258fSBjoern A. Zeeb txq_reinvoke_work.work);
28808e93258fSBjoern A. Zeeb
28818e93258fSBjoern A. Zeeb queue_work(rtwdev->txq_wq, &rtwdev->txq_work);
28828e93258fSBjoern A. Zeeb }
28838e93258fSBjoern A. Zeeb
rtw89_forbid_ba_work(struct work_struct * w)28848e93258fSBjoern A. Zeeb static void rtw89_forbid_ba_work(struct work_struct *w)
28858e93258fSBjoern A. Zeeb {
28868e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev,
28878e93258fSBjoern A. Zeeb forbid_ba_work.work);
28888e93258fSBjoern A. Zeeb struct rtw89_txq *rtwtxq, *tmp;
28898e93258fSBjoern A. Zeeb
28908e93258fSBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
28918e93258fSBjoern A. Zeeb list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->forbid_ba_list, list) {
28928e93258fSBjoern A. Zeeb clear_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags);
28938e93258fSBjoern A. Zeeb list_del_init(&rtwtxq->list);
28948e93258fSBjoern A. Zeeb }
28958e93258fSBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
28968e93258fSBjoern A. Zeeb }
28978e93258fSBjoern A. Zeeb
rtw89_core_sta_pending_tx_iter(void * data,struct ieee80211_sta * sta)2898e2340276SBjoern A. Zeeb static void rtw89_core_sta_pending_tx_iter(void *data,
2899e2340276SBjoern A. Zeeb struct ieee80211_sta *sta)
2900e2340276SBjoern A. Zeeb {
2901e2340276SBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
2902e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif_target = data, *rtwvif = rtwsta->rtwvif;
2903e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = rtwvif->rtwdev;
2904e2340276SBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
2905e2340276SBjoern A. Zeeb struct sk_buff *skb, *tmp;
2906e2340276SBjoern A. Zeeb int qsel, ret;
2907e2340276SBjoern A. Zeeb
2908e2340276SBjoern A. Zeeb if (rtwvif->sub_entity_idx != rtwvif_target->sub_entity_idx)
2909e2340276SBjoern A. Zeeb return;
2910e2340276SBjoern A. Zeeb
2911e2340276SBjoern A. Zeeb if (skb_queue_len(&rtwsta->roc_queue) == 0)
2912e2340276SBjoern A. Zeeb return;
2913e2340276SBjoern A. Zeeb
2914e2340276SBjoern A. Zeeb skb_queue_walk_safe(&rtwsta->roc_queue, skb, tmp) {
2915e2340276SBjoern A. Zeeb skb_unlink(skb, &rtwsta->roc_queue);
2916e2340276SBjoern A. Zeeb
2917e2340276SBjoern A. Zeeb ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
2918e2340276SBjoern A. Zeeb if (ret) {
2919e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "pending tx failed with %d\n", ret);
2920e2340276SBjoern A. Zeeb dev_kfree_skb_any(skb);
2921e2340276SBjoern A. Zeeb } else {
2922e2340276SBjoern A. Zeeb rtw89_core_tx_kick_off(rtwdev, qsel);
2923e2340276SBjoern A. Zeeb }
2924e2340276SBjoern A. Zeeb }
2925e2340276SBjoern A. Zeeb }
2926e2340276SBjoern A. Zeeb
rtw89_core_handle_sta_pending_tx(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)2927e2340276SBjoern A. Zeeb static void rtw89_core_handle_sta_pending_tx(struct rtw89_dev *rtwdev,
2928e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif)
2929e2340276SBjoern A. Zeeb {
2930e2340276SBjoern A. Zeeb ieee80211_iterate_stations_atomic(rtwdev->hw,
2931e2340276SBjoern A. Zeeb rtw89_core_sta_pending_tx_iter,
2932e2340276SBjoern A. Zeeb rtwvif);
2933e2340276SBjoern A. Zeeb }
2934e2340276SBjoern A. Zeeb
rtw89_core_send_nullfunc(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,bool qos,bool ps)2935e2340276SBjoern A. Zeeb static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev,
2936e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif, bool qos, bool ps)
2937e2340276SBjoern A. Zeeb {
2938e2340276SBjoern A. Zeeb struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
2939e2340276SBjoern A. Zeeb struct ieee80211_sta *sta;
2940e2340276SBjoern A. Zeeb struct ieee80211_hdr *hdr;
2941e2340276SBjoern A. Zeeb struct sk_buff *skb;
2942e2340276SBjoern A. Zeeb int ret, qsel;
2943e2340276SBjoern A. Zeeb
2944e2340276SBjoern A. Zeeb if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
2945e2340276SBjoern A. Zeeb return 0;
2946e2340276SBjoern A. Zeeb
2947e2340276SBjoern A. Zeeb rcu_read_lock();
2948e2340276SBjoern A. Zeeb sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
2949e2340276SBjoern A. Zeeb if (!sta) {
2950e2340276SBjoern A. Zeeb ret = -EINVAL;
2951e2340276SBjoern A. Zeeb goto out;
2952e2340276SBjoern A. Zeeb }
2953e2340276SBjoern A. Zeeb
2954e2340276SBjoern A. Zeeb skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, qos);
2955e2340276SBjoern A. Zeeb if (!skb) {
2956e2340276SBjoern A. Zeeb ret = -ENOMEM;
2957e2340276SBjoern A. Zeeb goto out;
2958e2340276SBjoern A. Zeeb }
2959e2340276SBjoern A. Zeeb
2960e2340276SBjoern A. Zeeb hdr = (struct ieee80211_hdr *)skb->data;
2961e2340276SBjoern A. Zeeb if (ps)
2962e2340276SBjoern A. Zeeb hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
2963e2340276SBjoern A. Zeeb
2964e2340276SBjoern A. Zeeb ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel);
2965e2340276SBjoern A. Zeeb if (ret) {
2966e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret);
2967e2340276SBjoern A. Zeeb dev_kfree_skb_any(skb);
2968e2340276SBjoern A. Zeeb goto out;
2969e2340276SBjoern A. Zeeb }
2970e2340276SBjoern A. Zeeb
2971e2340276SBjoern A. Zeeb rcu_read_unlock();
2972e2340276SBjoern A. Zeeb
2973e2340276SBjoern A. Zeeb return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel,
2974e2340276SBjoern A. Zeeb RTW89_ROC_TX_TIMEOUT);
2975e2340276SBjoern A. Zeeb out:
2976e2340276SBjoern A. Zeeb rcu_read_unlock();
2977e2340276SBjoern A. Zeeb
2978e2340276SBjoern A. Zeeb return ret;
2979e2340276SBjoern A. Zeeb }
2980e2340276SBjoern A. Zeeb
rtw89_roc_start(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)2981e2340276SBjoern A. Zeeb void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
2982e2340276SBjoern A. Zeeb {
29836d67aabdSBjoern A. Zeeb const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
2984e2340276SBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
2985e2340276SBjoern A. Zeeb struct rtw89_roc *roc = &rtwvif->roc;
2986e2340276SBjoern A. Zeeb struct cfg80211_chan_def roc_chan;
2987e2340276SBjoern A. Zeeb struct rtw89_vif *tmp;
2988e2340276SBjoern A. Zeeb int ret;
2989e2340276SBjoern A. Zeeb
2990e2340276SBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
2991e2340276SBjoern A. Zeeb
2992e2340276SBjoern A. Zeeb rtw89_leave_ips_by_hwflags(rtwdev);
2993e2340276SBjoern A. Zeeb rtw89_leave_lps(rtwdev);
29946d67aabdSBjoern A. Zeeb rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC);
2995e2340276SBjoern A. Zeeb
2996e2340276SBjoern A. Zeeb ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, true);
2997e2340276SBjoern A. Zeeb if (ret)
2998e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
2999e2340276SBjoern A. Zeeb "roc send null-1 failed: %d\n", ret);
3000e2340276SBjoern A. Zeeb
3001e2340276SBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, tmp)
3002e2340276SBjoern A. Zeeb if (tmp->sub_entity_idx == rtwvif->sub_entity_idx)
3003e2340276SBjoern A. Zeeb tmp->offchan = true;
3004e2340276SBjoern A. Zeeb
3005e2340276SBjoern A. Zeeb cfg80211_chandef_create(&roc_chan, &roc->chan, NL80211_CHAN_NO_HT);
3006e2340276SBjoern A. Zeeb rtw89_config_roc_chandef(rtwdev, rtwvif->sub_entity_idx, &roc_chan);
3007e2340276SBjoern A. Zeeb rtw89_set_channel(rtwdev);
3008e2340276SBjoern A. Zeeb rtw89_write32_clr(rtwdev,
30096d67aabdSBjoern A. Zeeb rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
3010e2340276SBjoern A. Zeeb B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH);
3011e2340276SBjoern A. Zeeb
3012e2340276SBjoern A. Zeeb ieee80211_ready_on_channel(hw);
30136d67aabdSBjoern A. Zeeb cancel_delayed_work(&rtwvif->roc.roc_work);
30146d67aabdSBjoern A. Zeeb ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work,
30156d67aabdSBjoern A. Zeeb msecs_to_jiffies(rtwvif->roc.duration));
3016e2340276SBjoern A. Zeeb }
3017e2340276SBjoern A. Zeeb
rtw89_roc_end(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)3018e2340276SBjoern A. Zeeb void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
3019e2340276SBjoern A. Zeeb {
30206d67aabdSBjoern A. Zeeb const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
3021e2340276SBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
3022e2340276SBjoern A. Zeeb struct rtw89_roc *roc = &rtwvif->roc;
3023e2340276SBjoern A. Zeeb struct rtw89_vif *tmp;
3024e2340276SBjoern A. Zeeb int ret;
3025e2340276SBjoern A. Zeeb
3026e2340276SBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
3027e2340276SBjoern A. Zeeb
3028e2340276SBjoern A. Zeeb ieee80211_remain_on_channel_expired(hw);
3029e2340276SBjoern A. Zeeb
3030e2340276SBjoern A. Zeeb rtw89_leave_ips_by_hwflags(rtwdev);
3031e2340276SBjoern A. Zeeb rtw89_leave_lps(rtwdev);
3032e2340276SBjoern A. Zeeb
3033e2340276SBjoern A. Zeeb rtw89_write32_mask(rtwdev,
30346d67aabdSBjoern A. Zeeb rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
3035e2340276SBjoern A. Zeeb B_AX_RX_FLTR_CFG_MASK,
3036e2340276SBjoern A. Zeeb rtwdev->hal.rx_fltr);
3037e2340276SBjoern A. Zeeb
3038e2340276SBjoern A. Zeeb roc->state = RTW89_ROC_IDLE;
3039e2340276SBjoern A. Zeeb rtw89_config_roc_chandef(rtwdev, rtwvif->sub_entity_idx, NULL);
30406d67aabdSBjoern A. Zeeb rtw89_chanctx_proceed(rtwdev);
3041e2340276SBjoern A. Zeeb ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, false);
3042e2340276SBjoern A. Zeeb if (ret)
3043e2340276SBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_TXRX,
3044e2340276SBjoern A. Zeeb "roc send null-0 failed: %d\n", ret);
3045e2340276SBjoern A. Zeeb
3046e2340276SBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, tmp)
3047e2340276SBjoern A. Zeeb if (tmp->sub_entity_idx == rtwvif->sub_entity_idx)
3048e2340276SBjoern A. Zeeb tmp->offchan = false;
3049e2340276SBjoern A. Zeeb
3050e2340276SBjoern A. Zeeb rtw89_core_handle_sta_pending_tx(rtwdev, rtwvif);
3051e2340276SBjoern A. Zeeb queue_work(rtwdev->txq_wq, &rtwdev->txq_work);
3052e2340276SBjoern A. Zeeb
3053e2340276SBjoern A. Zeeb if (hw->conf.flags & IEEE80211_CONF_IDLE)
3054e2340276SBjoern A. Zeeb ieee80211_queue_delayed_work(hw, &roc->roc_work,
30556d67aabdSBjoern A. Zeeb msecs_to_jiffies(RTW89_ROC_IDLE_TIMEOUT));
3056e2340276SBjoern A. Zeeb }
3057e2340276SBjoern A. Zeeb
rtw89_roc_work(struct work_struct * work)3058e2340276SBjoern A. Zeeb void rtw89_roc_work(struct work_struct *work)
3059e2340276SBjoern A. Zeeb {
3060e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = container_of(work, struct rtw89_vif,
3061e2340276SBjoern A. Zeeb roc.roc_work.work);
3062e2340276SBjoern A. Zeeb struct rtw89_dev *rtwdev = rtwvif->rtwdev;
3063e2340276SBjoern A. Zeeb struct rtw89_roc *roc = &rtwvif->roc;
3064e2340276SBjoern A. Zeeb
3065e2340276SBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
3066e2340276SBjoern A. Zeeb
3067e2340276SBjoern A. Zeeb switch (roc->state) {
3068e2340276SBjoern A. Zeeb case RTW89_ROC_IDLE:
3069e2340276SBjoern A. Zeeb rtw89_enter_ips_by_hwflags(rtwdev);
3070e2340276SBjoern A. Zeeb break;
3071e2340276SBjoern A. Zeeb case RTW89_ROC_MGMT:
3072e2340276SBjoern A. Zeeb case RTW89_ROC_NORMAL:
3073e2340276SBjoern A. Zeeb rtw89_roc_end(rtwdev, rtwvif);
3074e2340276SBjoern A. Zeeb break;
3075e2340276SBjoern A. Zeeb default:
3076e2340276SBjoern A. Zeeb break;
3077e2340276SBjoern A. Zeeb }
3078e2340276SBjoern A. Zeeb
3079e2340276SBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
3080e2340276SBjoern A. Zeeb }
3081e2340276SBjoern A. Zeeb
rtw89_get_traffic_level(struct rtw89_dev * rtwdev,u32 throughput,u64 cnt)30828e93258fSBjoern A. Zeeb static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev,
30838e93258fSBjoern A. Zeeb u32 throughput, u64 cnt)
30848e93258fSBjoern A. Zeeb {
30858e93258fSBjoern A. Zeeb if (cnt < 100)
30868e93258fSBjoern A. Zeeb return RTW89_TFC_IDLE;
30878e93258fSBjoern A. Zeeb if (throughput > 50)
30888e93258fSBjoern A. Zeeb return RTW89_TFC_HIGH;
30898e93258fSBjoern A. Zeeb if (throughput > 10)
30908e93258fSBjoern A. Zeeb return RTW89_TFC_MID;
30918e93258fSBjoern A. Zeeb if (throughput > 2)
30928e93258fSBjoern A. Zeeb return RTW89_TFC_LOW;
30938e93258fSBjoern A. Zeeb return RTW89_TFC_ULTRA_LOW;
30948e93258fSBjoern A. Zeeb }
30958e93258fSBjoern A. Zeeb
rtw89_traffic_stats_calc(struct rtw89_dev * rtwdev,struct rtw89_traffic_stats * stats)30968e93258fSBjoern A. Zeeb static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
30978e93258fSBjoern A. Zeeb struct rtw89_traffic_stats *stats)
30988e93258fSBjoern A. Zeeb {
30998e93258fSBjoern A. Zeeb enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
31008e93258fSBjoern A. Zeeb enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
31018e93258fSBjoern A. Zeeb
31028e93258fSBjoern A. Zeeb stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT);
31038e93258fSBjoern A. Zeeb stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT);
31048e93258fSBjoern A. Zeeb
31058e93258fSBjoern A. Zeeb ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw);
31068e93258fSBjoern A. Zeeb ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw);
31078e93258fSBjoern A. Zeeb
31088e93258fSBjoern A. Zeeb stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp);
31098e93258fSBjoern A. Zeeb stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp);
31108e93258fSBjoern A. Zeeb stats->tx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->tx_throughput,
31118e93258fSBjoern A. Zeeb stats->tx_cnt);
31128e93258fSBjoern A. Zeeb stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput,
31138e93258fSBjoern A. Zeeb stats->rx_cnt);
31148e93258fSBjoern A. Zeeb stats->tx_avg_len = stats->tx_cnt ?
31158e93258fSBjoern A. Zeeb DIV_ROUND_DOWN_ULL(stats->tx_unicast, stats->tx_cnt) : 0;
31168e93258fSBjoern A. Zeeb stats->rx_avg_len = stats->rx_cnt ?
31178e93258fSBjoern A. Zeeb DIV_ROUND_DOWN_ULL(stats->rx_unicast, stats->rx_cnt) : 0;
31188e93258fSBjoern A. Zeeb
31198e93258fSBjoern A. Zeeb stats->tx_unicast = 0;
31208e93258fSBjoern A. Zeeb stats->rx_unicast = 0;
31218e93258fSBjoern A. Zeeb stats->tx_cnt = 0;
31228e93258fSBjoern A. Zeeb stats->rx_cnt = 0;
31238e93258fSBjoern A. Zeeb stats->rx_tf_periodic = stats->rx_tf_acc;
31248e93258fSBjoern A. Zeeb stats->rx_tf_acc = 0;
31258e93258fSBjoern A. Zeeb
31268e93258fSBjoern A. Zeeb if (tx_tfc_lv != stats->tx_tfc_lv || rx_tfc_lv != stats->rx_tfc_lv)
31278e93258fSBjoern A. Zeeb return true;
31288e93258fSBjoern A. Zeeb
31298e93258fSBjoern A. Zeeb return false;
31308e93258fSBjoern A. Zeeb }
31318e93258fSBjoern A. Zeeb
rtw89_traffic_stats_track(struct rtw89_dev * rtwdev)31328e93258fSBjoern A. Zeeb static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
31338e93258fSBjoern A. Zeeb {
31348e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif;
31358e93258fSBjoern A. Zeeb bool tfc_changed;
31368e93258fSBjoern A. Zeeb
31378e93258fSBjoern A. Zeeb tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats);
3138e2340276SBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, rtwvif) {
31398e93258fSBjoern A. Zeeb rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats);
3140e2340276SBjoern A. Zeeb rtw89_fw_h2c_tp_offload(rtwdev, rtwvif);
3141e2340276SBjoern A. Zeeb }
31428e93258fSBjoern A. Zeeb
31438e93258fSBjoern A. Zeeb return tfc_changed;
31448e93258fSBjoern A. Zeeb }
31458e93258fSBjoern A. Zeeb
rtw89_vif_enter_lps(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif)31468e93258fSBjoern A. Zeeb static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
31478e93258fSBjoern A. Zeeb {
3148e2340276SBjoern A. Zeeb if ((rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION &&
3149e2340276SBjoern A. Zeeb rtwvif->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) ||
3150e2340276SBjoern A. Zeeb rtwvif->tdls_peer)
3151e2340276SBjoern A. Zeeb return;
3152e2340276SBjoern A. Zeeb
3153e2340276SBjoern A. Zeeb if (rtwvif->offchan)
31548e93258fSBjoern A. Zeeb return;
31558e93258fSBjoern A. Zeeb
31568e93258fSBjoern A. Zeeb if (rtwvif->stats.tx_tfc_lv == RTW89_TFC_IDLE &&
31578e93258fSBjoern A. Zeeb rtwvif->stats.rx_tfc_lv == RTW89_TFC_IDLE)
3158e2340276SBjoern A. Zeeb rtw89_enter_lps(rtwdev, rtwvif, true);
31598e93258fSBjoern A. Zeeb }
31608e93258fSBjoern A. Zeeb
rtw89_enter_lps_track(struct rtw89_dev * rtwdev)31618e93258fSBjoern A. Zeeb static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
31628e93258fSBjoern A. Zeeb {
31638e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif;
31648e93258fSBjoern A. Zeeb
31658e93258fSBjoern A. Zeeb rtw89_for_each_rtwvif(rtwdev, rtwvif)
31668e93258fSBjoern A. Zeeb rtw89_vif_enter_lps(rtwdev, rtwvif);
31678e93258fSBjoern A. Zeeb }
31688e93258fSBjoern A. Zeeb
rtw89_core_rfk_track(struct rtw89_dev * rtwdev)31696d67aabdSBjoern A. Zeeb static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev)
31706d67aabdSBjoern A. Zeeb {
31716d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode;
31726d67aabdSBjoern A. Zeeb
31736d67aabdSBjoern A. Zeeb mode = rtw89_get_entity_mode(rtwdev);
31746d67aabdSBjoern A. Zeeb if (mode == RTW89_ENTITY_MODE_MCC)
31756d67aabdSBjoern A. Zeeb return;
31766d67aabdSBjoern A. Zeeb
31776d67aabdSBjoern A. Zeeb rtw89_chip_rfk_track(rtwdev);
31786d67aabdSBjoern A. Zeeb }
31796d67aabdSBjoern A. Zeeb
rtw89_core_update_p2p_ps(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif)31806d67aabdSBjoern A. Zeeb void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
31816d67aabdSBjoern A. Zeeb {
31826d67aabdSBjoern A. Zeeb enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev);
31836d67aabdSBjoern A. Zeeb
31846d67aabdSBjoern A. Zeeb if (mode == RTW89_ENTITY_MODE_MCC)
31856d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_P2P_PS_CHANGE);
31866d67aabdSBjoern A. Zeeb else
31876d67aabdSBjoern A. Zeeb rtw89_process_p2p_ps(rtwdev, vif);
31886d67aabdSBjoern A. Zeeb }
31896d67aabdSBjoern A. Zeeb
rtw89_traffic_stats_init(struct rtw89_dev * rtwdev,struct rtw89_traffic_stats * stats)31908e93258fSBjoern A. Zeeb void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
31918e93258fSBjoern A. Zeeb struct rtw89_traffic_stats *stats)
31928e93258fSBjoern A. Zeeb {
31938e93258fSBjoern A. Zeeb stats->tx_unicast = 0;
31948e93258fSBjoern A. Zeeb stats->rx_unicast = 0;
31958e93258fSBjoern A. Zeeb stats->tx_cnt = 0;
31968e93258fSBjoern A. Zeeb stats->rx_cnt = 0;
31978e93258fSBjoern A. Zeeb ewma_tp_init(&stats->tx_ewma_tp);
31988e93258fSBjoern A. Zeeb ewma_tp_init(&stats->rx_ewma_tp);
31998e93258fSBjoern A. Zeeb }
32008e93258fSBjoern A. Zeeb
rtw89_track_work(struct work_struct * work)32018e93258fSBjoern A. Zeeb static void rtw89_track_work(struct work_struct *work)
32028e93258fSBjoern A. Zeeb {
32038e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
32048e93258fSBjoern A. Zeeb track_work.work);
32058e93258fSBjoern A. Zeeb bool tfc_changed;
32068e93258fSBjoern A. Zeeb
3207e2340276SBjoern A. Zeeb if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags))
3208e2340276SBjoern A. Zeeb return;
3209e2340276SBjoern A. Zeeb
32108e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
32118e93258fSBjoern A. Zeeb
32128e93258fSBjoern A. Zeeb if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
32138e93258fSBjoern A. Zeeb goto out;
32148e93258fSBjoern A. Zeeb
32158e93258fSBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work,
32168e93258fSBjoern A. Zeeb RTW89_TRACK_WORK_PERIOD);
32178e93258fSBjoern A. Zeeb
32188e93258fSBjoern A. Zeeb tfc_changed = rtw89_traffic_stats_track(rtwdev);
32198e93258fSBjoern A. Zeeb if (rtwdev->scanning)
32208e93258fSBjoern A. Zeeb goto out;
32218e93258fSBjoern A. Zeeb
32228e93258fSBjoern A. Zeeb rtw89_leave_lps(rtwdev);
32238e93258fSBjoern A. Zeeb
32248e93258fSBjoern A. Zeeb if (tfc_changed) {
32258e93258fSBjoern A. Zeeb rtw89_hci_recalc_int_mit(rtwdev);
32268e93258fSBjoern A. Zeeb rtw89_btc_ntfy_wl_sta(rtwdev);
32278e93258fSBjoern A. Zeeb }
32288e93258fSBjoern A. Zeeb rtw89_mac_bf_monitor_track(rtwdev);
32298e93258fSBjoern A. Zeeb rtw89_phy_stat_track(rtwdev);
32308e93258fSBjoern A. Zeeb rtw89_phy_env_monitor_track(rtwdev);
32318e93258fSBjoern A. Zeeb rtw89_phy_dig(rtwdev);
32326d67aabdSBjoern A. Zeeb rtw89_core_rfk_track(rtwdev);
32338e93258fSBjoern A. Zeeb rtw89_phy_ra_update(rtwdev);
32348e93258fSBjoern A. Zeeb rtw89_phy_cfo_track(rtwdev);
3235e2340276SBjoern A. Zeeb rtw89_phy_tx_path_div_track(rtwdev);
3236e2340276SBjoern A. Zeeb rtw89_phy_antdiv_track(rtwdev);
3237e2340276SBjoern A. Zeeb rtw89_phy_ul_tb_ctrl_track(rtwdev);
32386d67aabdSBjoern A. Zeeb rtw89_phy_edcca_track(rtwdev);
32396d67aabdSBjoern A. Zeeb rtw89_tas_track(rtwdev);
32406d67aabdSBjoern A. Zeeb rtw89_chanctx_track(rtwdev);
32418e93258fSBjoern A. Zeeb
32428e93258fSBjoern A. Zeeb if (rtwdev->lps_enabled && !rtwdev->btc.lps)
32438e93258fSBjoern A. Zeeb rtw89_enter_lps_track(rtwdev);
32448e93258fSBjoern A. Zeeb
32458e93258fSBjoern A. Zeeb out:
32468e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
32478e93258fSBjoern A. Zeeb }
32488e93258fSBjoern A. Zeeb
rtw89_core_acquire_bit_map(unsigned long * addr,unsigned long size)32498e93258fSBjoern A. Zeeb u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size)
32508e93258fSBjoern A. Zeeb {
32518e93258fSBjoern A. Zeeb unsigned long bit;
32528e93258fSBjoern A. Zeeb
32538e93258fSBjoern A. Zeeb bit = find_first_zero_bit(addr, size);
32548e93258fSBjoern A. Zeeb if (bit < size)
32558e93258fSBjoern A. Zeeb set_bit(bit, addr);
32568e93258fSBjoern A. Zeeb
32578e93258fSBjoern A. Zeeb return bit;
32588e93258fSBjoern A. Zeeb }
32598e93258fSBjoern A. Zeeb
rtw89_core_release_bit_map(unsigned long * addr,u8 bit)32608e93258fSBjoern A. Zeeb void rtw89_core_release_bit_map(unsigned long *addr, u8 bit)
32618e93258fSBjoern A. Zeeb {
32628e93258fSBjoern A. Zeeb clear_bit(bit, addr);
32638e93258fSBjoern A. Zeeb }
32648e93258fSBjoern A. Zeeb
rtw89_core_release_all_bits_map(unsigned long * addr,unsigned int nbits)32658e93258fSBjoern A. Zeeb void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits)
32668e93258fSBjoern A. Zeeb {
32678e93258fSBjoern A. Zeeb bitmap_zero(addr, nbits);
32688e93258fSBjoern A. Zeeb }
32698e93258fSBjoern A. Zeeb
rtw89_core_acquire_sta_ba_entry(struct rtw89_dev * rtwdev,struct rtw89_sta * rtwsta,u8 tid,u8 * cam_idx)32708e93258fSBjoern A. Zeeb int rtw89_core_acquire_sta_ba_entry(struct rtw89_dev *rtwdev,
32718e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx)
32728e93258fSBjoern A. Zeeb {
32738e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
32748e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
32758e93258fSBjoern A. Zeeb struct rtw89_ba_cam_entry *entry = NULL, *tmp;
32768e93258fSBjoern A. Zeeb u8 idx;
32778e93258fSBjoern A. Zeeb int i;
32788e93258fSBjoern A. Zeeb
32798e93258fSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
32808e93258fSBjoern A. Zeeb
32818e93258fSBjoern A. Zeeb idx = rtw89_core_acquire_bit_map(cam_info->ba_cam_map, chip->bacam_num);
32828e93258fSBjoern A. Zeeb if (idx == chip->bacam_num) {
32838e93258fSBjoern A. Zeeb /* allocate a static BA CAM to tid=0/5, so replace the existing
32848e93258fSBjoern A. Zeeb * one if BA CAM is full. Hardware will process the original tid
32858e93258fSBjoern A. Zeeb * automatically.
32868e93258fSBjoern A. Zeeb */
32878e93258fSBjoern A. Zeeb if (tid != 0 && tid != 5)
32888e93258fSBjoern A. Zeeb return -ENOSPC;
32898e93258fSBjoern A. Zeeb
32908e93258fSBjoern A. Zeeb for_each_set_bit(i, cam_info->ba_cam_map, chip->bacam_num) {
32918e93258fSBjoern A. Zeeb tmp = &cam_info->ba_cam_entry[i];
32928e93258fSBjoern A. Zeeb if (tmp->tid == 0 || tmp->tid == 5)
32938e93258fSBjoern A. Zeeb continue;
32948e93258fSBjoern A. Zeeb
32958e93258fSBjoern A. Zeeb idx = i;
32968e93258fSBjoern A. Zeeb entry = tmp;
32978e93258fSBjoern A. Zeeb list_del(&entry->list);
32988e93258fSBjoern A. Zeeb break;
32998e93258fSBjoern A. Zeeb }
33008e93258fSBjoern A. Zeeb
33018e93258fSBjoern A. Zeeb if (!entry)
33028e93258fSBjoern A. Zeeb return -ENOSPC;
33038e93258fSBjoern A. Zeeb } else {
33048e93258fSBjoern A. Zeeb entry = &cam_info->ba_cam_entry[idx];
33058e93258fSBjoern A. Zeeb }
33068e93258fSBjoern A. Zeeb
33078e93258fSBjoern A. Zeeb entry->tid = tid;
33088e93258fSBjoern A. Zeeb list_add_tail(&entry->list, &rtwsta->ba_cam_list);
33098e93258fSBjoern A. Zeeb
33108e93258fSBjoern A. Zeeb *cam_idx = idx;
33118e93258fSBjoern A. Zeeb
33128e93258fSBjoern A. Zeeb return 0;
33138e93258fSBjoern A. Zeeb }
33148e93258fSBjoern A. Zeeb
rtw89_core_release_sta_ba_entry(struct rtw89_dev * rtwdev,struct rtw89_sta * rtwsta,u8 tid,u8 * cam_idx)33158e93258fSBjoern A. Zeeb int rtw89_core_release_sta_ba_entry(struct rtw89_dev *rtwdev,
33168e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta, u8 tid, u8 *cam_idx)
33178e93258fSBjoern A. Zeeb {
33188e93258fSBjoern A. Zeeb struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
33198e93258fSBjoern A. Zeeb struct rtw89_ba_cam_entry *entry = NULL, *tmp;
33208e93258fSBjoern A. Zeeb u8 idx;
33218e93258fSBjoern A. Zeeb
33228e93258fSBjoern A. Zeeb lockdep_assert_held(&rtwdev->mutex);
33238e93258fSBjoern A. Zeeb
33248e93258fSBjoern A. Zeeb list_for_each_entry_safe(entry, tmp, &rtwsta->ba_cam_list, list) {
33258e93258fSBjoern A. Zeeb if (entry->tid != tid)
33268e93258fSBjoern A. Zeeb continue;
33278e93258fSBjoern A. Zeeb
33288e93258fSBjoern A. Zeeb idx = entry - cam_info->ba_cam_entry;
33298e93258fSBjoern A. Zeeb list_del(&entry->list);
33308e93258fSBjoern A. Zeeb
33318e93258fSBjoern A. Zeeb rtw89_core_release_bit_map(cam_info->ba_cam_map, idx);
33328e93258fSBjoern A. Zeeb *cam_idx = idx;
33338e93258fSBjoern A. Zeeb return 0;
33348e93258fSBjoern A. Zeeb }
33358e93258fSBjoern A. Zeeb
33368e93258fSBjoern A. Zeeb return -ENOENT;
33378e93258fSBjoern A. Zeeb }
33388e93258fSBjoern A. Zeeb
33398e93258fSBjoern A. Zeeb #define RTW89_TYPE_MAPPING(_type) \
33408e93258fSBjoern A. Zeeb case NL80211_IFTYPE_ ## _type: \
33418e93258fSBjoern A. Zeeb rtwvif->wifi_role = RTW89_WIFI_ROLE_ ## _type; \
33428e93258fSBjoern A. Zeeb break
rtw89_vif_type_mapping(struct ieee80211_vif * vif,bool assoc)33438e93258fSBjoern A. Zeeb void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc)
33448e93258fSBjoern A. Zeeb {
33458e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
33468e93258fSBjoern A. Zeeb
33478e93258fSBjoern A. Zeeb switch (vif->type) {
3348e2340276SBjoern A. Zeeb case NL80211_IFTYPE_STATION:
3349e2340276SBjoern A. Zeeb if (vif->p2p)
3350e2340276SBjoern A. Zeeb rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_CLIENT;
3351e2340276SBjoern A. Zeeb else
3352e2340276SBjoern A. Zeeb rtwvif->wifi_role = RTW89_WIFI_ROLE_STATION;
3353e2340276SBjoern A. Zeeb break;
3354e2340276SBjoern A. Zeeb case NL80211_IFTYPE_AP:
3355e2340276SBjoern A. Zeeb if (vif->p2p)
3356e2340276SBjoern A. Zeeb rtwvif->wifi_role = RTW89_WIFI_ROLE_P2P_GO;
3357e2340276SBjoern A. Zeeb else
3358e2340276SBjoern A. Zeeb rtwvif->wifi_role = RTW89_WIFI_ROLE_AP;
3359e2340276SBjoern A. Zeeb break;
33608e93258fSBjoern A. Zeeb RTW89_TYPE_MAPPING(ADHOC);
33618e93258fSBjoern A. Zeeb RTW89_TYPE_MAPPING(MONITOR);
33628e93258fSBjoern A. Zeeb RTW89_TYPE_MAPPING(MESH_POINT);
33638e93258fSBjoern A. Zeeb default:
33648e93258fSBjoern A. Zeeb WARN_ON(1);
33658e93258fSBjoern A. Zeeb break;
33668e93258fSBjoern A. Zeeb }
33678e93258fSBjoern A. Zeeb
33688e93258fSBjoern A. Zeeb switch (vif->type) {
33698e93258fSBjoern A. Zeeb case NL80211_IFTYPE_AP:
33708e93258fSBjoern A. Zeeb case NL80211_IFTYPE_MESH_POINT:
33718e93258fSBjoern A. Zeeb rtwvif->net_type = RTW89_NET_TYPE_AP_MODE;
33728e93258fSBjoern A. Zeeb rtwvif->self_role = RTW89_SELF_ROLE_AP;
33738e93258fSBjoern A. Zeeb break;
33748e93258fSBjoern A. Zeeb case NL80211_IFTYPE_ADHOC:
33758e93258fSBjoern A. Zeeb rtwvif->net_type = RTW89_NET_TYPE_AD_HOC;
33768e93258fSBjoern A. Zeeb rtwvif->self_role = RTW89_SELF_ROLE_CLIENT;
33778e93258fSBjoern A. Zeeb break;
33788e93258fSBjoern A. Zeeb case NL80211_IFTYPE_STATION:
33798e93258fSBjoern A. Zeeb if (assoc) {
33808e93258fSBjoern A. Zeeb rtwvif->net_type = RTW89_NET_TYPE_INFRA;
33818e93258fSBjoern A. Zeeb rtwvif->trigger = vif->bss_conf.he_support;
33828e93258fSBjoern A. Zeeb } else {
33838e93258fSBjoern A. Zeeb rtwvif->net_type = RTW89_NET_TYPE_NO_LINK;
33848e93258fSBjoern A. Zeeb rtwvif->trigger = false;
33858e93258fSBjoern A. Zeeb }
33868e93258fSBjoern A. Zeeb rtwvif->self_role = RTW89_SELF_ROLE_CLIENT;
33878e93258fSBjoern A. Zeeb rtwvif->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL;
33888e93258fSBjoern A. Zeeb break;
3389e2340276SBjoern A. Zeeb case NL80211_IFTYPE_MONITOR:
3390e2340276SBjoern A. Zeeb break;
33918e93258fSBjoern A. Zeeb default:
33928e93258fSBjoern A. Zeeb WARN_ON(1);
33938e93258fSBjoern A. Zeeb break;
33948e93258fSBjoern A. Zeeb }
33958e93258fSBjoern A. Zeeb }
33968e93258fSBjoern A. Zeeb
rtw89_core_sta_add(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)33978e93258fSBjoern A. Zeeb int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
33988e93258fSBjoern A. Zeeb struct ieee80211_vif *vif,
33998e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
34008e93258fSBjoern A. Zeeb {
34018e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
34028e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
3403e2340276SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
3404e2340276SBjoern A. Zeeb u8 ant_num = hal->ant_diversity ? 2 : rtwdev->chip->rf_path_num;
34058e93258fSBjoern A. Zeeb int i;
3406e2340276SBjoern A. Zeeb int ret;
34078e93258fSBjoern A. Zeeb
3408e2340276SBjoern A. Zeeb rtwsta->rtwdev = rtwdev;
34098e93258fSBjoern A. Zeeb rtwsta->rtwvif = rtwvif;
34108e93258fSBjoern A. Zeeb rtwsta->prev_rssi = 0;
34118e93258fSBjoern A. Zeeb INIT_LIST_HEAD(&rtwsta->ba_cam_list);
3412e2340276SBjoern A. Zeeb skb_queue_head_init(&rtwsta->roc_queue);
34138e93258fSBjoern A. Zeeb
34148e93258fSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
34158e93258fSBjoern A. Zeeb rtw89_core_txq_init(rtwdev, sta->txq[i]);
34168e93258fSBjoern A. Zeeb
34178e93258fSBjoern A. Zeeb ewma_rssi_init(&rtwsta->avg_rssi);
3418e2340276SBjoern A. Zeeb ewma_snr_init(&rtwsta->avg_snr);
3419e2340276SBjoern A. Zeeb for (i = 0; i < ant_num; i++) {
3420e2340276SBjoern A. Zeeb ewma_rssi_init(&rtwsta->rssi[i]);
3421e2340276SBjoern A. Zeeb ewma_evm_init(&rtwsta->evm_min[i]);
3422e2340276SBjoern A. Zeeb ewma_evm_init(&rtwsta->evm_max[i]);
3423e2340276SBjoern A. Zeeb }
34248e93258fSBjoern A. Zeeb
34258e93258fSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
34268e93258fSBjoern A. Zeeb /* for station mode, assign the mac_id from itself */
34278e93258fSBjoern A. Zeeb rtwsta->mac_id = rtwvif->mac_id;
34286d67aabdSBjoern A. Zeeb
34296d67aabdSBjoern A. Zeeb /* must do rtw89_reg_6ghz_recalc() before rfk channel */
34306d67aabdSBjoern A. Zeeb ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true);
34316d67aabdSBjoern A. Zeeb if (ret)
34326d67aabdSBjoern A. Zeeb return ret;
34336d67aabdSBjoern A. Zeeb
34348e93258fSBjoern A. Zeeb rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
34358e93258fSBjoern A. Zeeb BTC_ROLE_MSTS_STA_CONN_START);
34368e93258fSBjoern A. Zeeb rtw89_chip_rfk_channel(rtwdev);
34378e93258fSBjoern A. Zeeb } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
34386d67aabdSBjoern A. Zeeb rtwsta->mac_id = rtw89_acquire_mac_id(rtwdev);
3439e2340276SBjoern A. Zeeb if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM)
3440e2340276SBjoern A. Zeeb return -ENOSPC;
3441e2340276SBjoern A. Zeeb
3442e2340276SBjoern A. Zeeb ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false);
3443e2340276SBjoern A. Zeeb if (ret) {
34446d67aabdSBjoern A. Zeeb rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
3445e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c macid pause\n");
3446e2340276SBjoern A. Zeeb return ret;
3447e2340276SBjoern A. Zeeb }
3448e2340276SBjoern A. Zeeb
3449e2340276SBjoern A. Zeeb ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
3450e2340276SBjoern A. Zeeb RTW89_ROLE_CREATE);
3451e2340276SBjoern A. Zeeb if (ret) {
34526d67aabdSBjoern A. Zeeb rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
3453e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c role info\n");
3454e2340276SBjoern A. Zeeb return ret;
3455e2340276SBjoern A. Zeeb }
34566d67aabdSBjoern A. Zeeb
34576d67aabdSBjoern A. Zeeb ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta);
34586d67aabdSBjoern A. Zeeb if (ret)
34596d67aabdSBjoern A. Zeeb return ret;
34606d67aabdSBjoern A. Zeeb
34616d67aabdSBjoern A. Zeeb ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta);
34626d67aabdSBjoern A. Zeeb if (ret)
34636d67aabdSBjoern A. Zeeb return ret;
34646d67aabdSBjoern A. Zeeb
34656d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
34668e93258fSBjoern A. Zeeb }
34678e93258fSBjoern A. Zeeb
34688e93258fSBjoern A. Zeeb return 0;
34698e93258fSBjoern A. Zeeb }
34708e93258fSBjoern A. Zeeb
rtw89_core_sta_disassoc(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)34718e93258fSBjoern A. Zeeb int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev,
34728e93258fSBjoern A. Zeeb struct ieee80211_vif *vif,
34738e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
34748e93258fSBjoern A. Zeeb {
3475e2340276SBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
34768e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
34778e93258fSBjoern A. Zeeb
3478e2340276SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION)
3479e2340276SBjoern A. Zeeb rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, false);
3480e2340276SBjoern A. Zeeb
34818e93258fSBjoern A. Zeeb rtwdev->total_sta_assoc--;
3482e2340276SBjoern A. Zeeb if (sta->tdls)
3483e2340276SBjoern A. Zeeb rtwvif->tdls_peer--;
34848e93258fSBjoern A. Zeeb rtwsta->disassoc = true;
34858e93258fSBjoern A. Zeeb
34868e93258fSBjoern A. Zeeb return 0;
34878e93258fSBjoern A. Zeeb }
34888e93258fSBjoern A. Zeeb
rtw89_core_sta_disconnect(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)34898e93258fSBjoern A. Zeeb int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
34908e93258fSBjoern A. Zeeb struct ieee80211_vif *vif,
34918e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
34928e93258fSBjoern A. Zeeb {
34938e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
34948e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
34958e93258fSBjoern A. Zeeb int ret;
34968e93258fSBjoern A. Zeeb
34978e93258fSBjoern A. Zeeb rtw89_mac_bf_monitor_calc(rtwdev, sta, true);
34988e93258fSBjoern A. Zeeb rtw89_mac_bf_disassoc(rtwdev, vif, sta);
34998e93258fSBjoern A. Zeeb rtw89_core_free_sta_pending_ba(rtwdev, sta);
35008e93258fSBjoern A. Zeeb rtw89_core_free_sta_pending_forbid_ba(rtwdev, sta);
3501e2340276SBjoern A. Zeeb rtw89_core_free_sta_pending_roc_tx(rtwdev, sta);
3502e2340276SBjoern A. Zeeb
35038e93258fSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_AP || sta->tdls)
35048e93258fSBjoern A. Zeeb rtw89_cam_deinit_addr_cam(rtwdev, &rtwsta->addr_cam);
35058e93258fSBjoern A. Zeeb if (sta->tdls)
35068e93258fSBjoern A. Zeeb rtw89_cam_deinit_bssid_cam(rtwdev, &rtwsta->bssid_cam);
35078e93258fSBjoern A. Zeeb
3508e2340276SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
35098e93258fSBjoern A. Zeeb rtw89_vif_type_mapping(vif, false);
3510e2340276SBjoern A. Zeeb rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true);
3511e2340276SBjoern A. Zeeb }
35128e93258fSBjoern A. Zeeb
35136d67aabdSBjoern A. Zeeb ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
35148e93258fSBjoern A. Zeeb if (ret) {
35158e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
35168e93258fSBjoern A. Zeeb return ret;
35178e93258fSBjoern A. Zeeb }
35188e93258fSBjoern A. Zeeb
35198e93258fSBjoern A. Zeeb ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, true);
35208e93258fSBjoern A. Zeeb if (ret) {
35218e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c join info\n");
35228e93258fSBjoern A. Zeeb return ret;
35238e93258fSBjoern A. Zeeb }
35248e93258fSBjoern A. Zeeb
35258e93258fSBjoern A. Zeeb /* update cam aid mac_id net_type */
35268e93258fSBjoern A. Zeeb ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
35278e93258fSBjoern A. Zeeb if (ret) {
35288e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c cam\n");
35298e93258fSBjoern A. Zeeb return ret;
35308e93258fSBjoern A. Zeeb }
35318e93258fSBjoern A. Zeeb
35328e93258fSBjoern A. Zeeb return ret;
35338e93258fSBjoern A. Zeeb }
35348e93258fSBjoern A. Zeeb
rtw89_core_sta_assoc(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)35358e93258fSBjoern A. Zeeb int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
35368e93258fSBjoern A. Zeeb struct ieee80211_vif *vif,
35378e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
35388e93258fSBjoern A. Zeeb {
35398e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
35408e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
35418e93258fSBjoern A. Zeeb struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta);
35426d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
35436d67aabdSBjoern A. Zeeb rtwvif->sub_entity_idx);
35448e93258fSBjoern A. Zeeb int ret;
35458e93258fSBjoern A. Zeeb
35468e93258fSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
35478e93258fSBjoern A. Zeeb if (sta->tdls) {
35488e93258fSBjoern A. Zeeb ret = rtw89_cam_init_bssid_cam(rtwdev, rtwvif, bssid_cam, sta->addr);
35498e93258fSBjoern A. Zeeb if (ret) {
35508e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c init bssid cam for TDLS\n");
35518e93258fSBjoern A. Zeeb return ret;
35528e93258fSBjoern A. Zeeb }
35538e93258fSBjoern A. Zeeb }
35548e93258fSBjoern A. Zeeb
35558e93258fSBjoern A. Zeeb ret = rtw89_cam_init_addr_cam(rtwdev, &rtwsta->addr_cam, bssid_cam);
35568e93258fSBjoern A. Zeeb if (ret) {
35578e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c init addr cam\n");
35588e93258fSBjoern A. Zeeb return ret;
35598e93258fSBjoern A. Zeeb }
35608e93258fSBjoern A. Zeeb }
35618e93258fSBjoern A. Zeeb
35626d67aabdSBjoern A. Zeeb ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
35638e93258fSBjoern A. Zeeb if (ret) {
35648e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
35658e93258fSBjoern A. Zeeb return ret;
35668e93258fSBjoern A. Zeeb }
35678e93258fSBjoern A. Zeeb
35688e93258fSBjoern A. Zeeb ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, rtwsta, false);
35698e93258fSBjoern A. Zeeb if (ret) {
35708e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c join info\n");
35718e93258fSBjoern A. Zeeb return ret;
35728e93258fSBjoern A. Zeeb }
35738e93258fSBjoern A. Zeeb
35748e93258fSBjoern A. Zeeb /* update cam aid mac_id net_type */
3575e2340276SBjoern A. Zeeb ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
35768e93258fSBjoern A. Zeeb if (ret) {
35778e93258fSBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c cam\n");
35788e93258fSBjoern A. Zeeb return ret;
35798e93258fSBjoern A. Zeeb }
35808e93258fSBjoern A. Zeeb
35818e93258fSBjoern A. Zeeb rtwdev->total_sta_assoc++;
3582e2340276SBjoern A. Zeeb if (sta->tdls)
3583e2340276SBjoern A. Zeeb rtwvif->tdls_peer++;
35848e93258fSBjoern A. Zeeb rtw89_phy_ra_assoc(rtwdev, sta);
35858e93258fSBjoern A. Zeeb rtw89_mac_bf_assoc(rtwdev, vif, sta);
35868e93258fSBjoern A. Zeeb rtw89_mac_bf_monitor_calc(rtwdev, sta, false);
35878e93258fSBjoern A. Zeeb
35888e93258fSBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
3589e2340276SBjoern A. Zeeb struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
3590e2340276SBjoern A. Zeeb
3591e2340276SBjoern A. Zeeb if (bss_conf->he_support &&
3592e2340276SBjoern A. Zeeb !(bss_conf->he_oper.params & IEEE80211_HE_OPERATION_ER_SU_DISABLE))
3593e2340276SBjoern A. Zeeb rtwsta->er_cap = true;
3594e2340276SBjoern A. Zeeb
35958e93258fSBjoern A. Zeeb rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
35968e93258fSBjoern A. Zeeb BTC_ROLE_MSTS_STA_CONN_END);
35976d67aabdSBjoern A. Zeeb rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template, chan);
3598e2340276SBjoern A. Zeeb rtw89_phy_ul_tb_assoc(rtwdev, rtwvif);
3599e2340276SBjoern A. Zeeb
3600e2340276SBjoern A. Zeeb ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
3601e2340276SBjoern A. Zeeb if (ret) {
3602e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c general packet\n");
3603e2340276SBjoern A. Zeeb return ret;
3604e2340276SBjoern A. Zeeb }
36056d67aabdSBjoern A. Zeeb
36066d67aabdSBjoern A. Zeeb rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
36078e93258fSBjoern A. Zeeb }
36088e93258fSBjoern A. Zeeb
36098e93258fSBjoern A. Zeeb return ret;
36108e93258fSBjoern A. Zeeb }
36118e93258fSBjoern A. Zeeb
rtw89_core_sta_remove(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)36128e93258fSBjoern A. Zeeb int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
36138e93258fSBjoern A. Zeeb struct ieee80211_vif *vif,
36148e93258fSBjoern A. Zeeb struct ieee80211_sta *sta)
36158e93258fSBjoern A. Zeeb {
36168e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
36178e93258fSBjoern A. Zeeb struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
3618e2340276SBjoern A. Zeeb int ret;
36198e93258fSBjoern A. Zeeb
3620e2340276SBjoern A. Zeeb if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
36216d67aabdSBjoern A. Zeeb rtw89_reg_6ghz_recalc(rtwdev, rtwvif, false);
36228e93258fSBjoern A. Zeeb rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
36238e93258fSBjoern A. Zeeb BTC_ROLE_MSTS_STA_DIS_CONN);
3624e2340276SBjoern A. Zeeb } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
36256d67aabdSBjoern A. Zeeb rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
36268e93258fSBjoern A. Zeeb
3627e2340276SBjoern A. Zeeb ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
3628e2340276SBjoern A. Zeeb RTW89_ROLE_REMOVE);
3629e2340276SBjoern A. Zeeb if (ret) {
3630e2340276SBjoern A. Zeeb rtw89_warn(rtwdev, "failed to send h2c role info\n");
3631e2340276SBjoern A. Zeeb return ret;
3632e2340276SBjoern A. Zeeb }
36336d67aabdSBjoern A. Zeeb
36346d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
3635e2340276SBjoern A. Zeeb }
3636e2340276SBjoern A. Zeeb
36378e93258fSBjoern A. Zeeb return 0;
36388e93258fSBjoern A. Zeeb }
36398e93258fSBjoern A. Zeeb
_rtw89_core_set_tid_config(struct rtw89_dev * rtwdev,struct ieee80211_sta * sta,struct cfg80211_tid_cfg * tid_conf)3640e2340276SBjoern A. Zeeb static void _rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
3641e2340276SBjoern A. Zeeb struct ieee80211_sta *sta,
3642e2340276SBjoern A. Zeeb struct cfg80211_tid_cfg *tid_conf)
3643e2340276SBjoern A. Zeeb {
3644e2340276SBjoern A. Zeeb struct ieee80211_txq *txq;
3645e2340276SBjoern A. Zeeb struct rtw89_txq *rtwtxq;
3646e2340276SBjoern A. Zeeb u32 mask = tid_conf->mask;
3647e2340276SBjoern A. Zeeb u8 tids = tid_conf->tids;
3648e2340276SBjoern A. Zeeb int tids_nbit = BITS_PER_BYTE;
3649e2340276SBjoern A. Zeeb int i;
3650e2340276SBjoern A. Zeeb
3651e2340276SBjoern A. Zeeb for (i = 0; i < tids_nbit; i++, tids >>= 1) {
3652e2340276SBjoern A. Zeeb if (!tids)
3653e2340276SBjoern A. Zeeb break;
3654e2340276SBjoern A. Zeeb
3655e2340276SBjoern A. Zeeb if (!(tids & BIT(0)))
3656e2340276SBjoern A. Zeeb continue;
3657e2340276SBjoern A. Zeeb
3658e2340276SBjoern A. Zeeb txq = sta->txq[i];
3659e2340276SBjoern A. Zeeb rtwtxq = (struct rtw89_txq *)txq->drv_priv;
3660e2340276SBjoern A. Zeeb
3661e2340276SBjoern A. Zeeb if (mask & BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL)) {
3662e2340276SBjoern A. Zeeb if (tid_conf->ampdu == NL80211_TID_CONFIG_ENABLE) {
3663e2340276SBjoern A. Zeeb clear_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags);
3664e2340276SBjoern A. Zeeb } else {
3665e2340276SBjoern A. Zeeb if (test_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags))
3666e2340276SBjoern A. Zeeb ieee80211_stop_tx_ba_session(sta, txq->tid);
3667e2340276SBjoern A. Zeeb spin_lock_bh(&rtwdev->ba_lock);
3668e2340276SBjoern A. Zeeb list_del_init(&rtwtxq->list);
3669e2340276SBjoern A. Zeeb set_bit(RTW89_TXQ_F_FORBID_BA, &rtwtxq->flags);
3670e2340276SBjoern A. Zeeb spin_unlock_bh(&rtwdev->ba_lock);
3671e2340276SBjoern A. Zeeb }
3672e2340276SBjoern A. Zeeb }
3673e2340276SBjoern A. Zeeb
3674e2340276SBjoern A. Zeeb if (mask & BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL) && tids == 0xff) {
3675e2340276SBjoern A. Zeeb if (tid_conf->amsdu == NL80211_TID_CONFIG_ENABLE)
3676e2340276SBjoern A. Zeeb sta->max_amsdu_subframes = 0;
3677e2340276SBjoern A. Zeeb else
3678e2340276SBjoern A. Zeeb sta->max_amsdu_subframes = 1;
3679e2340276SBjoern A. Zeeb }
3680e2340276SBjoern A. Zeeb }
3681e2340276SBjoern A. Zeeb }
3682e2340276SBjoern A. Zeeb
rtw89_core_set_tid_config(struct rtw89_dev * rtwdev,struct ieee80211_sta * sta,struct cfg80211_tid_config * tid_config)3683e2340276SBjoern A. Zeeb void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
3684e2340276SBjoern A. Zeeb struct ieee80211_sta *sta,
3685e2340276SBjoern A. Zeeb struct cfg80211_tid_config *tid_config)
3686e2340276SBjoern A. Zeeb {
3687e2340276SBjoern A. Zeeb int i;
3688e2340276SBjoern A. Zeeb
3689e2340276SBjoern A. Zeeb for (i = 0; i < tid_config->n_tid_conf; i++)
3690e2340276SBjoern A. Zeeb _rtw89_core_set_tid_config(rtwdev, sta,
3691e2340276SBjoern A. Zeeb &tid_config->tid_conf[i]);
3692e2340276SBjoern A. Zeeb }
3693e2340276SBjoern A. Zeeb
rtw89_init_ht_cap(struct rtw89_dev * rtwdev,struct ieee80211_sta_ht_cap * ht_cap)36948e93258fSBjoern A. Zeeb static void rtw89_init_ht_cap(struct rtw89_dev *rtwdev,
36958e93258fSBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_cap)
36968e93258fSBjoern A. Zeeb {
36978e93258fSBjoern A. Zeeb static const __le16 highest[RF_PATH_MAX] = {
36988e93258fSBjoern A. Zeeb cpu_to_le16(150), cpu_to_le16(300), cpu_to_le16(450), cpu_to_le16(600),
36998e93258fSBjoern A. Zeeb };
37008e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
37018e93258fSBjoern A. Zeeb u8 nss = hal->rx_nss;
37028e93258fSBjoern A. Zeeb int i;
37038e93258fSBjoern A. Zeeb
37048e93258fSBjoern A. Zeeb ht_cap->ht_supported = true;
37058e93258fSBjoern A. Zeeb ht_cap->cap = 0;
37068e93258fSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_SGI_20 |
37078e93258fSBjoern A. Zeeb IEEE80211_HT_CAP_MAX_AMSDU |
37088e93258fSBjoern A. Zeeb IEEE80211_HT_CAP_TX_STBC |
37098e93258fSBjoern A. Zeeb (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
37108e93258fSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
37118e93258fSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
37128e93258fSBjoern A. Zeeb IEEE80211_HT_CAP_DSSSCCK40 |
37138e93258fSBjoern A. Zeeb IEEE80211_HT_CAP_SGI_40;
37148e93258fSBjoern A. Zeeb ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
37158e93258fSBjoern A. Zeeb ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
37168e93258fSBjoern A. Zeeb ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
37178e93258fSBjoern A. Zeeb for (i = 0; i < nss; i++)
37188e93258fSBjoern A. Zeeb ht_cap->mcs.rx_mask[i] = 0xFF;
37198e93258fSBjoern A. Zeeb ht_cap->mcs.rx_mask[4] = 0x01;
37208e93258fSBjoern A. Zeeb ht_cap->mcs.rx_highest = highest[nss - 1];
37218e93258fSBjoern A. Zeeb }
37228e93258fSBjoern A. Zeeb
rtw89_init_vht_cap(struct rtw89_dev * rtwdev,struct ieee80211_sta_vht_cap * vht_cap)37238e93258fSBjoern A. Zeeb static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev,
37248e93258fSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap)
37258e93258fSBjoern A. Zeeb {
37268e93258fSBjoern A. Zeeb static const __le16 highest_bw80[RF_PATH_MAX] = {
37278e93258fSBjoern A. Zeeb cpu_to_le16(433), cpu_to_le16(867), cpu_to_le16(1300), cpu_to_le16(1733),
37288e93258fSBjoern A. Zeeb };
37298e93258fSBjoern A. Zeeb static const __le16 highest_bw160[RF_PATH_MAX] = {
37308e93258fSBjoern A. Zeeb cpu_to_le16(867), cpu_to_le16(1733), cpu_to_le16(2600), cpu_to_le16(3467),
37318e93258fSBjoern A. Zeeb };
37328e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
37336d67aabdSBjoern A. Zeeb const __le16 *highest = chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160) ?
37346d67aabdSBjoern A. Zeeb highest_bw160 : highest_bw80;
37358e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
37368e93258fSBjoern A. Zeeb u16 tx_mcs_map = 0, rx_mcs_map = 0;
37378e93258fSBjoern A. Zeeb u8 sts_cap = 3;
37388e93258fSBjoern A. Zeeb int i;
37398e93258fSBjoern A. Zeeb
37408e93258fSBjoern A. Zeeb for (i = 0; i < 8; i++) {
37418e93258fSBjoern A. Zeeb if (i < hal->tx_nss)
37428e93258fSBjoern A. Zeeb tx_mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
37438e93258fSBjoern A. Zeeb else
37448e93258fSBjoern A. Zeeb tx_mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
37458e93258fSBjoern A. Zeeb if (i < hal->rx_nss)
37468e93258fSBjoern A. Zeeb rx_mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2);
37478e93258fSBjoern A. Zeeb else
37488e93258fSBjoern A. Zeeb rx_mcs_map |= IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2);
37498e93258fSBjoern A. Zeeb }
37508e93258fSBjoern A. Zeeb
37518e93258fSBjoern A. Zeeb vht_cap->vht_supported = true;
37528e93258fSBjoern A. Zeeb vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
37538e93258fSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_80 |
37548e93258fSBjoern A. Zeeb IEEE80211_VHT_CAP_RXSTBC_1 |
37558e93258fSBjoern A. Zeeb IEEE80211_VHT_CAP_HTC_VHT |
37568e93258fSBjoern A. Zeeb IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
37578e93258fSBjoern A. Zeeb 0;
37588e93258fSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
37598e93258fSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
37608e93258fSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
37618e93258fSBjoern A. Zeeb IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
37628e93258fSBjoern A. Zeeb vht_cap->cap |= sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
37636d67aabdSBjoern A. Zeeb if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
37648e93258fSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
37658e93258fSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_160;
37668e93258fSBjoern A. Zeeb vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rx_mcs_map);
37678e93258fSBjoern A. Zeeb vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(tx_mcs_map);
37688e93258fSBjoern A. Zeeb vht_cap->vht_mcs.rx_highest = highest[hal->rx_nss - 1];
37698e93258fSBjoern A. Zeeb vht_cap->vht_mcs.tx_highest = highest[hal->tx_nss - 1];
37708e93258fSBjoern A. Zeeb
37716d67aabdSBjoern A. Zeeb if (ieee80211_hw_check(rtwdev->hw, SUPPORTS_VHT_EXT_NSS_BW))
37726d67aabdSBjoern A. Zeeb vht_cap->vht_mcs.tx_highest |=
37736d67aabdSBjoern A. Zeeb cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
37746d67aabdSBjoern A. Zeeb }
37758e93258fSBjoern A. Zeeb
rtw89_init_he_cap(struct rtw89_dev * rtwdev,enum nl80211_band band,enum nl80211_iftype iftype,struct ieee80211_sband_iftype_data * iftype_data)37768e93258fSBjoern A. Zeeb static void rtw89_init_he_cap(struct rtw89_dev *rtwdev,
37778e93258fSBjoern A. Zeeb enum nl80211_band band,
37786d67aabdSBjoern A. Zeeb enum nl80211_iftype iftype,
37796d67aabdSBjoern A. Zeeb struct ieee80211_sband_iftype_data *iftype_data)
37808e93258fSBjoern A. Zeeb {
37818e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
37828e93258fSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
37838e93258fSBjoern A. Zeeb bool no_ng16 = (chip->chip_id == RTL8852A && hal->cv == CHIP_CBV) ||
37848e93258fSBjoern A. Zeeb (chip->chip_id == RTL8852B && hal->cv == CHIP_CAV);
37856d67aabdSBjoern A. Zeeb struct ieee80211_sta_he_cap *he_cap;
37866d67aabdSBjoern A. Zeeb int nss = hal->rx_nss;
37876d67aabdSBjoern A. Zeeb u8 *mac_cap_info;
37886d67aabdSBjoern A. Zeeb u8 *phy_cap_info;
37898e93258fSBjoern A. Zeeb u16 mcs_map = 0;
37908e93258fSBjoern A. Zeeb int i;
37918e93258fSBjoern A. Zeeb
37928e93258fSBjoern A. Zeeb for (i = 0; i < 8; i++) {
37938e93258fSBjoern A. Zeeb if (i < nss)
37948e93258fSBjoern A. Zeeb mcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2);
37958e93258fSBjoern A. Zeeb else
37968e93258fSBjoern A. Zeeb mcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
37978e93258fSBjoern A. Zeeb }
37988e93258fSBjoern A. Zeeb
37996d67aabdSBjoern A. Zeeb he_cap = &iftype_data->he_cap;
38008e93258fSBjoern A. Zeeb mac_cap_info = he_cap->he_cap_elem.mac_cap_info;
38018e93258fSBjoern A. Zeeb phy_cap_info = he_cap->he_cap_elem.phy_cap_info;
38028e93258fSBjoern A. Zeeb
38038e93258fSBjoern A. Zeeb he_cap->has_he = true;
38048e93258fSBjoern A. Zeeb mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE;
38056d67aabdSBjoern A. Zeeb if (iftype == NL80211_IFTYPE_STATION)
38068e93258fSBjoern A. Zeeb mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
38078e93258fSBjoern A. Zeeb mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK |
38088e93258fSBjoern A. Zeeb IEEE80211_HE_MAC_CAP2_BSR;
38098e93258fSBjoern A. Zeeb mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2;
38106d67aabdSBjoern A. Zeeb if (iftype == NL80211_IFTYPE_AP)
38118e93258fSBjoern A. Zeeb mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
38128e93258fSBjoern A. Zeeb mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS |
38138e93258fSBjoern A. Zeeb IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
38146d67aabdSBjoern A. Zeeb if (iftype == NL80211_IFTYPE_STATION)
38158e93258fSBjoern A. Zeeb mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX;
38168e93258fSBjoern A. Zeeb if (band == NL80211_BAND_2GHZ) {
38178e93258fSBjoern A. Zeeb phy_cap_info[0] =
38188e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
38198e93258fSBjoern A. Zeeb } else {
38208e93258fSBjoern A. Zeeb phy_cap_info[0] =
38218e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
38226d67aabdSBjoern A. Zeeb if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
38238e93258fSBjoern A. Zeeb phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
38248e93258fSBjoern A. Zeeb }
38258e93258fSBjoern A. Zeeb phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
38268e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
38278e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
38288e93258fSBjoern A. Zeeb phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
38298e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
38308e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
38318e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP2_DOPPLER_TX;
38328e93258fSBjoern A. Zeeb phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM;
38336d67aabdSBjoern A. Zeeb if (iftype == NL80211_IFTYPE_STATION)
38348e93258fSBjoern A. Zeeb phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM |
38358e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2;
38366d67aabdSBjoern A. Zeeb if (iftype == NL80211_IFTYPE_AP)
38378e93258fSBjoern A. Zeeb phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
38388e93258fSBjoern A. Zeeb phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
38398e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
38406d67aabdSBjoern A. Zeeb if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
38418e93258fSBjoern A. Zeeb phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
38428e93258fSBjoern A. Zeeb phy_cap_info[5] = no_ng16 ? 0 :
38438e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
38448e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
38458e93258fSBjoern A. Zeeb phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
38468e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
38478e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
38488e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE;
38498e93258fSBjoern A. Zeeb phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
38508e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
38518e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP7_MAX_NC_1;
38528e93258fSBjoern A. Zeeb phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
38538e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
38548e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996;
38556d67aabdSBjoern A. Zeeb if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
38568e93258fSBjoern A. Zeeb phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
38578e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
38588e93258fSBjoern A. Zeeb phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
38598e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
38608e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
38618e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
38628e93258fSBjoern A. Zeeb u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
38638e93258fSBjoern A. Zeeb IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
38646d67aabdSBjoern A. Zeeb if (iftype == NL80211_IFTYPE_STATION)
38658e93258fSBjoern A. Zeeb phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
38668e93258fSBjoern A. Zeeb he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map);
38678e93258fSBjoern A. Zeeb he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map);
38686d67aabdSBjoern A. Zeeb if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) {
38698e93258fSBjoern A. Zeeb he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map);
38708e93258fSBjoern A. Zeeb he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map);
38718e93258fSBjoern A. Zeeb }
38728e93258fSBjoern A. Zeeb
38738e93258fSBjoern A. Zeeb if (band == NL80211_BAND_6GHZ) {
38748e93258fSBjoern A. Zeeb __le16 capa;
38758e93258fSBjoern A. Zeeb
38768e93258fSBjoern A. Zeeb capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE,
38778e93258fSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
38788e93258fSBjoern A. Zeeb le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
38798e93258fSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
38808e93258fSBjoern A. Zeeb le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
38818e93258fSBjoern A. Zeeb IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
38826d67aabdSBjoern A. Zeeb iftype_data->he_6ghz_capa.capa = capa;
38838e93258fSBjoern A. Zeeb }
38846d67aabdSBjoern A. Zeeb }
38856d67aabdSBjoern A. Zeeb
rtw89_init_eht_cap(struct rtw89_dev * rtwdev,enum nl80211_band band,enum nl80211_iftype iftype,struct ieee80211_sband_iftype_data * iftype_data)38866d67aabdSBjoern A. Zeeb static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev,
38876d67aabdSBjoern A. Zeeb enum nl80211_band band,
38886d67aabdSBjoern A. Zeeb enum nl80211_iftype iftype,
38896d67aabdSBjoern A. Zeeb struct ieee80211_sband_iftype_data *iftype_data)
38906d67aabdSBjoern A. Zeeb {
38916d67aabdSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
38926d67aabdSBjoern A. Zeeb struct ieee80211_eht_cap_elem_fixed *eht_cap_elem;
38936d67aabdSBjoern A. Zeeb struct ieee80211_eht_mcs_nss_supp *eht_nss;
38946d67aabdSBjoern A. Zeeb struct ieee80211_sta_eht_cap *eht_cap;
38956d67aabdSBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
38966d67aabdSBjoern A. Zeeb bool support_320mhz = false;
38976d67aabdSBjoern A. Zeeb int sts = 8;
38986d67aabdSBjoern A. Zeeb u8 val;
38996d67aabdSBjoern A. Zeeb
39006d67aabdSBjoern A. Zeeb if (chip->chip_gen == RTW89_CHIP_AX)
39016d67aabdSBjoern A. Zeeb return;
39026d67aabdSBjoern A. Zeeb
39036d67aabdSBjoern A. Zeeb if (band == NL80211_BAND_6GHZ &&
39046d67aabdSBjoern A. Zeeb chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_320))
39056d67aabdSBjoern A. Zeeb support_320mhz = true;
39066d67aabdSBjoern A. Zeeb
39076d67aabdSBjoern A. Zeeb eht_cap = &iftype_data->eht_cap;
39086d67aabdSBjoern A. Zeeb eht_cap_elem = &eht_cap->eht_cap_elem;
39096d67aabdSBjoern A. Zeeb eht_nss = &eht_cap->eht_mcs_nss_supp;
39106d67aabdSBjoern A. Zeeb
39116d67aabdSBjoern A. Zeeb eht_cap->has_eht = true;
39126d67aabdSBjoern A. Zeeb
39136d67aabdSBjoern A. Zeeb eht_cap_elem->mac_cap_info[0] =
39146d67aabdSBjoern A. Zeeb u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991,
39156d67aabdSBjoern A. Zeeb IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK);
39166d67aabdSBjoern A. Zeeb eht_cap_elem->mac_cap_info[1] = 0;
39176d67aabdSBjoern A. Zeeb
39186d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[0] =
39196d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI |
39206d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
39216d67aabdSBjoern A. Zeeb if (support_320mhz)
39226d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[0] |=
39236d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
39246d67aabdSBjoern A. Zeeb
39256d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[0] |=
39266d67aabdSBjoern A. Zeeb u8_encode_bits(u8_get_bits(sts - 1, BIT(0)),
39276d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK);
39286d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[1] =
39296d67aabdSBjoern A. Zeeb u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)),
39306d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) |
39316d67aabdSBjoern A. Zeeb u8_encode_bits(sts - 1,
39326d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK);
39336d67aabdSBjoern A. Zeeb if (support_320mhz)
39346d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[1] |=
39356d67aabdSBjoern A. Zeeb u8_encode_bits(sts - 1,
39366d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
39376d67aabdSBjoern A. Zeeb
39386d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[2] = 0;
39396d67aabdSBjoern A. Zeeb
39406d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[3] =
39416d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
39426d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
39436d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
39446d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK;
39456d67aabdSBjoern A. Zeeb
39466d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[4] =
39476d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP |
39486d67aabdSBjoern A. Zeeb u8_encode_bits(1, IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK);
39496d67aabdSBjoern A. Zeeb
39506d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[5] =
39516d67aabdSBjoern A. Zeeb u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US,
39526d67aabdSBjoern A. Zeeb IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK);
39536d67aabdSBjoern A. Zeeb
39546d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[6] = 0;
39556d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[7] = 0;
39566d67aabdSBjoern A. Zeeb eht_cap_elem->phy_cap_info[8] = 0;
39576d67aabdSBjoern A. Zeeb
39586d67aabdSBjoern A. Zeeb val = u8_encode_bits(hal->rx_nss, IEEE80211_EHT_MCS_NSS_RX) |
39596d67aabdSBjoern A. Zeeb u8_encode_bits(hal->tx_nss, IEEE80211_EHT_MCS_NSS_TX);
39606d67aabdSBjoern A. Zeeb eht_nss->bw._80.rx_tx_mcs9_max_nss = val;
39616d67aabdSBjoern A. Zeeb eht_nss->bw._80.rx_tx_mcs11_max_nss = val;
39626d67aabdSBjoern A. Zeeb eht_nss->bw._80.rx_tx_mcs13_max_nss = val;
39636d67aabdSBjoern A. Zeeb eht_nss->bw._160.rx_tx_mcs9_max_nss = val;
39646d67aabdSBjoern A. Zeeb eht_nss->bw._160.rx_tx_mcs11_max_nss = val;
39656d67aabdSBjoern A. Zeeb eht_nss->bw._160.rx_tx_mcs13_max_nss = val;
39666d67aabdSBjoern A. Zeeb if (support_320mhz) {
39676d67aabdSBjoern A. Zeeb eht_nss->bw._320.rx_tx_mcs9_max_nss = val;
39686d67aabdSBjoern A. Zeeb eht_nss->bw._320.rx_tx_mcs11_max_nss = val;
39696d67aabdSBjoern A. Zeeb eht_nss->bw._320.rx_tx_mcs13_max_nss = val;
39706d67aabdSBjoern A. Zeeb }
39716d67aabdSBjoern A. Zeeb }
39726d67aabdSBjoern A. Zeeb
39736d67aabdSBjoern A. Zeeb #define RTW89_SBAND_IFTYPES_NR 2
39746d67aabdSBjoern A. Zeeb
rtw89_init_he_eht_cap(struct rtw89_dev * rtwdev,enum nl80211_band band,struct ieee80211_supported_band * sband)39756d67aabdSBjoern A. Zeeb static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev,
39766d67aabdSBjoern A. Zeeb enum nl80211_band band,
39776d67aabdSBjoern A. Zeeb struct ieee80211_supported_band *sband)
39786d67aabdSBjoern A. Zeeb {
39796d67aabdSBjoern A. Zeeb struct ieee80211_sband_iftype_data *iftype_data;
39806d67aabdSBjoern A. Zeeb enum nl80211_iftype iftype;
39816d67aabdSBjoern A. Zeeb int idx = 0;
39826d67aabdSBjoern A. Zeeb
39836d67aabdSBjoern A. Zeeb iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL);
39846d67aabdSBjoern A. Zeeb if (!iftype_data)
39856d67aabdSBjoern A. Zeeb return;
39866d67aabdSBjoern A. Zeeb
39876d67aabdSBjoern A. Zeeb for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
39886d67aabdSBjoern A. Zeeb switch (iftype) {
39896d67aabdSBjoern A. Zeeb case NL80211_IFTYPE_STATION:
39906d67aabdSBjoern A. Zeeb case NL80211_IFTYPE_AP:
39916d67aabdSBjoern A. Zeeb break;
39926d67aabdSBjoern A. Zeeb default:
39936d67aabdSBjoern A. Zeeb continue;
39946d67aabdSBjoern A. Zeeb }
39956d67aabdSBjoern A. Zeeb
39966d67aabdSBjoern A. Zeeb if (idx >= RTW89_SBAND_IFTYPES_NR) {
39976d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev, "run out of iftype_data\n");
39986d67aabdSBjoern A. Zeeb break;
39996d67aabdSBjoern A. Zeeb }
40006d67aabdSBjoern A. Zeeb
40016d67aabdSBjoern A. Zeeb iftype_data[idx].types_mask = BIT(iftype);
40026d67aabdSBjoern A. Zeeb
40036d67aabdSBjoern A. Zeeb rtw89_init_he_cap(rtwdev, band, iftype, &iftype_data[idx]);
40046d67aabdSBjoern A. Zeeb rtw89_init_eht_cap(rtwdev, band, iftype, &iftype_data[idx]);
40058e93258fSBjoern A. Zeeb
40068e93258fSBjoern A. Zeeb idx++;
40078e93258fSBjoern A. Zeeb }
40088e93258fSBjoern A. Zeeb
40096d67aabdSBjoern A. Zeeb _ieee80211_set_sband_iftype_data(sband, iftype_data, idx);
40108e93258fSBjoern A. Zeeb }
40118e93258fSBjoern A. Zeeb
rtw89_core_set_supported_band(struct rtw89_dev * rtwdev)40128e93258fSBjoern A. Zeeb static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
40138e93258fSBjoern A. Zeeb {
40148e93258fSBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
40158e93258fSBjoern A. Zeeb struct ieee80211_supported_band *sband_2ghz = NULL, *sband_5ghz = NULL;
40168e93258fSBjoern A. Zeeb struct ieee80211_supported_band *sband_6ghz = NULL;
40178e93258fSBjoern A. Zeeb u32 size = sizeof(struct ieee80211_supported_band);
40188e93258fSBjoern A. Zeeb u8 support_bands = rtwdev->chip->support_bands;
40198e93258fSBjoern A. Zeeb
40208e93258fSBjoern A. Zeeb if (support_bands & BIT(NL80211_BAND_2GHZ)) {
40218e93258fSBjoern A. Zeeb sband_2ghz = kmemdup(&rtw89_sband_2ghz, size, GFP_KERNEL);
40228e93258fSBjoern A. Zeeb if (!sband_2ghz)
40238e93258fSBjoern A. Zeeb goto err;
4024*7a5b55e3SBjoern A. Zeeb #if defined(__FreeBSD__)
4025*7a5b55e3SBjoern A. Zeeb if (rtw_ht_support)
4026*7a5b55e3SBjoern A. Zeeb #endif
40278e93258fSBjoern A. Zeeb rtw89_init_ht_cap(rtwdev, &sband_2ghz->ht_cap);
4028*7a5b55e3SBjoern A. Zeeb #if defined(__FreeBSD__)
4029*7a5b55e3SBjoern A. Zeeb if (rtw_eht_support)
4030*7a5b55e3SBjoern A. Zeeb #endif
40316d67aabdSBjoern A. Zeeb rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz);
40328e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_2GHZ] = sband_2ghz;
40338e93258fSBjoern A. Zeeb }
40348e93258fSBjoern A. Zeeb
40358e93258fSBjoern A. Zeeb if (support_bands & BIT(NL80211_BAND_5GHZ)) {
40368e93258fSBjoern A. Zeeb sband_5ghz = kmemdup(&rtw89_sband_5ghz, size, GFP_KERNEL);
40378e93258fSBjoern A. Zeeb if (!sband_5ghz)
40388e93258fSBjoern A. Zeeb goto err;
4039*7a5b55e3SBjoern A. Zeeb #if defined(__FreeBSD__)
4040*7a5b55e3SBjoern A. Zeeb if (rtw_ht_support)
4041*7a5b55e3SBjoern A. Zeeb #endif
40428e93258fSBjoern A. Zeeb rtw89_init_ht_cap(rtwdev, &sband_5ghz->ht_cap);
4043*7a5b55e3SBjoern A. Zeeb #if defined(__FreeBSD__)
4044*7a5b55e3SBjoern A. Zeeb if (rtw_vht_support)
4045*7a5b55e3SBjoern A. Zeeb #endif
40468e93258fSBjoern A. Zeeb rtw89_init_vht_cap(rtwdev, &sband_5ghz->vht_cap);
4047*7a5b55e3SBjoern A. Zeeb #if defined(__FreeBSD__)
4048*7a5b55e3SBjoern A. Zeeb if (rtw_eht_support)
4049*7a5b55e3SBjoern A. Zeeb #endif
40506d67aabdSBjoern A. Zeeb rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz);
40518e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_5GHZ] = sband_5ghz;
40528e93258fSBjoern A. Zeeb }
40538e93258fSBjoern A. Zeeb
40548e93258fSBjoern A. Zeeb if (support_bands & BIT(NL80211_BAND_6GHZ)) {
40558e93258fSBjoern A. Zeeb sband_6ghz = kmemdup(&rtw89_sband_6ghz, size, GFP_KERNEL);
40568e93258fSBjoern A. Zeeb if (!sband_6ghz)
40578e93258fSBjoern A. Zeeb goto err;
40586d67aabdSBjoern A. Zeeb rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz);
40598e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_6GHZ] = sband_6ghz;
40608e93258fSBjoern A. Zeeb }
40618e93258fSBjoern A. Zeeb
40628e93258fSBjoern A. Zeeb return 0;
40638e93258fSBjoern A. Zeeb
40648e93258fSBjoern A. Zeeb err:
40658e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
40668e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
40678e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
40688e93258fSBjoern A. Zeeb if (sband_2ghz)
40696d67aabdSBjoern A. Zeeb kfree((__force void *)sband_2ghz->iftype_data);
40708e93258fSBjoern A. Zeeb if (sband_5ghz)
40716d67aabdSBjoern A. Zeeb kfree((__force void *)sband_5ghz->iftype_data);
40728e93258fSBjoern A. Zeeb if (sband_6ghz)
40736d67aabdSBjoern A. Zeeb kfree((__force void *)sband_6ghz->iftype_data);
40748e93258fSBjoern A. Zeeb kfree(sband_2ghz);
40758e93258fSBjoern A. Zeeb kfree(sband_5ghz);
40768e93258fSBjoern A. Zeeb kfree(sband_6ghz);
40778e93258fSBjoern A. Zeeb return -ENOMEM;
40788e93258fSBjoern A. Zeeb }
40798e93258fSBjoern A. Zeeb
rtw89_core_clr_supported_band(struct rtw89_dev * rtwdev)40808e93258fSBjoern A. Zeeb static void rtw89_core_clr_supported_band(struct rtw89_dev *rtwdev)
40818e93258fSBjoern A. Zeeb {
40828e93258fSBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
40838e93258fSBjoern A. Zeeb
4084e2340276SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_2GHZ])
40856d67aabdSBjoern A. Zeeb kfree((__force void *)hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
4086e2340276SBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_5GHZ])
40876d67aabdSBjoern A. Zeeb kfree((__force void *)hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
40888e93258fSBjoern A. Zeeb if (hw->wiphy->bands[NL80211_BAND_6GHZ])
40896d67aabdSBjoern A. Zeeb kfree((__force void *)hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
40908e93258fSBjoern A. Zeeb kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
40918e93258fSBjoern A. Zeeb kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
40928e93258fSBjoern A. Zeeb kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]);
40938e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
40948e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
40958e93258fSBjoern A. Zeeb hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
40968e93258fSBjoern A. Zeeb }
40978e93258fSBjoern A. Zeeb
rtw89_core_ppdu_sts_init(struct rtw89_dev * rtwdev)40988e93258fSBjoern A. Zeeb static void rtw89_core_ppdu_sts_init(struct rtw89_dev *rtwdev)
40998e93258fSBjoern A. Zeeb {
41008e93258fSBjoern A. Zeeb int i;
41018e93258fSBjoern A. Zeeb
41028e93258fSBjoern A. Zeeb for (i = 0; i < RTW89_PHY_MAX; i++)
41038e93258fSBjoern A. Zeeb skb_queue_head_init(&rtwdev->ppdu_sts.rx_queue[i]);
41048e93258fSBjoern A. Zeeb for (i = 0; i < RTW89_PHY_MAX; i++)
41058e93258fSBjoern A. Zeeb rtwdev->ppdu_sts.curr_rx_ppdu_cnt[i] = U8_MAX;
41068e93258fSBjoern A. Zeeb }
41078e93258fSBjoern A. Zeeb
rtw89_core_update_beacon_work(struct work_struct * work)41088e93258fSBjoern A. Zeeb void rtw89_core_update_beacon_work(struct work_struct *work)
41098e93258fSBjoern A. Zeeb {
41108e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev;
41118e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = container_of(work, struct rtw89_vif,
41128e93258fSBjoern A. Zeeb update_beacon_work);
41138e93258fSBjoern A. Zeeb
41148e93258fSBjoern A. Zeeb if (rtwvif->net_type != RTW89_NET_TYPE_AP_MODE)
41158e93258fSBjoern A. Zeeb return;
41168e93258fSBjoern A. Zeeb
41178e93258fSBjoern A. Zeeb rtwdev = rtwvif->rtwdev;
41188e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
41196d67aabdSBjoern A. Zeeb rtw89_chip_h2c_update_beacon(rtwdev, rtwvif);
41208e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
41218e93258fSBjoern A. Zeeb }
41228e93258fSBjoern A. Zeeb
rtw89_wait_for_cond(struct rtw89_wait_info * wait,unsigned int cond)4123e2340276SBjoern A. Zeeb int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
4124e2340276SBjoern A. Zeeb {
4125e2340276SBjoern A. Zeeb struct completion *cmpl = &wait->completion;
41266d67aabdSBjoern A. Zeeb unsigned long time_left;
4127e2340276SBjoern A. Zeeb unsigned int cur;
4128e2340276SBjoern A. Zeeb
4129e2340276SBjoern A. Zeeb cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond);
4130e2340276SBjoern A. Zeeb if (cur != RTW89_WAIT_COND_IDLE)
4131e2340276SBjoern A. Zeeb return -EBUSY;
4132e2340276SBjoern A. Zeeb
41336d67aabdSBjoern A. Zeeb time_left = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT);
41346d67aabdSBjoern A. Zeeb if (time_left == 0) {
4135e2340276SBjoern A. Zeeb atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
4136e2340276SBjoern A. Zeeb return -ETIMEDOUT;
4137e2340276SBjoern A. Zeeb }
4138e2340276SBjoern A. Zeeb
4139e2340276SBjoern A. Zeeb if (wait->data.err)
4140e2340276SBjoern A. Zeeb return -EFAULT;
4141e2340276SBjoern A. Zeeb
4142e2340276SBjoern A. Zeeb return 0;
4143e2340276SBjoern A. Zeeb }
4144e2340276SBjoern A. Zeeb
rtw89_complete_cond(struct rtw89_wait_info * wait,unsigned int cond,const struct rtw89_completion_data * data)4145e2340276SBjoern A. Zeeb void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
4146e2340276SBjoern A. Zeeb const struct rtw89_completion_data *data)
4147e2340276SBjoern A. Zeeb {
4148e2340276SBjoern A. Zeeb unsigned int cur;
4149e2340276SBjoern A. Zeeb
4150e2340276SBjoern A. Zeeb cur = atomic_cmpxchg(&wait->cond, cond, RTW89_WAIT_COND_IDLE);
4151e2340276SBjoern A. Zeeb if (cur != cond)
4152e2340276SBjoern A. Zeeb return;
4153e2340276SBjoern A. Zeeb
4154e2340276SBjoern A. Zeeb wait->data = *data;
4155e2340276SBjoern A. Zeeb complete(&wait->completion);
4156e2340276SBjoern A. Zeeb }
4157e2340276SBjoern A. Zeeb
rtw89_core_ntfy_btc_event(struct rtw89_dev * rtwdev,enum rtw89_btc_hmsg event)41586d67aabdSBjoern A. Zeeb void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event)
41596d67aabdSBjoern A. Zeeb {
41606d67aabdSBjoern A. Zeeb u16 bt_req_len;
41616d67aabdSBjoern A. Zeeb
41626d67aabdSBjoern A. Zeeb switch (event) {
41636d67aabdSBjoern A. Zeeb case RTW89_BTC_HMSG_SET_BT_REQ_SLOT:
41646d67aabdSBjoern A. Zeeb bt_req_len = rtw89_coex_query_bt_req_len(rtwdev, RTW89_PHY_0);
41656d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_BTC,
41666d67aabdSBjoern A. Zeeb "coex updates BT req len to %d TU\n", bt_req_len);
41676d67aabdSBjoern A. Zeeb rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BT_SLOT_CHANGE);
41686d67aabdSBjoern A. Zeeb break;
41696d67aabdSBjoern A. Zeeb default:
41706d67aabdSBjoern A. Zeeb if (event < NUM_OF_RTW89_BTC_HMSG)
41716d67aabdSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_BTC,
41726d67aabdSBjoern A. Zeeb "unhandled BTC HMSG event: %d\n", event);
41736d67aabdSBjoern A. Zeeb else
41746d67aabdSBjoern A. Zeeb rtw89_warn(rtwdev,
41756d67aabdSBjoern A. Zeeb "unrecognized BTC HMSG event: %d\n", event);
41766d67aabdSBjoern A. Zeeb break;
41776d67aabdSBjoern A. Zeeb }
41786d67aabdSBjoern A. Zeeb }
41796d67aabdSBjoern A. Zeeb
rtw89_check_quirks(struct rtw89_dev * rtwdev,const struct dmi_system_id * quirks)41806d67aabdSBjoern A. Zeeb void rtw89_check_quirks(struct rtw89_dev *rtwdev, const struct dmi_system_id *quirks)
41816d67aabdSBjoern A. Zeeb {
41826d67aabdSBjoern A. Zeeb const struct dmi_system_id *match;
41836d67aabdSBjoern A. Zeeb enum rtw89_quirks quirk;
41846d67aabdSBjoern A. Zeeb
41856d67aabdSBjoern A. Zeeb if (!quirks)
41866d67aabdSBjoern A. Zeeb return;
41876d67aabdSBjoern A. Zeeb
41886d67aabdSBjoern A. Zeeb for (match = dmi_first_match(quirks); match; match = dmi_first_match(match + 1)) {
41896d67aabdSBjoern A. Zeeb quirk = (uintptr_t)match->driver_data;
41906d67aabdSBjoern A. Zeeb if (quirk >= NUM_OF_RTW89_QUIRKS)
41916d67aabdSBjoern A. Zeeb continue;
41926d67aabdSBjoern A. Zeeb
41936d67aabdSBjoern A. Zeeb set_bit(quirk, rtwdev->quirks);
41946d67aabdSBjoern A. Zeeb }
41956d67aabdSBjoern A. Zeeb }
41966d67aabdSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_check_quirks);
41976d67aabdSBjoern A. Zeeb
rtw89_core_start(struct rtw89_dev * rtwdev)41988e93258fSBjoern A. Zeeb int rtw89_core_start(struct rtw89_dev *rtwdev)
41998e93258fSBjoern A. Zeeb {
42008e93258fSBjoern A. Zeeb int ret;
42018e93258fSBjoern A. Zeeb
42028e93258fSBjoern A. Zeeb ret = rtw89_mac_init(rtwdev);
42038e93258fSBjoern A. Zeeb if (ret) {
42048e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret);
42058e93258fSBjoern A. Zeeb return ret;
42068e93258fSBjoern A. Zeeb }
42078e93258fSBjoern A. Zeeb
42088e93258fSBjoern A. Zeeb rtw89_btc_ntfy_poweron(rtwdev);
42098e93258fSBjoern A. Zeeb
42108e93258fSBjoern A. Zeeb /* efuse process */
42118e93258fSBjoern A. Zeeb
42128e93258fSBjoern A. Zeeb /* pre-config BB/RF, BB reset/RFC reset */
42136d67aabdSBjoern A. Zeeb ret = rtw89_chip_reset_bb_rf(rtwdev);
42148e93258fSBjoern A. Zeeb if (ret)
42158e93258fSBjoern A. Zeeb return ret;
42168e93258fSBjoern A. Zeeb
42178e93258fSBjoern A. Zeeb rtw89_phy_init_bb_reg(rtwdev);
42186d67aabdSBjoern A. Zeeb rtw89_chip_bb_postinit(rtwdev);
4219e2340276SBjoern A. Zeeb rtw89_phy_init_rf_reg(rtwdev, false);
42208e93258fSBjoern A. Zeeb
42218e93258fSBjoern A. Zeeb rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL);
42228e93258fSBjoern A. Zeeb
42238e93258fSBjoern A. Zeeb rtw89_phy_dm_init(rtwdev);
42248e93258fSBjoern A. Zeeb
42258e93258fSBjoern A. Zeeb rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
42268e93258fSBjoern A. Zeeb rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
42278e93258fSBjoern A. Zeeb
42286d67aabdSBjoern A. Zeeb rtw89_tas_reset(rtwdev);
42296d67aabdSBjoern A. Zeeb
42308e93258fSBjoern A. Zeeb ret = rtw89_hci_start(rtwdev);
42318e93258fSBjoern A. Zeeb if (ret) {
42328e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to start hci\n");
42338e93258fSBjoern A. Zeeb return ret;
42348e93258fSBjoern A. Zeeb }
42358e93258fSBjoern A. Zeeb
42368e93258fSBjoern A. Zeeb ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work,
42378e93258fSBjoern A. Zeeb RTW89_TRACK_WORK_PERIOD);
42388e93258fSBjoern A. Zeeb
42398e93258fSBjoern A. Zeeb set_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
42408e93258fSBjoern A. Zeeb
42416d67aabdSBjoern A. Zeeb rtw89_chip_rfk_init_late(rtwdev);
42428e93258fSBjoern A. Zeeb rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
4243e2340276SBjoern A. Zeeb rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable);
42448e93258fSBjoern A. Zeeb rtw89_fw_h2c_init_ba_cam(rtwdev);
42458e93258fSBjoern A. Zeeb
42468e93258fSBjoern A. Zeeb return 0;
42478e93258fSBjoern A. Zeeb }
42488e93258fSBjoern A. Zeeb
rtw89_core_stop(struct rtw89_dev * rtwdev)42498e93258fSBjoern A. Zeeb void rtw89_core_stop(struct rtw89_dev *rtwdev)
42508e93258fSBjoern A. Zeeb {
42518e93258fSBjoern A. Zeeb struct rtw89_btc *btc = &rtwdev->btc;
42528e93258fSBjoern A. Zeeb
42538e93258fSBjoern A. Zeeb /* Prvent to stop twice; enter_ips and ops_stop */
42548e93258fSBjoern A. Zeeb if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
42558e93258fSBjoern A. Zeeb return;
42568e93258fSBjoern A. Zeeb
42578e93258fSBjoern A. Zeeb rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_OFF);
42588e93258fSBjoern A. Zeeb
42598e93258fSBjoern A. Zeeb clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
42608e93258fSBjoern A. Zeeb
42618e93258fSBjoern A. Zeeb mutex_unlock(&rtwdev->mutex);
42628e93258fSBjoern A. Zeeb
42638e93258fSBjoern A. Zeeb cancel_work_sync(&rtwdev->c2h_work);
4264e2340276SBjoern A. Zeeb cancel_work_sync(&rtwdev->cancel_6ghz_probe_work);
42658e93258fSBjoern A. Zeeb cancel_work_sync(&btc->eapol_notify_work);
42668e93258fSBjoern A. Zeeb cancel_work_sync(&btc->arp_notify_work);
42678e93258fSBjoern A. Zeeb cancel_work_sync(&btc->dhcp_notify_work);
42688e93258fSBjoern A. Zeeb cancel_work_sync(&btc->icmp_notify_work);
42698e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
42708e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->track_work);
42716d67aabdSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->chanctx_work);
42728e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->coex_act1_work);
42738e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->coex_bt_devinfo_work);
42748e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->coex_rfk_chk_work);
42758e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->cfo_track_work);
42768e93258fSBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->forbid_ba_work);
4277e2340276SBjoern A. Zeeb cancel_delayed_work_sync(&rtwdev->antdiv_work);
42788e93258fSBjoern A. Zeeb
42798e93258fSBjoern A. Zeeb mutex_lock(&rtwdev->mutex);
42808e93258fSBjoern A. Zeeb
42818e93258fSBjoern A. Zeeb rtw89_btc_ntfy_poweroff(rtwdev);
42828e93258fSBjoern A. Zeeb rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, true);
42838e93258fSBjoern A. Zeeb rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, true);
42848e93258fSBjoern A. Zeeb rtw89_hci_stop(rtwdev);
42858e93258fSBjoern A. Zeeb rtw89_hci_deinit(rtwdev);
42868e93258fSBjoern A. Zeeb rtw89_mac_pwr_off(rtwdev);
42878e93258fSBjoern A. Zeeb rtw89_hci_reset(rtwdev);
42888e93258fSBjoern A. Zeeb }
42898e93258fSBjoern A. Zeeb
rtw89_acquire_mac_id(struct rtw89_dev * rtwdev)42906d67aabdSBjoern A. Zeeb u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev)
42916d67aabdSBjoern A. Zeeb {
42926d67aabdSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
42936d67aabdSBjoern A. Zeeb u8 mac_id_num = chip->support_macid_num;
42946d67aabdSBjoern A. Zeeb u8 mac_id;
42956d67aabdSBjoern A. Zeeb
42966d67aabdSBjoern A. Zeeb mac_id = find_first_zero_bit(rtwdev->mac_id_map, mac_id_num);
42976d67aabdSBjoern A. Zeeb if (mac_id == mac_id_num)
42986d67aabdSBjoern A. Zeeb return RTW89_MAX_MAC_ID_NUM;
42996d67aabdSBjoern A. Zeeb
43006d67aabdSBjoern A. Zeeb set_bit(mac_id, rtwdev->mac_id_map);
43016d67aabdSBjoern A. Zeeb return mac_id;
43026d67aabdSBjoern A. Zeeb }
43036d67aabdSBjoern A. Zeeb
rtw89_release_mac_id(struct rtw89_dev * rtwdev,u8 mac_id)43046d67aabdSBjoern A. Zeeb void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id)
43056d67aabdSBjoern A. Zeeb {
43066d67aabdSBjoern A. Zeeb clear_bit(mac_id, rtwdev->mac_id_map);
43076d67aabdSBjoern A. Zeeb }
43086d67aabdSBjoern A. Zeeb
rtw89_core_init(struct rtw89_dev * rtwdev)43098e93258fSBjoern A. Zeeb int rtw89_core_init(struct rtw89_dev *rtwdev)
43108e93258fSBjoern A. Zeeb {
43118e93258fSBjoern A. Zeeb struct rtw89_btc *btc = &rtwdev->btc;
43128e93258fSBjoern A. Zeeb u8 band;
43138e93258fSBjoern A. Zeeb
43148e93258fSBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->ba_list);
43158e93258fSBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->forbid_ba_list);
43168e93258fSBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->rtwvifs_list);
43178e93258fSBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->early_h2c_list);
43188e93258fSBjoern A. Zeeb for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {
43198e93258fSBjoern A. Zeeb if (!(rtwdev->chip->support_bands & BIT(band)))
43208e93258fSBjoern A. Zeeb continue;
43218e93258fSBjoern A. Zeeb INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]);
43228e93258fSBjoern A. Zeeb }
43238e93258fSBjoern A. Zeeb INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work);
43248e93258fSBjoern A. Zeeb INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
43258e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
43268e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->track_work, rtw89_track_work);
43276d67aabdSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->chanctx_work, rtw89_chanctx_work);
43288e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->coex_act1_work, rtw89_coex_act1_work);
43298e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work);
43308e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work);
43318e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work);
43328e93258fSBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work);
4333e2340276SBjoern A. Zeeb INIT_DELAYED_WORK(&rtwdev->antdiv_work, rtw89_phy_antdiv_work);
43348e93258fSBjoern A. Zeeb rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0);
4335e2340276SBjoern A. Zeeb if (!rtwdev->txq_wq)
4336e2340276SBjoern A. Zeeb return -ENOMEM;
43378e93258fSBjoern A. Zeeb spin_lock_init(&rtwdev->ba_lock);
43388e93258fSBjoern A. Zeeb spin_lock_init(&rtwdev->rpwm_lock);
43398e93258fSBjoern A. Zeeb mutex_init(&rtwdev->mutex);
43408e93258fSBjoern A. Zeeb mutex_init(&rtwdev->rf_mutex);
43418e93258fSBjoern A. Zeeb rtwdev->total_sta_assoc = 0;
43428e93258fSBjoern A. Zeeb
4343e2340276SBjoern A. Zeeb rtw89_init_wait(&rtwdev->mcc.wait);
4344e2340276SBjoern A. Zeeb rtw89_init_wait(&rtwdev->mac.fw_ofld_wait);
4345e2340276SBjoern A. Zeeb
43468e93258fSBjoern A. Zeeb INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work);
43478e93258fSBjoern A. Zeeb INIT_WORK(&rtwdev->ips_work, rtw89_ips_work);
4348e2340276SBjoern A. Zeeb INIT_WORK(&rtwdev->load_firmware_work, rtw89_load_firmware_work);
4349e2340276SBjoern A. Zeeb INIT_WORK(&rtwdev->cancel_6ghz_probe_work, rtw89_cancel_6ghz_probe_work);
4350e2340276SBjoern A. Zeeb
43518e93258fSBjoern A. Zeeb skb_queue_head_init(&rtwdev->c2h_queue);
43528e93258fSBjoern A. Zeeb rtw89_core_ppdu_sts_init(rtwdev);
43538e93258fSBjoern A. Zeeb rtw89_traffic_stats_init(rtwdev, &rtwdev->stats);
43548e93258fSBjoern A. Zeeb
43558e93258fSBjoern A. Zeeb rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR;
43566d67aabdSBjoern A. Zeeb rtwdev->dbcc_en = false;
43576d67aabdSBjoern A. Zeeb rtwdev->mlo_dbcc_mode = MLO_DBCC_NOT_SUPPORT;
43586d67aabdSBjoern A. Zeeb rtwdev->mac.qta_mode = RTW89_QTA_SCC;
43596d67aabdSBjoern A. Zeeb
43606d67aabdSBjoern A. Zeeb if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
43616d67aabdSBjoern A. Zeeb rtwdev->dbcc_en = true;
43626d67aabdSBjoern A. Zeeb rtwdev->mac.qta_mode = RTW89_QTA_DBCC;
43636d67aabdSBjoern A. Zeeb rtwdev->mlo_dbcc_mode = MLO_2_PLUS_0_1RF;
43646d67aabdSBjoern A. Zeeb }
43658e93258fSBjoern A. Zeeb
43668e93258fSBjoern A. Zeeb INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work);
43678e93258fSBjoern A. Zeeb INIT_WORK(&btc->arp_notify_work, rtw89_btc_ntfy_arp_packet_work);
43688e93258fSBjoern A. Zeeb INIT_WORK(&btc->dhcp_notify_work, rtw89_btc_ntfy_dhcp_packet_work);
43698e93258fSBjoern A. Zeeb INIT_WORK(&btc->icmp_notify_work, rtw89_btc_ntfy_icmp_packet_work);
43708e93258fSBjoern A. Zeeb
4371e2340276SBjoern A. Zeeb init_completion(&rtwdev->fw.req.completion);
43726d67aabdSBjoern A. Zeeb init_completion(&rtwdev->rfk_wait.completion);
4373e2340276SBjoern A. Zeeb
4374e2340276SBjoern A. Zeeb schedule_work(&rtwdev->load_firmware_work);
4375e2340276SBjoern A. Zeeb
43768e93258fSBjoern A. Zeeb rtw89_ser_init(rtwdev);
43778e93258fSBjoern A. Zeeb rtw89_entity_init(rtwdev);
43786d67aabdSBjoern A. Zeeb rtw89_tas_init(rtwdev);
43798e93258fSBjoern A. Zeeb
43808e93258fSBjoern A. Zeeb return 0;
43818e93258fSBjoern A. Zeeb }
43828e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_init);
43838e93258fSBjoern A. Zeeb
rtw89_core_deinit(struct rtw89_dev * rtwdev)43848e93258fSBjoern A. Zeeb void rtw89_core_deinit(struct rtw89_dev *rtwdev)
43858e93258fSBjoern A. Zeeb {
43868e93258fSBjoern A. Zeeb rtw89_ser_deinit(rtwdev);
43878e93258fSBjoern A. Zeeb rtw89_unload_firmware(rtwdev);
43888e93258fSBjoern A. Zeeb rtw89_fw_free_all_early_h2c(rtwdev);
43898e93258fSBjoern A. Zeeb
43908e93258fSBjoern A. Zeeb destroy_workqueue(rtwdev->txq_wq);
43918e93258fSBjoern A. Zeeb mutex_destroy(&rtwdev->rf_mutex);
43928e93258fSBjoern A. Zeeb mutex_destroy(&rtwdev->mutex);
43938e93258fSBjoern A. Zeeb }
43948e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_deinit);
43958e93258fSBjoern A. Zeeb
rtw89_core_scan_start(struct rtw89_dev * rtwdev,struct rtw89_vif * rtwvif,const u8 * mac_addr,bool hw_scan)43968e93258fSBjoern A. Zeeb void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
43978e93258fSBjoern A. Zeeb const u8 *mac_addr, bool hw_scan)
43988e93258fSBjoern A. Zeeb {
43996d67aabdSBjoern A. Zeeb const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
44006d67aabdSBjoern A. Zeeb rtwvif->sub_entity_idx);
44018e93258fSBjoern A. Zeeb
44028e93258fSBjoern A. Zeeb rtwdev->scanning = true;
44038e93258fSBjoern A. Zeeb rtw89_leave_lps(rtwdev);
4404e2340276SBjoern A. Zeeb if (hw_scan)
4405e2340276SBjoern A. Zeeb rtw89_leave_ips_by_hwflags(rtwdev);
44068e93258fSBjoern A. Zeeb
44078e93258fSBjoern A. Zeeb ether_addr_copy(rtwvif->mac_addr, mac_addr);
44088e93258fSBjoern A. Zeeb rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, chan->band_type);
44098e93258fSBjoern A. Zeeb rtw89_chip_rfk_scan(rtwdev, true);
44108e93258fSBjoern A. Zeeb rtw89_hci_recalc_int_mit(rtwdev);
4411e2340276SBjoern A. Zeeb rtw89_phy_config_edcca(rtwdev, true);
44128e93258fSBjoern A. Zeeb
44138e93258fSBjoern A. Zeeb rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, mac_addr);
44148e93258fSBjoern A. Zeeb }
44158e93258fSBjoern A. Zeeb
rtw89_core_scan_complete(struct rtw89_dev * rtwdev,struct ieee80211_vif * vif,bool hw_scan)44168e93258fSBjoern A. Zeeb void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
44178e93258fSBjoern A. Zeeb struct ieee80211_vif *vif, bool hw_scan)
44188e93258fSBjoern A. Zeeb {
44198e93258fSBjoern A. Zeeb struct rtw89_vif *rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
44208e93258fSBjoern A. Zeeb
44218e93258fSBjoern A. Zeeb if (!rtwvif)
44228e93258fSBjoern A. Zeeb return;
44238e93258fSBjoern A. Zeeb
44248e93258fSBjoern A. Zeeb ether_addr_copy(rtwvif->mac_addr, vif->addr);
44258e93258fSBjoern A. Zeeb rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
44268e93258fSBjoern A. Zeeb
44278e93258fSBjoern A. Zeeb rtw89_chip_rfk_scan(rtwdev, false);
44288e93258fSBjoern A. Zeeb rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0);
4429e2340276SBjoern A. Zeeb rtw89_phy_config_edcca(rtwdev, false);
44308e93258fSBjoern A. Zeeb
44318e93258fSBjoern A. Zeeb rtwdev->scanning = false;
44328e93258fSBjoern A. Zeeb rtwdev->dig.bypass_dig = true;
44338e93258fSBjoern A. Zeeb if (hw_scan && (rtwdev->hw->conf.flags & IEEE80211_CONF_IDLE))
44348e93258fSBjoern A. Zeeb ieee80211_queue_work(rtwdev->hw, &rtwdev->ips_work);
44358e93258fSBjoern A. Zeeb }
44368e93258fSBjoern A. Zeeb
rtw89_read_chip_ver(struct rtw89_dev * rtwdev)44378e93258fSBjoern A. Zeeb static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev)
44388e93258fSBjoern A. Zeeb {
44398e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
4440e2340276SBjoern A. Zeeb int ret;
4441e2340276SBjoern A. Zeeb u8 val;
44428e93258fSBjoern A. Zeeb u8 cv;
44438e93258fSBjoern A. Zeeb
44448e93258fSBjoern A. Zeeb cv = rtw89_read32_mask(rtwdev, R_AX_SYS_CFG1, B_AX_CHIP_VER_MASK);
44458e93258fSBjoern A. Zeeb if (chip->chip_id == RTL8852A && cv <= CHIP_CBV) {
44468e93258fSBjoern A. Zeeb if (rtw89_read32(rtwdev, R_AX_GPIO0_7_FUNC_SEL) == RTW89_R32_DEAD)
44478e93258fSBjoern A. Zeeb cv = CHIP_CAV;
44488e93258fSBjoern A. Zeeb else
44498e93258fSBjoern A. Zeeb cv = CHIP_CBV;
44508e93258fSBjoern A. Zeeb }
44518e93258fSBjoern A. Zeeb
44528e93258fSBjoern A. Zeeb rtwdev->hal.cv = cv;
4453e2340276SBjoern A. Zeeb
44546d67aabdSBjoern A. Zeeb if (rtw89_is_rtl885xb(rtwdev)) {
4455e2340276SBjoern A. Zeeb ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CV, &val);
4456e2340276SBjoern A. Zeeb if (ret)
4457e2340276SBjoern A. Zeeb return;
4458e2340276SBjoern A. Zeeb
4459e2340276SBjoern A. Zeeb rtwdev->hal.acv = u8_get_bits(val, XTAL_SI_ACV_MASK);
4460e2340276SBjoern A. Zeeb }
44618e93258fSBjoern A. Zeeb }
44628e93258fSBjoern A. Zeeb
rtw89_core_setup_phycap(struct rtw89_dev * rtwdev)44638e93258fSBjoern A. Zeeb static void rtw89_core_setup_phycap(struct rtw89_dev *rtwdev)
44648e93258fSBjoern A. Zeeb {
44658e93258fSBjoern A. Zeeb rtwdev->hal.support_cckpd =
44668e93258fSBjoern A. Zeeb !(rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV) &&
44678e93258fSBjoern A. Zeeb !(rtwdev->chip->chip_id == RTL8852B && rtwdev->hal.cv <= CHIP_CAV);
44688e93258fSBjoern A. Zeeb rtwdev->hal.support_igi =
44698e93258fSBjoern A. Zeeb rtwdev->chip->chip_id == RTL8852A && rtwdev->hal.cv <= CHIP_CBV;
44708e93258fSBjoern A. Zeeb }
44718e93258fSBjoern A. Zeeb
rtw89_core_setup_rfe_parms(struct rtw89_dev * rtwdev)4472e2340276SBjoern A. Zeeb static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev)
4473e2340276SBjoern A. Zeeb {
4474e2340276SBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
4475e2340276SBjoern A. Zeeb const struct rtw89_rfe_parms_conf *conf = chip->rfe_parms_conf;
4476e2340276SBjoern A. Zeeb struct rtw89_efuse *efuse = &rtwdev->efuse;
44776d67aabdSBjoern A. Zeeb const struct rtw89_rfe_parms *sel;
4478e2340276SBjoern A. Zeeb u8 rfe_type = efuse->rfe_type;
4479e2340276SBjoern A. Zeeb
44806d67aabdSBjoern A. Zeeb if (!conf) {
44816d67aabdSBjoern A. Zeeb sel = chip->dflt_parms;
4482e2340276SBjoern A. Zeeb goto out;
44836d67aabdSBjoern A. Zeeb }
4484e2340276SBjoern A. Zeeb
4485e2340276SBjoern A. Zeeb while (conf->rfe_parms) {
4486e2340276SBjoern A. Zeeb if (rfe_type == conf->rfe_type) {
44876d67aabdSBjoern A. Zeeb sel = conf->rfe_parms;
44886d67aabdSBjoern A. Zeeb goto out;
4489e2340276SBjoern A. Zeeb }
4490e2340276SBjoern A. Zeeb conf++;
4491e2340276SBjoern A. Zeeb }
4492e2340276SBjoern A. Zeeb
44936d67aabdSBjoern A. Zeeb sel = chip->dflt_parms;
44946d67aabdSBjoern A. Zeeb
4495e2340276SBjoern A. Zeeb out:
44966d67aabdSBjoern A. Zeeb rtwdev->rfe_parms = rtw89_load_rfe_data_from_fw(rtwdev, sel);
44976d67aabdSBjoern A. Zeeb rtw89_load_txpwr_table(rtwdev, rtwdev->rfe_parms->byr_tbl);
4498e2340276SBjoern A. Zeeb }
4499e2340276SBjoern A. Zeeb
rtw89_chip_efuse_info_setup(struct rtw89_dev * rtwdev)45008e93258fSBjoern A. Zeeb static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
45018e93258fSBjoern A. Zeeb {
45026d67aabdSBjoern A. Zeeb const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
45038e93258fSBjoern A. Zeeb int ret;
45048e93258fSBjoern A. Zeeb
45056d67aabdSBjoern A. Zeeb ret = rtw89_mac_partial_init(rtwdev, false);
45068e93258fSBjoern A. Zeeb if (ret)
45078e93258fSBjoern A. Zeeb return ret;
45088e93258fSBjoern A. Zeeb
45096d67aabdSBjoern A. Zeeb ret = mac->parse_efuse_map(rtwdev);
45108e93258fSBjoern A. Zeeb if (ret)
45118e93258fSBjoern A. Zeeb return ret;
45128e93258fSBjoern A. Zeeb
45136d67aabdSBjoern A. Zeeb ret = mac->parse_phycap_map(rtwdev);
45148e93258fSBjoern A. Zeeb if (ret)
45158e93258fSBjoern A. Zeeb return ret;
45168e93258fSBjoern A. Zeeb
45178e93258fSBjoern A. Zeeb ret = rtw89_mac_setup_phycap(rtwdev);
45188e93258fSBjoern A. Zeeb if (ret)
45198e93258fSBjoern A. Zeeb return ret;
45208e93258fSBjoern A. Zeeb
45218e93258fSBjoern A. Zeeb rtw89_core_setup_phycap(rtwdev);
45226d67aabdSBjoern A. Zeeb
45236d67aabdSBjoern A. Zeeb rtw89_hci_mac_pre_deinit(rtwdev);
45248e93258fSBjoern A. Zeeb
45258e93258fSBjoern A. Zeeb rtw89_mac_pwr_off(rtwdev);
45268e93258fSBjoern A. Zeeb
45278e93258fSBjoern A. Zeeb return 0;
45288e93258fSBjoern A. Zeeb }
45298e93258fSBjoern A. Zeeb
rtw89_chip_board_info_setup(struct rtw89_dev * rtwdev)45308e93258fSBjoern A. Zeeb static int rtw89_chip_board_info_setup(struct rtw89_dev *rtwdev)
45318e93258fSBjoern A. Zeeb {
45328e93258fSBjoern A. Zeeb rtw89_chip_fem_setup(rtwdev);
45338e93258fSBjoern A. Zeeb
45348e93258fSBjoern A. Zeeb return 0;
45358e93258fSBjoern A. Zeeb }
45368e93258fSBjoern A. Zeeb
rtw89_chip_info_setup(struct rtw89_dev * rtwdev)45378e93258fSBjoern A. Zeeb int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
45388e93258fSBjoern A. Zeeb {
45398e93258fSBjoern A. Zeeb int ret;
45408e93258fSBjoern A. Zeeb
45418e93258fSBjoern A. Zeeb rtw89_read_chip_ver(rtwdev);
45428e93258fSBjoern A. Zeeb
45438e93258fSBjoern A. Zeeb ret = rtw89_wait_firmware_completion(rtwdev);
45448e93258fSBjoern A. Zeeb if (ret) {
45458e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to wait firmware completion\n");
45468e93258fSBjoern A. Zeeb return ret;
45478e93258fSBjoern A. Zeeb }
45488e93258fSBjoern A. Zeeb
45498e93258fSBjoern A. Zeeb ret = rtw89_fw_recognize(rtwdev);
45508e93258fSBjoern A. Zeeb if (ret) {
45518e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to recognize firmware\n");
45528e93258fSBjoern A. Zeeb return ret;
45538e93258fSBjoern A. Zeeb }
45548e93258fSBjoern A. Zeeb
45556d67aabdSBjoern A. Zeeb ret = rtw89_chip_efuse_info_setup(rtwdev);
45566d67aabdSBjoern A. Zeeb if (ret)
45576d67aabdSBjoern A. Zeeb return ret;
45586d67aabdSBjoern A. Zeeb
4559e2340276SBjoern A. Zeeb ret = rtw89_fw_recognize_elements(rtwdev);
4560e2340276SBjoern A. Zeeb if (ret) {
4561e2340276SBjoern A. Zeeb rtw89_err(rtwdev, "failed to recognize firmware elements\n");
4562e2340276SBjoern A. Zeeb return ret;
4563e2340276SBjoern A. Zeeb }
4564e2340276SBjoern A. Zeeb
45658e93258fSBjoern A. Zeeb ret = rtw89_chip_board_info_setup(rtwdev);
45668e93258fSBjoern A. Zeeb if (ret)
45678e93258fSBjoern A. Zeeb return ret;
45688e93258fSBjoern A. Zeeb
45696d67aabdSBjoern A. Zeeb rtw89_core_setup_rfe_parms(rtwdev);
4570e2340276SBjoern A. Zeeb rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev);
4571e2340276SBjoern A. Zeeb
45728e93258fSBjoern A. Zeeb return 0;
45738e93258fSBjoern A. Zeeb }
45748e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_chip_info_setup);
45758e93258fSBjoern A. Zeeb
rtw89_core_register_hw(struct rtw89_dev * rtwdev)45768e93258fSBjoern A. Zeeb static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
45778e93258fSBjoern A. Zeeb {
45786d67aabdSBjoern A. Zeeb const struct rtw89_chip_info *chip = rtwdev->chip;
45798e93258fSBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
45808e93258fSBjoern A. Zeeb struct rtw89_efuse *efuse = &rtwdev->efuse;
4581e2340276SBjoern A. Zeeb struct rtw89_hal *hal = &rtwdev->hal;
45828e93258fSBjoern A. Zeeb int ret;
45838e93258fSBjoern A. Zeeb int tx_headroom = IEEE80211_HT_CTL_LEN;
45848e93258fSBjoern A. Zeeb
45858e93258fSBjoern A. Zeeb hw->vif_data_size = sizeof(struct rtw89_vif);
45868e93258fSBjoern A. Zeeb hw->sta_data_size = sizeof(struct rtw89_sta);
45878e93258fSBjoern A. Zeeb hw->txq_data_size = sizeof(struct rtw89_txq);
45888e93258fSBjoern A. Zeeb hw->chanctx_data_size = sizeof(struct rtw89_chanctx_cfg);
45898e93258fSBjoern A. Zeeb
45908e93258fSBjoern A. Zeeb SET_IEEE80211_PERM_ADDR(hw, efuse->addr);
45918e93258fSBjoern A. Zeeb
45928e93258fSBjoern A. Zeeb hw->extra_tx_headroom = tx_headroom;
45938e93258fSBjoern A. Zeeb hw->queues = IEEE80211_NUM_ACS;
45948e93258fSBjoern A. Zeeb hw->max_rx_aggregation_subframes = RTW89_MAX_RX_AGG_NUM;
45958e93258fSBjoern A. Zeeb hw->max_tx_aggregation_subframes = RTW89_MAX_TX_AGG_NUM;
4596e2340276SBjoern A. Zeeb hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
45978e93258fSBjoern A. Zeeb
45986d67aabdSBjoern A. Zeeb hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
45996d67aabdSBjoern A. Zeeb IEEE80211_RADIOTAP_MCS_HAVE_STBC;
46006d67aabdSBjoern A. Zeeb hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
46016d67aabdSBjoern A. Zeeb
46028e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SIGNAL_DBM);
46038e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, HAS_RATE_CONTROL);
46048e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, MFP_CAPABLE);
46058e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
46068e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, AMPDU_AGGREGATION);
46078e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, RX_INCLUDES_FCS);
46088e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, TX_AMSDU);
46098e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
46108e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
46118e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_PS);
46128e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
46138e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
46148e93258fSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
4615e2340276SBjoern A. Zeeb ieee80211_hw_set(hw, WANT_MONITOR_VIF);
46166d67aabdSBjoern A. Zeeb
46176d67aabdSBjoern A. Zeeb if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
46186d67aabdSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
46196d67aabdSBjoern A. Zeeb
4620e2340276SBjoern A. Zeeb if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw))
4621e2340276SBjoern A. Zeeb ieee80211_hw_set(hw, CONNECTION_MONITOR);
46228e93258fSBjoern A. Zeeb
46238e93258fSBjoern A. Zeeb hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
4624e2340276SBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) |
4625e2340276SBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) |
4626e2340276SBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO);
4627e2340276SBjoern A. Zeeb
4628e2340276SBjoern A. Zeeb if (hal->ant_diversity) {
4629e2340276SBjoern A. Zeeb hw->wiphy->available_antennas_tx = 0x3;
4630e2340276SBjoern A. Zeeb hw->wiphy->available_antennas_rx = 0x3;
4631e2340276SBjoern A. Zeeb } else {
46328e93258fSBjoern A. Zeeb hw->wiphy->available_antennas_tx = BIT(rtwdev->chip->rf_path_num) - 1;
46338e93258fSBjoern A. Zeeb hw->wiphy->available_antennas_rx = BIT(rtwdev->chip->rf_path_num) - 1;
4634e2340276SBjoern A. Zeeb }
46358e93258fSBjoern A. Zeeb
46368e93258fSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
4637e2340276SBjoern A. Zeeb WIPHY_FLAG_TDLS_EXTERNAL_SETUP |
46386d67aabdSBjoern A. Zeeb WIPHY_FLAG_AP_UAPSD |
46396d67aabdSBjoern A. Zeeb WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK;
46406d67aabdSBjoern A. Zeeb
46416d67aabdSBjoern A. Zeeb if (!chip->support_rnr)
46426d67aabdSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ;
46436d67aabdSBjoern A. Zeeb
46446d67aabdSBjoern A. Zeeb if (chip->chip_gen == RTW89_CHIP_BE)
46456d67aabdSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT;
46466d67aabdSBjoern A. Zeeb
46478e93258fSBjoern A. Zeeb hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
46488e93258fSBjoern A. Zeeb
46498e93258fSBjoern A. Zeeb hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID;
46508e93258fSBjoern A. Zeeb hw->wiphy->max_scan_ie_len = RTW89_SCANOFLD_MAX_IE_LEN;
46518e93258fSBjoern A. Zeeb
4652e2340276SBjoern A. Zeeb #ifdef CONFIG_PM
4653e2340276SBjoern A. Zeeb hw->wiphy->wowlan = rtwdev->chip->wowlan_stub;
4654e2340276SBjoern A. Zeeb #endif
4655e2340276SBjoern A. Zeeb
4656e2340276SBjoern A. Zeeb hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
4657e2340276SBjoern A. Zeeb hw->wiphy->tid_config_support.peer |= BIT(NL80211_TID_CONFIG_ATTR_AMPDU_CTRL);
4658e2340276SBjoern A. Zeeb hw->wiphy->tid_config_support.vif |= BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL);
4659e2340276SBjoern A. Zeeb hw->wiphy->tid_config_support.peer |= BIT(NL80211_TID_CONFIG_ATTR_AMSDU_CTRL);
4660e2340276SBjoern A. Zeeb hw->wiphy->max_remain_on_channel_duration = 1000;
4661e2340276SBjoern A. Zeeb
46628e93258fSBjoern A. Zeeb wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
46636d67aabdSBjoern A. Zeeb wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN);
46646d67aabdSBjoern A. Zeeb wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
46658e93258fSBjoern A. Zeeb
46668e93258fSBjoern A. Zeeb ret = rtw89_core_set_supported_band(rtwdev);
46678e93258fSBjoern A. Zeeb if (ret) {
46688e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to set supported band\n");
46698e93258fSBjoern A. Zeeb return ret;
46708e93258fSBjoern A. Zeeb }
46718e93258fSBjoern A. Zeeb
4672e2340276SBjoern A. Zeeb ret = rtw89_regd_setup(rtwdev);
4673e2340276SBjoern A. Zeeb if (ret) {
4674e2340276SBjoern A. Zeeb rtw89_err(rtwdev, "failed to set up regd\n");
4675e2340276SBjoern A. Zeeb goto err_free_supported_band;
4676e2340276SBjoern A. Zeeb }
4677e2340276SBjoern A. Zeeb
46788e93258fSBjoern A. Zeeb hw->wiphy->sar_capa = &rtw89_sar_capa;
46798e93258fSBjoern A. Zeeb
46808e93258fSBjoern A. Zeeb ret = ieee80211_register_hw(hw);
46818e93258fSBjoern A. Zeeb if (ret) {
46828e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to register hw\n");
4683e2340276SBjoern A. Zeeb goto err_free_supported_band;
46848e93258fSBjoern A. Zeeb }
46858e93258fSBjoern A. Zeeb
46868e93258fSBjoern A. Zeeb ret = rtw89_regd_init(rtwdev, rtw89_regd_notifier);
46878e93258fSBjoern A. Zeeb if (ret) {
46888e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to init regd\n");
4689e2340276SBjoern A. Zeeb goto err_unregister_hw;
46908e93258fSBjoern A. Zeeb }
46918e93258fSBjoern A. Zeeb
46928e93258fSBjoern A. Zeeb return 0;
46938e93258fSBjoern A. Zeeb
4694e2340276SBjoern A. Zeeb err_unregister_hw:
4695e2340276SBjoern A. Zeeb ieee80211_unregister_hw(hw);
4696e2340276SBjoern A. Zeeb err_free_supported_band:
4697e2340276SBjoern A. Zeeb rtw89_core_clr_supported_band(rtwdev);
4698e2340276SBjoern A. Zeeb
46998e93258fSBjoern A. Zeeb return ret;
47008e93258fSBjoern A. Zeeb }
47018e93258fSBjoern A. Zeeb
rtw89_core_unregister_hw(struct rtw89_dev * rtwdev)47028e93258fSBjoern A. Zeeb static void rtw89_core_unregister_hw(struct rtw89_dev *rtwdev)
47038e93258fSBjoern A. Zeeb {
47048e93258fSBjoern A. Zeeb struct ieee80211_hw *hw = rtwdev->hw;
47058e93258fSBjoern A. Zeeb
47068e93258fSBjoern A. Zeeb ieee80211_unregister_hw(hw);
47078e93258fSBjoern A. Zeeb rtw89_core_clr_supported_band(rtwdev);
47088e93258fSBjoern A. Zeeb }
47098e93258fSBjoern A. Zeeb
rtw89_core_register(struct rtw89_dev * rtwdev)47108e93258fSBjoern A. Zeeb int rtw89_core_register(struct rtw89_dev *rtwdev)
47118e93258fSBjoern A. Zeeb {
47128e93258fSBjoern A. Zeeb int ret;
47138e93258fSBjoern A. Zeeb
47148e93258fSBjoern A. Zeeb ret = rtw89_core_register_hw(rtwdev);
47158e93258fSBjoern A. Zeeb if (ret) {
47168e93258fSBjoern A. Zeeb rtw89_err(rtwdev, "failed to register core hw\n");
47178e93258fSBjoern A. Zeeb return ret;
47188e93258fSBjoern A. Zeeb }
47198e93258fSBjoern A. Zeeb
47208e93258fSBjoern A. Zeeb rtw89_debugfs_init(rtwdev);
47218e93258fSBjoern A. Zeeb
47228e93258fSBjoern A. Zeeb return 0;
47238e93258fSBjoern A. Zeeb }
47248e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_register);
47258e93258fSBjoern A. Zeeb
rtw89_core_unregister(struct rtw89_dev * rtwdev)47268e93258fSBjoern A. Zeeb void rtw89_core_unregister(struct rtw89_dev *rtwdev)
47278e93258fSBjoern A. Zeeb {
47288e93258fSBjoern A. Zeeb rtw89_core_unregister_hw(rtwdev);
47298e93258fSBjoern A. Zeeb }
47308e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_core_unregister);
47318e93258fSBjoern A. Zeeb
rtw89_alloc_ieee80211_hw(struct device * device,u32 bus_data_size,const struct rtw89_chip_info * chip)47328e93258fSBjoern A. Zeeb struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
47338e93258fSBjoern A. Zeeb u32 bus_data_size,
47348e93258fSBjoern A. Zeeb const struct rtw89_chip_info *chip)
47358e93258fSBjoern A. Zeeb {
4736e2340276SBjoern A. Zeeb struct rtw89_fw_info early_fw = {};
4737e2340276SBjoern A. Zeeb const struct firmware *firmware;
47388e93258fSBjoern A. Zeeb struct ieee80211_hw *hw;
47398e93258fSBjoern A. Zeeb struct rtw89_dev *rtwdev;
47408e93258fSBjoern A. Zeeb struct ieee80211_ops *ops;
47418e93258fSBjoern A. Zeeb u32 driver_data_size;
4742e2340276SBjoern A. Zeeb int fw_format = -1;
47438e93258fSBjoern A. Zeeb bool no_chanctx;
47448e93258fSBjoern A. Zeeb
4745e2340276SBjoern A. Zeeb firmware = rtw89_early_fw_feature_recognize(device, chip, &early_fw, &fw_format);
47468e93258fSBjoern A. Zeeb
47478e93258fSBjoern A. Zeeb ops = kmemdup(&rtw89_ops, sizeof(rtw89_ops), GFP_KERNEL);
47488e93258fSBjoern A. Zeeb if (!ops)
47498e93258fSBjoern A. Zeeb goto err;
47508e93258fSBjoern A. Zeeb
47518e93258fSBjoern A. Zeeb no_chanctx = chip->support_chanctx_num == 0 ||
4752e2340276SBjoern A. Zeeb !RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &early_fw) ||
4753e2340276SBjoern A. Zeeb !RTW89_CHK_FW_FEATURE(BEACON_FILTER, &early_fw);
47548e93258fSBjoern A. Zeeb
47558e93258fSBjoern A. Zeeb if (no_chanctx) {
47566d67aabdSBjoern A. Zeeb ops->add_chanctx = ieee80211_emulate_add_chanctx;
47576d67aabdSBjoern A. Zeeb ops->remove_chanctx = ieee80211_emulate_remove_chanctx;
47586d67aabdSBjoern A. Zeeb ops->change_chanctx = ieee80211_emulate_change_chanctx;
47596d67aabdSBjoern A. Zeeb ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx;
47608e93258fSBjoern A. Zeeb ops->assign_vif_chanctx = NULL;
47618e93258fSBjoern A. Zeeb ops->unassign_vif_chanctx = NULL;
4762e2340276SBjoern A. Zeeb ops->remain_on_channel = NULL;
4763e2340276SBjoern A. Zeeb ops->cancel_remain_on_channel = NULL;
47648e93258fSBjoern A. Zeeb }
47658e93258fSBjoern A. Zeeb
47668e93258fSBjoern A. Zeeb driver_data_size = sizeof(struct rtw89_dev) + bus_data_size;
47678e93258fSBjoern A. Zeeb hw = ieee80211_alloc_hw(driver_data_size, ops);
47688e93258fSBjoern A. Zeeb if (!hw)
47698e93258fSBjoern A. Zeeb goto err;
47708e93258fSBjoern A. Zeeb
4771e2340276SBjoern A. Zeeb hw->wiphy->iface_combinations = rtw89_iface_combs;
47726d67aabdSBjoern A. Zeeb
47736d67aabdSBjoern A. Zeeb if (no_chanctx || chip->support_chanctx_num == 1)
47746d67aabdSBjoern A. Zeeb hw->wiphy->n_iface_combinations = 1;
47756d67aabdSBjoern A. Zeeb else
4776e2340276SBjoern A. Zeeb hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw89_iface_combs);
4777e2340276SBjoern A. Zeeb
47788e93258fSBjoern A. Zeeb rtwdev = hw->priv;
47798e93258fSBjoern A. Zeeb rtwdev->hw = hw;
47808e93258fSBjoern A. Zeeb rtwdev->dev = device;
47818e93258fSBjoern A. Zeeb rtwdev->ops = ops;
47828e93258fSBjoern A. Zeeb rtwdev->chip = chip;
4783e2340276SBjoern A. Zeeb rtwdev->fw.req.firmware = firmware;
4784e2340276SBjoern A. Zeeb rtwdev->fw.fw_format = fw_format;
47858e93258fSBjoern A. Zeeb
47868e93258fSBjoern A. Zeeb rtw89_debug(rtwdev, RTW89_DBG_FW, "probe driver %s chanctx\n",
47878e93258fSBjoern A. Zeeb no_chanctx ? "without" : "with");
47888e93258fSBjoern A. Zeeb
47898e93258fSBjoern A. Zeeb return rtwdev;
47908e93258fSBjoern A. Zeeb
47918e93258fSBjoern A. Zeeb err:
47928e93258fSBjoern A. Zeeb kfree(ops);
4793e2340276SBjoern A. Zeeb release_firmware(firmware);
47948e93258fSBjoern A. Zeeb return NULL;
47958e93258fSBjoern A. Zeeb }
47968e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw);
47978e93258fSBjoern A. Zeeb
rtw89_free_ieee80211_hw(struct rtw89_dev * rtwdev)47988e93258fSBjoern A. Zeeb void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev)
47998e93258fSBjoern A. Zeeb {
48008e93258fSBjoern A. Zeeb kfree(rtwdev->ops);
48016d67aabdSBjoern A. Zeeb kfree(rtwdev->rfe_data);
4802e2340276SBjoern A. Zeeb release_firmware(rtwdev->fw.req.firmware);
48038e93258fSBjoern A. Zeeb ieee80211_free_hw(rtwdev->hw);
48048e93258fSBjoern A. Zeeb }
48058e93258fSBjoern A. Zeeb EXPORT_SYMBOL(rtw89_free_ieee80211_hw);
48068e93258fSBjoern A. Zeeb
48078e93258fSBjoern A. Zeeb MODULE_AUTHOR("Realtek Corporation");
48088e93258fSBjoern A. Zeeb MODULE_DESCRIPTION("Realtek 802.11ax wireless core module");
48098e93258fSBjoern A. Zeeb MODULE_LICENSE("Dual BSD/GPL");
4810