xref: /freebsd/sys/contrib/dev/mediatek/mt76/mac80211.c (revision cbb3ec25236ba72f91cbdf23f8b78b9d1af0cedf)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /*
36c92544dSBjoern A. Zeeb  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
46c92544dSBjoern A. Zeeb  */
56c92544dSBjoern A. Zeeb #include <linux/sched.h>
66c92544dSBjoern A. Zeeb #if defined(CONFIG_OF)
76c92544dSBjoern A. Zeeb #include <linux/of.h>
86c92544dSBjoern A. Zeeb #endif
9*cbb3ec25SBjoern A. Zeeb #include <net/page_pool.h>
106c92544dSBjoern A. Zeeb #if defined(__FreeBSD__)
116c92544dSBjoern A. Zeeb #include <linux/math64.h>
12*cbb3ec25SBjoern A. Zeeb #include <linux/numa.h>
136c92544dSBjoern A. Zeeb #endif
146c92544dSBjoern A. Zeeb #include "mt76.h"
156c92544dSBjoern A. Zeeb 
166c92544dSBjoern A. Zeeb #define CHAN2G(_idx, _freq) {			\
176c92544dSBjoern A. Zeeb 	.band = NL80211_BAND_2GHZ,		\
186c92544dSBjoern A. Zeeb 	.center_freq = (_freq),			\
196c92544dSBjoern A. Zeeb 	.hw_value = (_idx),			\
206c92544dSBjoern A. Zeeb 	.max_power = 30,			\
216c92544dSBjoern A. Zeeb }
226c92544dSBjoern A. Zeeb 
236c92544dSBjoern A. Zeeb #define CHAN5G(_idx, _freq) {			\
246c92544dSBjoern A. Zeeb 	.band = NL80211_BAND_5GHZ,		\
256c92544dSBjoern A. Zeeb 	.center_freq = (_freq),			\
266c92544dSBjoern A. Zeeb 	.hw_value = (_idx),			\
276c92544dSBjoern A. Zeeb 	.max_power = 30,			\
286c92544dSBjoern A. Zeeb }
296c92544dSBjoern A. Zeeb 
306c92544dSBjoern A. Zeeb #define CHAN6G(_idx, _freq) {			\
316c92544dSBjoern A. Zeeb 	.band = NL80211_BAND_6GHZ,		\
326c92544dSBjoern A. Zeeb 	.center_freq = (_freq),			\
336c92544dSBjoern A. Zeeb 	.hw_value = (_idx),			\
346c92544dSBjoern A. Zeeb 	.max_power = 30,			\
356c92544dSBjoern A. Zeeb }
366c92544dSBjoern A. Zeeb 
376c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_2ghz[] = {
386c92544dSBjoern A. Zeeb 	CHAN2G(1, 2412),
396c92544dSBjoern A. Zeeb 	CHAN2G(2, 2417),
406c92544dSBjoern A. Zeeb 	CHAN2G(3, 2422),
416c92544dSBjoern A. Zeeb 	CHAN2G(4, 2427),
426c92544dSBjoern A. Zeeb 	CHAN2G(5, 2432),
436c92544dSBjoern A. Zeeb 	CHAN2G(6, 2437),
446c92544dSBjoern A. Zeeb 	CHAN2G(7, 2442),
456c92544dSBjoern A. Zeeb 	CHAN2G(8, 2447),
466c92544dSBjoern A. Zeeb 	CHAN2G(9, 2452),
476c92544dSBjoern A. Zeeb 	CHAN2G(10, 2457),
486c92544dSBjoern A. Zeeb 	CHAN2G(11, 2462),
496c92544dSBjoern A. Zeeb 	CHAN2G(12, 2467),
506c92544dSBjoern A. Zeeb 	CHAN2G(13, 2472),
516c92544dSBjoern A. Zeeb 	CHAN2G(14, 2484),
526c92544dSBjoern A. Zeeb };
536c92544dSBjoern A. Zeeb 
546c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_5ghz[] = {
556c92544dSBjoern A. Zeeb 	CHAN5G(36, 5180),
566c92544dSBjoern A. Zeeb 	CHAN5G(40, 5200),
576c92544dSBjoern A. Zeeb 	CHAN5G(44, 5220),
586c92544dSBjoern A. Zeeb 	CHAN5G(48, 5240),
596c92544dSBjoern A. Zeeb 
606c92544dSBjoern A. Zeeb 	CHAN5G(52, 5260),
616c92544dSBjoern A. Zeeb 	CHAN5G(56, 5280),
626c92544dSBjoern A. Zeeb 	CHAN5G(60, 5300),
636c92544dSBjoern A. Zeeb 	CHAN5G(64, 5320),
646c92544dSBjoern A. Zeeb 
656c92544dSBjoern A. Zeeb 	CHAN5G(100, 5500),
666c92544dSBjoern A. Zeeb 	CHAN5G(104, 5520),
676c92544dSBjoern A. Zeeb 	CHAN5G(108, 5540),
686c92544dSBjoern A. Zeeb 	CHAN5G(112, 5560),
696c92544dSBjoern A. Zeeb 	CHAN5G(116, 5580),
706c92544dSBjoern A. Zeeb 	CHAN5G(120, 5600),
716c92544dSBjoern A. Zeeb 	CHAN5G(124, 5620),
726c92544dSBjoern A. Zeeb 	CHAN5G(128, 5640),
736c92544dSBjoern A. Zeeb 	CHAN5G(132, 5660),
746c92544dSBjoern A. Zeeb 	CHAN5G(136, 5680),
756c92544dSBjoern A. Zeeb 	CHAN5G(140, 5700),
766c92544dSBjoern A. Zeeb 	CHAN5G(144, 5720),
776c92544dSBjoern A. Zeeb 
786c92544dSBjoern A. Zeeb 	CHAN5G(149, 5745),
796c92544dSBjoern A. Zeeb 	CHAN5G(153, 5765),
806c92544dSBjoern A. Zeeb 	CHAN5G(157, 5785),
816c92544dSBjoern A. Zeeb 	CHAN5G(161, 5805),
826c92544dSBjoern A. Zeeb 	CHAN5G(165, 5825),
836c92544dSBjoern A. Zeeb 	CHAN5G(169, 5845),
846c92544dSBjoern A. Zeeb 	CHAN5G(173, 5865),
85*cbb3ec25SBjoern A. Zeeb 	CHAN5G(177, 5885),
866c92544dSBjoern A. Zeeb };
876c92544dSBjoern A. Zeeb 
886c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_6ghz[] = {
896c92544dSBjoern A. Zeeb 	/* UNII-5 */
906c92544dSBjoern A. Zeeb 	CHAN6G(1, 5955),
916c92544dSBjoern A. Zeeb 	CHAN6G(5, 5975),
926c92544dSBjoern A. Zeeb 	CHAN6G(9, 5995),
936c92544dSBjoern A. Zeeb 	CHAN6G(13, 6015),
946c92544dSBjoern A. Zeeb 	CHAN6G(17, 6035),
956c92544dSBjoern A. Zeeb 	CHAN6G(21, 6055),
966c92544dSBjoern A. Zeeb 	CHAN6G(25, 6075),
976c92544dSBjoern A. Zeeb 	CHAN6G(29, 6095),
986c92544dSBjoern A. Zeeb 	CHAN6G(33, 6115),
996c92544dSBjoern A. Zeeb 	CHAN6G(37, 6135),
1006c92544dSBjoern A. Zeeb 	CHAN6G(41, 6155),
1016c92544dSBjoern A. Zeeb 	CHAN6G(45, 6175),
1026c92544dSBjoern A. Zeeb 	CHAN6G(49, 6195),
1036c92544dSBjoern A. Zeeb 	CHAN6G(53, 6215),
1046c92544dSBjoern A. Zeeb 	CHAN6G(57, 6235),
1056c92544dSBjoern A. Zeeb 	CHAN6G(61, 6255),
1066c92544dSBjoern A. Zeeb 	CHAN6G(65, 6275),
1076c92544dSBjoern A. Zeeb 	CHAN6G(69, 6295),
1086c92544dSBjoern A. Zeeb 	CHAN6G(73, 6315),
1096c92544dSBjoern A. Zeeb 	CHAN6G(77, 6335),
1106c92544dSBjoern A. Zeeb 	CHAN6G(81, 6355),
1116c92544dSBjoern A. Zeeb 	CHAN6G(85, 6375),
1126c92544dSBjoern A. Zeeb 	CHAN6G(89, 6395),
1136c92544dSBjoern A. Zeeb 	CHAN6G(93, 6415),
1146c92544dSBjoern A. Zeeb 	/* UNII-6 */
1156c92544dSBjoern A. Zeeb 	CHAN6G(97, 6435),
1166c92544dSBjoern A. Zeeb 	CHAN6G(101, 6455),
1176c92544dSBjoern A. Zeeb 	CHAN6G(105, 6475),
1186c92544dSBjoern A. Zeeb 	CHAN6G(109, 6495),
1196c92544dSBjoern A. Zeeb 	CHAN6G(113, 6515),
1206c92544dSBjoern A. Zeeb 	CHAN6G(117, 6535),
1216c92544dSBjoern A. Zeeb 	/* UNII-7 */
1226c92544dSBjoern A. Zeeb 	CHAN6G(121, 6555),
1236c92544dSBjoern A. Zeeb 	CHAN6G(125, 6575),
1246c92544dSBjoern A. Zeeb 	CHAN6G(129, 6595),
1256c92544dSBjoern A. Zeeb 	CHAN6G(133, 6615),
1266c92544dSBjoern A. Zeeb 	CHAN6G(137, 6635),
1276c92544dSBjoern A. Zeeb 	CHAN6G(141, 6655),
1286c92544dSBjoern A. Zeeb 	CHAN6G(145, 6675),
1296c92544dSBjoern A. Zeeb 	CHAN6G(149, 6695),
1306c92544dSBjoern A. Zeeb 	CHAN6G(153, 6715),
1316c92544dSBjoern A. Zeeb 	CHAN6G(157, 6735),
1326c92544dSBjoern A. Zeeb 	CHAN6G(161, 6755),
1336c92544dSBjoern A. Zeeb 	CHAN6G(165, 6775),
1346c92544dSBjoern A. Zeeb 	CHAN6G(169, 6795),
1356c92544dSBjoern A. Zeeb 	CHAN6G(173, 6815),
1366c92544dSBjoern A. Zeeb 	CHAN6G(177, 6835),
1376c92544dSBjoern A. Zeeb 	CHAN6G(181, 6855),
1386c92544dSBjoern A. Zeeb 	CHAN6G(185, 6875),
1396c92544dSBjoern A. Zeeb 	/* UNII-8 */
1406c92544dSBjoern A. Zeeb 	CHAN6G(189, 6895),
1416c92544dSBjoern A. Zeeb 	CHAN6G(193, 6915),
1426c92544dSBjoern A. Zeeb 	CHAN6G(197, 6935),
1436c92544dSBjoern A. Zeeb 	CHAN6G(201, 6955),
1446c92544dSBjoern A. Zeeb 	CHAN6G(205, 6975),
1456c92544dSBjoern A. Zeeb 	CHAN6G(209, 6995),
1466c92544dSBjoern A. Zeeb 	CHAN6G(213, 7015),
1476c92544dSBjoern A. Zeeb 	CHAN6G(217, 7035),
1486c92544dSBjoern A. Zeeb 	CHAN6G(221, 7055),
1496c92544dSBjoern A. Zeeb 	CHAN6G(225, 7075),
1506c92544dSBjoern A. Zeeb 	CHAN6G(229, 7095),
1516c92544dSBjoern A. Zeeb 	CHAN6G(233, 7115),
1526c92544dSBjoern A. Zeeb };
1536c92544dSBjoern A. Zeeb 
1546c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
1556c92544dSBjoern A. Zeeb static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
1566c92544dSBjoern A. Zeeb 	{ .throughput =   0 * 1024, .blink_time = 334 },
1576c92544dSBjoern A. Zeeb 	{ .throughput =   1 * 1024, .blink_time = 260 },
1586c92544dSBjoern A. Zeeb 	{ .throughput =   5 * 1024, .blink_time = 220 },
1596c92544dSBjoern A. Zeeb 	{ .throughput =  10 * 1024, .blink_time = 190 },
1606c92544dSBjoern A. Zeeb 	{ .throughput =  20 * 1024, .blink_time = 170 },
1616c92544dSBjoern A. Zeeb 	{ .throughput =  50 * 1024, .blink_time = 150 },
1626c92544dSBjoern A. Zeeb 	{ .throughput =  70 * 1024, .blink_time = 130 },
1636c92544dSBjoern A. Zeeb 	{ .throughput = 100 * 1024, .blink_time = 110 },
1646c92544dSBjoern A. Zeeb 	{ .throughput = 200 * 1024, .blink_time =  80 },
1656c92544dSBjoern A. Zeeb 	{ .throughput = 300 * 1024, .blink_time =  50 },
1666c92544dSBjoern A. Zeeb };
1676c92544dSBjoern A. Zeeb #endif
1686c92544dSBjoern A. Zeeb 
1696c92544dSBjoern A. Zeeb struct ieee80211_rate mt76_rates[] = {
1706c92544dSBjoern A. Zeeb 	CCK_RATE(0, 10),
1716c92544dSBjoern A. Zeeb 	CCK_RATE(1, 20),
1726c92544dSBjoern A. Zeeb 	CCK_RATE(2, 55),
1736c92544dSBjoern A. Zeeb 	CCK_RATE(3, 110),
1746c92544dSBjoern A. Zeeb 	OFDM_RATE(11, 60),
1756c92544dSBjoern A. Zeeb 	OFDM_RATE(15, 90),
1766c92544dSBjoern A. Zeeb 	OFDM_RATE(10, 120),
1776c92544dSBjoern A. Zeeb 	OFDM_RATE(14, 180),
1786c92544dSBjoern A. Zeeb 	OFDM_RATE(9,  240),
1796c92544dSBjoern A. Zeeb 	OFDM_RATE(13, 360),
1806c92544dSBjoern A. Zeeb 	OFDM_RATE(8,  480),
1816c92544dSBjoern A. Zeeb 	OFDM_RATE(12, 540),
1826c92544dSBjoern A. Zeeb };
1836c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rates);
1846c92544dSBjoern A. Zeeb 
1856c92544dSBjoern A. Zeeb static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
1866c92544dSBjoern A. Zeeb 	{ .start_freq = 2402, .end_freq = 2494, },
1876c92544dSBjoern A. Zeeb 	{ .start_freq = 5150, .end_freq = 5350, },
1886c92544dSBjoern A. Zeeb 	{ .start_freq = 5350, .end_freq = 5470, },
1896c92544dSBjoern A. Zeeb 	{ .start_freq = 5470, .end_freq = 5725, },
1906c92544dSBjoern A. Zeeb 	{ .start_freq = 5725, .end_freq = 5950, },
1916c92544dSBjoern A. Zeeb 	{ .start_freq = 5945, .end_freq = 6165, },
1926c92544dSBjoern A. Zeeb 	{ .start_freq = 6165, .end_freq = 6405, },
1936c92544dSBjoern A. Zeeb 	{ .start_freq = 6405, .end_freq = 6525, },
1946c92544dSBjoern A. Zeeb 	{ .start_freq = 6525, .end_freq = 6705, },
1956c92544dSBjoern A. Zeeb 	{ .start_freq = 6705, .end_freq = 6865, },
1966c92544dSBjoern A. Zeeb 	{ .start_freq = 6865, .end_freq = 7125, },
1976c92544dSBjoern A. Zeeb };
1986c92544dSBjoern A. Zeeb 
1996c92544dSBjoern A. Zeeb static const struct cfg80211_sar_capa mt76_sar_capa = {
2006c92544dSBjoern A. Zeeb 	.type = NL80211_SAR_TYPE_POWER,
2016c92544dSBjoern A. Zeeb 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
2026c92544dSBjoern A. Zeeb 	.freq_ranges = &mt76_sar_freq_ranges[0],
2036c92544dSBjoern A. Zeeb };
2046c92544dSBjoern A. Zeeb 
2056c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
206*cbb3ec25SBjoern A. Zeeb static int mt76_led_init(struct mt76_phy *phy)
2076c92544dSBjoern A. Zeeb {
208*cbb3ec25SBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
209*cbb3ec25SBjoern A. Zeeb 	struct ieee80211_hw *hw = phy->hw;
2106c92544dSBjoern A. Zeeb 
211*cbb3ec25SBjoern A. Zeeb 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
2126c92544dSBjoern A. Zeeb 		return 0;
2136c92544dSBjoern A. Zeeb 
214*cbb3ec25SBjoern A. Zeeb 	snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
215*cbb3ec25SBjoern A. Zeeb 		 wiphy_name(hw->wiphy));
2166c92544dSBjoern A. Zeeb 
217*cbb3ec25SBjoern A. Zeeb 	phy->leds.cdev.name = phy->leds.name;
218*cbb3ec25SBjoern A. Zeeb 	phy->leds.cdev.default_trigger =
2196c92544dSBjoern A. Zeeb 		ieee80211_create_tpt_led_trigger(hw,
2206c92544dSBjoern A. Zeeb 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
2216c92544dSBjoern A. Zeeb 					mt76_tpt_blink,
2226c92544dSBjoern A. Zeeb 					ARRAY_SIZE(mt76_tpt_blink));
2236c92544dSBjoern A. Zeeb 
2246c92544dSBjoern A. Zeeb #if defined(CONFIG_OF)
225*cbb3ec25SBjoern A. Zeeb 	if (phy == &dev->phy) {
226*cbb3ec25SBjoern A. Zeeb 		struct device_node *np = dev->dev->of_node;
227*cbb3ec25SBjoern A. Zeeb 
2286c92544dSBjoern A. Zeeb 		np = of_get_child_by_name(np, "led");
2296c92544dSBjoern A. Zeeb 		if (np) {
230*cbb3ec25SBjoern A. Zeeb 			int led_pin;
231*cbb3ec25SBjoern A. Zeeb 
2326c92544dSBjoern A. Zeeb 			if (!of_property_read_u32(np, "led-sources", &led_pin))
233*cbb3ec25SBjoern A. Zeeb 				phy->leds.pin = led_pin;
234*cbb3ec25SBjoern A. Zeeb 			phy->leds.al = of_property_read_bool(np,
235*cbb3ec25SBjoern A. Zeeb 							     "led-active-low");
2366c92544dSBjoern A. Zeeb 			of_node_put(np);
2376c92544dSBjoern A. Zeeb 		}
238*cbb3ec25SBjoern A. Zeeb 	}
2396c92544dSBjoern A. Zeeb #endif
2406c92544dSBjoern A. Zeeb 
241*cbb3ec25SBjoern A. Zeeb 	return led_classdev_register(dev->dev, &phy->leds.cdev);
2426c92544dSBjoern A. Zeeb }
2436c92544dSBjoern A. Zeeb 
244*cbb3ec25SBjoern A. Zeeb static void mt76_led_cleanup(struct mt76_phy *phy)
2456c92544dSBjoern A. Zeeb {
246*cbb3ec25SBjoern A. Zeeb 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
2476c92544dSBjoern A. Zeeb 		return;
2486c92544dSBjoern A. Zeeb 
249*cbb3ec25SBjoern A. Zeeb 	led_classdev_unregister(&phy->leds.cdev);
2506c92544dSBjoern A. Zeeb }
2516c92544dSBjoern A. Zeeb #endif
2526c92544dSBjoern A. Zeeb 
2536c92544dSBjoern A. Zeeb static void mt76_init_stream_cap(struct mt76_phy *phy,
2546c92544dSBjoern A. Zeeb 				 struct ieee80211_supported_band *sband,
2556c92544dSBjoern A. Zeeb 				 bool vht)
2566c92544dSBjoern A. Zeeb {
2576c92544dSBjoern A. Zeeb 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
2586c92544dSBjoern A. Zeeb 	int i, nstream = hweight8(phy->antenna_mask);
2596c92544dSBjoern A. Zeeb 	struct ieee80211_sta_vht_cap *vht_cap;
2606c92544dSBjoern A. Zeeb 	u16 mcs_map = 0;
2616c92544dSBjoern A. Zeeb 
2626c92544dSBjoern A. Zeeb 	if (nstream > 1)
2636c92544dSBjoern A. Zeeb 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
2646c92544dSBjoern A. Zeeb 	else
2656c92544dSBjoern A. Zeeb 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
2666c92544dSBjoern A. Zeeb 
2676c92544dSBjoern A. Zeeb 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
2686c92544dSBjoern A. Zeeb 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
2696c92544dSBjoern A. Zeeb 
2706c92544dSBjoern A. Zeeb 	if (!vht)
2716c92544dSBjoern A. Zeeb 		return;
2726c92544dSBjoern A. Zeeb 
2736c92544dSBjoern A. Zeeb 	vht_cap = &sband->vht_cap;
2746c92544dSBjoern A. Zeeb 	if (nstream > 1)
2756c92544dSBjoern A. Zeeb 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
2766c92544dSBjoern A. Zeeb 	else
2776c92544dSBjoern A. Zeeb 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
2786c92544dSBjoern A. Zeeb 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
2796c92544dSBjoern A. Zeeb 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
2806c92544dSBjoern A. Zeeb 
2816c92544dSBjoern A. Zeeb 	for (i = 0; i < 8; i++) {
2826c92544dSBjoern A. Zeeb 		if (i < nstream)
2836c92544dSBjoern A. Zeeb 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
2846c92544dSBjoern A. Zeeb 		else
2856c92544dSBjoern A. Zeeb 			mcs_map |=
2866c92544dSBjoern A. Zeeb 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
2876c92544dSBjoern A. Zeeb 	}
2886c92544dSBjoern A. Zeeb 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
2896c92544dSBjoern A. Zeeb 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
2906c92544dSBjoern A. Zeeb 	if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
2916c92544dSBjoern A. Zeeb 		vht_cap->vht_mcs.tx_highest |=
2926c92544dSBjoern A. Zeeb 				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
2936c92544dSBjoern A. Zeeb }
2946c92544dSBjoern A. Zeeb 
2956c92544dSBjoern A. Zeeb void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2966c92544dSBjoern A. Zeeb {
2976c92544dSBjoern A. Zeeb 	if (phy->cap.has_2ghz)
2986c92544dSBjoern A. Zeeb 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
2996c92544dSBjoern A. Zeeb 	if (phy->cap.has_5ghz)
3006c92544dSBjoern A. Zeeb 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
3016c92544dSBjoern A. Zeeb 	if (phy->cap.has_6ghz)
3026c92544dSBjoern A. Zeeb 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
3036c92544dSBjoern A. Zeeb }
3046c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
3056c92544dSBjoern A. Zeeb 
3066c92544dSBjoern A. Zeeb static int
3076c92544dSBjoern A. Zeeb mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
3086c92544dSBjoern A. Zeeb 		const struct ieee80211_channel *chan, int n_chan,
3096c92544dSBjoern A. Zeeb 		struct ieee80211_rate *rates, int n_rates,
3106c92544dSBjoern A. Zeeb 		bool ht, bool vht)
3116c92544dSBjoern A. Zeeb {
3126c92544dSBjoern A. Zeeb 	struct ieee80211_supported_band *sband = &msband->sband;
3136c92544dSBjoern A. Zeeb 	struct ieee80211_sta_vht_cap *vht_cap;
3146c92544dSBjoern A. Zeeb 	struct ieee80211_sta_ht_cap *ht_cap;
3156c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
3166c92544dSBjoern A. Zeeb 	void *chanlist;
3176c92544dSBjoern A. Zeeb 	int size;
3186c92544dSBjoern A. Zeeb 
3196c92544dSBjoern A. Zeeb 	size = n_chan * sizeof(*chan);
3206c92544dSBjoern A. Zeeb 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
3216c92544dSBjoern A. Zeeb 	if (!chanlist)
3226c92544dSBjoern A. Zeeb 		return -ENOMEM;
3236c92544dSBjoern A. Zeeb 
3246c92544dSBjoern A. Zeeb 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
3256c92544dSBjoern A. Zeeb 				    GFP_KERNEL);
3266c92544dSBjoern A. Zeeb 	if (!msband->chan)
3276c92544dSBjoern A. Zeeb 		return -ENOMEM;
3286c92544dSBjoern A. Zeeb 
3296c92544dSBjoern A. Zeeb 	sband->channels = chanlist;
3306c92544dSBjoern A. Zeeb 	sband->n_channels = n_chan;
3316c92544dSBjoern A. Zeeb 	sband->bitrates = rates;
3326c92544dSBjoern A. Zeeb 	sband->n_bitrates = n_rates;
3336c92544dSBjoern A. Zeeb 
3346c92544dSBjoern A. Zeeb 	if (!ht)
3356c92544dSBjoern A. Zeeb 		return 0;
3366c92544dSBjoern A. Zeeb 
3376c92544dSBjoern A. Zeeb 	ht_cap = &sband->ht_cap;
3386c92544dSBjoern A. Zeeb 	ht_cap->ht_supported = true;
3396c92544dSBjoern A. Zeeb 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
3406c92544dSBjoern A. Zeeb 		       IEEE80211_HT_CAP_GRN_FLD |
3416c92544dSBjoern A. Zeeb 		       IEEE80211_HT_CAP_SGI_20 |
3426c92544dSBjoern A. Zeeb 		       IEEE80211_HT_CAP_SGI_40 |
3436c92544dSBjoern A. Zeeb 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
3446c92544dSBjoern A. Zeeb 
3456c92544dSBjoern A. Zeeb 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
3466c92544dSBjoern A. Zeeb 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
3476c92544dSBjoern A. Zeeb 
3486c92544dSBjoern A. Zeeb 	mt76_init_stream_cap(phy, sband, vht);
3496c92544dSBjoern A. Zeeb 
3506c92544dSBjoern A. Zeeb 	if (!vht)
3516c92544dSBjoern A. Zeeb 		return 0;
3526c92544dSBjoern A. Zeeb 
3536c92544dSBjoern A. Zeeb 	vht_cap = &sband->vht_cap;
3546c92544dSBjoern A. Zeeb 	vht_cap->vht_supported = true;
3556c92544dSBjoern A. Zeeb 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
3566c92544dSBjoern A. Zeeb 			IEEE80211_VHT_CAP_RXSTBC_1 |
3576c92544dSBjoern A. Zeeb 			IEEE80211_VHT_CAP_SHORT_GI_80 |
3586c92544dSBjoern A. Zeeb 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
3596c92544dSBjoern A. Zeeb 
3606c92544dSBjoern A. Zeeb 	return 0;
3616c92544dSBjoern A. Zeeb }
3626c92544dSBjoern A. Zeeb 
3636c92544dSBjoern A. Zeeb static int
3646c92544dSBjoern A. Zeeb mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3656c92544dSBjoern A. Zeeb 		   int n_rates)
3666c92544dSBjoern A. Zeeb {
3676c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
3686c92544dSBjoern A. Zeeb 
3696c92544dSBjoern A. Zeeb 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
3706c92544dSBjoern A. Zeeb 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
3716c92544dSBjoern A. Zeeb 			       n_rates, true, false);
3726c92544dSBjoern A. Zeeb }
3736c92544dSBjoern A. Zeeb 
3746c92544dSBjoern A. Zeeb static int
3756c92544dSBjoern A. Zeeb mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3766c92544dSBjoern A. Zeeb 		   int n_rates, bool vht)
3776c92544dSBjoern A. Zeeb {
3786c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
3796c92544dSBjoern A. Zeeb 
3806c92544dSBjoern A. Zeeb 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
3816c92544dSBjoern A. Zeeb 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
3826c92544dSBjoern A. Zeeb 			       n_rates, true, vht);
3836c92544dSBjoern A. Zeeb }
3846c92544dSBjoern A. Zeeb 
3856c92544dSBjoern A. Zeeb static int
3866c92544dSBjoern A. Zeeb mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3876c92544dSBjoern A. Zeeb 		   int n_rates)
3886c92544dSBjoern A. Zeeb {
3896c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
3906c92544dSBjoern A. Zeeb 
3916c92544dSBjoern A. Zeeb 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
3926c92544dSBjoern A. Zeeb 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
3936c92544dSBjoern A. Zeeb 			       n_rates, false, false);
3946c92544dSBjoern A. Zeeb }
3956c92544dSBjoern A. Zeeb 
3966c92544dSBjoern A. Zeeb static void
3976c92544dSBjoern A. Zeeb mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
3986c92544dSBjoern A. Zeeb 		 enum nl80211_band band)
3996c92544dSBjoern A. Zeeb {
4006c92544dSBjoern A. Zeeb 	struct ieee80211_supported_band *sband = &msband->sband;
4016c92544dSBjoern A. Zeeb 	bool found = false;
4026c92544dSBjoern A. Zeeb 	int i;
4036c92544dSBjoern A. Zeeb 
4046c92544dSBjoern A. Zeeb 	if (!sband)
4056c92544dSBjoern A. Zeeb 		return;
4066c92544dSBjoern A. Zeeb 
4076c92544dSBjoern A. Zeeb 	for (i = 0; i < sband->n_channels; i++) {
4086c92544dSBjoern A. Zeeb 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
4096c92544dSBjoern A. Zeeb 			continue;
4106c92544dSBjoern A. Zeeb 
4116c92544dSBjoern A. Zeeb 		found = true;
4126c92544dSBjoern A. Zeeb 		break;
4136c92544dSBjoern A. Zeeb 	}
4146c92544dSBjoern A. Zeeb 
4156c92544dSBjoern A. Zeeb 	if (found) {
4166c92544dSBjoern A. Zeeb 		phy->chandef.chan = &sband->channels[0];
4176c92544dSBjoern A. Zeeb 		phy->chan_state = &msband->chan[0];
4186c92544dSBjoern A. Zeeb 		return;
4196c92544dSBjoern A. Zeeb 	}
4206c92544dSBjoern A. Zeeb 
4216c92544dSBjoern A. Zeeb 	sband->n_channels = 0;
4226c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[band] = NULL;
4236c92544dSBjoern A. Zeeb }
4246c92544dSBjoern A. Zeeb 
4256c92544dSBjoern A. Zeeb static int
4266c92544dSBjoern A. Zeeb mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
4276c92544dSBjoern A. Zeeb {
4286c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
4296c92544dSBjoern A. Zeeb 	struct wiphy *wiphy = hw->wiphy;
4306c92544dSBjoern A. Zeeb 
4316c92544dSBjoern A. Zeeb 	SET_IEEE80211_DEV(hw, dev->dev);
4326c92544dSBjoern A. Zeeb 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
4336c92544dSBjoern A. Zeeb 
434*cbb3ec25SBjoern A. Zeeb 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
435*cbb3ec25SBjoern A. Zeeb 			   NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
4366c92544dSBjoern A. Zeeb 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
4376c92544dSBjoern A. Zeeb 			WIPHY_FLAG_SUPPORTS_TDLS |
4386c92544dSBjoern A. Zeeb 			WIPHY_FLAG_AP_UAPSD;
4396c92544dSBjoern A. Zeeb 
4406c92544dSBjoern A. Zeeb 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
4416c92544dSBjoern A. Zeeb 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
4426c92544dSBjoern A. Zeeb 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
4436c92544dSBjoern A. Zeeb 
4446c92544dSBjoern A. Zeeb 	wiphy->available_antennas_tx = phy->antenna_mask;
4456c92544dSBjoern A. Zeeb 	wiphy->available_antennas_rx = phy->antenna_mask;
4466c92544dSBjoern A. Zeeb 
4476c92544dSBjoern A. Zeeb 	wiphy->sar_capa = &mt76_sar_capa;
4486c92544dSBjoern A. Zeeb 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
4496c92544dSBjoern A. Zeeb 				sizeof(struct mt76_freq_range_power),
4506c92544dSBjoern A. Zeeb 				GFP_KERNEL);
4516c92544dSBjoern A. Zeeb 	if (!phy->frp)
4526c92544dSBjoern A. Zeeb 		return -ENOMEM;
4536c92544dSBjoern A. Zeeb 
4546c92544dSBjoern A. Zeeb 	hw->txq_data_size = sizeof(struct mt76_txq);
4556c92544dSBjoern A. Zeeb 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
4566c92544dSBjoern A. Zeeb 
4576c92544dSBjoern A. Zeeb 	if (!hw->max_tx_fragments)
4586c92544dSBjoern A. Zeeb 		hw->max_tx_fragments = 16;
4596c92544dSBjoern A. Zeeb 
4606c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SIGNAL_DBM);
4616c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
4626c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
4636c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
4646c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
4656c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
4666c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
467*cbb3ec25SBjoern A. Zeeb 
468*cbb3ec25SBjoern A. Zeeb 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
4696c92544dSBjoern A. Zeeb 		ieee80211_hw_set(hw, TX_AMSDU);
4706c92544dSBjoern A. Zeeb 		ieee80211_hw_set(hw, TX_FRAG_LIST);
471*cbb3ec25SBjoern A. Zeeb 	}
472*cbb3ec25SBjoern A. Zeeb 
4736c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, MFP_CAPABLE);
4746c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, AP_LINK_PS);
4756c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
4766c92544dSBjoern A. Zeeb 
4776c92544dSBjoern A. Zeeb 	return 0;
4786c92544dSBjoern A. Zeeb }
4796c92544dSBjoern A. Zeeb 
4806c92544dSBjoern A. Zeeb struct mt76_phy *
4816c92544dSBjoern A. Zeeb mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
4826c92544dSBjoern A. Zeeb 	       const struct ieee80211_ops *ops, u8 band_idx)
4836c92544dSBjoern A. Zeeb {
4846c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
4856c92544dSBjoern A. Zeeb 	unsigned int phy_size;
4866c92544dSBjoern A. Zeeb 	struct mt76_phy *phy;
4876c92544dSBjoern A. Zeeb 
4886c92544dSBjoern A. Zeeb 	phy_size = ALIGN(sizeof(*phy), 8);
4896c92544dSBjoern A. Zeeb 	hw = ieee80211_alloc_hw(size + phy_size, ops);
4906c92544dSBjoern A. Zeeb 	if (!hw)
4916c92544dSBjoern A. Zeeb 		return NULL;
4926c92544dSBjoern A. Zeeb 
4936c92544dSBjoern A. Zeeb 	phy = hw->priv;
4946c92544dSBjoern A. Zeeb 	phy->dev = dev;
4956c92544dSBjoern A. Zeeb 	phy->hw = hw;
4966c92544dSBjoern A. Zeeb #if defined(__linux__)
4976c92544dSBjoern A. Zeeb 	phy->priv = hw->priv + phy_size;
4986c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
4996c92544dSBjoern A. Zeeb 	phy->priv = (u8 *)hw->priv + phy_size;
5006c92544dSBjoern A. Zeeb #endif
5016c92544dSBjoern A. Zeeb 	phy->band_idx = band_idx;
5026c92544dSBjoern A. Zeeb 
5036c92544dSBjoern A. Zeeb 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5046c92544dSBjoern A. Zeeb 	hw->wiphy->interface_modes =
5056c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_STATION) |
5066c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_AP) |
5076c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH
5086c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_MESH_POINT) |
5096c92544dSBjoern A. Zeeb #endif
5106c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5116c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_GO) |
5126c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_ADHOC);
5136c92544dSBjoern A. Zeeb 
5146c92544dSBjoern A. Zeeb 	return phy;
5156c92544dSBjoern A. Zeeb }
5166c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_phy);
5176c92544dSBjoern A. Zeeb 
5186c92544dSBjoern A. Zeeb int mt76_register_phy(struct mt76_phy *phy, bool vht,
5196c92544dSBjoern A. Zeeb 		      struct ieee80211_rate *rates, int n_rates)
5206c92544dSBjoern A. Zeeb {
5216c92544dSBjoern A. Zeeb 	int ret;
5226c92544dSBjoern A. Zeeb 
5236c92544dSBjoern A. Zeeb 	ret = mt76_phy_init(phy, phy->hw);
5246c92544dSBjoern A. Zeeb 	if (ret)
5256c92544dSBjoern A. Zeeb 		return ret;
5266c92544dSBjoern A. Zeeb 
5276c92544dSBjoern A. Zeeb 	if (phy->cap.has_2ghz) {
5286c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_2g(phy, rates, n_rates);
5296c92544dSBjoern A. Zeeb 		if (ret)
5306c92544dSBjoern A. Zeeb 			return ret;
5316c92544dSBjoern A. Zeeb 	}
5326c92544dSBjoern A. Zeeb 
5336c92544dSBjoern A. Zeeb 	if (phy->cap.has_5ghz) {
5346c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
5356c92544dSBjoern A. Zeeb 		if (ret)
5366c92544dSBjoern A. Zeeb 			return ret;
5376c92544dSBjoern A. Zeeb 	}
5386c92544dSBjoern A. Zeeb 
5396c92544dSBjoern A. Zeeb 	if (phy->cap.has_6ghz) {
5406c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
5416c92544dSBjoern A. Zeeb 		if (ret)
5426c92544dSBjoern A. Zeeb 			return ret;
5436c92544dSBjoern A. Zeeb 	}
5446c92544dSBjoern A. Zeeb 
545*cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
546*cbb3ec25SBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
547*cbb3ec25SBjoern A. Zeeb 		ret = mt76_led_init(phy);
548*cbb3ec25SBjoern A. Zeeb 		if (ret)
549*cbb3ec25SBjoern A. Zeeb 			return ret;
550*cbb3ec25SBjoern A. Zeeb 	}
551*cbb3ec25SBjoern A. Zeeb #endif
552*cbb3ec25SBjoern A. Zeeb 
5536c92544dSBjoern A. Zeeb 	wiphy_read_of_freq_limits(phy->hw->wiphy);
5546c92544dSBjoern A. Zeeb 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
5556c92544dSBjoern A. Zeeb 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
5566c92544dSBjoern A. Zeeb 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
5576c92544dSBjoern A. Zeeb 
5586c92544dSBjoern A. Zeeb 	ret = ieee80211_register_hw(phy->hw);
5596c92544dSBjoern A. Zeeb 	if (ret)
5606c92544dSBjoern A. Zeeb 		return ret;
5616c92544dSBjoern A. Zeeb 
562*cbb3ec25SBjoern A. Zeeb 	set_bit(MT76_STATE_REGISTERED, &phy->state);
5636c92544dSBjoern A. Zeeb 	phy->dev->phys[phy->band_idx] = phy;
5646c92544dSBjoern A. Zeeb 
5656c92544dSBjoern A. Zeeb 	return 0;
5666c92544dSBjoern A. Zeeb }
5676c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_phy);
5686c92544dSBjoern A. Zeeb 
5696c92544dSBjoern A. Zeeb void mt76_unregister_phy(struct mt76_phy *phy)
5706c92544dSBjoern A. Zeeb {
5716c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
5726c92544dSBjoern A. Zeeb 
573*cbb3ec25SBjoern A. Zeeb 	if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
574*cbb3ec25SBjoern A. Zeeb 		return;
575*cbb3ec25SBjoern A. Zeeb 
576*cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
577*cbb3ec25SBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS))
578*cbb3ec25SBjoern A. Zeeb 		mt76_led_cleanup(phy);
579*cbb3ec25SBjoern A. Zeeb #endif
5806c92544dSBjoern A. Zeeb 	mt76_tx_status_check(dev, true);
5816c92544dSBjoern A. Zeeb 	ieee80211_unregister_hw(phy->hw);
5826c92544dSBjoern A. Zeeb 	dev->phys[phy->band_idx] = NULL;
5836c92544dSBjoern A. Zeeb }
5846c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_phy);
5856c92544dSBjoern A. Zeeb 
586*cbb3ec25SBjoern A. Zeeb int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
587*cbb3ec25SBjoern A. Zeeb {
588*cbb3ec25SBjoern A. Zeeb 	struct page_pool_params pp_params = {
589*cbb3ec25SBjoern A. Zeeb 		.order = 0,
590*cbb3ec25SBjoern A. Zeeb 		.flags = PP_FLAG_PAGE_FRAG,
591*cbb3ec25SBjoern A. Zeeb 		.nid = NUMA_NO_NODE,
592*cbb3ec25SBjoern A. Zeeb 		.dev = dev->dma_dev,
593*cbb3ec25SBjoern A. Zeeb 	};
594*cbb3ec25SBjoern A. Zeeb 	int idx = q - dev->q_rx;
595*cbb3ec25SBjoern A. Zeeb 
596*cbb3ec25SBjoern A. Zeeb 	switch (idx) {
597*cbb3ec25SBjoern A. Zeeb 	case MT_RXQ_MAIN:
598*cbb3ec25SBjoern A. Zeeb 	case MT_RXQ_BAND1:
599*cbb3ec25SBjoern A. Zeeb 	case MT_RXQ_BAND2:
600*cbb3ec25SBjoern A. Zeeb 		pp_params.pool_size = 256;
601*cbb3ec25SBjoern A. Zeeb 		break;
602*cbb3ec25SBjoern A. Zeeb 	default:
603*cbb3ec25SBjoern A. Zeeb 		pp_params.pool_size = 16;
604*cbb3ec25SBjoern A. Zeeb 		break;
605*cbb3ec25SBjoern A. Zeeb 	}
606*cbb3ec25SBjoern A. Zeeb 
607*cbb3ec25SBjoern A. Zeeb 	if (mt76_is_mmio(dev)) {
608*cbb3ec25SBjoern A. Zeeb 		/* rely on page_pool for DMA mapping */
609*cbb3ec25SBjoern A. Zeeb 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
610*cbb3ec25SBjoern A. Zeeb 		pp_params.dma_dir = DMA_FROM_DEVICE;
611*cbb3ec25SBjoern A. Zeeb 		pp_params.max_len = PAGE_SIZE;
612*cbb3ec25SBjoern A. Zeeb 		pp_params.offset = 0;
613*cbb3ec25SBjoern A. Zeeb 	}
614*cbb3ec25SBjoern A. Zeeb 
615*cbb3ec25SBjoern A. Zeeb 	q->page_pool = page_pool_create(&pp_params);
616*cbb3ec25SBjoern A. Zeeb 	if (IS_ERR(q->page_pool)) {
617*cbb3ec25SBjoern A. Zeeb 		int err = PTR_ERR(q->page_pool);
618*cbb3ec25SBjoern A. Zeeb 
619*cbb3ec25SBjoern A. Zeeb 		q->page_pool = NULL;
620*cbb3ec25SBjoern A. Zeeb 		return err;
621*cbb3ec25SBjoern A. Zeeb 	}
622*cbb3ec25SBjoern A. Zeeb 
623*cbb3ec25SBjoern A. Zeeb 	return 0;
624*cbb3ec25SBjoern A. Zeeb }
625*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_create_page_pool);
626*cbb3ec25SBjoern A. Zeeb 
6276c92544dSBjoern A. Zeeb struct mt76_dev *
6286c92544dSBjoern A. Zeeb mt76_alloc_device(struct device *pdev, unsigned int size,
6296c92544dSBjoern A. Zeeb 		  const struct ieee80211_ops *ops,
6306c92544dSBjoern A. Zeeb 		  const struct mt76_driver_ops *drv_ops)
6316c92544dSBjoern A. Zeeb {
6326c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
6336c92544dSBjoern A. Zeeb 	struct mt76_phy *phy;
6346c92544dSBjoern A. Zeeb 	struct mt76_dev *dev;
6356c92544dSBjoern A. Zeeb 	int i;
6366c92544dSBjoern A. Zeeb 
6376c92544dSBjoern A. Zeeb 	hw = ieee80211_alloc_hw(size, ops);
6386c92544dSBjoern A. Zeeb 	if (!hw)
6396c92544dSBjoern A. Zeeb 		return NULL;
6406c92544dSBjoern A. Zeeb 
6416c92544dSBjoern A. Zeeb 	dev = hw->priv;
6426c92544dSBjoern A. Zeeb 	dev->hw = hw;
6436c92544dSBjoern A. Zeeb 	dev->dev = pdev;
6446c92544dSBjoern A. Zeeb 	dev->drv = drv_ops;
6456c92544dSBjoern A. Zeeb 	dev->dma_dev = pdev;
6466c92544dSBjoern A. Zeeb 
6476c92544dSBjoern A. Zeeb 	phy = &dev->phy;
6486c92544dSBjoern A. Zeeb 	phy->dev = dev;
6496c92544dSBjoern A. Zeeb 	phy->hw = hw;
6506c92544dSBjoern A. Zeeb 	phy->band_idx = MT_BAND0;
6516c92544dSBjoern A. Zeeb 	dev->phys[phy->band_idx] = phy;
6526c92544dSBjoern A. Zeeb 
6536c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->rx_lock);
6546c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->lock);
6556c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->cc_lock);
6566c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->status_lock);
657*cbb3ec25SBjoern A. Zeeb 	spin_lock_init(&dev->wed_lock);
6586c92544dSBjoern A. Zeeb 	mutex_init(&dev->mutex);
6596c92544dSBjoern A. Zeeb 	init_waitqueue_head(&dev->tx_wait);
6606c92544dSBjoern A. Zeeb 
6616c92544dSBjoern A. Zeeb 	skb_queue_head_init(&dev->mcu.res_q);
6626c92544dSBjoern A. Zeeb 	init_waitqueue_head(&dev->mcu.wait);
6636c92544dSBjoern A. Zeeb 	mutex_init(&dev->mcu.mutex);
6646c92544dSBjoern A. Zeeb 	dev->tx_worker.fn = mt76_tx_worker;
6656c92544dSBjoern A. Zeeb 
6666c92544dSBjoern A. Zeeb 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6676c92544dSBjoern A. Zeeb 	hw->wiphy->interface_modes =
6686c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_STATION) |
6696c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_AP) |
6706c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH
6716c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_MESH_POINT) |
6726c92544dSBjoern A. Zeeb #endif
6736c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
6746c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_GO) |
6756c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_ADHOC);
6766c92544dSBjoern A. Zeeb 
6776c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->token_lock);
6786c92544dSBjoern A. Zeeb 	idr_init(&dev->token);
6796c92544dSBjoern A. Zeeb 
680*cbb3ec25SBjoern A. Zeeb 	spin_lock_init(&dev->rx_token_lock);
681*cbb3ec25SBjoern A. Zeeb 	idr_init(&dev->rx_token);
682*cbb3ec25SBjoern A. Zeeb 
6836c92544dSBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->wcid_list);
684*cbb3ec25SBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->sta_poll_list);
685*cbb3ec25SBjoern A. Zeeb 	spin_lock_init(&dev->sta_poll_lock);
6866c92544dSBjoern A. Zeeb 
6876c92544dSBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->txwi_cache);
688*cbb3ec25SBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->rxwi_cache);
6896c92544dSBjoern A. Zeeb 	dev->token_size = dev->drv->token_size;
6906c92544dSBjoern A. Zeeb 
6916c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
6926c92544dSBjoern A. Zeeb 		skb_queue_head_init(&dev->rx_skb[i]);
6936c92544dSBjoern A. Zeeb 
6946c92544dSBjoern A. Zeeb 	dev->wq = alloc_ordered_workqueue("mt76", 0);
6956c92544dSBjoern A. Zeeb 	if (!dev->wq) {
6966c92544dSBjoern A. Zeeb 		ieee80211_free_hw(hw);
6976c92544dSBjoern A. Zeeb 		return NULL;
6986c92544dSBjoern A. Zeeb 	}
6996c92544dSBjoern A. Zeeb 
7006c92544dSBjoern A. Zeeb 	return dev;
7016c92544dSBjoern A. Zeeb }
7026c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_device);
7036c92544dSBjoern A. Zeeb 
7046c92544dSBjoern A. Zeeb int mt76_register_device(struct mt76_dev *dev, bool vht,
7056c92544dSBjoern A. Zeeb 			 struct ieee80211_rate *rates, int n_rates)
7066c92544dSBjoern A. Zeeb {
7076c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = dev->hw;
7086c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = &dev->phy;
7096c92544dSBjoern A. Zeeb 	int ret;
7106c92544dSBjoern A. Zeeb 
7116c92544dSBjoern A. Zeeb 	dev_set_drvdata(dev->dev, dev);
7126c92544dSBjoern A. Zeeb 	ret = mt76_phy_init(phy, hw);
7136c92544dSBjoern A. Zeeb 	if (ret)
7146c92544dSBjoern A. Zeeb 		return ret;
7156c92544dSBjoern A. Zeeb 
7166c92544dSBjoern A. Zeeb 	if (phy->cap.has_2ghz) {
7176c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_2g(phy, rates, n_rates);
7186c92544dSBjoern A. Zeeb 		if (ret)
7196c92544dSBjoern A. Zeeb 			return ret;
7206c92544dSBjoern A. Zeeb 	}
7216c92544dSBjoern A. Zeeb 
7226c92544dSBjoern A. Zeeb 	if (phy->cap.has_5ghz) {
7236c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
7246c92544dSBjoern A. Zeeb 		if (ret)
7256c92544dSBjoern A. Zeeb 			return ret;
7266c92544dSBjoern A. Zeeb 	}
7276c92544dSBjoern A. Zeeb 
7286c92544dSBjoern A. Zeeb 	if (phy->cap.has_6ghz) {
7296c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
7306c92544dSBjoern A. Zeeb 		if (ret)
7316c92544dSBjoern A. Zeeb 			return ret;
7326c92544dSBjoern A. Zeeb 	}
7336c92544dSBjoern A. Zeeb 
7346c92544dSBjoern A. Zeeb 	wiphy_read_of_freq_limits(hw->wiphy);
7356c92544dSBjoern A. Zeeb 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
7366c92544dSBjoern A. Zeeb 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
7376c92544dSBjoern A. Zeeb 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
7386c92544dSBjoern A. Zeeb 
7396c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
7406c92544dSBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
741*cbb3ec25SBjoern A. Zeeb 		ret = mt76_led_init(phy);
7426c92544dSBjoern A. Zeeb 		if (ret)
7436c92544dSBjoern A. Zeeb 			return ret;
7446c92544dSBjoern A. Zeeb 	}
7456c92544dSBjoern A. Zeeb #endif
7466c92544dSBjoern A. Zeeb 
7476c92544dSBjoern A. Zeeb 	ret = ieee80211_register_hw(hw);
7486c92544dSBjoern A. Zeeb 	if (ret)
7496c92544dSBjoern A. Zeeb 		return ret;
7506c92544dSBjoern A. Zeeb 
7516c92544dSBjoern A. Zeeb 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
752*cbb3ec25SBjoern A. Zeeb 	set_bit(MT76_STATE_REGISTERED, &phy->state);
7536c92544dSBjoern A. Zeeb 	sched_set_fifo_low(dev->tx_worker.task);
7546c92544dSBjoern A. Zeeb 
7556c92544dSBjoern A. Zeeb 	return 0;
7566c92544dSBjoern A. Zeeb }
7576c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_device);
7586c92544dSBjoern A. Zeeb 
7596c92544dSBjoern A. Zeeb void mt76_unregister_device(struct mt76_dev *dev)
7606c92544dSBjoern A. Zeeb {
761*cbb3ec25SBjoern A. Zeeb #if defined(__linux__)
7626c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = dev->hw;
763*cbb3ec25SBjoern A. Zeeb #endif
764*cbb3ec25SBjoern A. Zeeb 
765*cbb3ec25SBjoern A. Zeeb 	if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
766*cbb3ec25SBjoern A. Zeeb 		return;
7676c92544dSBjoern A. Zeeb 
7686c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
7696c92544dSBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS))
770*cbb3ec25SBjoern A. Zeeb 		mt76_led_cleanup(&dev->phy);
7716c92544dSBjoern A. Zeeb #endif
7726c92544dSBjoern A. Zeeb 	mt76_tx_status_check(dev, true);
773*cbb3ec25SBjoern A. Zeeb #if defined(__linux__)
7746c92544dSBjoern A. Zeeb 	ieee80211_unregister_hw(hw);
775*cbb3ec25SBjoern A. Zeeb #elif defined(__FreeBSD__)
776*cbb3ec25SBjoern A. Zeeb 	ieee80211_unregister_hw(dev->hw);
777*cbb3ec25SBjoern A. Zeeb #endif
7786c92544dSBjoern A. Zeeb }
7796c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_device);
7806c92544dSBjoern A. Zeeb 
7816c92544dSBjoern A. Zeeb void mt76_free_device(struct mt76_dev *dev)
7826c92544dSBjoern A. Zeeb {
7836c92544dSBjoern A. Zeeb 	mt76_worker_teardown(&dev->tx_worker);
7846c92544dSBjoern A. Zeeb 	if (dev->wq) {
7856c92544dSBjoern A. Zeeb 		destroy_workqueue(dev->wq);
7866c92544dSBjoern A. Zeeb 		dev->wq = NULL;
7876c92544dSBjoern A. Zeeb 	}
7886c92544dSBjoern A. Zeeb 	ieee80211_free_hw(dev->hw);
7896c92544dSBjoern A. Zeeb }
7906c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_free_device);
7916c92544dSBjoern A. Zeeb 
7926c92544dSBjoern A. Zeeb static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
7936c92544dSBjoern A. Zeeb {
7946c92544dSBjoern A. Zeeb 	struct sk_buff *skb = phy->rx_amsdu[q].head;
7956c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
7966c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
7976c92544dSBjoern A. Zeeb 
7986c92544dSBjoern A. Zeeb 	phy->rx_amsdu[q].head = NULL;
7996c92544dSBjoern A. Zeeb 	phy->rx_amsdu[q].tail = NULL;
8006c92544dSBjoern A. Zeeb 
8016c92544dSBjoern A. Zeeb 	/*
8026c92544dSBjoern A. Zeeb 	 * Validate if the amsdu has a proper first subframe.
8036c92544dSBjoern A. Zeeb 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
8046c92544dSBjoern A. Zeeb 	 * flag of the QoS header gets flipped. In such cases, the first
8056c92544dSBjoern A. Zeeb 	 * subframe has a LLC/SNAP header in the location of the destination
8066c92544dSBjoern A. Zeeb 	 * address.
8076c92544dSBjoern A. Zeeb 	 */
8086c92544dSBjoern A. Zeeb 	if (skb_shinfo(skb)->frag_list) {
8096c92544dSBjoern A. Zeeb 		int offset = 0;
8106c92544dSBjoern A. Zeeb 
8116c92544dSBjoern A. Zeeb 		if (!(status->flag & RX_FLAG_8023)) {
8126c92544dSBjoern A. Zeeb 			offset = ieee80211_get_hdrlen_from_skb(skb);
8136c92544dSBjoern A. Zeeb 
8146c92544dSBjoern A. Zeeb 			if ((status->flag &
8156c92544dSBjoern A. Zeeb 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
8166c92544dSBjoern A. Zeeb 			    RX_FLAG_DECRYPTED)
8176c92544dSBjoern A. Zeeb 				offset += 8;
8186c92544dSBjoern A. Zeeb 		}
8196c92544dSBjoern A. Zeeb 
8206c92544dSBjoern A. Zeeb 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
8216c92544dSBjoern A. Zeeb 			dev_kfree_skb(skb);
8226c92544dSBjoern A. Zeeb 			return;
8236c92544dSBjoern A. Zeeb 		}
8246c92544dSBjoern A. Zeeb 	}
8256c92544dSBjoern A. Zeeb 	__skb_queue_tail(&dev->rx_skb[q], skb);
8266c92544dSBjoern A. Zeeb }
8276c92544dSBjoern A. Zeeb 
8286c92544dSBjoern A. Zeeb static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
8296c92544dSBjoern A. Zeeb 				  struct sk_buff *skb)
8306c92544dSBjoern A. Zeeb {
8316c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8326c92544dSBjoern A. Zeeb 
8336c92544dSBjoern A. Zeeb 	if (phy->rx_amsdu[q].head &&
8346c92544dSBjoern A. Zeeb 	    (!status->amsdu || status->first_amsdu ||
8356c92544dSBjoern A. Zeeb 	     status->seqno != phy->rx_amsdu[q].seqno))
8366c92544dSBjoern A. Zeeb 		mt76_rx_release_amsdu(phy, q);
8376c92544dSBjoern A. Zeeb 
8386c92544dSBjoern A. Zeeb 	if (!phy->rx_amsdu[q].head) {
8396c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
8406c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].seqno = status->seqno;
8416c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].head = skb;
8426c92544dSBjoern A. Zeeb 	} else {
8436c92544dSBjoern A. Zeeb 		*phy->rx_amsdu[q].tail = skb;
8446c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].tail = &skb->next;
8456c92544dSBjoern A. Zeeb 	}
8466c92544dSBjoern A. Zeeb 
8476c92544dSBjoern A. Zeeb 	if (!status->amsdu || status->last_amsdu)
8486c92544dSBjoern A. Zeeb 		mt76_rx_release_amsdu(phy, q);
8496c92544dSBjoern A. Zeeb }
8506c92544dSBjoern A. Zeeb 
8516c92544dSBjoern A. Zeeb void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
8526c92544dSBjoern A. Zeeb {
8536c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8546c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
8556c92544dSBjoern A. Zeeb 
8566c92544dSBjoern A. Zeeb 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
8576c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
8586c92544dSBjoern A. Zeeb 		return;
8596c92544dSBjoern A. Zeeb 	}
8606c92544dSBjoern A. Zeeb 
8616c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE
8626c92544dSBjoern A. Zeeb 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
8636c92544dSBjoern A. Zeeb 		phy->test.rx_stats.packets[q]++;
8646c92544dSBjoern A. Zeeb 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
8656c92544dSBjoern A. Zeeb 			phy->test.rx_stats.fcs_error[q]++;
8666c92544dSBjoern A. Zeeb 	}
8676c92544dSBjoern A. Zeeb #endif
8686c92544dSBjoern A. Zeeb 
8696c92544dSBjoern A. Zeeb 	mt76_rx_release_burst(phy, q, skb);
8706c92544dSBjoern A. Zeeb }
8716c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx);
8726c92544dSBjoern A. Zeeb 
8736c92544dSBjoern A. Zeeb bool mt76_has_tx_pending(struct mt76_phy *phy)
8746c92544dSBjoern A. Zeeb {
8756c92544dSBjoern A. Zeeb 	struct mt76_queue *q;
8766c92544dSBjoern A. Zeeb 	int i;
8776c92544dSBjoern A. Zeeb 
8786c92544dSBjoern A. Zeeb 	for (i = 0; i < __MT_TXQ_MAX; i++) {
8796c92544dSBjoern A. Zeeb 		q = phy->q_tx[i];
8806c92544dSBjoern A. Zeeb 		if (q && q->queued)
8816c92544dSBjoern A. Zeeb 			return true;
8826c92544dSBjoern A. Zeeb 	}
8836c92544dSBjoern A. Zeeb 
8846c92544dSBjoern A. Zeeb 	return false;
8856c92544dSBjoern A. Zeeb }
8866c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
8876c92544dSBjoern A. Zeeb 
8886c92544dSBjoern A. Zeeb static struct mt76_channel_state *
8896c92544dSBjoern A. Zeeb mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8906c92544dSBjoern A. Zeeb {
8916c92544dSBjoern A. Zeeb 	struct mt76_sband *msband;
8926c92544dSBjoern A. Zeeb 	int idx;
8936c92544dSBjoern A. Zeeb 
8946c92544dSBjoern A. Zeeb 	if (c->band == NL80211_BAND_2GHZ)
8956c92544dSBjoern A. Zeeb 		msband = &phy->sband_2g;
8966c92544dSBjoern A. Zeeb 	else if (c->band == NL80211_BAND_6GHZ)
8976c92544dSBjoern A. Zeeb 		msband = &phy->sband_6g;
8986c92544dSBjoern A. Zeeb 	else
8996c92544dSBjoern A. Zeeb 		msband = &phy->sband_5g;
9006c92544dSBjoern A. Zeeb 
9016c92544dSBjoern A. Zeeb 	idx = c - &msband->sband.channels[0];
9026c92544dSBjoern A. Zeeb 	return &msband->chan[idx];
9036c92544dSBjoern A. Zeeb }
9046c92544dSBjoern A. Zeeb 
9056c92544dSBjoern A. Zeeb void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
9066c92544dSBjoern A. Zeeb {
9076c92544dSBjoern A. Zeeb 	struct mt76_channel_state *state = phy->chan_state;
9086c92544dSBjoern A. Zeeb 
9096c92544dSBjoern A. Zeeb 	state->cc_active += ktime_to_us(ktime_sub(time,
9106c92544dSBjoern A. Zeeb 						  phy->survey_time));
9116c92544dSBjoern A. Zeeb 	phy->survey_time = time;
9126c92544dSBjoern A. Zeeb }
9136c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
9146c92544dSBjoern A. Zeeb 
9156c92544dSBjoern A. Zeeb void mt76_update_survey(struct mt76_phy *phy)
9166c92544dSBjoern A. Zeeb {
9176c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
9186c92544dSBjoern A. Zeeb 	ktime_t cur_time;
9196c92544dSBjoern A. Zeeb 
9206c92544dSBjoern A. Zeeb 	if (dev->drv->update_survey)
9216c92544dSBjoern A. Zeeb 		dev->drv->update_survey(phy);
9226c92544dSBjoern A. Zeeb 
9236c92544dSBjoern A. Zeeb 	cur_time = ktime_get_boottime();
9246c92544dSBjoern A. Zeeb 	mt76_update_survey_active_time(phy, cur_time);
9256c92544dSBjoern A. Zeeb 
9266c92544dSBjoern A. Zeeb 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
9276c92544dSBjoern A. Zeeb 		struct mt76_channel_state *state = phy->chan_state;
9286c92544dSBjoern A. Zeeb 
9296c92544dSBjoern A. Zeeb 		spin_lock_bh(&dev->cc_lock);
9306c92544dSBjoern A. Zeeb 		state->cc_bss_rx += dev->cur_cc_bss_rx;
9316c92544dSBjoern A. Zeeb 		dev->cur_cc_bss_rx = 0;
9326c92544dSBjoern A. Zeeb 		spin_unlock_bh(&dev->cc_lock);
9336c92544dSBjoern A. Zeeb 	}
9346c92544dSBjoern A. Zeeb }
9356c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey);
9366c92544dSBjoern A. Zeeb 
9376c92544dSBjoern A. Zeeb void mt76_set_channel(struct mt76_phy *phy)
9386c92544dSBjoern A. Zeeb {
9396c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
9406c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = phy->hw;
9416c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
9426c92544dSBjoern A. Zeeb 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
9436c92544dSBjoern A. Zeeb 	int timeout = HZ / 5;
9446c92544dSBjoern A. Zeeb 
9456c92544dSBjoern A. Zeeb 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
9466c92544dSBjoern A. Zeeb 	mt76_update_survey(phy);
9476c92544dSBjoern A. Zeeb 
9486c92544dSBjoern A. Zeeb 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9496c92544dSBjoern A. Zeeb 	    phy->chandef.width != chandef->width)
9506c92544dSBjoern A. Zeeb 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9516c92544dSBjoern A. Zeeb 
9526c92544dSBjoern A. Zeeb 	phy->chandef = *chandef;
9536c92544dSBjoern A. Zeeb 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
9546c92544dSBjoern A. Zeeb 
9556c92544dSBjoern A. Zeeb 	if (!offchannel)
9566c92544dSBjoern A. Zeeb 		phy->main_chan = chandef->chan;
9576c92544dSBjoern A. Zeeb 
9586c92544dSBjoern A. Zeeb 	if (chandef->chan != phy->main_chan)
9596c92544dSBjoern A. Zeeb 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
9606c92544dSBjoern A. Zeeb }
9616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_channel);
9626c92544dSBjoern A. Zeeb 
9636c92544dSBjoern A. Zeeb int mt76_get_survey(struct ieee80211_hw *hw, int idx,
9646c92544dSBjoern A. Zeeb 		    struct survey_info *survey)
9656c92544dSBjoern A. Zeeb {
9666c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
9676c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
9686c92544dSBjoern A. Zeeb 	struct mt76_sband *sband;
9696c92544dSBjoern A. Zeeb 	struct ieee80211_channel *chan;
9706c92544dSBjoern A. Zeeb 	struct mt76_channel_state *state;
9716c92544dSBjoern A. Zeeb 	int ret = 0;
9726c92544dSBjoern A. Zeeb 
9736c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
9746c92544dSBjoern A. Zeeb 	if (idx == 0 && dev->drv->update_survey)
9756c92544dSBjoern A. Zeeb 		mt76_update_survey(phy);
9766c92544dSBjoern A. Zeeb 
9776c92544dSBjoern A. Zeeb 	if (idx >= phy->sband_2g.sband.n_channels +
9786c92544dSBjoern A. Zeeb 		   phy->sband_5g.sband.n_channels) {
9796c92544dSBjoern A. Zeeb 		idx -= (phy->sband_2g.sband.n_channels +
9806c92544dSBjoern A. Zeeb 			phy->sband_5g.sband.n_channels);
9816c92544dSBjoern A. Zeeb 		sband = &phy->sband_6g;
9826c92544dSBjoern A. Zeeb 	} else if (idx >= phy->sband_2g.sband.n_channels) {
9836c92544dSBjoern A. Zeeb 		idx -= phy->sband_2g.sband.n_channels;
9846c92544dSBjoern A. Zeeb 		sband = &phy->sband_5g;
9856c92544dSBjoern A. Zeeb 	} else {
9866c92544dSBjoern A. Zeeb 		sband = &phy->sband_2g;
9876c92544dSBjoern A. Zeeb 	}
9886c92544dSBjoern A. Zeeb 
9896c92544dSBjoern A. Zeeb 	if (idx >= sband->sband.n_channels) {
9906c92544dSBjoern A. Zeeb 		ret = -ENOENT;
9916c92544dSBjoern A. Zeeb 		goto out;
9926c92544dSBjoern A. Zeeb 	}
9936c92544dSBjoern A. Zeeb 
9946c92544dSBjoern A. Zeeb 	chan = &sband->sband.channels[idx];
9956c92544dSBjoern A. Zeeb 	state = mt76_channel_state(phy, chan);
9966c92544dSBjoern A. Zeeb 
9976c92544dSBjoern A. Zeeb 	memset(survey, 0, sizeof(*survey));
9986c92544dSBjoern A. Zeeb 	survey->channel = chan;
9996c92544dSBjoern A. Zeeb 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
10006c92544dSBjoern A. Zeeb 	survey->filled |= dev->drv->survey_flags;
10016c92544dSBjoern A. Zeeb 	if (state->noise)
10026c92544dSBjoern A. Zeeb 		survey->filled |= SURVEY_INFO_NOISE_DBM;
10036c92544dSBjoern A. Zeeb 
10046c92544dSBjoern A. Zeeb 	if (chan == phy->main_chan) {
10056c92544dSBjoern A. Zeeb 		survey->filled |= SURVEY_INFO_IN_USE;
10066c92544dSBjoern A. Zeeb 
10076c92544dSBjoern A. Zeeb 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
10086c92544dSBjoern A. Zeeb 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
10096c92544dSBjoern A. Zeeb 	}
10106c92544dSBjoern A. Zeeb 
10116c92544dSBjoern A. Zeeb 	survey->time_busy = div_u64(state->cc_busy, 1000);
10126c92544dSBjoern A. Zeeb 	survey->time_rx = div_u64(state->cc_rx, 1000);
10136c92544dSBjoern A. Zeeb 	survey->time = div_u64(state->cc_active, 1000);
10146c92544dSBjoern A. Zeeb 	survey->noise = state->noise;
10156c92544dSBjoern A. Zeeb 
10166c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->cc_lock);
10176c92544dSBjoern A. Zeeb 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
10186c92544dSBjoern A. Zeeb 	survey->time_tx = div_u64(state->cc_tx, 1000);
10196c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->cc_lock);
10206c92544dSBjoern A. Zeeb 
10216c92544dSBjoern A. Zeeb out:
10226c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
10236c92544dSBjoern A. Zeeb 
10246c92544dSBjoern A. Zeeb 	return ret;
10256c92544dSBjoern A. Zeeb }
10266c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_survey);
10276c92544dSBjoern A. Zeeb 
10286c92544dSBjoern A. Zeeb void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
10296c92544dSBjoern A. Zeeb 			 struct ieee80211_key_conf *key)
10306c92544dSBjoern A. Zeeb {
10316c92544dSBjoern A. Zeeb 	struct ieee80211_key_seq seq;
10326c92544dSBjoern A. Zeeb 	int i;
10336c92544dSBjoern A. Zeeb 
10346c92544dSBjoern A. Zeeb 	wcid->rx_check_pn = false;
10356c92544dSBjoern A. Zeeb 
10366c92544dSBjoern A. Zeeb 	if (!key)
10376c92544dSBjoern A. Zeeb 		return;
10386c92544dSBjoern A. Zeeb 
10396c92544dSBjoern A. Zeeb 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
10406c92544dSBjoern A. Zeeb 		return;
10416c92544dSBjoern A. Zeeb 
10426c92544dSBjoern A. Zeeb 	wcid->rx_check_pn = true;
10436c92544dSBjoern A. Zeeb 
10446c92544dSBjoern A. Zeeb 	/* data frame */
10456c92544dSBjoern A. Zeeb 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
10466c92544dSBjoern A. Zeeb 		ieee80211_get_key_rx_seq(key, i, &seq);
10476c92544dSBjoern A. Zeeb 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
10486c92544dSBjoern A. Zeeb 	}
10496c92544dSBjoern A. Zeeb 
10506c92544dSBjoern A. Zeeb 	/* robust management frame */
10516c92544dSBjoern A. Zeeb 	ieee80211_get_key_rx_seq(key, -1, &seq);
10526c92544dSBjoern A. Zeeb 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
10536c92544dSBjoern A. Zeeb 
10546c92544dSBjoern A. Zeeb }
10556c92544dSBjoern A. Zeeb EXPORT_SYMBOL(mt76_wcid_key_setup);
10566c92544dSBjoern A. Zeeb 
1057*cbb3ec25SBjoern A. Zeeb int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10586c92544dSBjoern A. Zeeb {
10596c92544dSBjoern A. Zeeb 	int signal = -128;
10606c92544dSBjoern A. Zeeb 	u8 chains;
10616c92544dSBjoern A. Zeeb 
1062*cbb3ec25SBjoern A. Zeeb 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10636c92544dSBjoern A. Zeeb 		int cur, diff;
10646c92544dSBjoern A. Zeeb 
10656c92544dSBjoern A. Zeeb 		cur = *chain_signal;
10666c92544dSBjoern A. Zeeb 		if (!(chains & BIT(0)) ||
10676c92544dSBjoern A. Zeeb 		    cur > 0)
10686c92544dSBjoern A. Zeeb 			continue;
10696c92544dSBjoern A. Zeeb 
10706c92544dSBjoern A. Zeeb 		if (cur > signal)
10716c92544dSBjoern A. Zeeb 			swap(cur, signal);
10726c92544dSBjoern A. Zeeb 
10736c92544dSBjoern A. Zeeb 		diff = signal - cur;
10746c92544dSBjoern A. Zeeb 		if (diff == 0)
10756c92544dSBjoern A. Zeeb 			signal += 3;
10766c92544dSBjoern A. Zeeb 		else if (diff <= 2)
10776c92544dSBjoern A. Zeeb 			signal += 2;
10786c92544dSBjoern A. Zeeb 		else if (diff <= 6)
10796c92544dSBjoern A. Zeeb 			signal += 1;
10806c92544dSBjoern A. Zeeb 	}
10816c92544dSBjoern A. Zeeb 
10826c92544dSBjoern A. Zeeb 	return signal;
10836c92544dSBjoern A. Zeeb }
1084*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL(mt76_rx_signal);
10856c92544dSBjoern A. Zeeb 
10866c92544dSBjoern A. Zeeb static void
10876c92544dSBjoern A. Zeeb mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
10886c92544dSBjoern A. Zeeb 		struct ieee80211_hw **hw,
10896c92544dSBjoern A. Zeeb 		struct ieee80211_sta **sta)
10906c92544dSBjoern A. Zeeb {
10916c92544dSBjoern A. Zeeb 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
10926c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
10936c92544dSBjoern A. Zeeb 	struct mt76_rx_status mstat;
10946c92544dSBjoern A. Zeeb 
10956c92544dSBjoern A. Zeeb 	mstat = *((struct mt76_rx_status *)skb->cb);
10966c92544dSBjoern A. Zeeb 	memset(status, 0, sizeof(*status));
10976c92544dSBjoern A. Zeeb 
10986c92544dSBjoern A. Zeeb 	status->flag = mstat.flag;
10996c92544dSBjoern A. Zeeb 	status->freq = mstat.freq;
11006c92544dSBjoern A. Zeeb 	status->enc_flags = mstat.enc_flags;
11016c92544dSBjoern A. Zeeb 	status->encoding = mstat.encoding;
11026c92544dSBjoern A. Zeeb 	status->bw = mstat.bw;
1103*cbb3ec25SBjoern A. Zeeb 	if (status->encoding == RX_ENC_EHT) {
1104*cbb3ec25SBjoern A. Zeeb 		status->eht.ru = mstat.eht.ru;
1105*cbb3ec25SBjoern A. Zeeb 		status->eht.gi = mstat.eht.gi;
1106*cbb3ec25SBjoern A. Zeeb 	} else {
11076c92544dSBjoern A. Zeeb 		status->he_ru = mstat.he_ru;
11086c92544dSBjoern A. Zeeb 		status->he_gi = mstat.he_gi;
11096c92544dSBjoern A. Zeeb 		status->he_dcm = mstat.he_dcm;
1110*cbb3ec25SBjoern A. Zeeb 	}
11116c92544dSBjoern A. Zeeb 	status->rate_idx = mstat.rate_idx;
11126c92544dSBjoern A. Zeeb 	status->nss = mstat.nss;
11136c92544dSBjoern A. Zeeb 	status->band = mstat.band;
11146c92544dSBjoern A. Zeeb 	status->signal = mstat.signal;
11156c92544dSBjoern A. Zeeb 	status->chains = mstat.chains;
11166c92544dSBjoern A. Zeeb 	status->ampdu_reference = mstat.ampdu_ref;
11176c92544dSBjoern A. Zeeb 	status->device_timestamp = mstat.timestamp;
11186c92544dSBjoern A. Zeeb 	status->mactime = mstat.timestamp;
1119*cbb3ec25SBjoern A. Zeeb 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
11206c92544dSBjoern A. Zeeb 	if (status->signal <= -128)
11216c92544dSBjoern A. Zeeb 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
11226c92544dSBjoern A. Zeeb 
11236c92544dSBjoern A. Zeeb 	if (ieee80211_is_beacon(hdr->frame_control) ||
11246c92544dSBjoern A. Zeeb 	    ieee80211_is_probe_resp(hdr->frame_control))
11256c92544dSBjoern A. Zeeb 		status->boottime_ns = ktime_get_boottime_ns();
11266c92544dSBjoern A. Zeeb 
11276c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
11286c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
11296c92544dSBjoern A. Zeeb 		     sizeof(mstat.chain_signal));
11306c92544dSBjoern A. Zeeb 	memcpy(status->chain_signal, mstat.chain_signal,
11316c92544dSBjoern A. Zeeb 	       sizeof(mstat.chain_signal));
11326c92544dSBjoern A. Zeeb 
11336c92544dSBjoern A. Zeeb 	*sta = wcid_to_sta(mstat.wcid);
11346c92544dSBjoern A. Zeeb 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
11356c92544dSBjoern A. Zeeb }
11366c92544dSBjoern A. Zeeb 
11376c92544dSBjoern A. Zeeb static void
11386c92544dSBjoern A. Zeeb mt76_check_ccmp_pn(struct sk_buff *skb)
11396c92544dSBjoern A. Zeeb {
11406c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
11416c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
11426c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr;
11436c92544dSBjoern A. Zeeb 	int security_idx;
11446c92544dSBjoern A. Zeeb 	int ret;
11456c92544dSBjoern A. Zeeb 
11466c92544dSBjoern A. Zeeb 	if (!(status->flag & RX_FLAG_DECRYPTED))
11476c92544dSBjoern A. Zeeb 		return;
11486c92544dSBjoern A. Zeeb 
11496c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_ONLY_MONITOR)
11506c92544dSBjoern A. Zeeb 		return;
11516c92544dSBjoern A. Zeeb 
11526c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->rx_check_pn)
11536c92544dSBjoern A. Zeeb 		return;
11546c92544dSBjoern A. Zeeb 
11556c92544dSBjoern A. Zeeb 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11566c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_8023)
11576c92544dSBjoern A. Zeeb 		goto skip_hdr_check;
11586c92544dSBjoern A. Zeeb 
11596c92544dSBjoern A. Zeeb 	hdr = mt76_skb_get_hdr(skb);
11606c92544dSBjoern A. Zeeb 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
11616c92544dSBjoern A. Zeeb 		/*
11626c92544dSBjoern A. Zeeb 		 * Validate the first fragment both here and in mac80211
11636c92544dSBjoern A. Zeeb 		 * All further fragments will be validated by mac80211 only.
11646c92544dSBjoern A. Zeeb 		 */
11656c92544dSBjoern A. Zeeb 		if (ieee80211_is_frag(hdr) &&
11666c92544dSBjoern A. Zeeb 		    !ieee80211_is_first_frag(hdr->frame_control))
11676c92544dSBjoern A. Zeeb 			return;
11686c92544dSBjoern A. Zeeb 	}
11696c92544dSBjoern A. Zeeb 
11706c92544dSBjoern A. Zeeb 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
11716c92544dSBjoern A. Zeeb 	 *
11726c92544dSBjoern A. Zeeb 	 * the recipient shall maintain a single replay counter for received
11736c92544dSBjoern A. Zeeb 	 * individually addressed robust Management frames that are received
11746c92544dSBjoern A. Zeeb 	 * with the To DS subfield equal to 0, [...]
11756c92544dSBjoern A. Zeeb 	 */
11766c92544dSBjoern A. Zeeb 	if (ieee80211_is_mgmt(hdr->frame_control) &&
11776c92544dSBjoern A. Zeeb 	    !ieee80211_has_tods(hdr->frame_control))
11786c92544dSBjoern A. Zeeb 		security_idx = IEEE80211_NUM_TIDS;
11796c92544dSBjoern A. Zeeb 
11806c92544dSBjoern A. Zeeb skip_hdr_check:
11816c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
11826c92544dSBjoern A. Zeeb 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
11836c92544dSBjoern A. Zeeb 		     sizeof(status->iv));
11846c92544dSBjoern A. Zeeb 	if (ret <= 0) {
11856c92544dSBjoern A. Zeeb 		status->flag |= RX_FLAG_ONLY_MONITOR;
11866c92544dSBjoern A. Zeeb 		return;
11876c92544dSBjoern A. Zeeb 	}
11886c92544dSBjoern A. Zeeb 
11896c92544dSBjoern A. Zeeb 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
11906c92544dSBjoern A. Zeeb 
11916c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_IV_STRIPPED)
11926c92544dSBjoern A. Zeeb 		status->flag |= RX_FLAG_PN_VALIDATED;
11936c92544dSBjoern A. Zeeb }
11946c92544dSBjoern A. Zeeb 
11956c92544dSBjoern A. Zeeb static void
11966c92544dSBjoern A. Zeeb mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
11976c92544dSBjoern A. Zeeb 		    int len)
11986c92544dSBjoern A. Zeeb {
11996c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
12006c92544dSBjoern A. Zeeb 	struct ieee80211_rx_status info = {
12016c92544dSBjoern A. Zeeb 		.enc_flags = status->enc_flags,
12026c92544dSBjoern A. Zeeb 		.rate_idx = status->rate_idx,
12036c92544dSBjoern A. Zeeb 		.encoding = status->encoding,
12046c92544dSBjoern A. Zeeb 		.band = status->band,
12056c92544dSBjoern A. Zeeb 		.nss = status->nss,
12066c92544dSBjoern A. Zeeb 		.bw = status->bw,
12076c92544dSBjoern A. Zeeb 	};
12086c92544dSBjoern A. Zeeb 	struct ieee80211_sta *sta;
12096c92544dSBjoern A. Zeeb 	u32 airtime;
12106c92544dSBjoern A. Zeeb 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
12116c92544dSBjoern A. Zeeb 
12126c92544dSBjoern A. Zeeb 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
12136c92544dSBjoern A. Zeeb 	spin_lock(&dev->cc_lock);
12146c92544dSBjoern A. Zeeb 	dev->cur_cc_bss_rx += airtime;
12156c92544dSBjoern A. Zeeb 	spin_unlock(&dev->cc_lock);
12166c92544dSBjoern A. Zeeb 
12176c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->sta)
12186c92544dSBjoern A. Zeeb 		return;
12196c92544dSBjoern A. Zeeb 
12206c92544dSBjoern A. Zeeb 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
12216c92544dSBjoern A. Zeeb 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
12226c92544dSBjoern A. Zeeb }
12236c92544dSBjoern A. Zeeb 
12246c92544dSBjoern A. Zeeb static void
12256c92544dSBjoern A. Zeeb mt76_airtime_flush_ampdu(struct mt76_dev *dev)
12266c92544dSBjoern A. Zeeb {
12276c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid;
12286c92544dSBjoern A. Zeeb 	int wcid_idx;
12296c92544dSBjoern A. Zeeb 
12306c92544dSBjoern A. Zeeb 	if (!dev->rx_ampdu_len)
12316c92544dSBjoern A. Zeeb 		return;
12326c92544dSBjoern A. Zeeb 
12336c92544dSBjoern A. Zeeb 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
12346c92544dSBjoern A. Zeeb 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
12356c92544dSBjoern A. Zeeb 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
12366c92544dSBjoern A. Zeeb 	else
12376c92544dSBjoern A. Zeeb 		wcid = NULL;
12386c92544dSBjoern A. Zeeb 	dev->rx_ampdu_status.wcid = wcid;
12396c92544dSBjoern A. Zeeb 
12406c92544dSBjoern A. Zeeb 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
12416c92544dSBjoern A. Zeeb 
12426c92544dSBjoern A. Zeeb 	dev->rx_ampdu_len = 0;
12436c92544dSBjoern A. Zeeb 	dev->rx_ampdu_ref = 0;
12446c92544dSBjoern A. Zeeb }
12456c92544dSBjoern A. Zeeb 
12466c92544dSBjoern A. Zeeb static void
12476c92544dSBjoern A. Zeeb mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12486c92544dSBjoern A. Zeeb {
12496c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12506c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
12516c92544dSBjoern A. Zeeb 
12526c92544dSBjoern A. Zeeb 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12536c92544dSBjoern A. Zeeb 		return;
12546c92544dSBjoern A. Zeeb 
12556c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->sta) {
12566c92544dSBjoern A. Zeeb 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
12576c92544dSBjoern A. Zeeb 
12586c92544dSBjoern A. Zeeb 		if (status->flag & RX_FLAG_8023)
12596c92544dSBjoern A. Zeeb 			return;
12606c92544dSBjoern A. Zeeb 
12616c92544dSBjoern A. Zeeb 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12626c92544dSBjoern A. Zeeb 			return;
12636c92544dSBjoern A. Zeeb 
12646c92544dSBjoern A. Zeeb 		wcid = NULL;
12656c92544dSBjoern A. Zeeb 	}
12666c92544dSBjoern A. Zeeb 
12676c92544dSBjoern A. Zeeb 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12686c92544dSBjoern A. Zeeb 	    status->ampdu_ref != dev->rx_ampdu_ref)
12696c92544dSBjoern A. Zeeb 		mt76_airtime_flush_ampdu(dev);
12706c92544dSBjoern A. Zeeb 
12716c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12726c92544dSBjoern A. Zeeb 		if (!dev->rx_ampdu_len ||
12736c92544dSBjoern A. Zeeb 		    status->ampdu_ref != dev->rx_ampdu_ref) {
12746c92544dSBjoern A. Zeeb 			dev->rx_ampdu_status = *status;
12756c92544dSBjoern A. Zeeb 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
12766c92544dSBjoern A. Zeeb 			dev->rx_ampdu_ref = status->ampdu_ref;
12776c92544dSBjoern A. Zeeb 		}
12786c92544dSBjoern A. Zeeb 
12796c92544dSBjoern A. Zeeb 		dev->rx_ampdu_len += skb->len;
12806c92544dSBjoern A. Zeeb 		return;
12816c92544dSBjoern A. Zeeb 	}
12826c92544dSBjoern A. Zeeb 
12836c92544dSBjoern A. Zeeb 	mt76_airtime_report(dev, status, skb->len);
12846c92544dSBjoern A. Zeeb }
12856c92544dSBjoern A. Zeeb 
12866c92544dSBjoern A. Zeeb static void
12876c92544dSBjoern A. Zeeb mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
12886c92544dSBjoern A. Zeeb {
12896c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12906c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
12916c92544dSBjoern A. Zeeb 	struct ieee80211_sta *sta;
12926c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
12936c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
12946c92544dSBjoern A. Zeeb 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
12956c92544dSBjoern A. Zeeb 	bool ps;
12966c92544dSBjoern A. Zeeb 
12976c92544dSBjoern A. Zeeb 	hw = mt76_phy_hw(dev, status->phy_idx);
12986c92544dSBjoern A. Zeeb 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
12996c92544dSBjoern A. Zeeb 	    !(status->flag & RX_FLAG_8023)) {
13006c92544dSBjoern A. Zeeb 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
13016c92544dSBjoern A. Zeeb 		if (sta)
13026c92544dSBjoern A. Zeeb 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
13036c92544dSBjoern A. Zeeb 	}
13046c92544dSBjoern A. Zeeb 
13056c92544dSBjoern A. Zeeb 	mt76_airtime_check(dev, skb);
13066c92544dSBjoern A. Zeeb 
13076c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->sta)
13086c92544dSBjoern A. Zeeb 		return;
13096c92544dSBjoern A. Zeeb 
13106c92544dSBjoern A. Zeeb 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
13116c92544dSBjoern A. Zeeb 
13126c92544dSBjoern A. Zeeb 	if (status->signal <= 0)
13136c92544dSBjoern A. Zeeb 		ewma_signal_add(&wcid->rssi, -status->signal);
13146c92544dSBjoern A. Zeeb 
13156c92544dSBjoern A. Zeeb 	wcid->inactive_count = 0;
13166c92544dSBjoern A. Zeeb 
13176c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_8023)
13186c92544dSBjoern A. Zeeb 		return;
13196c92544dSBjoern A. Zeeb 
13206c92544dSBjoern A. Zeeb 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
13216c92544dSBjoern A. Zeeb 		return;
13226c92544dSBjoern A. Zeeb 
13236c92544dSBjoern A. Zeeb 	if (ieee80211_is_pspoll(hdr->frame_control)) {
13246c92544dSBjoern A. Zeeb 		ieee80211_sta_pspoll(sta);
13256c92544dSBjoern A. Zeeb 		return;
13266c92544dSBjoern A. Zeeb 	}
13276c92544dSBjoern A. Zeeb 
13286c92544dSBjoern A. Zeeb 	if (ieee80211_has_morefrags(hdr->frame_control) ||
13296c92544dSBjoern A. Zeeb 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
13306c92544dSBjoern A. Zeeb 	      ieee80211_is_data(hdr->frame_control)))
13316c92544dSBjoern A. Zeeb 		return;
13326c92544dSBjoern A. Zeeb 
13336c92544dSBjoern A. Zeeb 	ps = ieee80211_has_pm(hdr->frame_control);
13346c92544dSBjoern A. Zeeb 
13356c92544dSBjoern A. Zeeb 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
13366c92544dSBjoern A. Zeeb 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
13376c92544dSBjoern A. Zeeb 		ieee80211_sta_uapsd_trigger(sta, tidno);
13386c92544dSBjoern A. Zeeb 
13396c92544dSBjoern A. Zeeb 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
13406c92544dSBjoern A. Zeeb 		return;
13416c92544dSBjoern A. Zeeb 
13426c92544dSBjoern A. Zeeb 	if (ps)
13436c92544dSBjoern A. Zeeb 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
13446c92544dSBjoern A. Zeeb 
1345*cbb3ec25SBjoern A. Zeeb 	if (dev->drv->sta_ps)
13466c92544dSBjoern A. Zeeb 		dev->drv->sta_ps(dev, sta, ps);
13476c92544dSBjoern A. Zeeb 
13486c92544dSBjoern A. Zeeb 	if (!ps)
13496c92544dSBjoern A. Zeeb 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
13506c92544dSBjoern A. Zeeb 
13516c92544dSBjoern A. Zeeb 	ieee80211_sta_ps_transition(sta, ps);
13526c92544dSBjoern A. Zeeb }
13536c92544dSBjoern A. Zeeb 
13546c92544dSBjoern A. Zeeb void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
13556c92544dSBjoern A. Zeeb 		      struct napi_struct *napi)
13566c92544dSBjoern A. Zeeb {
13576c92544dSBjoern A. Zeeb 	struct ieee80211_sta *sta;
13586c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
13596c92544dSBjoern A. Zeeb 	struct sk_buff *skb, *tmp;
13606c92544dSBjoern A. Zeeb #if defined(__linux__)
13616c92544dSBjoern A. Zeeb 	LIST_HEAD(list);
13626c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
13636c92544dSBjoern A. Zeeb 	LINUX_LIST_HEAD(list);
13646c92544dSBjoern A. Zeeb #endif
13656c92544dSBjoern A. Zeeb 
13666c92544dSBjoern A. Zeeb 	spin_lock(&dev->rx_lock);
13676c92544dSBjoern A. Zeeb 	while ((skb = __skb_dequeue(frames)) != NULL) {
13686c92544dSBjoern A. Zeeb 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
13696c92544dSBjoern A. Zeeb 
13706c92544dSBjoern A. Zeeb 		mt76_check_ccmp_pn(skb);
13716c92544dSBjoern A. Zeeb 		skb_shinfo(skb)->frag_list = NULL;
13726c92544dSBjoern A. Zeeb 		mt76_rx_convert(dev, skb, &hw, &sta);
13736c92544dSBjoern A. Zeeb 		ieee80211_rx_list(hw, sta, skb, &list);
13746c92544dSBjoern A. Zeeb 
13756c92544dSBjoern A. Zeeb 		/* subsequent amsdu frames */
13766c92544dSBjoern A. Zeeb 		while (nskb) {
13776c92544dSBjoern A. Zeeb 			skb = nskb;
13786c92544dSBjoern A. Zeeb 			nskb = nskb->next;
13796c92544dSBjoern A. Zeeb 			skb->next = NULL;
13806c92544dSBjoern A. Zeeb 
13816c92544dSBjoern A. Zeeb 			mt76_rx_convert(dev, skb, &hw, &sta);
13826c92544dSBjoern A. Zeeb 			ieee80211_rx_list(hw, sta, skb, &list);
13836c92544dSBjoern A. Zeeb 		}
13846c92544dSBjoern A. Zeeb 	}
13856c92544dSBjoern A. Zeeb 	spin_unlock(&dev->rx_lock);
13866c92544dSBjoern A. Zeeb 
13876c92544dSBjoern A. Zeeb 	if (!napi) {
13886c92544dSBjoern A. Zeeb 		netif_receive_skb_list(&list);
13896c92544dSBjoern A. Zeeb 		return;
13906c92544dSBjoern A. Zeeb 	}
13916c92544dSBjoern A. Zeeb 
13926c92544dSBjoern A. Zeeb 	list_for_each_entry_safe(skb, tmp, &list, list) {
13936c92544dSBjoern A. Zeeb 		skb_list_del_init(skb);
13946c92544dSBjoern A. Zeeb 		napi_gro_receive(napi, skb);
13956c92544dSBjoern A. Zeeb 	}
13966c92544dSBjoern A. Zeeb }
13976c92544dSBjoern A. Zeeb 
13986c92544dSBjoern A. Zeeb void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
13996c92544dSBjoern A. Zeeb 			   struct napi_struct *napi)
14006c92544dSBjoern A. Zeeb {
14016c92544dSBjoern A. Zeeb 	struct sk_buff_head frames;
14026c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
14036c92544dSBjoern A. Zeeb 
14046c92544dSBjoern A. Zeeb 	__skb_queue_head_init(&frames);
14056c92544dSBjoern A. Zeeb 
14066c92544dSBjoern A. Zeeb 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
14076c92544dSBjoern A. Zeeb 		mt76_check_sta(dev, skb);
1408*cbb3ec25SBjoern A. Zeeb 		if (mtk_wed_device_active(&dev->mmio.wed))
1409*cbb3ec25SBjoern A. Zeeb 			__skb_queue_tail(&frames, skb);
1410*cbb3ec25SBjoern A. Zeeb 		else
14116c92544dSBjoern A. Zeeb 			mt76_rx_aggr_reorder(skb, &frames);
14126c92544dSBjoern A. Zeeb 	}
14136c92544dSBjoern A. Zeeb 
14146c92544dSBjoern A. Zeeb 	mt76_rx_complete(dev, &frames, napi);
14156c92544dSBjoern A. Zeeb }
14166c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
14176c92544dSBjoern A. Zeeb 
14186c92544dSBjoern A. Zeeb static int
14196c92544dSBjoern A. Zeeb mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
14206c92544dSBjoern A. Zeeb 	     struct ieee80211_sta *sta)
14216c92544dSBjoern A. Zeeb {
14226c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
14236c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
14246c92544dSBjoern A. Zeeb 	int ret;
14256c92544dSBjoern A. Zeeb 	int i;
14266c92544dSBjoern A. Zeeb 
14276c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
14286c92544dSBjoern A. Zeeb 
14296c92544dSBjoern A. Zeeb 	ret = dev->drv->sta_add(dev, vif, sta);
14306c92544dSBjoern A. Zeeb 	if (ret)
14316c92544dSBjoern A. Zeeb 		goto out;
14326c92544dSBjoern A. Zeeb 
14336c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
14346c92544dSBjoern A. Zeeb 		struct mt76_txq *mtxq;
14356c92544dSBjoern A. Zeeb 
14366c92544dSBjoern A. Zeeb 		if (!sta->txq[i])
14376c92544dSBjoern A. Zeeb 			continue;
14386c92544dSBjoern A. Zeeb 
14396c92544dSBjoern A. Zeeb 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
14406c92544dSBjoern A. Zeeb 		mtxq->wcid = wcid->idx;
14416c92544dSBjoern A. Zeeb 	}
14426c92544dSBjoern A. Zeeb 
14436c92544dSBjoern A. Zeeb 	ewma_signal_init(&wcid->rssi);
14446c92544dSBjoern A. Zeeb 	if (phy->band_idx == MT_BAND1)
14456c92544dSBjoern A. Zeeb 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
14466c92544dSBjoern A. Zeeb 	wcid->phy_idx = phy->band_idx;
14476c92544dSBjoern A. Zeeb 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
14486c92544dSBjoern A. Zeeb 
14496c92544dSBjoern A. Zeeb 	mt76_packet_id_init(wcid);
14506c92544dSBjoern A. Zeeb out:
14516c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
14526c92544dSBjoern A. Zeeb 
14536c92544dSBjoern A. Zeeb 	return ret;
14546c92544dSBjoern A. Zeeb }
14556c92544dSBjoern A. Zeeb 
14566c92544dSBjoern A. Zeeb void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
14576c92544dSBjoern A. Zeeb 		       struct ieee80211_sta *sta)
14586c92544dSBjoern A. Zeeb {
14596c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
14606c92544dSBjoern A. Zeeb 	int i, idx = wcid->idx;
14616c92544dSBjoern A. Zeeb 
14626c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
14636c92544dSBjoern A. Zeeb 		mt76_rx_aggr_stop(dev, wcid, i);
14646c92544dSBjoern A. Zeeb 
14656c92544dSBjoern A. Zeeb 	if (dev->drv->sta_remove)
14666c92544dSBjoern A. Zeeb 		dev->drv->sta_remove(dev, vif, sta);
14676c92544dSBjoern A. Zeeb 
14686c92544dSBjoern A. Zeeb 	mt76_packet_id_flush(dev, wcid);
14696c92544dSBjoern A. Zeeb 
14706c92544dSBjoern A. Zeeb 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
14716c92544dSBjoern A. Zeeb 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
14726c92544dSBjoern A. Zeeb }
14736c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_sta_remove);
14746c92544dSBjoern A. Zeeb 
14756c92544dSBjoern A. Zeeb static void
14766c92544dSBjoern A. Zeeb mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
14776c92544dSBjoern A. Zeeb 		struct ieee80211_sta *sta)
14786c92544dSBjoern A. Zeeb {
14796c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
14806c92544dSBjoern A. Zeeb 	__mt76_sta_remove(dev, vif, sta);
14816c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
14826c92544dSBjoern A. Zeeb }
14836c92544dSBjoern A. Zeeb 
14846c92544dSBjoern A. Zeeb int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
14856c92544dSBjoern A. Zeeb 		   struct ieee80211_sta *sta,
14866c92544dSBjoern A. Zeeb 		   enum ieee80211_sta_state old_state,
14876c92544dSBjoern A. Zeeb 		   enum ieee80211_sta_state new_state)
14886c92544dSBjoern A. Zeeb {
14896c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
14906c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
14916c92544dSBjoern A. Zeeb 
14926c92544dSBjoern A. Zeeb 	if (old_state == IEEE80211_STA_NOTEXIST &&
14936c92544dSBjoern A. Zeeb 	    new_state == IEEE80211_STA_NONE)
14946c92544dSBjoern A. Zeeb 		return mt76_sta_add(phy, vif, sta);
14956c92544dSBjoern A. Zeeb 
14966c92544dSBjoern A. Zeeb 	if (old_state == IEEE80211_STA_AUTH &&
14976c92544dSBjoern A. Zeeb 	    new_state == IEEE80211_STA_ASSOC &&
14986c92544dSBjoern A. Zeeb 	    dev->drv->sta_assoc)
14996c92544dSBjoern A. Zeeb 		dev->drv->sta_assoc(dev, vif, sta);
15006c92544dSBjoern A. Zeeb 
15016c92544dSBjoern A. Zeeb 	if (old_state == IEEE80211_STA_NONE &&
15026c92544dSBjoern A. Zeeb 	    new_state == IEEE80211_STA_NOTEXIST)
15036c92544dSBjoern A. Zeeb 		mt76_sta_remove(dev, vif, sta);
15046c92544dSBjoern A. Zeeb 
15056c92544dSBjoern A. Zeeb 	return 0;
15066c92544dSBjoern A. Zeeb }
15076c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_state);
15086c92544dSBjoern A. Zeeb 
15096c92544dSBjoern A. Zeeb void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15106c92544dSBjoern A. Zeeb 			     struct ieee80211_sta *sta)
15116c92544dSBjoern A. Zeeb {
15126c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
15136c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
15146c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
15156c92544dSBjoern A. Zeeb 
15166c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
15176c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->status_lock);
15186c92544dSBjoern A. Zeeb 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
15196c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->status_lock);
15206c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
15216c92544dSBjoern A. Zeeb }
15226c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
15236c92544dSBjoern A. Zeeb 
15246c92544dSBjoern A. Zeeb int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15256c92544dSBjoern A. Zeeb 		     int *dbm)
15266c92544dSBjoern A. Zeeb {
15276c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
15286c92544dSBjoern A. Zeeb 	int n_chains = hweight8(phy->antenna_mask);
15296c92544dSBjoern A. Zeeb 	int delta = mt76_tx_power_nss_delta(n_chains);
15306c92544dSBjoern A. Zeeb 
15316c92544dSBjoern A. Zeeb 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
15326c92544dSBjoern A. Zeeb 
15336c92544dSBjoern A. Zeeb 	return 0;
15346c92544dSBjoern A. Zeeb }
15356c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_txpower);
15366c92544dSBjoern A. Zeeb 
15376c92544dSBjoern A. Zeeb int mt76_init_sar_power(struct ieee80211_hw *hw,
15386c92544dSBjoern A. Zeeb 			const struct cfg80211_sar_specs *sar)
15396c92544dSBjoern A. Zeeb {
15406c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
15416c92544dSBjoern A. Zeeb 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
15426c92544dSBjoern A. Zeeb 	int i;
15436c92544dSBjoern A. Zeeb 
15446c92544dSBjoern A. Zeeb 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
15456c92544dSBjoern A. Zeeb 		return -EINVAL;
15466c92544dSBjoern A. Zeeb 
15476c92544dSBjoern A. Zeeb 	for (i = 0; i < sar->num_sub_specs; i++) {
15486c92544dSBjoern A. Zeeb 		u32 index = sar->sub_specs[i].freq_range_index;
15496c92544dSBjoern A. Zeeb 		/* SAR specifies power limitaton in 0.25dbm */
15506c92544dSBjoern A. Zeeb 		s32 power = sar->sub_specs[i].power >> 1;
15516c92544dSBjoern A. Zeeb 
15526c92544dSBjoern A. Zeeb 		if (power > 127 || power < -127)
15536c92544dSBjoern A. Zeeb 			power = 127;
15546c92544dSBjoern A. Zeeb 
15556c92544dSBjoern A. Zeeb 		phy->frp[index].range = &capa->freq_ranges[index];
15566c92544dSBjoern A. Zeeb 		phy->frp[index].power = power;
15576c92544dSBjoern A. Zeeb 	}
15586c92544dSBjoern A. Zeeb 
15596c92544dSBjoern A. Zeeb 	return 0;
15606c92544dSBjoern A. Zeeb }
15616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_sar_power);
15626c92544dSBjoern A. Zeeb 
15636c92544dSBjoern A. Zeeb int mt76_get_sar_power(struct mt76_phy *phy,
15646c92544dSBjoern A. Zeeb 		       struct ieee80211_channel *chan,
15656c92544dSBjoern A. Zeeb 		       int power)
15666c92544dSBjoern A. Zeeb {
15676c92544dSBjoern A. Zeeb 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
15686c92544dSBjoern A. Zeeb 	int freq, i;
15696c92544dSBjoern A. Zeeb 
15706c92544dSBjoern A. Zeeb 	if (!capa || !phy->frp)
15716c92544dSBjoern A. Zeeb 		return power;
15726c92544dSBjoern A. Zeeb 
15736c92544dSBjoern A. Zeeb 	if (power > 127 || power < -127)
15746c92544dSBjoern A. Zeeb 		power = 127;
15756c92544dSBjoern A. Zeeb 
15766c92544dSBjoern A. Zeeb 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
15776c92544dSBjoern A. Zeeb 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
15786c92544dSBjoern A. Zeeb 		if (phy->frp[i].range &&
15796c92544dSBjoern A. Zeeb 		    freq >= phy->frp[i].range->start_freq &&
15806c92544dSBjoern A. Zeeb 		    freq < phy->frp[i].range->end_freq) {
15816c92544dSBjoern A. Zeeb 			power = min_t(int, phy->frp[i].power, power);
15826c92544dSBjoern A. Zeeb 			break;
15836c92544dSBjoern A. Zeeb 		}
15846c92544dSBjoern A. Zeeb 	}
15856c92544dSBjoern A. Zeeb 
15866c92544dSBjoern A. Zeeb 	return power;
15876c92544dSBjoern A. Zeeb }
15886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_sar_power);
15896c92544dSBjoern A. Zeeb 
15906c92544dSBjoern A. Zeeb static void
15916c92544dSBjoern A. Zeeb __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
15926c92544dSBjoern A. Zeeb {
15936c92544dSBjoern A. Zeeb 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
15946c92544dSBjoern A. Zeeb 		ieee80211_csa_finish(vif);
15956c92544dSBjoern A. Zeeb }
15966c92544dSBjoern A. Zeeb 
15976c92544dSBjoern A. Zeeb void mt76_csa_finish(struct mt76_dev *dev)
15986c92544dSBjoern A. Zeeb {
15996c92544dSBjoern A. Zeeb 	if (!dev->csa_complete)
16006c92544dSBjoern A. Zeeb 		return;
16016c92544dSBjoern A. Zeeb 
16026c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
16036c92544dSBjoern A. Zeeb 		IEEE80211_IFACE_ITER_RESUME_ALL,
16046c92544dSBjoern A. Zeeb 		__mt76_csa_finish, dev);
16056c92544dSBjoern A. Zeeb 
16066c92544dSBjoern A. Zeeb 	dev->csa_complete = 0;
16076c92544dSBjoern A. Zeeb }
16086c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_finish);
16096c92544dSBjoern A. Zeeb 
16106c92544dSBjoern A. Zeeb static void
16116c92544dSBjoern A. Zeeb __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
16126c92544dSBjoern A. Zeeb {
16136c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = priv;
16146c92544dSBjoern A. Zeeb 
16156c92544dSBjoern A. Zeeb 	if (!vif->bss_conf.csa_active)
16166c92544dSBjoern A. Zeeb 		return;
16176c92544dSBjoern A. Zeeb 
16186c92544dSBjoern A. Zeeb 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
16196c92544dSBjoern A. Zeeb }
16206c92544dSBjoern A. Zeeb 
16216c92544dSBjoern A. Zeeb void mt76_csa_check(struct mt76_dev *dev)
16226c92544dSBjoern A. Zeeb {
16236c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
16246c92544dSBjoern A. Zeeb 		IEEE80211_IFACE_ITER_RESUME_ALL,
16256c92544dSBjoern A. Zeeb 		__mt76_csa_check, dev);
16266c92544dSBjoern A. Zeeb }
16276c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_check);
16286c92544dSBjoern A. Zeeb 
16296c92544dSBjoern A. Zeeb int
16306c92544dSBjoern A. Zeeb mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
16316c92544dSBjoern A. Zeeb {
16326c92544dSBjoern A. Zeeb 	return 0;
16336c92544dSBjoern A. Zeeb }
16346c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_tim);
16356c92544dSBjoern A. Zeeb 
16366c92544dSBjoern A. Zeeb void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
16376c92544dSBjoern A. Zeeb {
16386c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
16396c92544dSBjoern A. Zeeb 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
16406c92544dSBjoern A. Zeeb 	u8 *hdr, *pn = status->iv;
16416c92544dSBjoern A. Zeeb 
16426c92544dSBjoern A. Zeeb 	__skb_push(skb, 8);
16436c92544dSBjoern A. Zeeb 	memmove(skb->data, skb->data + 8, hdr_len);
16446c92544dSBjoern A. Zeeb 	hdr = skb->data + hdr_len;
16456c92544dSBjoern A. Zeeb 
16466c92544dSBjoern A. Zeeb 	hdr[0] = pn[5];
16476c92544dSBjoern A. Zeeb 	hdr[1] = pn[4];
16486c92544dSBjoern A. Zeeb 	hdr[2] = 0;
16496c92544dSBjoern A. Zeeb 	hdr[3] = 0x20 | (key_id << 6);
16506c92544dSBjoern A. Zeeb 	hdr[4] = pn[3];
16516c92544dSBjoern A. Zeeb 	hdr[5] = pn[2];
16526c92544dSBjoern A. Zeeb 	hdr[6] = pn[1];
16536c92544dSBjoern A. Zeeb 	hdr[7] = pn[0];
16546c92544dSBjoern A. Zeeb 
16556c92544dSBjoern A. Zeeb 	status->flag &= ~RX_FLAG_IV_STRIPPED;
16566c92544dSBjoern A. Zeeb }
16576c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
16586c92544dSBjoern A. Zeeb 
16596c92544dSBjoern A. Zeeb int mt76_get_rate(struct mt76_dev *dev,
16606c92544dSBjoern A. Zeeb 		  struct ieee80211_supported_band *sband,
16616c92544dSBjoern A. Zeeb 		  int idx, bool cck)
16626c92544dSBjoern A. Zeeb {
16636c92544dSBjoern A. Zeeb 	int i, offset = 0, len = sband->n_bitrates;
16646c92544dSBjoern A. Zeeb 
16656c92544dSBjoern A. Zeeb 	if (cck) {
16666c92544dSBjoern A. Zeeb 		if (sband != &dev->phy.sband_2g.sband)
16676c92544dSBjoern A. Zeeb 			return 0;
16686c92544dSBjoern A. Zeeb 
16696c92544dSBjoern A. Zeeb 		idx &= ~BIT(2); /* short preamble */
16706c92544dSBjoern A. Zeeb 	} else if (sband == &dev->phy.sband_2g.sband) {
16716c92544dSBjoern A. Zeeb 		offset = 4;
16726c92544dSBjoern A. Zeeb 	}
16736c92544dSBjoern A. Zeeb 
16746c92544dSBjoern A. Zeeb 	for (i = offset; i < len; i++) {
16756c92544dSBjoern A. Zeeb 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
16766c92544dSBjoern A. Zeeb 			return i;
16776c92544dSBjoern A. Zeeb 	}
16786c92544dSBjoern A. Zeeb 
16796c92544dSBjoern A. Zeeb 	return 0;
16806c92544dSBjoern A. Zeeb }
16816c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_rate);
16826c92544dSBjoern A. Zeeb 
16836c92544dSBjoern A. Zeeb void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16846c92544dSBjoern A. Zeeb 		  const u8 *mac)
16856c92544dSBjoern A. Zeeb {
16866c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
16876c92544dSBjoern A. Zeeb 
16886c92544dSBjoern A. Zeeb 	set_bit(MT76_SCANNING, &phy->state);
16896c92544dSBjoern A. Zeeb }
16906c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan);
16916c92544dSBjoern A. Zeeb 
16926c92544dSBjoern A. Zeeb void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
16936c92544dSBjoern A. Zeeb {
16946c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
16956c92544dSBjoern A. Zeeb 
16966c92544dSBjoern A. Zeeb 	clear_bit(MT76_SCANNING, &phy->state);
16976c92544dSBjoern A. Zeeb }
16986c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
16996c92544dSBjoern A. Zeeb 
17006c92544dSBjoern A. Zeeb int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
17016c92544dSBjoern A. Zeeb {
17026c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
17036c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
17046c92544dSBjoern A. Zeeb 
17056c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
17066c92544dSBjoern A. Zeeb 	*tx_ant = phy->antenna_mask;
17076c92544dSBjoern A. Zeeb 	*rx_ant = phy->antenna_mask;
17086c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
17096c92544dSBjoern A. Zeeb 
17106c92544dSBjoern A. Zeeb 	return 0;
17116c92544dSBjoern A. Zeeb }
17126c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_antenna);
17136c92544dSBjoern A. Zeeb 
17146c92544dSBjoern A. Zeeb struct mt76_queue *
17156c92544dSBjoern A. Zeeb mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
17166c92544dSBjoern A. Zeeb 		int ring_base, u32 flags)
17176c92544dSBjoern A. Zeeb {
17186c92544dSBjoern A. Zeeb 	struct mt76_queue *hwq;
17196c92544dSBjoern A. Zeeb 	int err;
17206c92544dSBjoern A. Zeeb 
17216c92544dSBjoern A. Zeeb 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
17226c92544dSBjoern A. Zeeb 	if (!hwq)
17236c92544dSBjoern A. Zeeb 		return ERR_PTR(-ENOMEM);
17246c92544dSBjoern A. Zeeb 
17256c92544dSBjoern A. Zeeb 	hwq->flags = flags;
17266c92544dSBjoern A. Zeeb 
17276c92544dSBjoern A. Zeeb 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
17286c92544dSBjoern A. Zeeb 	if (err < 0)
17296c92544dSBjoern A. Zeeb 		return ERR_PTR(err);
17306c92544dSBjoern A. Zeeb 
17316c92544dSBjoern A. Zeeb 	return hwq;
17326c92544dSBjoern A. Zeeb }
17336c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_queue);
17346c92544dSBjoern A. Zeeb 
17356c92544dSBjoern A. Zeeb u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
17366c92544dSBjoern A. Zeeb {
17376c92544dSBjoern A. Zeeb 	int offset = 0;
17386c92544dSBjoern A. Zeeb 
17396c92544dSBjoern A. Zeeb 	if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
17406c92544dSBjoern A. Zeeb 		offset = 4;
17416c92544dSBjoern A. Zeeb 
17426c92544dSBjoern A. Zeeb 	/* pick the lowest rate for hidden nodes */
17436c92544dSBjoern A. Zeeb 	if (rateidx < 0)
17446c92544dSBjoern A. Zeeb 		rateidx = 0;
17456c92544dSBjoern A. Zeeb 
17466c92544dSBjoern A. Zeeb 	rateidx += offset;
17476c92544dSBjoern A. Zeeb 	if (rateidx >= ARRAY_SIZE(mt76_rates))
17486c92544dSBjoern A. Zeeb 		rateidx = offset;
17496c92544dSBjoern A. Zeeb 
17506c92544dSBjoern A. Zeeb 	return mt76_rates[rateidx].hw_value;
17516c92544dSBjoern A. Zeeb }
17526c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
17536c92544dSBjoern A. Zeeb 
17546c92544dSBjoern A. Zeeb void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1755*cbb3ec25SBjoern A. Zeeb 			 struct mt76_sta_stats *stats, bool eht)
17566c92544dSBjoern A. Zeeb {
17576c92544dSBjoern A. Zeeb 	int i, ei = wi->initial_stat_idx;
17586c92544dSBjoern A. Zeeb 	u64 *data = wi->data;
17596c92544dSBjoern A. Zeeb 
17606c92544dSBjoern A. Zeeb 	wi->sta_count++;
17616c92544dSBjoern A. Zeeb 
17626c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
17636c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
17646c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
17656c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
17666c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
17676c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
17686c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
17696c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
17706c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1771*cbb3ec25SBjoern A. Zeeb 	if (eht) {
1772*cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1773*cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1774*cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1775*cbb3ec25SBjoern A. Zeeb 	}
17766c92544dSBjoern A. Zeeb 
1777*cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
17786c92544dSBjoern A. Zeeb 		data[ei++] += stats->tx_bw[i];
17796c92544dSBjoern A. Zeeb 
1780*cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < (eht ? 14 : 12); i++)
17816c92544dSBjoern A. Zeeb 		data[ei++] += stats->tx_mcs[i];
17826c92544dSBjoern A. Zeeb 
1783*cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < 4; i++)
1784*cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_nss[i];
1785*cbb3ec25SBjoern A. Zeeb 
17866c92544dSBjoern A. Zeeb 	wi->worker_stat_count = ei - wi->initial_stat_idx;
17876c92544dSBjoern A. Zeeb }
17886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
17896c92544dSBjoern A. Zeeb 
1790*cbb3ec25SBjoern A. Zeeb void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1791*cbb3ec25SBjoern A. Zeeb {
1792*cbb3ec25SBjoern A. Zeeb #ifdef CONFIG_PAGE_POOL_STATS
1793*cbb3ec25SBjoern A. Zeeb 	struct page_pool_stats stats = {};
1794*cbb3ec25SBjoern A. Zeeb 	int i;
1795*cbb3ec25SBjoern A. Zeeb 
1796*cbb3ec25SBjoern A. Zeeb 	mt76_for_each_q_rx(dev, i)
1797*cbb3ec25SBjoern A. Zeeb 		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
1798*cbb3ec25SBjoern A. Zeeb 
1799*cbb3ec25SBjoern A. Zeeb 	page_pool_ethtool_stats_get(data, &stats);
1800*cbb3ec25SBjoern A. Zeeb 	*index += page_pool_ethtool_stats_get_count();
1801*cbb3ec25SBjoern A. Zeeb #endif
1802*cbb3ec25SBjoern A. Zeeb }
1803*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
1804*cbb3ec25SBjoern A. Zeeb 
18056c92544dSBjoern A. Zeeb enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
18066c92544dSBjoern A. Zeeb {
18076c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = phy->hw;
18086c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
18096c92544dSBjoern A. Zeeb 
18106c92544dSBjoern A. Zeeb 	if (dev->region == NL80211_DFS_UNSET ||
18116c92544dSBjoern A. Zeeb 	    test_bit(MT76_SCANNING, &phy->state))
18126c92544dSBjoern A. Zeeb 		return MT_DFS_STATE_DISABLED;
18136c92544dSBjoern A. Zeeb 
18146c92544dSBjoern A. Zeeb 	if (!hw->conf.radar_enabled) {
18156c92544dSBjoern A. Zeeb 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
18166c92544dSBjoern A. Zeeb 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
18176c92544dSBjoern A. Zeeb 			return MT_DFS_STATE_ACTIVE;
18186c92544dSBjoern A. Zeeb 
18196c92544dSBjoern A. Zeeb 		return MT_DFS_STATE_DISABLED;
18206c92544dSBjoern A. Zeeb 	}
18216c92544dSBjoern A. Zeeb 
18226c92544dSBjoern A. Zeeb 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
18236c92544dSBjoern A. Zeeb 		return MT_DFS_STATE_CAC;
18246c92544dSBjoern A. Zeeb 
18256c92544dSBjoern A. Zeeb 	return MT_DFS_STATE_ACTIVE;
18266c92544dSBjoern A. Zeeb }
18276c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1828