xref: /freebsd/sys/contrib/dev/mediatek/mt76/mac80211.c (revision 8ba4d145d351db26e07695b8e90697398c5dfec2)
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
96c92544dSBjoern A. Zeeb #if defined(__FreeBSD__)
106c92544dSBjoern A. Zeeb #include <linux/math64.h>
11cbb3ec25SBjoern A. Zeeb #include <linux/numa.h>
126c92544dSBjoern A. Zeeb #endif
136c92544dSBjoern A. Zeeb #include "mt76.h"
146c92544dSBjoern A. Zeeb 
156c92544dSBjoern A. Zeeb #define CHAN2G(_idx, _freq) {			\
166c92544dSBjoern A. Zeeb 	.band = NL80211_BAND_2GHZ,		\
176c92544dSBjoern A. Zeeb 	.center_freq = (_freq),			\
186c92544dSBjoern A. Zeeb 	.hw_value = (_idx),			\
196c92544dSBjoern A. Zeeb 	.max_power = 30,			\
206c92544dSBjoern A. Zeeb }
216c92544dSBjoern A. Zeeb 
226c92544dSBjoern A. Zeeb #define CHAN5G(_idx, _freq) {			\
236c92544dSBjoern A. Zeeb 	.band = NL80211_BAND_5GHZ,		\
246c92544dSBjoern A. Zeeb 	.center_freq = (_freq),			\
256c92544dSBjoern A. Zeeb 	.hw_value = (_idx),			\
266c92544dSBjoern A. Zeeb 	.max_power = 30,			\
276c92544dSBjoern A. Zeeb }
286c92544dSBjoern A. Zeeb 
296c92544dSBjoern A. Zeeb #define CHAN6G(_idx, _freq) {			\
306c92544dSBjoern A. Zeeb 	.band = NL80211_BAND_6GHZ,		\
316c92544dSBjoern A. Zeeb 	.center_freq = (_freq),			\
326c92544dSBjoern A. Zeeb 	.hw_value = (_idx),			\
336c92544dSBjoern A. Zeeb 	.max_power = 30,			\
346c92544dSBjoern A. Zeeb }
356c92544dSBjoern A. Zeeb 
366c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_2ghz[] = {
376c92544dSBjoern A. Zeeb 	CHAN2G(1, 2412),
386c92544dSBjoern A. Zeeb 	CHAN2G(2, 2417),
396c92544dSBjoern A. Zeeb 	CHAN2G(3, 2422),
406c92544dSBjoern A. Zeeb 	CHAN2G(4, 2427),
416c92544dSBjoern A. Zeeb 	CHAN2G(5, 2432),
426c92544dSBjoern A. Zeeb 	CHAN2G(6, 2437),
436c92544dSBjoern A. Zeeb 	CHAN2G(7, 2442),
446c92544dSBjoern A. Zeeb 	CHAN2G(8, 2447),
456c92544dSBjoern A. Zeeb 	CHAN2G(9, 2452),
466c92544dSBjoern A. Zeeb 	CHAN2G(10, 2457),
476c92544dSBjoern A. Zeeb 	CHAN2G(11, 2462),
486c92544dSBjoern A. Zeeb 	CHAN2G(12, 2467),
496c92544dSBjoern A. Zeeb 	CHAN2G(13, 2472),
506c92544dSBjoern A. Zeeb 	CHAN2G(14, 2484),
516c92544dSBjoern A. Zeeb };
526c92544dSBjoern A. Zeeb 
536c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_5ghz[] = {
546c92544dSBjoern A. Zeeb 	CHAN5G(36, 5180),
556c92544dSBjoern A. Zeeb 	CHAN5G(40, 5200),
566c92544dSBjoern A. Zeeb 	CHAN5G(44, 5220),
576c92544dSBjoern A. Zeeb 	CHAN5G(48, 5240),
586c92544dSBjoern A. Zeeb 
596c92544dSBjoern A. Zeeb 	CHAN5G(52, 5260),
606c92544dSBjoern A. Zeeb 	CHAN5G(56, 5280),
616c92544dSBjoern A. Zeeb 	CHAN5G(60, 5300),
626c92544dSBjoern A. Zeeb 	CHAN5G(64, 5320),
636c92544dSBjoern A. Zeeb 
646c92544dSBjoern A. Zeeb 	CHAN5G(100, 5500),
656c92544dSBjoern A. Zeeb 	CHAN5G(104, 5520),
666c92544dSBjoern A. Zeeb 	CHAN5G(108, 5540),
676c92544dSBjoern A. Zeeb 	CHAN5G(112, 5560),
686c92544dSBjoern A. Zeeb 	CHAN5G(116, 5580),
696c92544dSBjoern A. Zeeb 	CHAN5G(120, 5600),
706c92544dSBjoern A. Zeeb 	CHAN5G(124, 5620),
716c92544dSBjoern A. Zeeb 	CHAN5G(128, 5640),
726c92544dSBjoern A. Zeeb 	CHAN5G(132, 5660),
736c92544dSBjoern A. Zeeb 	CHAN5G(136, 5680),
746c92544dSBjoern A. Zeeb 	CHAN5G(140, 5700),
756c92544dSBjoern A. Zeeb 	CHAN5G(144, 5720),
766c92544dSBjoern A. Zeeb 
776c92544dSBjoern A. Zeeb 	CHAN5G(149, 5745),
786c92544dSBjoern A. Zeeb 	CHAN5G(153, 5765),
796c92544dSBjoern A. Zeeb 	CHAN5G(157, 5785),
806c92544dSBjoern A. Zeeb 	CHAN5G(161, 5805),
816c92544dSBjoern A. Zeeb 	CHAN5G(165, 5825),
826c92544dSBjoern A. Zeeb 	CHAN5G(169, 5845),
836c92544dSBjoern A. Zeeb 	CHAN5G(173, 5865),
84cbb3ec25SBjoern A. Zeeb 	CHAN5G(177, 5885),
856c92544dSBjoern A. Zeeb };
866c92544dSBjoern A. Zeeb 
876c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_6ghz[] = {
886c92544dSBjoern A. Zeeb 	/* UNII-5 */
896c92544dSBjoern A. Zeeb 	CHAN6G(1, 5955),
906c92544dSBjoern A. Zeeb 	CHAN6G(5, 5975),
916c92544dSBjoern A. Zeeb 	CHAN6G(9, 5995),
926c92544dSBjoern A. Zeeb 	CHAN6G(13, 6015),
936c92544dSBjoern A. Zeeb 	CHAN6G(17, 6035),
946c92544dSBjoern A. Zeeb 	CHAN6G(21, 6055),
956c92544dSBjoern A. Zeeb 	CHAN6G(25, 6075),
966c92544dSBjoern A. Zeeb 	CHAN6G(29, 6095),
976c92544dSBjoern A. Zeeb 	CHAN6G(33, 6115),
986c92544dSBjoern A. Zeeb 	CHAN6G(37, 6135),
996c92544dSBjoern A. Zeeb 	CHAN6G(41, 6155),
1006c92544dSBjoern A. Zeeb 	CHAN6G(45, 6175),
1016c92544dSBjoern A. Zeeb 	CHAN6G(49, 6195),
1026c92544dSBjoern A. Zeeb 	CHAN6G(53, 6215),
1036c92544dSBjoern A. Zeeb 	CHAN6G(57, 6235),
1046c92544dSBjoern A. Zeeb 	CHAN6G(61, 6255),
1056c92544dSBjoern A. Zeeb 	CHAN6G(65, 6275),
1066c92544dSBjoern A. Zeeb 	CHAN6G(69, 6295),
1076c92544dSBjoern A. Zeeb 	CHAN6G(73, 6315),
1086c92544dSBjoern A. Zeeb 	CHAN6G(77, 6335),
1096c92544dSBjoern A. Zeeb 	CHAN6G(81, 6355),
1106c92544dSBjoern A. Zeeb 	CHAN6G(85, 6375),
1116c92544dSBjoern A. Zeeb 	CHAN6G(89, 6395),
1126c92544dSBjoern A. Zeeb 	CHAN6G(93, 6415),
1136c92544dSBjoern A. Zeeb 	/* UNII-6 */
1146c92544dSBjoern A. Zeeb 	CHAN6G(97, 6435),
1156c92544dSBjoern A. Zeeb 	CHAN6G(101, 6455),
1166c92544dSBjoern A. Zeeb 	CHAN6G(105, 6475),
1176c92544dSBjoern A. Zeeb 	CHAN6G(109, 6495),
1186c92544dSBjoern A. Zeeb 	CHAN6G(113, 6515),
1196c92544dSBjoern A. Zeeb 	CHAN6G(117, 6535),
1206c92544dSBjoern A. Zeeb 	/* UNII-7 */
1216c92544dSBjoern A. Zeeb 	CHAN6G(121, 6555),
1226c92544dSBjoern A. Zeeb 	CHAN6G(125, 6575),
1236c92544dSBjoern A. Zeeb 	CHAN6G(129, 6595),
1246c92544dSBjoern A. Zeeb 	CHAN6G(133, 6615),
1256c92544dSBjoern A. Zeeb 	CHAN6G(137, 6635),
1266c92544dSBjoern A. Zeeb 	CHAN6G(141, 6655),
1276c92544dSBjoern A. Zeeb 	CHAN6G(145, 6675),
1286c92544dSBjoern A. Zeeb 	CHAN6G(149, 6695),
1296c92544dSBjoern A. Zeeb 	CHAN6G(153, 6715),
1306c92544dSBjoern A. Zeeb 	CHAN6G(157, 6735),
1316c92544dSBjoern A. Zeeb 	CHAN6G(161, 6755),
1326c92544dSBjoern A. Zeeb 	CHAN6G(165, 6775),
1336c92544dSBjoern A. Zeeb 	CHAN6G(169, 6795),
1346c92544dSBjoern A. Zeeb 	CHAN6G(173, 6815),
1356c92544dSBjoern A. Zeeb 	CHAN6G(177, 6835),
1366c92544dSBjoern A. Zeeb 	CHAN6G(181, 6855),
1376c92544dSBjoern A. Zeeb 	CHAN6G(185, 6875),
1386c92544dSBjoern A. Zeeb 	/* UNII-8 */
1396c92544dSBjoern A. Zeeb 	CHAN6G(189, 6895),
1406c92544dSBjoern A. Zeeb 	CHAN6G(193, 6915),
1416c92544dSBjoern A. Zeeb 	CHAN6G(197, 6935),
1426c92544dSBjoern A. Zeeb 	CHAN6G(201, 6955),
1436c92544dSBjoern A. Zeeb 	CHAN6G(205, 6975),
1446c92544dSBjoern A. Zeeb 	CHAN6G(209, 6995),
1456c92544dSBjoern A. Zeeb 	CHAN6G(213, 7015),
1466c92544dSBjoern A. Zeeb 	CHAN6G(217, 7035),
1476c92544dSBjoern A. Zeeb 	CHAN6G(221, 7055),
1486c92544dSBjoern A. Zeeb 	CHAN6G(225, 7075),
1496c92544dSBjoern A. Zeeb 	CHAN6G(229, 7095),
1506c92544dSBjoern A. Zeeb 	CHAN6G(233, 7115),
1516c92544dSBjoern A. Zeeb };
1526c92544dSBjoern A. Zeeb 
1536c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
1546c92544dSBjoern A. Zeeb static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
1556c92544dSBjoern A. Zeeb 	{ .throughput =   0 * 1024, .blink_time = 334 },
1566c92544dSBjoern A. Zeeb 	{ .throughput =   1 * 1024, .blink_time = 260 },
1576c92544dSBjoern A. Zeeb 	{ .throughput =   5 * 1024, .blink_time = 220 },
1586c92544dSBjoern A. Zeeb 	{ .throughput =  10 * 1024, .blink_time = 190 },
1596c92544dSBjoern A. Zeeb 	{ .throughput =  20 * 1024, .blink_time = 170 },
1606c92544dSBjoern A. Zeeb 	{ .throughput =  50 * 1024, .blink_time = 150 },
1616c92544dSBjoern A. Zeeb 	{ .throughput =  70 * 1024, .blink_time = 130 },
1626c92544dSBjoern A. Zeeb 	{ .throughput = 100 * 1024, .blink_time = 110 },
1636c92544dSBjoern A. Zeeb 	{ .throughput = 200 * 1024, .blink_time =  80 },
1646c92544dSBjoern A. Zeeb 	{ .throughput = 300 * 1024, .blink_time =  50 },
1656c92544dSBjoern A. Zeeb };
1666c92544dSBjoern A. Zeeb #endif
1676c92544dSBjoern A. Zeeb 
1686c92544dSBjoern A. Zeeb struct ieee80211_rate mt76_rates[] = {
1696c92544dSBjoern A. Zeeb 	CCK_RATE(0, 10),
1706c92544dSBjoern A. Zeeb 	CCK_RATE(1, 20),
1716c92544dSBjoern A. Zeeb 	CCK_RATE(2, 55),
1726c92544dSBjoern A. Zeeb 	CCK_RATE(3, 110),
1736c92544dSBjoern A. Zeeb 	OFDM_RATE(11, 60),
1746c92544dSBjoern A. Zeeb 	OFDM_RATE(15, 90),
1756c92544dSBjoern A. Zeeb 	OFDM_RATE(10, 120),
1766c92544dSBjoern A. Zeeb 	OFDM_RATE(14, 180),
1776c92544dSBjoern A. Zeeb 	OFDM_RATE(9,  240),
1786c92544dSBjoern A. Zeeb 	OFDM_RATE(13, 360),
1796c92544dSBjoern A. Zeeb 	OFDM_RATE(8,  480),
1806c92544dSBjoern A. Zeeb 	OFDM_RATE(12, 540),
1816c92544dSBjoern A. Zeeb };
1826c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rates);
1836c92544dSBjoern A. Zeeb 
1846c92544dSBjoern A. Zeeb static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
1856c92544dSBjoern A. Zeeb 	{ .start_freq = 2402, .end_freq = 2494, },
1866c92544dSBjoern A. Zeeb 	{ .start_freq = 5150, .end_freq = 5350, },
1876c92544dSBjoern A. Zeeb 	{ .start_freq = 5350, .end_freq = 5470, },
1886c92544dSBjoern A. Zeeb 	{ .start_freq = 5470, .end_freq = 5725, },
1896c92544dSBjoern A. Zeeb 	{ .start_freq = 5725, .end_freq = 5950, },
1906c92544dSBjoern A. Zeeb 	{ .start_freq = 5945, .end_freq = 6165, },
1916c92544dSBjoern A. Zeeb 	{ .start_freq = 6165, .end_freq = 6405, },
1926c92544dSBjoern A. Zeeb 	{ .start_freq = 6405, .end_freq = 6525, },
1936c92544dSBjoern A. Zeeb 	{ .start_freq = 6525, .end_freq = 6705, },
1946c92544dSBjoern A. Zeeb 	{ .start_freq = 6705, .end_freq = 6865, },
1956c92544dSBjoern A. Zeeb 	{ .start_freq = 6865, .end_freq = 7125, },
1966c92544dSBjoern A. Zeeb };
1976c92544dSBjoern A. Zeeb 
1986c92544dSBjoern A. Zeeb static const struct cfg80211_sar_capa mt76_sar_capa = {
1996c92544dSBjoern A. Zeeb 	.type = NL80211_SAR_TYPE_POWER,
2006c92544dSBjoern A. Zeeb 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
2016c92544dSBjoern A. Zeeb 	.freq_ranges = &mt76_sar_freq_ranges[0],
2026c92544dSBjoern A. Zeeb };
2036c92544dSBjoern A. Zeeb 
2046c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
mt76_led_init(struct mt76_phy * phy)205cbb3ec25SBjoern A. Zeeb static int mt76_led_init(struct mt76_phy *phy)
2066c92544dSBjoern A. Zeeb {
207cbb3ec25SBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
208cbb3ec25SBjoern A. Zeeb 	struct ieee80211_hw *hw = phy->hw;
209*8ba4d145SBjoern A. Zeeb 	struct device_node *np = dev->dev->of_node;
2106c92544dSBjoern A. Zeeb 
211cbb3ec25SBjoern A. Zeeb 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
2126c92544dSBjoern A. Zeeb 		return 0;
2136c92544dSBjoern A. Zeeb 
214*8ba4d145SBjoern A. Zeeb 	np = of_get_child_by_name(np, "led");
215*8ba4d145SBjoern A. Zeeb 	if (np) {
216*8ba4d145SBjoern A. Zeeb 		if (!of_device_is_available(np)) {
217*8ba4d145SBjoern A. Zeeb 			of_node_put(np);
218*8ba4d145SBjoern A. Zeeb 			dev_info(dev->dev,
219*8ba4d145SBjoern A. Zeeb 				"led registration was explicitly disabled by dts\n");
220*8ba4d145SBjoern A. Zeeb 			return 0;
221*8ba4d145SBjoern A. Zeeb 		}
222*8ba4d145SBjoern A. Zeeb 
223*8ba4d145SBjoern A. Zeeb 		if (phy == &dev->phy) {
224*8ba4d145SBjoern A. Zeeb 			int led_pin;
225*8ba4d145SBjoern A. Zeeb 
226*8ba4d145SBjoern A. Zeeb 			if (!of_property_read_u32(np, "led-sources", &led_pin))
227*8ba4d145SBjoern A. Zeeb 				phy->leds.pin = led_pin;
228*8ba4d145SBjoern A. Zeeb 
229*8ba4d145SBjoern A. Zeeb 			phy->leds.al =
230*8ba4d145SBjoern A. Zeeb 				of_property_read_bool(np, "led-active-low");
231*8ba4d145SBjoern A. Zeeb 		}
232*8ba4d145SBjoern A. Zeeb 
233*8ba4d145SBjoern A. Zeeb 		of_node_put(np);
234*8ba4d145SBjoern A. Zeeb 	}
235*8ba4d145SBjoern A. Zeeb 
236cbb3ec25SBjoern A. Zeeb 	snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
237cbb3ec25SBjoern A. Zeeb 		 wiphy_name(hw->wiphy));
2386c92544dSBjoern A. Zeeb 
239cbb3ec25SBjoern A. Zeeb 	phy->leds.cdev.name = phy->leds.name;
240cbb3ec25SBjoern A. Zeeb 	phy->leds.cdev.default_trigger =
2416c92544dSBjoern A. Zeeb 		ieee80211_create_tpt_led_trigger(hw,
2426c92544dSBjoern A. Zeeb 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
2436c92544dSBjoern A. Zeeb 					mt76_tpt_blink,
2446c92544dSBjoern A. Zeeb 					ARRAY_SIZE(mt76_tpt_blink));
2456c92544dSBjoern A. Zeeb 
246*8ba4d145SBjoern A. Zeeb 	dev_info(dev->dev,
247*8ba4d145SBjoern A. Zeeb 		"registering led '%s'\n", phy->leds.name);
2486c92544dSBjoern A. Zeeb 
249cbb3ec25SBjoern A. Zeeb 	return led_classdev_register(dev->dev, &phy->leds.cdev);
2506c92544dSBjoern A. Zeeb }
2516c92544dSBjoern A. Zeeb 
mt76_led_cleanup(struct mt76_phy * phy)252cbb3ec25SBjoern A. Zeeb static void mt76_led_cleanup(struct mt76_phy *phy)
2536c92544dSBjoern A. Zeeb {
254cbb3ec25SBjoern A. Zeeb 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
2556c92544dSBjoern A. Zeeb 		return;
2566c92544dSBjoern A. Zeeb 
257cbb3ec25SBjoern A. Zeeb 	led_classdev_unregister(&phy->leds.cdev);
2586c92544dSBjoern A. Zeeb }
2596c92544dSBjoern A. Zeeb #endif
2606c92544dSBjoern A. Zeeb 
mt76_init_stream_cap(struct mt76_phy * phy,struct ieee80211_supported_band * sband,bool vht)2616c92544dSBjoern A. Zeeb static void mt76_init_stream_cap(struct mt76_phy *phy,
2626c92544dSBjoern A. Zeeb 				 struct ieee80211_supported_band *sband,
2636c92544dSBjoern A. Zeeb 				 bool vht)
2646c92544dSBjoern A. Zeeb {
2656c92544dSBjoern A. Zeeb 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
2666c92544dSBjoern A. Zeeb 	int i, nstream = hweight8(phy->antenna_mask);
2676c92544dSBjoern A. Zeeb 	struct ieee80211_sta_vht_cap *vht_cap;
2686c92544dSBjoern A. Zeeb 	u16 mcs_map = 0;
2696c92544dSBjoern A. Zeeb 
2706c92544dSBjoern A. Zeeb 	if (nstream > 1)
2716c92544dSBjoern A. Zeeb 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
2726c92544dSBjoern A. Zeeb 	else
2736c92544dSBjoern A. Zeeb 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
2746c92544dSBjoern A. Zeeb 
2756c92544dSBjoern A. Zeeb 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
2766c92544dSBjoern A. Zeeb 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
2776c92544dSBjoern A. Zeeb 
2786c92544dSBjoern A. Zeeb 	if (!vht)
2796c92544dSBjoern A. Zeeb 		return;
2806c92544dSBjoern A. Zeeb 
2816c92544dSBjoern A. Zeeb 	vht_cap = &sband->vht_cap;
2826c92544dSBjoern A. Zeeb 	if (nstream > 1)
2836c92544dSBjoern A. Zeeb 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
2846c92544dSBjoern A. Zeeb 	else
2856c92544dSBjoern A. Zeeb 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
2866c92544dSBjoern A. Zeeb 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
2876c92544dSBjoern A. Zeeb 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
2886c92544dSBjoern A. Zeeb 
2896c92544dSBjoern A. Zeeb 	for (i = 0; i < 8; i++) {
2906c92544dSBjoern A. Zeeb 		if (i < nstream)
2916c92544dSBjoern A. Zeeb 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
2926c92544dSBjoern A. Zeeb 		else
2936c92544dSBjoern A. Zeeb 			mcs_map |=
2946c92544dSBjoern A. Zeeb 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
2956c92544dSBjoern A. Zeeb 	}
2966c92544dSBjoern A. Zeeb 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
2976c92544dSBjoern A. Zeeb 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
2986c92544dSBjoern A. Zeeb 	if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
2996c92544dSBjoern A. Zeeb 		vht_cap->vht_mcs.tx_highest |=
3006c92544dSBjoern A. Zeeb 				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
3016c92544dSBjoern A. Zeeb }
3026c92544dSBjoern A. Zeeb 
mt76_set_stream_caps(struct mt76_phy * phy,bool vht)3036c92544dSBjoern A. Zeeb void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
3046c92544dSBjoern A. Zeeb {
3056c92544dSBjoern A. Zeeb 	if (phy->cap.has_2ghz)
3066c92544dSBjoern A. Zeeb 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
3076c92544dSBjoern A. Zeeb 	if (phy->cap.has_5ghz)
3086c92544dSBjoern A. Zeeb 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
3096c92544dSBjoern A. Zeeb 	if (phy->cap.has_6ghz)
3106c92544dSBjoern A. Zeeb 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
3116c92544dSBjoern A. Zeeb }
3126c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
3136c92544dSBjoern A. Zeeb 
3146c92544dSBjoern A. Zeeb static int
mt76_init_sband(struct mt76_phy * phy,struct mt76_sband * msband,const struct ieee80211_channel * chan,int n_chan,struct ieee80211_rate * rates,int n_rates,bool ht,bool vht)3156c92544dSBjoern A. Zeeb mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
3166c92544dSBjoern A. Zeeb 		const struct ieee80211_channel *chan, int n_chan,
3176c92544dSBjoern A. Zeeb 		struct ieee80211_rate *rates, int n_rates,
3186c92544dSBjoern A. Zeeb 		bool ht, bool vht)
3196c92544dSBjoern A. Zeeb {
3206c92544dSBjoern A. Zeeb 	struct ieee80211_supported_band *sband = &msband->sband;
3216c92544dSBjoern A. Zeeb 	struct ieee80211_sta_vht_cap *vht_cap;
3226c92544dSBjoern A. Zeeb 	struct ieee80211_sta_ht_cap *ht_cap;
3236c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
3246c92544dSBjoern A. Zeeb 	void *chanlist;
3256c92544dSBjoern A. Zeeb 	int size;
3266c92544dSBjoern A. Zeeb 
3276c92544dSBjoern A. Zeeb 	size = n_chan * sizeof(*chan);
3286c92544dSBjoern A. Zeeb 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
3296c92544dSBjoern A. Zeeb 	if (!chanlist)
3306c92544dSBjoern A. Zeeb 		return -ENOMEM;
3316c92544dSBjoern A. Zeeb 
3326c92544dSBjoern A. Zeeb 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
3336c92544dSBjoern A. Zeeb 				    GFP_KERNEL);
3346c92544dSBjoern A. Zeeb 	if (!msband->chan)
3356c92544dSBjoern A. Zeeb 		return -ENOMEM;
3366c92544dSBjoern A. Zeeb 
3376c92544dSBjoern A. Zeeb 	sband->channels = chanlist;
3386c92544dSBjoern A. Zeeb 	sband->n_channels = n_chan;
3396c92544dSBjoern A. Zeeb 	sband->bitrates = rates;
3406c92544dSBjoern A. Zeeb 	sband->n_bitrates = n_rates;
3416c92544dSBjoern A. Zeeb 
3426c92544dSBjoern A. Zeeb 	if (!ht)
3436c92544dSBjoern A. Zeeb 		return 0;
3446c92544dSBjoern A. Zeeb 
3456c92544dSBjoern A. Zeeb 	ht_cap = &sband->ht_cap;
3466c92544dSBjoern A. Zeeb 	ht_cap->ht_supported = true;
3476c92544dSBjoern A. Zeeb 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
3486c92544dSBjoern A. Zeeb 		       IEEE80211_HT_CAP_GRN_FLD |
3496c92544dSBjoern A. Zeeb 		       IEEE80211_HT_CAP_SGI_20 |
3506c92544dSBjoern A. Zeeb 		       IEEE80211_HT_CAP_SGI_40 |
3516c92544dSBjoern A. Zeeb 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
3526c92544dSBjoern A. Zeeb 
3536c92544dSBjoern A. Zeeb 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
3546c92544dSBjoern A. Zeeb 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
3556c92544dSBjoern A. Zeeb 
3566c92544dSBjoern A. Zeeb 	mt76_init_stream_cap(phy, sband, vht);
3576c92544dSBjoern A. Zeeb 
3586c92544dSBjoern A. Zeeb 	if (!vht)
3596c92544dSBjoern A. Zeeb 		return 0;
3606c92544dSBjoern A. Zeeb 
3616c92544dSBjoern A. Zeeb 	vht_cap = &sband->vht_cap;
3626c92544dSBjoern A. Zeeb 	vht_cap->vht_supported = true;
3636c92544dSBjoern A. Zeeb 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
3646c92544dSBjoern A. Zeeb 			IEEE80211_VHT_CAP_RXSTBC_1 |
3656c92544dSBjoern A. Zeeb 			IEEE80211_VHT_CAP_SHORT_GI_80 |
3666c92544dSBjoern A. Zeeb 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
3676c92544dSBjoern A. Zeeb 
3686c92544dSBjoern A. Zeeb 	return 0;
3696c92544dSBjoern A. Zeeb }
3706c92544dSBjoern A. Zeeb 
3716c92544dSBjoern A. Zeeb static int
mt76_init_sband_2g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)3726c92544dSBjoern A. Zeeb mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3736c92544dSBjoern A. Zeeb 		   int n_rates)
3746c92544dSBjoern A. Zeeb {
3756c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
3766c92544dSBjoern A. Zeeb 
3776c92544dSBjoern A. Zeeb 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
3786c92544dSBjoern A. Zeeb 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
3796c92544dSBjoern A. Zeeb 			       n_rates, true, false);
3806c92544dSBjoern A. Zeeb }
3816c92544dSBjoern A. Zeeb 
3826c92544dSBjoern A. Zeeb static int
mt76_init_sband_5g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates,bool vht)3836c92544dSBjoern A. Zeeb mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3846c92544dSBjoern A. Zeeb 		   int n_rates, bool vht)
3856c92544dSBjoern A. Zeeb {
3866c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
3876c92544dSBjoern A. Zeeb 
3886c92544dSBjoern A. Zeeb 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
3896c92544dSBjoern A. Zeeb 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
3906c92544dSBjoern A. Zeeb 			       n_rates, true, vht);
3916c92544dSBjoern A. Zeeb }
3926c92544dSBjoern A. Zeeb 
3936c92544dSBjoern A. Zeeb static int
mt76_init_sband_6g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)3946c92544dSBjoern A. Zeeb mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3956c92544dSBjoern A. Zeeb 		   int n_rates)
3966c92544dSBjoern A. Zeeb {
3976c92544dSBjoern A. Zeeb 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
3986c92544dSBjoern A. Zeeb 
3996c92544dSBjoern A. Zeeb 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
4006c92544dSBjoern A. Zeeb 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
4016c92544dSBjoern A. Zeeb 			       n_rates, false, false);
4026c92544dSBjoern A. Zeeb }
4036c92544dSBjoern A. Zeeb 
4046c92544dSBjoern A. Zeeb static void
mt76_check_sband(struct mt76_phy * phy,struct mt76_sband * msband,enum nl80211_band band)4056c92544dSBjoern A. Zeeb mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
4066c92544dSBjoern A. Zeeb 		 enum nl80211_band band)
4076c92544dSBjoern A. Zeeb {
4086c92544dSBjoern A. Zeeb 	struct ieee80211_supported_band *sband = &msband->sband;
4096c92544dSBjoern A. Zeeb 	bool found = false;
4106c92544dSBjoern A. Zeeb 	int i;
4116c92544dSBjoern A. Zeeb 
4126c92544dSBjoern A. Zeeb 	if (!sband)
4136c92544dSBjoern A. Zeeb 		return;
4146c92544dSBjoern A. Zeeb 
4156c92544dSBjoern A. Zeeb 	for (i = 0; i < sband->n_channels; i++) {
4166c92544dSBjoern A. Zeeb 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
4176c92544dSBjoern A. Zeeb 			continue;
4186c92544dSBjoern A. Zeeb 
4196c92544dSBjoern A. Zeeb 		found = true;
4206c92544dSBjoern A. Zeeb 		break;
4216c92544dSBjoern A. Zeeb 	}
4226c92544dSBjoern A. Zeeb 
4236c92544dSBjoern A. Zeeb 	if (found) {
424*8ba4d145SBjoern A. Zeeb 		cfg80211_chandef_create(&phy->chandef, &sband->channels[0],
425*8ba4d145SBjoern A. Zeeb 					NL80211_CHAN_HT20);
4266c92544dSBjoern A. Zeeb 		phy->chan_state = &msband->chan[0];
427*8ba4d145SBjoern A. Zeeb 		phy->dev->band_phys[band] = phy;
4286c92544dSBjoern A. Zeeb 		return;
4296c92544dSBjoern A. Zeeb 	}
4306c92544dSBjoern A. Zeeb 
4316c92544dSBjoern A. Zeeb 	sband->n_channels = 0;
432*8ba4d145SBjoern A. Zeeb 	if (phy->hw->wiphy->bands[band] == sband)
4336c92544dSBjoern A. Zeeb 		phy->hw->wiphy->bands[band] = NULL;
4346c92544dSBjoern A. Zeeb }
4356c92544dSBjoern A. Zeeb 
4366c92544dSBjoern A. Zeeb static int
mt76_phy_init(struct mt76_phy * phy,struct ieee80211_hw * hw)4376c92544dSBjoern A. Zeeb mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
4386c92544dSBjoern A. Zeeb {
4396c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
4406c92544dSBjoern A. Zeeb 	struct wiphy *wiphy = hw->wiphy;
4416c92544dSBjoern A. Zeeb 
442*8ba4d145SBjoern A. Zeeb 	INIT_LIST_HEAD(&phy->tx_list);
443*8ba4d145SBjoern A. Zeeb 	spin_lock_init(&phy->tx_lock);
444*8ba4d145SBjoern A. Zeeb 	INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work);
445*8ba4d145SBjoern A. Zeeb 
446*8ba4d145SBjoern A. Zeeb 	if ((void *)phy != hw->priv)
447*8ba4d145SBjoern A. Zeeb 		return 0;
448*8ba4d145SBjoern A. Zeeb 
4496c92544dSBjoern A. Zeeb 	SET_IEEE80211_DEV(hw, dev->dev);
4506c92544dSBjoern A. Zeeb 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
4516c92544dSBjoern A. Zeeb 
452cbb3ec25SBjoern A. Zeeb 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
453cbb3ec25SBjoern A. Zeeb 			   NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
4546c92544dSBjoern A. Zeeb 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
4556c92544dSBjoern A. Zeeb 			WIPHY_FLAG_SUPPORTS_TDLS |
4566c92544dSBjoern A. Zeeb 			WIPHY_FLAG_AP_UAPSD;
4576c92544dSBjoern A. Zeeb 
4586c92544dSBjoern A. Zeeb 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
4596c92544dSBjoern A. Zeeb 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
4606c92544dSBjoern A. Zeeb 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
4616c92544dSBjoern A. Zeeb 
4626c92544dSBjoern A. Zeeb 	wiphy->available_antennas_tx = phy->antenna_mask;
4636c92544dSBjoern A. Zeeb 	wiphy->available_antennas_rx = phy->antenna_mask;
4646c92544dSBjoern A. Zeeb 
4656c92544dSBjoern A. Zeeb 	wiphy->sar_capa = &mt76_sar_capa;
4666c92544dSBjoern A. Zeeb 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
4676c92544dSBjoern A. Zeeb 				sizeof(struct mt76_freq_range_power),
4686c92544dSBjoern A. Zeeb 				GFP_KERNEL);
4696c92544dSBjoern A. Zeeb 	if (!phy->frp)
4706c92544dSBjoern A. Zeeb 		return -ENOMEM;
4716c92544dSBjoern A. Zeeb 
4726c92544dSBjoern A. Zeeb 	hw->txq_data_size = sizeof(struct mt76_txq);
4736c92544dSBjoern A. Zeeb 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
4746c92544dSBjoern A. Zeeb 
4756c92544dSBjoern A. Zeeb 	if (!hw->max_tx_fragments)
4766c92544dSBjoern A. Zeeb 		hw->max_tx_fragments = 16;
4776c92544dSBjoern A. Zeeb 
4786c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SIGNAL_DBM);
4796c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
4806c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
4816c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
4826c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
4836c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
4846c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
485*8ba4d145SBjoern A. Zeeb 	ieee80211_hw_set(hw, SPECTRUM_MGMT);
486cbb3ec25SBjoern A. Zeeb 
487*8ba4d145SBjoern A. Zeeb 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD) &&
488*8ba4d145SBjoern A. Zeeb 	    hw->max_tx_fragments > 1) {
4896c92544dSBjoern A. Zeeb 		ieee80211_hw_set(hw, TX_AMSDU);
4906c92544dSBjoern A. Zeeb 		ieee80211_hw_set(hw, TX_FRAG_LIST);
491cbb3ec25SBjoern A. Zeeb 	}
492cbb3ec25SBjoern A. Zeeb 
4936c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, MFP_CAPABLE);
4946c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, AP_LINK_PS);
4956c92544dSBjoern A. Zeeb 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
4966c92544dSBjoern A. Zeeb 
4976c92544dSBjoern A. Zeeb 	return 0;
4986c92544dSBjoern A. Zeeb }
4996c92544dSBjoern A. Zeeb 
5006c92544dSBjoern A. Zeeb struct mt76_phy *
mt76_alloc_radio_phy(struct mt76_dev * dev,unsigned int size,u8 band_idx)501*8ba4d145SBjoern A. Zeeb mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size,
502*8ba4d145SBjoern A. Zeeb 		     u8 band_idx)
503*8ba4d145SBjoern A. Zeeb {
504*8ba4d145SBjoern A. Zeeb 	struct ieee80211_hw *hw = dev->phy.hw;
505*8ba4d145SBjoern A. Zeeb 	unsigned int phy_size;
506*8ba4d145SBjoern A. Zeeb 	struct mt76_phy *phy;
507*8ba4d145SBjoern A. Zeeb 
508*8ba4d145SBjoern A. Zeeb 	phy_size = ALIGN(sizeof(*phy), 8);
509*8ba4d145SBjoern A. Zeeb 	phy = devm_kzalloc(dev->dev, size + phy_size, GFP_KERNEL);
510*8ba4d145SBjoern A. Zeeb 	if (!phy)
511*8ba4d145SBjoern A. Zeeb 		return NULL;
512*8ba4d145SBjoern A. Zeeb 
513*8ba4d145SBjoern A. Zeeb 	phy->dev = dev;
514*8ba4d145SBjoern A. Zeeb 	phy->hw = hw;
515*8ba4d145SBjoern A. Zeeb #if defined(__linux__)
516*8ba4d145SBjoern A. Zeeb 	phy->priv = (void *)phy + phy_size;
517*8ba4d145SBjoern A. Zeeb #elif defined(__FreeBSD__)
518*8ba4d145SBjoern A. Zeeb 	phy->priv = (u8 *)phy + phy_size;
519*8ba4d145SBjoern A. Zeeb #endif
520*8ba4d145SBjoern A. Zeeb 	phy->band_idx = band_idx;
521*8ba4d145SBjoern A. Zeeb 
522*8ba4d145SBjoern A. Zeeb 	return phy;
523*8ba4d145SBjoern A. Zeeb }
524*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_radio_phy);
525*8ba4d145SBjoern A. Zeeb 
526*8ba4d145SBjoern A. Zeeb struct mt76_phy *
mt76_alloc_phy(struct mt76_dev * dev,unsigned int size,const struct ieee80211_ops * ops,u8 band_idx)5276c92544dSBjoern A. Zeeb mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
5286c92544dSBjoern A. Zeeb 	       const struct ieee80211_ops *ops, u8 band_idx)
5296c92544dSBjoern A. Zeeb {
5306c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
5316c92544dSBjoern A. Zeeb 	unsigned int phy_size;
5326c92544dSBjoern A. Zeeb 	struct mt76_phy *phy;
5336c92544dSBjoern A. Zeeb 
5346c92544dSBjoern A. Zeeb 	phy_size = ALIGN(sizeof(*phy), 8);
5356c92544dSBjoern A. Zeeb 	hw = ieee80211_alloc_hw(size + phy_size, ops);
5366c92544dSBjoern A. Zeeb 	if (!hw)
5376c92544dSBjoern A. Zeeb 		return NULL;
5386c92544dSBjoern A. Zeeb 
5396c92544dSBjoern A. Zeeb 	phy = hw->priv;
5406c92544dSBjoern A. Zeeb 	phy->dev = dev;
5416c92544dSBjoern A. Zeeb 	phy->hw = hw;
5426c92544dSBjoern A. Zeeb #if defined(__linux__)
5436c92544dSBjoern A. Zeeb 	phy->priv = hw->priv + phy_size;
5446c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
5456c92544dSBjoern A. Zeeb 	phy->priv = (u8 *)hw->priv + phy_size;
5466c92544dSBjoern A. Zeeb #endif
5476c92544dSBjoern A. Zeeb 	phy->band_idx = band_idx;
5486c92544dSBjoern A. Zeeb 
5496c92544dSBjoern A. Zeeb 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5506c92544dSBjoern A. Zeeb 	hw->wiphy->interface_modes =
5516c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_STATION) |
5526c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_AP) |
5536c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH
5546c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_MESH_POINT) |
5556c92544dSBjoern A. Zeeb #endif
5566c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5576c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_GO) |
5586c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_ADHOC);
5596c92544dSBjoern A. Zeeb 
5606c92544dSBjoern A. Zeeb 	return phy;
5616c92544dSBjoern A. Zeeb }
5626c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_phy);
5636c92544dSBjoern A. Zeeb 
mt76_register_phy(struct mt76_phy * phy,bool vht,struct ieee80211_rate * rates,int n_rates)5646c92544dSBjoern A. Zeeb int mt76_register_phy(struct mt76_phy *phy, bool vht,
5656c92544dSBjoern A. Zeeb 		      struct ieee80211_rate *rates, int n_rates)
5666c92544dSBjoern A. Zeeb {
5676c92544dSBjoern A. Zeeb 	int ret;
5686c92544dSBjoern A. Zeeb 
5696c92544dSBjoern A. Zeeb 	ret = mt76_phy_init(phy, phy->hw);
5706c92544dSBjoern A. Zeeb 	if (ret)
5716c92544dSBjoern A. Zeeb 		return ret;
5726c92544dSBjoern A. Zeeb 
5736c92544dSBjoern A. Zeeb 	if (phy->cap.has_2ghz) {
5746c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_2g(phy, rates, n_rates);
5756c92544dSBjoern A. Zeeb 		if (ret)
5766c92544dSBjoern A. Zeeb 			return ret;
5776c92544dSBjoern A. Zeeb 	}
5786c92544dSBjoern A. Zeeb 
5796c92544dSBjoern A. Zeeb 	if (phy->cap.has_5ghz) {
5806c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
5816c92544dSBjoern A. Zeeb 		if (ret)
5826c92544dSBjoern A. Zeeb 			return ret;
5836c92544dSBjoern A. Zeeb 	}
5846c92544dSBjoern A. Zeeb 
5856c92544dSBjoern A. Zeeb 	if (phy->cap.has_6ghz) {
5866c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
5876c92544dSBjoern A. Zeeb 		if (ret)
5886c92544dSBjoern A. Zeeb 			return ret;
5896c92544dSBjoern A. Zeeb 	}
5906c92544dSBjoern A. Zeeb 
591cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
592cbb3ec25SBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
593cbb3ec25SBjoern A. Zeeb 		ret = mt76_led_init(phy);
594cbb3ec25SBjoern A. Zeeb 		if (ret)
595cbb3ec25SBjoern A. Zeeb 			return ret;
596cbb3ec25SBjoern A. Zeeb 	}
597cbb3ec25SBjoern A. Zeeb #endif
598cbb3ec25SBjoern A. Zeeb 
5996c92544dSBjoern A. Zeeb 	wiphy_read_of_freq_limits(phy->hw->wiphy);
6006c92544dSBjoern A. Zeeb 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
6016c92544dSBjoern A. Zeeb 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
6026c92544dSBjoern A. Zeeb 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
6036c92544dSBjoern A. Zeeb 
604*8ba4d145SBjoern A. Zeeb 	if ((void *)phy == phy->hw->priv) {
6056c92544dSBjoern A. Zeeb 		ret = ieee80211_register_hw(phy->hw);
6066c92544dSBjoern A. Zeeb 		if (ret)
6076c92544dSBjoern A. Zeeb 			return ret;
608*8ba4d145SBjoern A. Zeeb 	}
6096c92544dSBjoern A. Zeeb 
610cbb3ec25SBjoern A. Zeeb 	set_bit(MT76_STATE_REGISTERED, &phy->state);
6116c92544dSBjoern A. Zeeb 	phy->dev->phys[phy->band_idx] = phy;
6126c92544dSBjoern A. Zeeb 
6136c92544dSBjoern A. Zeeb 	return 0;
6146c92544dSBjoern A. Zeeb }
6156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_phy);
6166c92544dSBjoern A. Zeeb 
mt76_unregister_phy(struct mt76_phy * phy)6176c92544dSBjoern A. Zeeb void mt76_unregister_phy(struct mt76_phy *phy)
6186c92544dSBjoern A. Zeeb {
6196c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
6206c92544dSBjoern A. Zeeb 
621cbb3ec25SBjoern A. Zeeb 	if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
622cbb3ec25SBjoern A. Zeeb 		return;
623cbb3ec25SBjoern A. Zeeb 
624cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
625cbb3ec25SBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS))
626cbb3ec25SBjoern A. Zeeb 		mt76_led_cleanup(phy);
627cbb3ec25SBjoern A. Zeeb #endif
6286c92544dSBjoern A. Zeeb 	mt76_tx_status_check(dev, true);
6296c92544dSBjoern A. Zeeb 	ieee80211_unregister_hw(phy->hw);
6306c92544dSBjoern A. Zeeb 	dev->phys[phy->band_idx] = NULL;
6316c92544dSBjoern A. Zeeb }
6326c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_phy);
6336c92544dSBjoern A. Zeeb 
mt76_create_page_pool(struct mt76_dev * dev,struct mt76_queue * q)634cbb3ec25SBjoern A. Zeeb int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
635cbb3ec25SBjoern A. Zeeb {
636*8ba4d145SBjoern A. Zeeb 	bool is_qrx = mt76_queue_is_rx(dev, q);
637cbb3ec25SBjoern A. Zeeb 	struct page_pool_params pp_params = {
638cbb3ec25SBjoern A. Zeeb 		.order = 0,
639*8ba4d145SBjoern A. Zeeb 		.flags = 0,
640cbb3ec25SBjoern A. Zeeb 		.nid = NUMA_NO_NODE,
641cbb3ec25SBjoern A. Zeeb 		.dev = dev->dma_dev,
642cbb3ec25SBjoern A. Zeeb 	};
643*8ba4d145SBjoern A. Zeeb 	int idx = is_qrx ? q - dev->q_rx : -1;
644*8ba4d145SBjoern A. Zeeb 
645*8ba4d145SBjoern A. Zeeb 	/* Allocate page_pools just for rx/wed_tx_free queues */
646*8ba4d145SBjoern A. Zeeb 	if (!is_qrx && !mt76_queue_is_wed_tx_free(q))
647*8ba4d145SBjoern A. Zeeb 		return 0;
648cbb3ec25SBjoern A. Zeeb 
649cbb3ec25SBjoern A. Zeeb 	switch (idx) {
650cbb3ec25SBjoern A. Zeeb 	case MT_RXQ_MAIN:
651cbb3ec25SBjoern A. Zeeb 	case MT_RXQ_BAND1:
652cbb3ec25SBjoern A. Zeeb 	case MT_RXQ_BAND2:
653cbb3ec25SBjoern A. Zeeb 		pp_params.pool_size = 256;
654cbb3ec25SBjoern A. Zeeb 		break;
655cbb3ec25SBjoern A. Zeeb 	default:
656cbb3ec25SBjoern A. Zeeb 		pp_params.pool_size = 16;
657cbb3ec25SBjoern A. Zeeb 		break;
658cbb3ec25SBjoern A. Zeeb 	}
659cbb3ec25SBjoern A. Zeeb 
660cbb3ec25SBjoern A. Zeeb 	if (mt76_is_mmio(dev)) {
661cbb3ec25SBjoern A. Zeeb 		/* rely on page_pool for DMA mapping */
662cbb3ec25SBjoern A. Zeeb 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
663cbb3ec25SBjoern A. Zeeb 		pp_params.dma_dir = DMA_FROM_DEVICE;
664cbb3ec25SBjoern A. Zeeb 		pp_params.max_len = PAGE_SIZE;
665cbb3ec25SBjoern A. Zeeb 		pp_params.offset = 0;
666*8ba4d145SBjoern A. Zeeb 		/* NAPI is available just for rx queues */
667*8ba4d145SBjoern A. Zeeb 		if (idx >= 0 && idx < ARRAY_SIZE(dev->napi))
668*8ba4d145SBjoern A. Zeeb 			pp_params.napi = &dev->napi[idx];
669cbb3ec25SBjoern A. Zeeb 	}
670cbb3ec25SBjoern A. Zeeb 
671cbb3ec25SBjoern A. Zeeb 	q->page_pool = page_pool_create(&pp_params);
672cbb3ec25SBjoern A. Zeeb 	if (IS_ERR(q->page_pool)) {
673cbb3ec25SBjoern A. Zeeb 		int err = PTR_ERR(q->page_pool);
674cbb3ec25SBjoern A. Zeeb 
675cbb3ec25SBjoern A. Zeeb 		q->page_pool = NULL;
676cbb3ec25SBjoern A. Zeeb 		return err;
677cbb3ec25SBjoern A. Zeeb 	}
678cbb3ec25SBjoern A. Zeeb 
679cbb3ec25SBjoern A. Zeeb 	return 0;
680cbb3ec25SBjoern A. Zeeb }
681cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_create_page_pool);
682cbb3ec25SBjoern A. Zeeb 
6836c92544dSBjoern A. Zeeb struct mt76_dev *
mt76_alloc_device(struct device * pdev,unsigned int size,const struct ieee80211_ops * ops,const struct mt76_driver_ops * drv_ops)6846c92544dSBjoern A. Zeeb mt76_alloc_device(struct device *pdev, unsigned int size,
6856c92544dSBjoern A. Zeeb 		  const struct ieee80211_ops *ops,
6866c92544dSBjoern A. Zeeb 		  const struct mt76_driver_ops *drv_ops)
6876c92544dSBjoern A. Zeeb {
6886c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
6896c92544dSBjoern A. Zeeb 	struct mt76_phy *phy;
6906c92544dSBjoern A. Zeeb 	struct mt76_dev *dev;
6916c92544dSBjoern A. Zeeb 	int i;
6926c92544dSBjoern A. Zeeb 
6936c92544dSBjoern A. Zeeb 	hw = ieee80211_alloc_hw(size, ops);
6946c92544dSBjoern A. Zeeb 	if (!hw)
6956c92544dSBjoern A. Zeeb 		return NULL;
6966c92544dSBjoern A. Zeeb 
6976c92544dSBjoern A. Zeeb 	dev = hw->priv;
6986c92544dSBjoern A. Zeeb 	dev->hw = hw;
6996c92544dSBjoern A. Zeeb 	dev->dev = pdev;
7006c92544dSBjoern A. Zeeb 	dev->drv = drv_ops;
7016c92544dSBjoern A. Zeeb 	dev->dma_dev = pdev;
7026c92544dSBjoern A. Zeeb 
7036c92544dSBjoern A. Zeeb 	phy = &dev->phy;
7046c92544dSBjoern A. Zeeb 	phy->dev = dev;
7056c92544dSBjoern A. Zeeb 	phy->hw = hw;
7066c92544dSBjoern A. Zeeb 	phy->band_idx = MT_BAND0;
7076c92544dSBjoern A. Zeeb 	dev->phys[phy->band_idx] = phy;
7086c92544dSBjoern A. Zeeb 
7096c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->rx_lock);
7106c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->lock);
7116c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->cc_lock);
7126c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->status_lock);
713cbb3ec25SBjoern A. Zeeb 	spin_lock_init(&dev->wed_lock);
7146c92544dSBjoern A. Zeeb 	mutex_init(&dev->mutex);
7156c92544dSBjoern A. Zeeb 	init_waitqueue_head(&dev->tx_wait);
7166c92544dSBjoern A. Zeeb 
7176c92544dSBjoern A. Zeeb 	skb_queue_head_init(&dev->mcu.res_q);
7186c92544dSBjoern A. Zeeb 	init_waitqueue_head(&dev->mcu.wait);
7196c92544dSBjoern A. Zeeb 	mutex_init(&dev->mcu.mutex);
7206c92544dSBjoern A. Zeeb 	dev->tx_worker.fn = mt76_tx_worker;
7216c92544dSBjoern A. Zeeb 
7226c92544dSBjoern A. Zeeb 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
7236c92544dSBjoern A. Zeeb 	hw->wiphy->interface_modes =
7246c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_STATION) |
7256c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_AP) |
7266c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH
7276c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_MESH_POINT) |
7286c92544dSBjoern A. Zeeb #endif
7296c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
7306c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_P2P_GO) |
7316c92544dSBjoern A. Zeeb 		BIT(NL80211_IFTYPE_ADHOC);
7326c92544dSBjoern A. Zeeb 
7336c92544dSBjoern A. Zeeb 	spin_lock_init(&dev->token_lock);
7346c92544dSBjoern A. Zeeb 	idr_init(&dev->token);
7356c92544dSBjoern A. Zeeb 
736cbb3ec25SBjoern A. Zeeb 	spin_lock_init(&dev->rx_token_lock);
737cbb3ec25SBjoern A. Zeeb 	idr_init(&dev->rx_token);
738cbb3ec25SBjoern A. Zeeb 
7396c92544dSBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->wcid_list);
740cbb3ec25SBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->sta_poll_list);
741cbb3ec25SBjoern A. Zeeb 	spin_lock_init(&dev->sta_poll_lock);
7426c92544dSBjoern A. Zeeb 
7436c92544dSBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->txwi_cache);
744cbb3ec25SBjoern A. Zeeb 	INIT_LIST_HEAD(&dev->rxwi_cache);
7456c92544dSBjoern A. Zeeb 	dev->token_size = dev->drv->token_size;
746*8ba4d145SBjoern A. Zeeb 	INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work);
7476c92544dSBjoern A. Zeeb 
7486c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
7496c92544dSBjoern A. Zeeb 		skb_queue_head_init(&dev->rx_skb[i]);
7506c92544dSBjoern A. Zeeb 
7516c92544dSBjoern A. Zeeb 	dev->wq = alloc_ordered_workqueue("mt76", 0);
7526c92544dSBjoern A. Zeeb 	if (!dev->wq) {
7536c92544dSBjoern A. Zeeb 		ieee80211_free_hw(hw);
7546c92544dSBjoern A. Zeeb 		return NULL;
7556c92544dSBjoern A. Zeeb 	}
7566c92544dSBjoern A. Zeeb 
7576c92544dSBjoern A. Zeeb 	return dev;
7586c92544dSBjoern A. Zeeb }
7596c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_device);
7606c92544dSBjoern A. Zeeb 
mt76_register_device(struct mt76_dev * dev,bool vht,struct ieee80211_rate * rates,int n_rates)7616c92544dSBjoern A. Zeeb int mt76_register_device(struct mt76_dev *dev, bool vht,
7626c92544dSBjoern A. Zeeb 			 struct ieee80211_rate *rates, int n_rates)
7636c92544dSBjoern A. Zeeb {
7646c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = dev->hw;
7656c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = &dev->phy;
7666c92544dSBjoern A. Zeeb 	int ret;
7676c92544dSBjoern A. Zeeb 
7686c92544dSBjoern A. Zeeb 	dev_set_drvdata(dev->dev, dev);
769*8ba4d145SBjoern A. Zeeb 	mt76_wcid_init(&dev->global_wcid, phy->band_idx);
7706c92544dSBjoern A. Zeeb 	ret = mt76_phy_init(phy, hw);
7716c92544dSBjoern A. Zeeb 	if (ret)
7726c92544dSBjoern A. Zeeb 		return ret;
7736c92544dSBjoern A. Zeeb 
7746c92544dSBjoern A. Zeeb 	if (phy->cap.has_2ghz) {
7756c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_2g(phy, rates, n_rates);
7766c92544dSBjoern A. Zeeb 		if (ret)
7776c92544dSBjoern A. Zeeb 			return ret;
7786c92544dSBjoern A. Zeeb 	}
7796c92544dSBjoern A. Zeeb 
7806c92544dSBjoern A. Zeeb 	if (phy->cap.has_5ghz) {
7816c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
7826c92544dSBjoern A. Zeeb 		if (ret)
7836c92544dSBjoern A. Zeeb 			return ret;
7846c92544dSBjoern A. Zeeb 	}
7856c92544dSBjoern A. Zeeb 
7866c92544dSBjoern A. Zeeb 	if (phy->cap.has_6ghz) {
7876c92544dSBjoern A. Zeeb 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
7886c92544dSBjoern A. Zeeb 		if (ret)
7896c92544dSBjoern A. Zeeb 			return ret;
7906c92544dSBjoern A. Zeeb 	}
7916c92544dSBjoern A. Zeeb 
7926c92544dSBjoern A. Zeeb 	wiphy_read_of_freq_limits(hw->wiphy);
7936c92544dSBjoern A. Zeeb 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
7946c92544dSBjoern A. Zeeb 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
7956c92544dSBjoern A. Zeeb 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
7966c92544dSBjoern A. Zeeb 
7976c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
7986c92544dSBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
799cbb3ec25SBjoern A. Zeeb 		ret = mt76_led_init(phy);
8006c92544dSBjoern A. Zeeb 		if (ret)
8016c92544dSBjoern A. Zeeb 			return ret;
8026c92544dSBjoern A. Zeeb 	}
8036c92544dSBjoern A. Zeeb #endif
8046c92544dSBjoern A. Zeeb 
8056c92544dSBjoern A. Zeeb 	ret = ieee80211_register_hw(hw);
8066c92544dSBjoern A. Zeeb 	if (ret)
8076c92544dSBjoern A. Zeeb 		return ret;
8086c92544dSBjoern A. Zeeb 
8096c92544dSBjoern A. Zeeb 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
810cbb3ec25SBjoern A. Zeeb 	set_bit(MT76_STATE_REGISTERED, &phy->state);
8116c92544dSBjoern A. Zeeb 	sched_set_fifo_low(dev->tx_worker.task);
8126c92544dSBjoern A. Zeeb 
8136c92544dSBjoern A. Zeeb 	return 0;
8146c92544dSBjoern A. Zeeb }
8156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_device);
8166c92544dSBjoern A. Zeeb 
mt76_unregister_device(struct mt76_dev * dev)8176c92544dSBjoern A. Zeeb void mt76_unregister_device(struct mt76_dev *dev)
8186c92544dSBjoern A. Zeeb {
819cbb3ec25SBjoern A. Zeeb #if defined(__linux__)
8206c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = dev->hw;
821cbb3ec25SBjoern A. Zeeb #endif
822cbb3ec25SBjoern A. Zeeb 
823cbb3ec25SBjoern A. Zeeb 	if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
824cbb3ec25SBjoern A. Zeeb 		return;
8256c92544dSBjoern A. Zeeb 
8266c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
8276c92544dSBjoern A. Zeeb 	if (IS_ENABLED(CONFIG_MT76_LEDS))
828cbb3ec25SBjoern A. Zeeb 		mt76_led_cleanup(&dev->phy);
8296c92544dSBjoern A. Zeeb #endif
8306c92544dSBjoern A. Zeeb 	mt76_tx_status_check(dev, true);
831*8ba4d145SBjoern A. Zeeb 	mt76_wcid_cleanup(dev, &dev->global_wcid);
832cbb3ec25SBjoern A. Zeeb #if defined(__linux__)
8336c92544dSBjoern A. Zeeb 	ieee80211_unregister_hw(hw);
834cbb3ec25SBjoern A. Zeeb #elif defined(__FreeBSD__)
835cbb3ec25SBjoern A. Zeeb 	ieee80211_unregister_hw(dev->hw);
836cbb3ec25SBjoern A. Zeeb #endif
8376c92544dSBjoern A. Zeeb }
8386c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_device);
8396c92544dSBjoern A. Zeeb 
mt76_free_device(struct mt76_dev * dev)8406c92544dSBjoern A. Zeeb void mt76_free_device(struct mt76_dev *dev)
8416c92544dSBjoern A. Zeeb {
8426c92544dSBjoern A. Zeeb 	mt76_worker_teardown(&dev->tx_worker);
8436c92544dSBjoern A. Zeeb 	if (dev->wq) {
8446c92544dSBjoern A. Zeeb 		destroy_workqueue(dev->wq);
8456c92544dSBjoern A. Zeeb 		dev->wq = NULL;
8466c92544dSBjoern A. Zeeb 	}
8476c92544dSBjoern A. Zeeb 	ieee80211_free_hw(dev->hw);
8486c92544dSBjoern A. Zeeb }
8496c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_free_device);
8506c92544dSBjoern A. Zeeb 
851*8ba4d145SBjoern A. Zeeb static struct mt76_phy *
mt76_vif_phy(struct ieee80211_hw * hw,struct ieee80211_vif * vif)852*8ba4d145SBjoern A. Zeeb mt76_vif_phy(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
853*8ba4d145SBjoern A. Zeeb {
854*8ba4d145SBjoern A. Zeeb 	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
855*8ba4d145SBjoern A. Zeeb 	struct mt76_chanctx *ctx;
856*8ba4d145SBjoern A. Zeeb 
857*8ba4d145SBjoern A. Zeeb 	if (!hw->wiphy->n_radio)
858*8ba4d145SBjoern A. Zeeb 		return hw->priv;
859*8ba4d145SBjoern A. Zeeb 
860*8ba4d145SBjoern A. Zeeb 	if (!mlink->ctx)
861*8ba4d145SBjoern A. Zeeb 		return NULL;
862*8ba4d145SBjoern A. Zeeb 
863*8ba4d145SBjoern A. Zeeb 	ctx = (struct mt76_chanctx *)mlink->ctx->drv_priv;
864*8ba4d145SBjoern A. Zeeb 	return ctx->phy;
865*8ba4d145SBjoern A. Zeeb }
866*8ba4d145SBjoern A. Zeeb 
mt76_rx_release_amsdu(struct mt76_phy * phy,enum mt76_rxq_id q)8676c92544dSBjoern A. Zeeb static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
8686c92544dSBjoern A. Zeeb {
8696c92544dSBjoern A. Zeeb 	struct sk_buff *skb = phy->rx_amsdu[q].head;
8706c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8716c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
8726c92544dSBjoern A. Zeeb 
8736c92544dSBjoern A. Zeeb 	phy->rx_amsdu[q].head = NULL;
8746c92544dSBjoern A. Zeeb 	phy->rx_amsdu[q].tail = NULL;
8756c92544dSBjoern A. Zeeb 
8766c92544dSBjoern A. Zeeb 	/*
8776c92544dSBjoern A. Zeeb 	 * Validate if the amsdu has a proper first subframe.
8786c92544dSBjoern A. Zeeb 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
8796c92544dSBjoern A. Zeeb 	 * flag of the QoS header gets flipped. In such cases, the first
8806c92544dSBjoern A. Zeeb 	 * subframe has a LLC/SNAP header in the location of the destination
8816c92544dSBjoern A. Zeeb 	 * address.
8826c92544dSBjoern A. Zeeb 	 */
8836c92544dSBjoern A. Zeeb 	if (skb_shinfo(skb)->frag_list) {
8846c92544dSBjoern A. Zeeb 		int offset = 0;
8856c92544dSBjoern A. Zeeb 
8866c92544dSBjoern A. Zeeb 		if (!(status->flag & RX_FLAG_8023)) {
8876c92544dSBjoern A. Zeeb 			offset = ieee80211_get_hdrlen_from_skb(skb);
8886c92544dSBjoern A. Zeeb 
8896c92544dSBjoern A. Zeeb 			if ((status->flag &
8906c92544dSBjoern A. Zeeb 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
8916c92544dSBjoern A. Zeeb 			    RX_FLAG_DECRYPTED)
8926c92544dSBjoern A. Zeeb 				offset += 8;
8936c92544dSBjoern A. Zeeb 		}
8946c92544dSBjoern A. Zeeb 
8956c92544dSBjoern A. Zeeb 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
8966c92544dSBjoern A. Zeeb 			dev_kfree_skb(skb);
8976c92544dSBjoern A. Zeeb 			return;
8986c92544dSBjoern A. Zeeb 		}
8996c92544dSBjoern A. Zeeb 	}
9006c92544dSBjoern A. Zeeb 	__skb_queue_tail(&dev->rx_skb[q], skb);
9016c92544dSBjoern A. Zeeb }
9026c92544dSBjoern A. Zeeb 
mt76_rx_release_burst(struct mt76_phy * phy,enum mt76_rxq_id q,struct sk_buff * skb)9036c92544dSBjoern A. Zeeb static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
9046c92544dSBjoern A. Zeeb 				  struct sk_buff *skb)
9056c92544dSBjoern A. Zeeb {
9066c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
9076c92544dSBjoern A. Zeeb 
9086c92544dSBjoern A. Zeeb 	if (phy->rx_amsdu[q].head &&
9096c92544dSBjoern A. Zeeb 	    (!status->amsdu || status->first_amsdu ||
9106c92544dSBjoern A. Zeeb 	     status->seqno != phy->rx_amsdu[q].seqno))
9116c92544dSBjoern A. Zeeb 		mt76_rx_release_amsdu(phy, q);
9126c92544dSBjoern A. Zeeb 
9136c92544dSBjoern A. Zeeb 	if (!phy->rx_amsdu[q].head) {
9146c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
9156c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].seqno = status->seqno;
9166c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].head = skb;
9176c92544dSBjoern A. Zeeb 	} else {
9186c92544dSBjoern A. Zeeb 		*phy->rx_amsdu[q].tail = skb;
9196c92544dSBjoern A. Zeeb 		phy->rx_amsdu[q].tail = &skb->next;
9206c92544dSBjoern A. Zeeb 	}
9216c92544dSBjoern A. Zeeb 
9226c92544dSBjoern A. Zeeb 	if (!status->amsdu || status->last_amsdu)
9236c92544dSBjoern A. Zeeb 		mt76_rx_release_amsdu(phy, q);
9246c92544dSBjoern A. Zeeb }
9256c92544dSBjoern A. Zeeb 
mt76_rx(struct mt76_dev * dev,enum mt76_rxq_id q,struct sk_buff * skb)9266c92544dSBjoern A. Zeeb void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
9276c92544dSBjoern A. Zeeb {
9286c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
9296c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
9306c92544dSBjoern A. Zeeb 
9316c92544dSBjoern A. Zeeb 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
9326c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
9336c92544dSBjoern A. Zeeb 		return;
9346c92544dSBjoern A. Zeeb 	}
9356c92544dSBjoern A. Zeeb 
9366c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE
9376c92544dSBjoern A. Zeeb 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
9386c92544dSBjoern A. Zeeb 		phy->test.rx_stats.packets[q]++;
9396c92544dSBjoern A. Zeeb 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
9406c92544dSBjoern A. Zeeb 			phy->test.rx_stats.fcs_error[q]++;
9416c92544dSBjoern A. Zeeb 	}
9426c92544dSBjoern A. Zeeb #endif
9436c92544dSBjoern A. Zeeb 
9446c92544dSBjoern A. Zeeb 	mt76_rx_release_burst(phy, q, skb);
9456c92544dSBjoern A. Zeeb }
9466c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx);
9476c92544dSBjoern A. Zeeb 
mt76_has_tx_pending(struct mt76_phy * phy)9486c92544dSBjoern A. Zeeb bool mt76_has_tx_pending(struct mt76_phy *phy)
9496c92544dSBjoern A. Zeeb {
9506c92544dSBjoern A. Zeeb 	struct mt76_queue *q;
9516c92544dSBjoern A. Zeeb 	int i;
9526c92544dSBjoern A. Zeeb 
9536c92544dSBjoern A. Zeeb 	for (i = 0; i < __MT_TXQ_MAX; i++) {
9546c92544dSBjoern A. Zeeb 		q = phy->q_tx[i];
9556c92544dSBjoern A. Zeeb 		if (q && q->queued)
9566c92544dSBjoern A. Zeeb 			return true;
9576c92544dSBjoern A. Zeeb 	}
9586c92544dSBjoern A. Zeeb 
9596c92544dSBjoern A. Zeeb 	return false;
9606c92544dSBjoern A. Zeeb }
9616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
9626c92544dSBjoern A. Zeeb 
9636c92544dSBjoern A. Zeeb static struct mt76_channel_state *
mt76_channel_state(struct mt76_phy * phy,struct ieee80211_channel * c)9646c92544dSBjoern A. Zeeb mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
9656c92544dSBjoern A. Zeeb {
9666c92544dSBjoern A. Zeeb 	struct mt76_sband *msband;
9676c92544dSBjoern A. Zeeb 	int idx;
9686c92544dSBjoern A. Zeeb 
9696c92544dSBjoern A. Zeeb 	if (c->band == NL80211_BAND_2GHZ)
9706c92544dSBjoern A. Zeeb 		msband = &phy->sband_2g;
9716c92544dSBjoern A. Zeeb 	else if (c->band == NL80211_BAND_6GHZ)
9726c92544dSBjoern A. Zeeb 		msband = &phy->sband_6g;
9736c92544dSBjoern A. Zeeb 	else
9746c92544dSBjoern A. Zeeb 		msband = &phy->sband_5g;
9756c92544dSBjoern A. Zeeb 
9766c92544dSBjoern A. Zeeb 	idx = c - &msband->sband.channels[0];
9776c92544dSBjoern A. Zeeb 	return &msband->chan[idx];
9786c92544dSBjoern A. Zeeb }
9796c92544dSBjoern A. Zeeb 
mt76_update_survey_active_time(struct mt76_phy * phy,ktime_t time)9806c92544dSBjoern A. Zeeb void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
9816c92544dSBjoern A. Zeeb {
9826c92544dSBjoern A. Zeeb 	struct mt76_channel_state *state = phy->chan_state;
9836c92544dSBjoern A. Zeeb 
9846c92544dSBjoern A. Zeeb 	state->cc_active += ktime_to_us(ktime_sub(time,
9856c92544dSBjoern A. Zeeb 						  phy->survey_time));
9866c92544dSBjoern A. Zeeb 	phy->survey_time = time;
9876c92544dSBjoern A. Zeeb }
9886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
9896c92544dSBjoern A. Zeeb 
mt76_update_survey(struct mt76_phy * phy)9906c92544dSBjoern A. Zeeb void mt76_update_survey(struct mt76_phy *phy)
9916c92544dSBjoern A. Zeeb {
9926c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
9936c92544dSBjoern A. Zeeb 	ktime_t cur_time;
9946c92544dSBjoern A. Zeeb 
9956c92544dSBjoern A. Zeeb 	if (dev->drv->update_survey)
9966c92544dSBjoern A. Zeeb 		dev->drv->update_survey(phy);
9976c92544dSBjoern A. Zeeb 
9986c92544dSBjoern A. Zeeb 	cur_time = ktime_get_boottime();
9996c92544dSBjoern A. Zeeb 	mt76_update_survey_active_time(phy, cur_time);
10006c92544dSBjoern A. Zeeb 
10016c92544dSBjoern A. Zeeb 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
10026c92544dSBjoern A. Zeeb 		struct mt76_channel_state *state = phy->chan_state;
10036c92544dSBjoern A. Zeeb 
10046c92544dSBjoern A. Zeeb 		spin_lock_bh(&dev->cc_lock);
10056c92544dSBjoern A. Zeeb 		state->cc_bss_rx += dev->cur_cc_bss_rx;
10066c92544dSBjoern A. Zeeb 		dev->cur_cc_bss_rx = 0;
10076c92544dSBjoern A. Zeeb 		spin_unlock_bh(&dev->cc_lock);
10086c92544dSBjoern A. Zeeb 	}
10096c92544dSBjoern A. Zeeb }
10106c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey);
10116c92544dSBjoern A. Zeeb 
__mt76_set_channel(struct mt76_phy * phy,struct cfg80211_chan_def * chandef,bool offchannel)1012*8ba4d145SBjoern A. Zeeb int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
1013*8ba4d145SBjoern A. Zeeb 		       bool offchannel)
10146c92544dSBjoern A. Zeeb {
10156c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
10166c92544dSBjoern A. Zeeb 	int timeout = HZ / 5;
1017*8ba4d145SBjoern A. Zeeb 	int ret;
10186c92544dSBjoern A. Zeeb 
1019*8ba4d145SBjoern A. Zeeb 	set_bit(MT76_RESET, &phy->state);
1020*8ba4d145SBjoern A. Zeeb 
1021*8ba4d145SBjoern A. Zeeb 	mt76_worker_disable(&dev->tx_worker);
10226c92544dSBjoern A. Zeeb 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
10236c92544dSBjoern A. Zeeb 	mt76_update_survey(phy);
10246c92544dSBjoern A. Zeeb 
10256c92544dSBjoern A. Zeeb 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
10266c92544dSBjoern A. Zeeb 	    phy->chandef.width != chandef->width)
10276c92544dSBjoern A. Zeeb 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
10286c92544dSBjoern A. Zeeb 
10296c92544dSBjoern A. Zeeb 	phy->chandef = *chandef;
10306c92544dSBjoern A. Zeeb 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
1031*8ba4d145SBjoern A. Zeeb 	phy->offchannel = offchannel;
10326c92544dSBjoern A. Zeeb 
10336c92544dSBjoern A. Zeeb 	if (!offchannel)
1034*8ba4d145SBjoern A. Zeeb 		phy->main_chandef = *chandef;
10356c92544dSBjoern A. Zeeb 
1036*8ba4d145SBjoern A. Zeeb 	if (chandef->chan != phy->main_chandef.chan)
10376c92544dSBjoern A. Zeeb 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
1038*8ba4d145SBjoern A. Zeeb 
1039*8ba4d145SBjoern A. Zeeb 	ret = dev->drv->set_channel(phy);
1040*8ba4d145SBjoern A. Zeeb 
1041*8ba4d145SBjoern A. Zeeb 	clear_bit(MT76_RESET, &phy->state);
1042*8ba4d145SBjoern A. Zeeb 	mt76_worker_enable(&dev->tx_worker);
1043*8ba4d145SBjoern A. Zeeb 	mt76_worker_schedule(&dev->tx_worker);
1044*8ba4d145SBjoern A. Zeeb 
1045*8ba4d145SBjoern A. Zeeb 	return ret;
10466c92544dSBjoern A. Zeeb }
1047*8ba4d145SBjoern A. Zeeb 
mt76_set_channel(struct mt76_phy * phy,struct cfg80211_chan_def * chandef,bool offchannel)1048*8ba4d145SBjoern A. Zeeb int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
1049*8ba4d145SBjoern A. Zeeb 		     bool offchannel)
1050*8ba4d145SBjoern A. Zeeb {
1051*8ba4d145SBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
1052*8ba4d145SBjoern A. Zeeb 	int ret;
1053*8ba4d145SBjoern A. Zeeb 
1054*8ba4d145SBjoern A. Zeeb 	cancel_delayed_work_sync(&phy->mac_work);
1055*8ba4d145SBjoern A. Zeeb 
1056*8ba4d145SBjoern A. Zeeb 	mutex_lock(&dev->mutex);
1057*8ba4d145SBjoern A. Zeeb 	ret = __mt76_set_channel(phy, chandef, offchannel);
1058*8ba4d145SBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
1059*8ba4d145SBjoern A. Zeeb 
1060*8ba4d145SBjoern A. Zeeb 	return ret;
1061*8ba4d145SBjoern A. Zeeb }
1062*8ba4d145SBjoern A. Zeeb 
mt76_update_channel(struct mt76_phy * phy)1063*8ba4d145SBjoern A. Zeeb int mt76_update_channel(struct mt76_phy *phy)
1064*8ba4d145SBjoern A. Zeeb {
1065*8ba4d145SBjoern A. Zeeb 	struct ieee80211_hw *hw = phy->hw;
1066*8ba4d145SBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
1067*8ba4d145SBjoern A. Zeeb 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
1068*8ba4d145SBjoern A. Zeeb 
1069*8ba4d145SBjoern A. Zeeb 	phy->radar_enabled = hw->conf.radar_enabled;
1070*8ba4d145SBjoern A. Zeeb 
1071*8ba4d145SBjoern A. Zeeb 	return mt76_set_channel(phy, chandef, offchannel);
1072*8ba4d145SBjoern A. Zeeb }
1073*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_channel);
1074*8ba4d145SBjoern A. Zeeb 
1075*8ba4d145SBjoern A. Zeeb static struct mt76_sband *
mt76_get_survey_sband(struct mt76_phy * phy,int * idx)1076*8ba4d145SBjoern A. Zeeb mt76_get_survey_sband(struct mt76_phy *phy, int *idx)
1077*8ba4d145SBjoern A. Zeeb {
1078*8ba4d145SBjoern A. Zeeb 	if (*idx < phy->sband_2g.sband.n_channels)
1079*8ba4d145SBjoern A. Zeeb 		return &phy->sband_2g;
1080*8ba4d145SBjoern A. Zeeb 
1081*8ba4d145SBjoern A. Zeeb 	*idx -= phy->sband_2g.sband.n_channels;
1082*8ba4d145SBjoern A. Zeeb 	if (*idx < phy->sband_5g.sband.n_channels)
1083*8ba4d145SBjoern A. Zeeb 		return &phy->sband_5g;
1084*8ba4d145SBjoern A. Zeeb 
1085*8ba4d145SBjoern A. Zeeb 	*idx -= phy->sband_5g.sband.n_channels;
1086*8ba4d145SBjoern A. Zeeb 	if (*idx < phy->sband_6g.sband.n_channels)
1087*8ba4d145SBjoern A. Zeeb 		return &phy->sband_6g;
1088*8ba4d145SBjoern A. Zeeb 
1089*8ba4d145SBjoern A. Zeeb 	*idx -= phy->sband_6g.sband.n_channels;
1090*8ba4d145SBjoern A. Zeeb 	return NULL;
1091*8ba4d145SBjoern A. Zeeb }
10926c92544dSBjoern A. Zeeb 
mt76_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)10936c92544dSBjoern A. Zeeb int mt76_get_survey(struct ieee80211_hw *hw, int idx,
10946c92544dSBjoern A. Zeeb 		    struct survey_info *survey)
10956c92544dSBjoern A. Zeeb {
10966c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
10976c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
1098*8ba4d145SBjoern A. Zeeb 	struct mt76_sband *sband = NULL;
10996c92544dSBjoern A. Zeeb 	struct ieee80211_channel *chan;
11006c92544dSBjoern A. Zeeb 	struct mt76_channel_state *state;
1101*8ba4d145SBjoern A. Zeeb 	int phy_idx = 0;
11026c92544dSBjoern A. Zeeb 	int ret = 0;
11036c92544dSBjoern A. Zeeb 
11046c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
1105*8ba4d145SBjoern A. Zeeb 
1106*8ba4d145SBjoern A. Zeeb 	for (phy_idx = 0; phy_idx < ARRAY_SIZE(dev->phys); phy_idx++) {
1107*8ba4d145SBjoern A. Zeeb 		sband = NULL;
1108*8ba4d145SBjoern A. Zeeb 		phy = dev->phys[phy_idx];
1109*8ba4d145SBjoern A. Zeeb 		if (!phy || phy->hw != hw)
1110*8ba4d145SBjoern A. Zeeb 			continue;
1111*8ba4d145SBjoern A. Zeeb 
1112*8ba4d145SBjoern A. Zeeb 		sband = mt76_get_survey_sband(phy, &idx);
1113*8ba4d145SBjoern A. Zeeb 
1114*8ba4d145SBjoern A. Zeeb 		if (idx == 0 && phy->dev->drv->update_survey)
11156c92544dSBjoern A. Zeeb 			mt76_update_survey(phy);
11166c92544dSBjoern A. Zeeb 
1117*8ba4d145SBjoern A. Zeeb 		if (sband || !hw->wiphy->n_radio)
1118*8ba4d145SBjoern A. Zeeb 			break;
11196c92544dSBjoern A. Zeeb 	}
11206c92544dSBjoern A. Zeeb 
1121*8ba4d145SBjoern A. Zeeb 	if (!sband) {
11226c92544dSBjoern A. Zeeb 		ret = -ENOENT;
11236c92544dSBjoern A. Zeeb 		goto out;
11246c92544dSBjoern A. Zeeb 	}
11256c92544dSBjoern A. Zeeb 
11266c92544dSBjoern A. Zeeb 	chan = &sband->sband.channels[idx];
11276c92544dSBjoern A. Zeeb 	state = mt76_channel_state(phy, chan);
11286c92544dSBjoern A. Zeeb 
11296c92544dSBjoern A. Zeeb 	memset(survey, 0, sizeof(*survey));
11306c92544dSBjoern A. Zeeb 	survey->channel = chan;
11316c92544dSBjoern A. Zeeb 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
11326c92544dSBjoern A. Zeeb 	survey->filled |= dev->drv->survey_flags;
11336c92544dSBjoern A. Zeeb 	if (state->noise)
11346c92544dSBjoern A. Zeeb 		survey->filled |= SURVEY_INFO_NOISE_DBM;
11356c92544dSBjoern A. Zeeb 
1136*8ba4d145SBjoern A. Zeeb 	if (chan == phy->main_chandef.chan) {
11376c92544dSBjoern A. Zeeb 		survey->filled |= SURVEY_INFO_IN_USE;
11386c92544dSBjoern A. Zeeb 
11396c92544dSBjoern A. Zeeb 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
11406c92544dSBjoern A. Zeeb 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
11416c92544dSBjoern A. Zeeb 	}
11426c92544dSBjoern A. Zeeb 
11436c92544dSBjoern A. Zeeb 	survey->time_busy = div_u64(state->cc_busy, 1000);
11446c92544dSBjoern A. Zeeb 	survey->time_rx = div_u64(state->cc_rx, 1000);
11456c92544dSBjoern A. Zeeb 	survey->time = div_u64(state->cc_active, 1000);
11466c92544dSBjoern A. Zeeb 	survey->noise = state->noise;
11476c92544dSBjoern A. Zeeb 
11486c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->cc_lock);
11496c92544dSBjoern A. Zeeb 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
11506c92544dSBjoern A. Zeeb 	survey->time_tx = div_u64(state->cc_tx, 1000);
11516c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->cc_lock);
11526c92544dSBjoern A. Zeeb 
11536c92544dSBjoern A. Zeeb out:
11546c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
11556c92544dSBjoern A. Zeeb 
11566c92544dSBjoern A. Zeeb 	return ret;
11576c92544dSBjoern A. Zeeb }
11586c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_survey);
11596c92544dSBjoern A. Zeeb 
mt76_wcid_key_setup(struct mt76_dev * dev,struct mt76_wcid * wcid,struct ieee80211_key_conf * key)11606c92544dSBjoern A. Zeeb void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
11616c92544dSBjoern A. Zeeb 			 struct ieee80211_key_conf *key)
11626c92544dSBjoern A. Zeeb {
11636c92544dSBjoern A. Zeeb 	struct ieee80211_key_seq seq;
11646c92544dSBjoern A. Zeeb 	int i;
11656c92544dSBjoern A. Zeeb 
11666c92544dSBjoern A. Zeeb 	wcid->rx_check_pn = false;
11676c92544dSBjoern A. Zeeb 
11686c92544dSBjoern A. Zeeb 	if (!key)
11696c92544dSBjoern A. Zeeb 		return;
11706c92544dSBjoern A. Zeeb 
11716c92544dSBjoern A. Zeeb 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
11726c92544dSBjoern A. Zeeb 		return;
11736c92544dSBjoern A. Zeeb 
11746c92544dSBjoern A. Zeeb 	wcid->rx_check_pn = true;
11756c92544dSBjoern A. Zeeb 
11766c92544dSBjoern A. Zeeb 	/* data frame */
11776c92544dSBjoern A. Zeeb 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
11786c92544dSBjoern A. Zeeb 		ieee80211_get_key_rx_seq(key, i, &seq);
11796c92544dSBjoern A. Zeeb 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
11806c92544dSBjoern A. Zeeb 	}
11816c92544dSBjoern A. Zeeb 
11826c92544dSBjoern A. Zeeb 	/* robust management frame */
11836c92544dSBjoern A. Zeeb 	ieee80211_get_key_rx_seq(key, -1, &seq);
11846c92544dSBjoern A. Zeeb 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
11856c92544dSBjoern A. Zeeb 
11866c92544dSBjoern A. Zeeb }
11876c92544dSBjoern A. Zeeb EXPORT_SYMBOL(mt76_wcid_key_setup);
11886c92544dSBjoern A. Zeeb 
mt76_rx_signal(u8 chain_mask,s8 * chain_signal)1189cbb3ec25SBjoern A. Zeeb int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
11906c92544dSBjoern A. Zeeb {
11916c92544dSBjoern A. Zeeb 	int signal = -128;
11926c92544dSBjoern A. Zeeb 	u8 chains;
11936c92544dSBjoern A. Zeeb 
1194cbb3ec25SBjoern A. Zeeb 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
11956c92544dSBjoern A. Zeeb 		int cur, diff;
11966c92544dSBjoern A. Zeeb 
11976c92544dSBjoern A. Zeeb 		cur = *chain_signal;
11986c92544dSBjoern A. Zeeb 		if (!(chains & BIT(0)) ||
11996c92544dSBjoern A. Zeeb 		    cur > 0)
12006c92544dSBjoern A. Zeeb 			continue;
12016c92544dSBjoern A. Zeeb 
12026c92544dSBjoern A. Zeeb 		if (cur > signal)
12036c92544dSBjoern A. Zeeb 			swap(cur, signal);
12046c92544dSBjoern A. Zeeb 
12056c92544dSBjoern A. Zeeb 		diff = signal - cur;
12066c92544dSBjoern A. Zeeb 		if (diff == 0)
12076c92544dSBjoern A. Zeeb 			signal += 3;
12086c92544dSBjoern A. Zeeb 		else if (diff <= 2)
12096c92544dSBjoern A. Zeeb 			signal += 2;
12106c92544dSBjoern A. Zeeb 		else if (diff <= 6)
12116c92544dSBjoern A. Zeeb 			signal += 1;
12126c92544dSBjoern A. Zeeb 	}
12136c92544dSBjoern A. Zeeb 
12146c92544dSBjoern A. Zeeb 	return signal;
12156c92544dSBjoern A. Zeeb }
1216cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL(mt76_rx_signal);
12176c92544dSBjoern A. Zeeb 
12186c92544dSBjoern A. Zeeb static void
mt76_rx_convert(struct mt76_dev * dev,struct sk_buff * skb,struct ieee80211_hw ** hw,struct ieee80211_sta ** sta)12196c92544dSBjoern A. Zeeb mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
12206c92544dSBjoern A. Zeeb 		struct ieee80211_hw **hw,
12216c92544dSBjoern A. Zeeb 		struct ieee80211_sta **sta)
12226c92544dSBjoern A. Zeeb {
12236c92544dSBjoern A. Zeeb 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
12246c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
12256c92544dSBjoern A. Zeeb 	struct mt76_rx_status mstat;
12266c92544dSBjoern A. Zeeb 
12276c92544dSBjoern A. Zeeb 	mstat = *((struct mt76_rx_status *)skb->cb);
12286c92544dSBjoern A. Zeeb 	memset(status, 0, sizeof(*status));
12296c92544dSBjoern A. Zeeb 
12306c92544dSBjoern A. Zeeb 	status->flag = mstat.flag;
12316c92544dSBjoern A. Zeeb 	status->freq = mstat.freq;
12326c92544dSBjoern A. Zeeb 	status->enc_flags = mstat.enc_flags;
12336c92544dSBjoern A. Zeeb 	status->encoding = mstat.encoding;
12346c92544dSBjoern A. Zeeb 	status->bw = mstat.bw;
1235cbb3ec25SBjoern A. Zeeb 	if (status->encoding == RX_ENC_EHT) {
1236cbb3ec25SBjoern A. Zeeb 		status->eht.ru = mstat.eht.ru;
1237cbb3ec25SBjoern A. Zeeb 		status->eht.gi = mstat.eht.gi;
1238cbb3ec25SBjoern A. Zeeb 	} else {
12396c92544dSBjoern A. Zeeb 		status->he_ru = mstat.he_ru;
12406c92544dSBjoern A. Zeeb 		status->he_gi = mstat.he_gi;
12416c92544dSBjoern A. Zeeb 		status->he_dcm = mstat.he_dcm;
1242cbb3ec25SBjoern A. Zeeb 	}
12436c92544dSBjoern A. Zeeb 	status->rate_idx = mstat.rate_idx;
12446c92544dSBjoern A. Zeeb 	status->nss = mstat.nss;
12456c92544dSBjoern A. Zeeb 	status->band = mstat.band;
12466c92544dSBjoern A. Zeeb 	status->signal = mstat.signal;
12476c92544dSBjoern A. Zeeb 	status->chains = mstat.chains;
12486c92544dSBjoern A. Zeeb 	status->ampdu_reference = mstat.ampdu_ref;
12496c92544dSBjoern A. Zeeb 	status->device_timestamp = mstat.timestamp;
12506c92544dSBjoern A. Zeeb 	status->mactime = mstat.timestamp;
1251cbb3ec25SBjoern A. Zeeb 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
12526c92544dSBjoern A. Zeeb 	if (status->signal <= -128)
12536c92544dSBjoern A. Zeeb 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
12546c92544dSBjoern A. Zeeb 
12556c92544dSBjoern A. Zeeb 	if (ieee80211_is_beacon(hdr->frame_control) ||
12566c92544dSBjoern A. Zeeb 	    ieee80211_is_probe_resp(hdr->frame_control))
12576c92544dSBjoern A. Zeeb 		status->boottime_ns = ktime_get_boottime_ns();
12586c92544dSBjoern A. Zeeb 
12596c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
12606c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
12616c92544dSBjoern A. Zeeb 		     sizeof(mstat.chain_signal));
12626c92544dSBjoern A. Zeeb 	memcpy(status->chain_signal, mstat.chain_signal,
12636c92544dSBjoern A. Zeeb 	       sizeof(mstat.chain_signal));
12646c92544dSBjoern A. Zeeb 
1265*8ba4d145SBjoern A. Zeeb 	if (mstat.wcid) {
1266*8ba4d145SBjoern A. Zeeb 		status->link_valid = mstat.wcid->link_valid;
1267*8ba4d145SBjoern A. Zeeb 		status->link_id = mstat.wcid->link_id;
1268*8ba4d145SBjoern A. Zeeb 	}
1269*8ba4d145SBjoern A. Zeeb 
12706c92544dSBjoern A. Zeeb 	*sta = wcid_to_sta(mstat.wcid);
12716c92544dSBjoern A. Zeeb 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
12726c92544dSBjoern A. Zeeb }
12736c92544dSBjoern A. Zeeb 
12746c92544dSBjoern A. Zeeb static void
mt76_check_ccmp_pn(struct sk_buff * skb)12756c92544dSBjoern A. Zeeb mt76_check_ccmp_pn(struct sk_buff *skb)
12766c92544dSBjoern A. Zeeb {
12776c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12786c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
12796c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr;
12806c92544dSBjoern A. Zeeb 	int security_idx;
12816c92544dSBjoern A. Zeeb 	int ret;
12826c92544dSBjoern A. Zeeb 
12836c92544dSBjoern A. Zeeb 	if (!(status->flag & RX_FLAG_DECRYPTED))
12846c92544dSBjoern A. Zeeb 		return;
12856c92544dSBjoern A. Zeeb 
12866c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_ONLY_MONITOR)
12876c92544dSBjoern A. Zeeb 		return;
12886c92544dSBjoern A. Zeeb 
12896c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->rx_check_pn)
12906c92544dSBjoern A. Zeeb 		return;
12916c92544dSBjoern A. Zeeb 
12926c92544dSBjoern A. Zeeb 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
12936c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_8023)
12946c92544dSBjoern A. Zeeb 		goto skip_hdr_check;
12956c92544dSBjoern A. Zeeb 
12966c92544dSBjoern A. Zeeb 	hdr = mt76_skb_get_hdr(skb);
12976c92544dSBjoern A. Zeeb 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
12986c92544dSBjoern A. Zeeb 		/*
12996c92544dSBjoern A. Zeeb 		 * Validate the first fragment both here and in mac80211
13006c92544dSBjoern A. Zeeb 		 * All further fragments will be validated by mac80211 only.
13016c92544dSBjoern A. Zeeb 		 */
13026c92544dSBjoern A. Zeeb 		if (ieee80211_is_frag(hdr) &&
13036c92544dSBjoern A. Zeeb 		    !ieee80211_is_first_frag(hdr->frame_control))
13046c92544dSBjoern A. Zeeb 			return;
13056c92544dSBjoern A. Zeeb 	}
13066c92544dSBjoern A. Zeeb 
13076c92544dSBjoern A. Zeeb 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
13086c92544dSBjoern A. Zeeb 	 *
13096c92544dSBjoern A. Zeeb 	 * the recipient shall maintain a single replay counter for received
13106c92544dSBjoern A. Zeeb 	 * individually addressed robust Management frames that are received
13116c92544dSBjoern A. Zeeb 	 * with the To DS subfield equal to 0, [...]
13126c92544dSBjoern A. Zeeb 	 */
13136c92544dSBjoern A. Zeeb 	if (ieee80211_is_mgmt(hdr->frame_control) &&
13146c92544dSBjoern A. Zeeb 	    !ieee80211_has_tods(hdr->frame_control))
13156c92544dSBjoern A. Zeeb 		security_idx = IEEE80211_NUM_TIDS;
13166c92544dSBjoern A. Zeeb 
13176c92544dSBjoern A. Zeeb skip_hdr_check:
13186c92544dSBjoern A. Zeeb 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
13196c92544dSBjoern A. Zeeb 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
13206c92544dSBjoern A. Zeeb 		     sizeof(status->iv));
13216c92544dSBjoern A. Zeeb 	if (ret <= 0) {
13226c92544dSBjoern A. Zeeb 		status->flag |= RX_FLAG_ONLY_MONITOR;
13236c92544dSBjoern A. Zeeb 		return;
13246c92544dSBjoern A. Zeeb 	}
13256c92544dSBjoern A. Zeeb 
13266c92544dSBjoern A. Zeeb 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
13276c92544dSBjoern A. Zeeb 
13286c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_IV_STRIPPED)
13296c92544dSBjoern A. Zeeb 		status->flag |= RX_FLAG_PN_VALIDATED;
13306c92544dSBjoern A. Zeeb }
13316c92544dSBjoern A. Zeeb 
13326c92544dSBjoern A. Zeeb static void
mt76_airtime_report(struct mt76_dev * dev,struct mt76_rx_status * status,int len)13336c92544dSBjoern A. Zeeb mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
13346c92544dSBjoern A. Zeeb 		    int len)
13356c92544dSBjoern A. Zeeb {
13366c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
13376c92544dSBjoern A. Zeeb 	struct ieee80211_rx_status info = {
13386c92544dSBjoern A. Zeeb 		.enc_flags = status->enc_flags,
13396c92544dSBjoern A. Zeeb 		.rate_idx = status->rate_idx,
13406c92544dSBjoern A. Zeeb 		.encoding = status->encoding,
13416c92544dSBjoern A. Zeeb 		.band = status->band,
13426c92544dSBjoern A. Zeeb 		.nss = status->nss,
13436c92544dSBjoern A. Zeeb 		.bw = status->bw,
13446c92544dSBjoern A. Zeeb 	};
13456c92544dSBjoern A. Zeeb 	struct ieee80211_sta *sta;
13466c92544dSBjoern A. Zeeb 	u32 airtime;
13476c92544dSBjoern A. Zeeb 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
13486c92544dSBjoern A. Zeeb 
13496c92544dSBjoern A. Zeeb 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
13506c92544dSBjoern A. Zeeb 	spin_lock(&dev->cc_lock);
13516c92544dSBjoern A. Zeeb 	dev->cur_cc_bss_rx += airtime;
13526c92544dSBjoern A. Zeeb 	spin_unlock(&dev->cc_lock);
13536c92544dSBjoern A. Zeeb 
13546c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->sta)
13556c92544dSBjoern A. Zeeb 		return;
13566c92544dSBjoern A. Zeeb 
13576c92544dSBjoern A. Zeeb 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
13586c92544dSBjoern A. Zeeb 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
13596c92544dSBjoern A. Zeeb }
13606c92544dSBjoern A. Zeeb 
13616c92544dSBjoern A. Zeeb static void
mt76_airtime_flush_ampdu(struct mt76_dev * dev)13626c92544dSBjoern A. Zeeb mt76_airtime_flush_ampdu(struct mt76_dev *dev)
13636c92544dSBjoern A. Zeeb {
13646c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid;
13656c92544dSBjoern A. Zeeb 	int wcid_idx;
13666c92544dSBjoern A. Zeeb 
13676c92544dSBjoern A. Zeeb 	if (!dev->rx_ampdu_len)
13686c92544dSBjoern A. Zeeb 		return;
13696c92544dSBjoern A. Zeeb 
13706c92544dSBjoern A. Zeeb 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
13716c92544dSBjoern A. Zeeb 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
13726c92544dSBjoern A. Zeeb 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
13736c92544dSBjoern A. Zeeb 	else
13746c92544dSBjoern A. Zeeb 		wcid = NULL;
13756c92544dSBjoern A. Zeeb 	dev->rx_ampdu_status.wcid = wcid;
13766c92544dSBjoern A. Zeeb 
13776c92544dSBjoern A. Zeeb 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
13786c92544dSBjoern A. Zeeb 
13796c92544dSBjoern A. Zeeb 	dev->rx_ampdu_len = 0;
13806c92544dSBjoern A. Zeeb 	dev->rx_ampdu_ref = 0;
13816c92544dSBjoern A. Zeeb }
13826c92544dSBjoern A. Zeeb 
13836c92544dSBjoern A. Zeeb static void
mt76_airtime_check(struct mt76_dev * dev,struct sk_buff * skb)13846c92544dSBjoern A. Zeeb mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
13856c92544dSBjoern A. Zeeb {
13866c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
13876c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
13886c92544dSBjoern A. Zeeb 
13896c92544dSBjoern A. Zeeb 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
13906c92544dSBjoern A. Zeeb 		return;
13916c92544dSBjoern A. Zeeb 
13926c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->sta) {
13936c92544dSBjoern A. Zeeb 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
13946c92544dSBjoern A. Zeeb 
13956c92544dSBjoern A. Zeeb 		if (status->flag & RX_FLAG_8023)
13966c92544dSBjoern A. Zeeb 			return;
13976c92544dSBjoern A. Zeeb 
13986c92544dSBjoern A. Zeeb 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
13996c92544dSBjoern A. Zeeb 			return;
14006c92544dSBjoern A. Zeeb 
14016c92544dSBjoern A. Zeeb 		wcid = NULL;
14026c92544dSBjoern A. Zeeb 	}
14036c92544dSBjoern A. Zeeb 
14046c92544dSBjoern A. Zeeb 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
14056c92544dSBjoern A. Zeeb 	    status->ampdu_ref != dev->rx_ampdu_ref)
14066c92544dSBjoern A. Zeeb 		mt76_airtime_flush_ampdu(dev);
14076c92544dSBjoern A. Zeeb 
14086c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
14096c92544dSBjoern A. Zeeb 		if (!dev->rx_ampdu_len ||
14106c92544dSBjoern A. Zeeb 		    status->ampdu_ref != dev->rx_ampdu_ref) {
14116c92544dSBjoern A. Zeeb 			dev->rx_ampdu_status = *status;
14126c92544dSBjoern A. Zeeb 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
14136c92544dSBjoern A. Zeeb 			dev->rx_ampdu_ref = status->ampdu_ref;
14146c92544dSBjoern A. Zeeb 		}
14156c92544dSBjoern A. Zeeb 
14166c92544dSBjoern A. Zeeb 		dev->rx_ampdu_len += skb->len;
14176c92544dSBjoern A. Zeeb 		return;
14186c92544dSBjoern A. Zeeb 	}
14196c92544dSBjoern A. Zeeb 
14206c92544dSBjoern A. Zeeb 	mt76_airtime_report(dev, status, skb->len);
14216c92544dSBjoern A. Zeeb }
14226c92544dSBjoern A. Zeeb 
14236c92544dSBjoern A. Zeeb static void
mt76_check_sta(struct mt76_dev * dev,struct sk_buff * skb)14246c92544dSBjoern A. Zeeb mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
14256c92544dSBjoern A. Zeeb {
14266c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
14276c92544dSBjoern A. Zeeb 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
14286c92544dSBjoern A. Zeeb 	struct ieee80211_sta *sta;
14296c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
14306c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = status->wcid;
14316c92544dSBjoern A. Zeeb 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
14326c92544dSBjoern A. Zeeb 	bool ps;
14336c92544dSBjoern A. Zeeb 
14346c92544dSBjoern A. Zeeb 	hw = mt76_phy_hw(dev, status->phy_idx);
14356c92544dSBjoern A. Zeeb 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
14366c92544dSBjoern A. Zeeb 	    !(status->flag & RX_FLAG_8023)) {
14376c92544dSBjoern A. Zeeb 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
14386c92544dSBjoern A. Zeeb 		if (sta)
14396c92544dSBjoern A. Zeeb 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
14406c92544dSBjoern A. Zeeb 	}
14416c92544dSBjoern A. Zeeb 
14426c92544dSBjoern A. Zeeb 	mt76_airtime_check(dev, skb);
14436c92544dSBjoern A. Zeeb 
14446c92544dSBjoern A. Zeeb 	if (!wcid || !wcid->sta)
14456c92544dSBjoern A. Zeeb 		return;
14466c92544dSBjoern A. Zeeb 
14476c92544dSBjoern A. Zeeb 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
14486c92544dSBjoern A. Zeeb 
14496c92544dSBjoern A. Zeeb 	if (status->signal <= 0)
14506c92544dSBjoern A. Zeeb 		ewma_signal_add(&wcid->rssi, -status->signal);
14516c92544dSBjoern A. Zeeb 
14526c92544dSBjoern A. Zeeb 	wcid->inactive_count = 0;
14536c92544dSBjoern A. Zeeb 
14546c92544dSBjoern A. Zeeb 	if (status->flag & RX_FLAG_8023)
14556c92544dSBjoern A. Zeeb 		return;
14566c92544dSBjoern A. Zeeb 
14576c92544dSBjoern A. Zeeb 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
14586c92544dSBjoern A. Zeeb 		return;
14596c92544dSBjoern A. Zeeb 
14606c92544dSBjoern A. Zeeb 	if (ieee80211_is_pspoll(hdr->frame_control)) {
14616c92544dSBjoern A. Zeeb 		ieee80211_sta_pspoll(sta);
14626c92544dSBjoern A. Zeeb 		return;
14636c92544dSBjoern A. Zeeb 	}
14646c92544dSBjoern A. Zeeb 
14656c92544dSBjoern A. Zeeb 	if (ieee80211_has_morefrags(hdr->frame_control) ||
14666c92544dSBjoern A. Zeeb 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
14676c92544dSBjoern A. Zeeb 	      ieee80211_is_data(hdr->frame_control)))
14686c92544dSBjoern A. Zeeb 		return;
14696c92544dSBjoern A. Zeeb 
14706c92544dSBjoern A. Zeeb 	ps = ieee80211_has_pm(hdr->frame_control);
14716c92544dSBjoern A. Zeeb 
14726c92544dSBjoern A. Zeeb 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
14736c92544dSBjoern A. Zeeb 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
14746c92544dSBjoern A. Zeeb 		ieee80211_sta_uapsd_trigger(sta, tidno);
14756c92544dSBjoern A. Zeeb 
14766c92544dSBjoern A. Zeeb 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
14776c92544dSBjoern A. Zeeb 		return;
14786c92544dSBjoern A. Zeeb 
14796c92544dSBjoern A. Zeeb 	if (ps)
14806c92544dSBjoern A. Zeeb 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
14816c92544dSBjoern A. Zeeb 
1482cbb3ec25SBjoern A. Zeeb 	if (dev->drv->sta_ps)
14836c92544dSBjoern A. Zeeb 		dev->drv->sta_ps(dev, sta, ps);
14846c92544dSBjoern A. Zeeb 
14856c92544dSBjoern A. Zeeb 	if (!ps)
14866c92544dSBjoern A. Zeeb 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
14876c92544dSBjoern A. Zeeb 
14886c92544dSBjoern A. Zeeb 	ieee80211_sta_ps_transition(sta, ps);
14896c92544dSBjoern A. Zeeb }
14906c92544dSBjoern A. Zeeb 
mt76_rx_complete(struct mt76_dev * dev,struct sk_buff_head * frames,struct napi_struct * napi)14916c92544dSBjoern A. Zeeb void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
14926c92544dSBjoern A. Zeeb 		      struct napi_struct *napi)
14936c92544dSBjoern A. Zeeb {
14946c92544dSBjoern A. Zeeb 	struct ieee80211_sta *sta;
14956c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw;
14966c92544dSBjoern A. Zeeb 	struct sk_buff *skb, *tmp;
14976c92544dSBjoern A. Zeeb #if defined(__linux__)
14986c92544dSBjoern A. Zeeb 	LIST_HEAD(list);
14996c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
15006c92544dSBjoern A. Zeeb 	LINUX_LIST_HEAD(list);
15016c92544dSBjoern A. Zeeb #endif
15026c92544dSBjoern A. Zeeb 
15036c92544dSBjoern A. Zeeb 	spin_lock(&dev->rx_lock);
15046c92544dSBjoern A. Zeeb 	while ((skb = __skb_dequeue(frames)) != NULL) {
15056c92544dSBjoern A. Zeeb 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
15066c92544dSBjoern A. Zeeb 
15076c92544dSBjoern A. Zeeb 		mt76_check_ccmp_pn(skb);
15086c92544dSBjoern A. Zeeb 		skb_shinfo(skb)->frag_list = NULL;
15096c92544dSBjoern A. Zeeb 		mt76_rx_convert(dev, skb, &hw, &sta);
15106c92544dSBjoern A. Zeeb 		ieee80211_rx_list(hw, sta, skb, &list);
15116c92544dSBjoern A. Zeeb 
15126c92544dSBjoern A. Zeeb 		/* subsequent amsdu frames */
15136c92544dSBjoern A. Zeeb 		while (nskb) {
15146c92544dSBjoern A. Zeeb 			skb = nskb;
15156c92544dSBjoern A. Zeeb 			nskb = nskb->next;
15166c92544dSBjoern A. Zeeb 			skb->next = NULL;
15176c92544dSBjoern A. Zeeb 
15186c92544dSBjoern A. Zeeb 			mt76_rx_convert(dev, skb, &hw, &sta);
15196c92544dSBjoern A. Zeeb 			ieee80211_rx_list(hw, sta, skb, &list);
15206c92544dSBjoern A. Zeeb 		}
15216c92544dSBjoern A. Zeeb 	}
15226c92544dSBjoern A. Zeeb 	spin_unlock(&dev->rx_lock);
15236c92544dSBjoern A. Zeeb 
15246c92544dSBjoern A. Zeeb 	if (!napi) {
15256c92544dSBjoern A. Zeeb 		netif_receive_skb_list(&list);
15266c92544dSBjoern A. Zeeb 		return;
15276c92544dSBjoern A. Zeeb 	}
15286c92544dSBjoern A. Zeeb 
15296c92544dSBjoern A. Zeeb 	list_for_each_entry_safe(skb, tmp, &list, list) {
15306c92544dSBjoern A. Zeeb 		skb_list_del_init(skb);
15316c92544dSBjoern A. Zeeb 		napi_gro_receive(napi, skb);
15326c92544dSBjoern A. Zeeb 	}
15336c92544dSBjoern A. Zeeb }
15346c92544dSBjoern A. Zeeb 
mt76_rx_poll_complete(struct mt76_dev * dev,enum mt76_rxq_id q,struct napi_struct * napi)15356c92544dSBjoern A. Zeeb void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
15366c92544dSBjoern A. Zeeb 			   struct napi_struct *napi)
15376c92544dSBjoern A. Zeeb {
15386c92544dSBjoern A. Zeeb 	struct sk_buff_head frames;
15396c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
15406c92544dSBjoern A. Zeeb 
15416c92544dSBjoern A. Zeeb 	__skb_queue_head_init(&frames);
15426c92544dSBjoern A. Zeeb 
15436c92544dSBjoern A. Zeeb 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
15446c92544dSBjoern A. Zeeb 		mt76_check_sta(dev, skb);
1545cbb3ec25SBjoern A. Zeeb 		if (mtk_wed_device_active(&dev->mmio.wed))
1546cbb3ec25SBjoern A. Zeeb 			__skb_queue_tail(&frames, skb);
1547cbb3ec25SBjoern A. Zeeb 		else
15486c92544dSBjoern A. Zeeb 			mt76_rx_aggr_reorder(skb, &frames);
15496c92544dSBjoern A. Zeeb 	}
15506c92544dSBjoern A. Zeeb 
15516c92544dSBjoern A. Zeeb 	mt76_rx_complete(dev, &frames, napi);
15526c92544dSBjoern A. Zeeb }
15536c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
15546c92544dSBjoern A. Zeeb 
15556c92544dSBjoern A. Zeeb static int
mt76_sta_add(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)15566c92544dSBjoern A. Zeeb mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
15576c92544dSBjoern A. Zeeb 	     struct ieee80211_sta *sta)
15586c92544dSBjoern A. Zeeb {
15596c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
15606c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
15616c92544dSBjoern A. Zeeb 	int ret;
15626c92544dSBjoern A. Zeeb 	int i;
15636c92544dSBjoern A. Zeeb 
15646c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
15656c92544dSBjoern A. Zeeb 
15666c92544dSBjoern A. Zeeb 	ret = dev->drv->sta_add(dev, vif, sta);
15676c92544dSBjoern A. Zeeb 	if (ret)
15686c92544dSBjoern A. Zeeb 		goto out;
15696c92544dSBjoern A. Zeeb 
15706c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
15716c92544dSBjoern A. Zeeb 		struct mt76_txq *mtxq;
15726c92544dSBjoern A. Zeeb 
15736c92544dSBjoern A. Zeeb 		if (!sta->txq[i])
15746c92544dSBjoern A. Zeeb 			continue;
15756c92544dSBjoern A. Zeeb 
15766c92544dSBjoern A. Zeeb 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
15776c92544dSBjoern A. Zeeb 		mtxq->wcid = wcid->idx;
15786c92544dSBjoern A. Zeeb 	}
15796c92544dSBjoern A. Zeeb 
15806c92544dSBjoern A. Zeeb 	ewma_signal_init(&wcid->rssi);
15816c92544dSBjoern A. Zeeb 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1582*8ba4d145SBjoern A. Zeeb 	phy->num_sta++;
15836c92544dSBjoern A. Zeeb 
1584*8ba4d145SBjoern A. Zeeb 	mt76_wcid_init(wcid, phy->band_idx);
15856c92544dSBjoern A. Zeeb out:
15866c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
15876c92544dSBjoern A. Zeeb 
15886c92544dSBjoern A. Zeeb 	return ret;
15896c92544dSBjoern A. Zeeb }
15906c92544dSBjoern A. Zeeb 
__mt76_sta_remove(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1591*8ba4d145SBjoern A. Zeeb void __mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif,
15926c92544dSBjoern A. Zeeb 		       struct ieee80211_sta *sta)
15936c92544dSBjoern A. Zeeb {
1594*8ba4d145SBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
15956c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
15966c92544dSBjoern A. Zeeb 	int i, idx = wcid->idx;
15976c92544dSBjoern A. Zeeb 
15986c92544dSBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
15996c92544dSBjoern A. Zeeb 		mt76_rx_aggr_stop(dev, wcid, i);
16006c92544dSBjoern A. Zeeb 
16016c92544dSBjoern A. Zeeb 	if (dev->drv->sta_remove)
16026c92544dSBjoern A. Zeeb 		dev->drv->sta_remove(dev, vif, sta);
16036c92544dSBjoern A. Zeeb 
1604*8ba4d145SBjoern A. Zeeb 	mt76_wcid_cleanup(dev, wcid);
16056c92544dSBjoern A. Zeeb 
16066c92544dSBjoern A. Zeeb 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1607*8ba4d145SBjoern A. Zeeb 	phy->num_sta--;
16086c92544dSBjoern A. Zeeb }
16096c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_sta_remove);
16106c92544dSBjoern A. Zeeb 
16116c92544dSBjoern A. Zeeb static void
mt76_sta_remove(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1612*8ba4d145SBjoern A. Zeeb mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif,
16136c92544dSBjoern A. Zeeb 		struct ieee80211_sta *sta)
16146c92544dSBjoern A. Zeeb {
1615*8ba4d145SBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
1616*8ba4d145SBjoern A. Zeeb 
16176c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
1618*8ba4d145SBjoern A. Zeeb 	__mt76_sta_remove(phy, vif, sta);
16196c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
16206c92544dSBjoern A. Zeeb }
16216c92544dSBjoern A. Zeeb 
mt76_sta_state(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,enum ieee80211_sta_state old_state,enum ieee80211_sta_state new_state)16226c92544dSBjoern A. Zeeb int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16236c92544dSBjoern A. Zeeb 		   struct ieee80211_sta *sta,
16246c92544dSBjoern A. Zeeb 		   enum ieee80211_sta_state old_state,
16256c92544dSBjoern A. Zeeb 		   enum ieee80211_sta_state new_state)
16266c92544dSBjoern A. Zeeb {
16276c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
16286c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
1629*8ba4d145SBjoern A. Zeeb 	enum mt76_sta_event ev;
1630*8ba4d145SBjoern A. Zeeb 
1631*8ba4d145SBjoern A. Zeeb 	phy = mt76_vif_phy(hw, vif);
1632*8ba4d145SBjoern A. Zeeb 	if (!phy)
1633*8ba4d145SBjoern A. Zeeb 		return -EINVAL;
16346c92544dSBjoern A. Zeeb 
16356c92544dSBjoern A. Zeeb 	if (old_state == IEEE80211_STA_NOTEXIST &&
16366c92544dSBjoern A. Zeeb 	    new_state == IEEE80211_STA_NONE)
16376c92544dSBjoern A. Zeeb 		return mt76_sta_add(phy, vif, sta);
16386c92544dSBjoern A. Zeeb 
16396c92544dSBjoern A. Zeeb 	if (old_state == IEEE80211_STA_NONE &&
16406c92544dSBjoern A. Zeeb 	    new_state == IEEE80211_STA_NOTEXIST)
1641*8ba4d145SBjoern A. Zeeb 		mt76_sta_remove(phy, vif, sta);
16426c92544dSBjoern A. Zeeb 
1643*8ba4d145SBjoern A. Zeeb 	if (!dev->drv->sta_event)
16446c92544dSBjoern A. Zeeb 		return 0;
1645*8ba4d145SBjoern A. Zeeb 
1646*8ba4d145SBjoern A. Zeeb 	if (old_state == IEEE80211_STA_AUTH &&
1647*8ba4d145SBjoern A. Zeeb 	    new_state == IEEE80211_STA_ASSOC)
1648*8ba4d145SBjoern A. Zeeb 		ev = MT76_STA_EVENT_ASSOC;
1649*8ba4d145SBjoern A. Zeeb 	else if (old_state == IEEE80211_STA_ASSOC &&
1650*8ba4d145SBjoern A. Zeeb 		 new_state == IEEE80211_STA_AUTHORIZED)
1651*8ba4d145SBjoern A. Zeeb 		ev = MT76_STA_EVENT_AUTHORIZE;
1652*8ba4d145SBjoern A. Zeeb 	else if (old_state == IEEE80211_STA_ASSOC &&
1653*8ba4d145SBjoern A. Zeeb 		 new_state == IEEE80211_STA_AUTH)
1654*8ba4d145SBjoern A. Zeeb 		ev = MT76_STA_EVENT_DISASSOC;
1655*8ba4d145SBjoern A. Zeeb 	else
1656*8ba4d145SBjoern A. Zeeb 		return 0;
1657*8ba4d145SBjoern A. Zeeb 
1658*8ba4d145SBjoern A. Zeeb 	return dev->drv->sta_event(dev, vif, sta, ev);
16596c92544dSBjoern A. Zeeb }
16606c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_state);
16616c92544dSBjoern A. Zeeb 
mt76_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)16626c92544dSBjoern A. Zeeb void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16636c92544dSBjoern A. Zeeb 			     struct ieee80211_sta *sta)
16646c92544dSBjoern A. Zeeb {
16656c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
16666c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
16676c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
16686c92544dSBjoern A. Zeeb 
16696c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
16706c92544dSBjoern A. Zeeb 	spin_lock_bh(&dev->status_lock);
16716c92544dSBjoern A. Zeeb 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
16726c92544dSBjoern A. Zeeb 	spin_unlock_bh(&dev->status_lock);
16736c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
16746c92544dSBjoern A. Zeeb }
16756c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
16766c92544dSBjoern A. Zeeb 
mt76_wcid_init(struct mt76_wcid * wcid,u8 band_idx)1677*8ba4d145SBjoern A. Zeeb void mt76_wcid_init(struct mt76_wcid *wcid, u8 band_idx)
16786c92544dSBjoern A. Zeeb {
1679*8ba4d145SBjoern A. Zeeb 	wcid->hw_key_idx = -1;
1680*8ba4d145SBjoern A. Zeeb 	wcid->phy_idx = band_idx;
16816c92544dSBjoern A. Zeeb 
1682*8ba4d145SBjoern A. Zeeb 	INIT_LIST_HEAD(&wcid->tx_list);
1683*8ba4d145SBjoern A. Zeeb 	skb_queue_head_init(&wcid->tx_pending);
1684*8ba4d145SBjoern A. Zeeb 	skb_queue_head_init(&wcid->tx_offchannel);
1685*8ba4d145SBjoern A. Zeeb 
1686*8ba4d145SBjoern A. Zeeb 	INIT_LIST_HEAD(&wcid->list);
1687*8ba4d145SBjoern A. Zeeb 	idr_init(&wcid->pktid);
1688*8ba4d145SBjoern A. Zeeb 
1689*8ba4d145SBjoern A. Zeeb 	INIT_LIST_HEAD(&wcid->poll_list);
1690*8ba4d145SBjoern A. Zeeb }
1691*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_init);
1692*8ba4d145SBjoern A. Zeeb 
mt76_wcid_cleanup(struct mt76_dev * dev,struct mt76_wcid * wcid)1693*8ba4d145SBjoern A. Zeeb void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
1694*8ba4d145SBjoern A. Zeeb {
1695*8ba4d145SBjoern A. Zeeb 	struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx);
1696*8ba4d145SBjoern A. Zeeb 	struct ieee80211_hw *hw;
1697*8ba4d145SBjoern A. Zeeb 	struct sk_buff_head list;
1698*8ba4d145SBjoern A. Zeeb 	struct sk_buff *skb;
1699*8ba4d145SBjoern A. Zeeb 
1700*8ba4d145SBjoern A. Zeeb 	mt76_tx_status_lock(dev, &list);
1701*8ba4d145SBjoern A. Zeeb 	mt76_tx_status_skb_get(dev, wcid, -1, &list);
1702*8ba4d145SBjoern A. Zeeb 	mt76_tx_status_unlock(dev, &list);
1703*8ba4d145SBjoern A. Zeeb 
1704*8ba4d145SBjoern A. Zeeb 	idr_destroy(&wcid->pktid);
1705*8ba4d145SBjoern A. Zeeb 
1706*8ba4d145SBjoern A. Zeeb 	spin_lock_bh(&phy->tx_lock);
1707*8ba4d145SBjoern A. Zeeb 
1708*8ba4d145SBjoern A. Zeeb 	if (!list_empty(&wcid->tx_list))
1709*8ba4d145SBjoern A. Zeeb 		list_del_init(&wcid->tx_list);
1710*8ba4d145SBjoern A. Zeeb 
1711*8ba4d145SBjoern A. Zeeb 	spin_lock(&wcid->tx_pending.lock);
1712*8ba4d145SBjoern A. Zeeb 	skb_queue_splice_tail_init(&wcid->tx_pending, &list);
1713*8ba4d145SBjoern A. Zeeb 	spin_unlock(&wcid->tx_pending.lock);
1714*8ba4d145SBjoern A. Zeeb 
1715*8ba4d145SBjoern A. Zeeb 	spin_unlock_bh(&phy->tx_lock);
1716*8ba4d145SBjoern A. Zeeb 
1717*8ba4d145SBjoern A. Zeeb 	while ((skb = __skb_dequeue(&list)) != NULL) {
1718*8ba4d145SBjoern A. Zeeb 		hw = mt76_tx_status_get_hw(dev, skb);
1719*8ba4d145SBjoern A. Zeeb 		ieee80211_free_txskb(hw, skb);
1720*8ba4d145SBjoern A. Zeeb 	}
1721*8ba4d145SBjoern A. Zeeb }
1722*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
1723*8ba4d145SBjoern A. Zeeb 
mt76_wcid_add_poll(struct mt76_dev * dev,struct mt76_wcid * wcid)1724*8ba4d145SBjoern A. Zeeb void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid)
1725*8ba4d145SBjoern A. Zeeb {
1726*8ba4d145SBjoern A. Zeeb 	if (test_bit(MT76_MCU_RESET, &dev->phy.state))
1727*8ba4d145SBjoern A. Zeeb 		return;
1728*8ba4d145SBjoern A. Zeeb 
1729*8ba4d145SBjoern A. Zeeb 	spin_lock_bh(&dev->sta_poll_lock);
1730*8ba4d145SBjoern A. Zeeb 	if (list_empty(&wcid->poll_list))
1731*8ba4d145SBjoern A. Zeeb 		list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
1732*8ba4d145SBjoern A. Zeeb 	spin_unlock_bh(&dev->sta_poll_lock);
1733*8ba4d145SBjoern A. Zeeb }
1734*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_add_poll);
1735*8ba4d145SBjoern A. Zeeb 
mt76_get_txpower(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id,int * dbm)1736*8ba4d145SBjoern A. Zeeb int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1737*8ba4d145SBjoern A. Zeeb 		     unsigned int link_id, int *dbm)
1738*8ba4d145SBjoern A. Zeeb {
1739*8ba4d145SBjoern A. Zeeb 	struct mt76_phy *phy = mt76_vif_phy(hw, vif);
1740*8ba4d145SBjoern A. Zeeb 	int n_chains, delta;
1741*8ba4d145SBjoern A. Zeeb 
1742*8ba4d145SBjoern A. Zeeb 	if (!phy)
1743*8ba4d145SBjoern A. Zeeb 		return -EINVAL;
1744*8ba4d145SBjoern A. Zeeb 
1745*8ba4d145SBjoern A. Zeeb 	n_chains = hweight16(phy->chainmask);
1746*8ba4d145SBjoern A. Zeeb 	delta = mt76_tx_power_nss_delta(n_chains);
17476c92544dSBjoern A. Zeeb 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
17486c92544dSBjoern A. Zeeb 
17496c92544dSBjoern A. Zeeb 	return 0;
17506c92544dSBjoern A. Zeeb }
17516c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_txpower);
17526c92544dSBjoern A. Zeeb 
mt76_init_sar_power(struct ieee80211_hw * hw,const struct cfg80211_sar_specs * sar)17536c92544dSBjoern A. Zeeb int mt76_init_sar_power(struct ieee80211_hw *hw,
17546c92544dSBjoern A. Zeeb 			const struct cfg80211_sar_specs *sar)
17556c92544dSBjoern A. Zeeb {
17566c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
17576c92544dSBjoern A. Zeeb 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
17586c92544dSBjoern A. Zeeb 	int i;
17596c92544dSBjoern A. Zeeb 
17606c92544dSBjoern A. Zeeb 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
17616c92544dSBjoern A. Zeeb 		return -EINVAL;
17626c92544dSBjoern A. Zeeb 
17636c92544dSBjoern A. Zeeb 	for (i = 0; i < sar->num_sub_specs; i++) {
17646c92544dSBjoern A. Zeeb 		u32 index = sar->sub_specs[i].freq_range_index;
17656c92544dSBjoern A. Zeeb 		/* SAR specifies power limitaton in 0.25dbm */
17666c92544dSBjoern A. Zeeb 		s32 power = sar->sub_specs[i].power >> 1;
17676c92544dSBjoern A. Zeeb 
17686c92544dSBjoern A. Zeeb 		if (power > 127 || power < -127)
17696c92544dSBjoern A. Zeeb 			power = 127;
17706c92544dSBjoern A. Zeeb 
17716c92544dSBjoern A. Zeeb 		phy->frp[index].range = &capa->freq_ranges[index];
17726c92544dSBjoern A. Zeeb 		phy->frp[index].power = power;
17736c92544dSBjoern A. Zeeb 	}
17746c92544dSBjoern A. Zeeb 
17756c92544dSBjoern A. Zeeb 	return 0;
17766c92544dSBjoern A. Zeeb }
17776c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_sar_power);
17786c92544dSBjoern A. Zeeb 
mt76_get_sar_power(struct mt76_phy * phy,struct ieee80211_channel * chan,int power)17796c92544dSBjoern A. Zeeb int mt76_get_sar_power(struct mt76_phy *phy,
17806c92544dSBjoern A. Zeeb 		       struct ieee80211_channel *chan,
17816c92544dSBjoern A. Zeeb 		       int power)
17826c92544dSBjoern A. Zeeb {
17836c92544dSBjoern A. Zeeb 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
17846c92544dSBjoern A. Zeeb 	int freq, i;
17856c92544dSBjoern A. Zeeb 
17866c92544dSBjoern A. Zeeb 	if (!capa || !phy->frp)
17876c92544dSBjoern A. Zeeb 		return power;
17886c92544dSBjoern A. Zeeb 
17896c92544dSBjoern A. Zeeb 	if (power > 127 || power < -127)
17906c92544dSBjoern A. Zeeb 		power = 127;
17916c92544dSBjoern A. Zeeb 
17926c92544dSBjoern A. Zeeb 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
17936c92544dSBjoern A. Zeeb 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
17946c92544dSBjoern A. Zeeb 		if (phy->frp[i].range &&
17956c92544dSBjoern A. Zeeb 		    freq >= phy->frp[i].range->start_freq &&
17966c92544dSBjoern A. Zeeb 		    freq < phy->frp[i].range->end_freq) {
17976c92544dSBjoern A. Zeeb 			power = min_t(int, phy->frp[i].power, power);
17986c92544dSBjoern A. Zeeb 			break;
17996c92544dSBjoern A. Zeeb 		}
18006c92544dSBjoern A. Zeeb 	}
18016c92544dSBjoern A. Zeeb 
18026c92544dSBjoern A. Zeeb 	return power;
18036c92544dSBjoern A. Zeeb }
18046c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_sar_power);
18056c92544dSBjoern A. Zeeb 
18066c92544dSBjoern A. Zeeb static void
__mt76_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)18076c92544dSBjoern A. Zeeb __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
18086c92544dSBjoern A. Zeeb {
1809*8ba4d145SBjoern A. Zeeb 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0))
1810*8ba4d145SBjoern A. Zeeb 		ieee80211_csa_finish(vif, 0);
18116c92544dSBjoern A. Zeeb }
18126c92544dSBjoern A. Zeeb 
mt76_csa_finish(struct mt76_dev * dev)18136c92544dSBjoern A. Zeeb void mt76_csa_finish(struct mt76_dev *dev)
18146c92544dSBjoern A. Zeeb {
18156c92544dSBjoern A. Zeeb 	if (!dev->csa_complete)
18166c92544dSBjoern A. Zeeb 		return;
18176c92544dSBjoern A. Zeeb 
18186c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
18196c92544dSBjoern A. Zeeb 		IEEE80211_IFACE_ITER_RESUME_ALL,
18206c92544dSBjoern A. Zeeb 		__mt76_csa_finish, dev);
18216c92544dSBjoern A. Zeeb 
18226c92544dSBjoern A. Zeeb 	dev->csa_complete = 0;
18236c92544dSBjoern A. Zeeb }
18246c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_finish);
18256c92544dSBjoern A. Zeeb 
18266c92544dSBjoern A. Zeeb static void
__mt76_csa_check(void * priv,u8 * mac,struct ieee80211_vif * vif)18276c92544dSBjoern A. Zeeb __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
18286c92544dSBjoern A. Zeeb {
18296c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = priv;
18306c92544dSBjoern A. Zeeb 
18316c92544dSBjoern A. Zeeb 	if (!vif->bss_conf.csa_active)
18326c92544dSBjoern A. Zeeb 		return;
18336c92544dSBjoern A. Zeeb 
1834*8ba4d145SBjoern A. Zeeb 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0);
18356c92544dSBjoern A. Zeeb }
18366c92544dSBjoern A. Zeeb 
mt76_csa_check(struct mt76_dev * dev)18376c92544dSBjoern A. Zeeb void mt76_csa_check(struct mt76_dev *dev)
18386c92544dSBjoern A. Zeeb {
18396c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
18406c92544dSBjoern A. Zeeb 		IEEE80211_IFACE_ITER_RESUME_ALL,
18416c92544dSBjoern A. Zeeb 		__mt76_csa_check, dev);
18426c92544dSBjoern A. Zeeb }
18436c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_check);
18446c92544dSBjoern A. Zeeb 
18456c92544dSBjoern A. Zeeb int
mt76_set_tim(struct ieee80211_hw * hw,struct ieee80211_sta * sta,bool set)18466c92544dSBjoern A. Zeeb mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
18476c92544dSBjoern A. Zeeb {
18486c92544dSBjoern A. Zeeb 	return 0;
18496c92544dSBjoern A. Zeeb }
18506c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_tim);
18516c92544dSBjoern A. Zeeb 
mt76_insert_ccmp_hdr(struct sk_buff * skb,u8 key_id)18526c92544dSBjoern A. Zeeb void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
18536c92544dSBjoern A. Zeeb {
18546c92544dSBjoern A. Zeeb 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
18556c92544dSBjoern A. Zeeb 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
18566c92544dSBjoern A. Zeeb 	u8 *hdr, *pn = status->iv;
18576c92544dSBjoern A. Zeeb 
18586c92544dSBjoern A. Zeeb 	__skb_push(skb, 8);
18596c92544dSBjoern A. Zeeb 	memmove(skb->data, skb->data + 8, hdr_len);
18606c92544dSBjoern A. Zeeb 	hdr = skb->data + hdr_len;
18616c92544dSBjoern A. Zeeb 
18626c92544dSBjoern A. Zeeb 	hdr[0] = pn[5];
18636c92544dSBjoern A. Zeeb 	hdr[1] = pn[4];
18646c92544dSBjoern A. Zeeb 	hdr[2] = 0;
18656c92544dSBjoern A. Zeeb 	hdr[3] = 0x20 | (key_id << 6);
18666c92544dSBjoern A. Zeeb 	hdr[4] = pn[3];
18676c92544dSBjoern A. Zeeb 	hdr[5] = pn[2];
18686c92544dSBjoern A. Zeeb 	hdr[6] = pn[1];
18696c92544dSBjoern A. Zeeb 	hdr[7] = pn[0];
18706c92544dSBjoern A. Zeeb 
18716c92544dSBjoern A. Zeeb 	status->flag &= ~RX_FLAG_IV_STRIPPED;
18726c92544dSBjoern A. Zeeb }
18736c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
18746c92544dSBjoern A. Zeeb 
mt76_get_rate(struct mt76_dev * dev,struct ieee80211_supported_band * sband,int idx,bool cck)18756c92544dSBjoern A. Zeeb int mt76_get_rate(struct mt76_dev *dev,
18766c92544dSBjoern A. Zeeb 		  struct ieee80211_supported_band *sband,
18776c92544dSBjoern A. Zeeb 		  int idx, bool cck)
18786c92544dSBjoern A. Zeeb {
1879*8ba4d145SBjoern A. Zeeb 	bool is_2g = sband->band == NL80211_BAND_2GHZ;
18806c92544dSBjoern A. Zeeb 	int i, offset = 0, len = sband->n_bitrates;
18816c92544dSBjoern A. Zeeb 
18826c92544dSBjoern A. Zeeb 	if (cck) {
1883*8ba4d145SBjoern A. Zeeb 		if (!is_2g)
18846c92544dSBjoern A. Zeeb 			return 0;
18856c92544dSBjoern A. Zeeb 
18866c92544dSBjoern A. Zeeb 		idx &= ~BIT(2); /* short preamble */
1887*8ba4d145SBjoern A. Zeeb 	} else if (is_2g) {
18886c92544dSBjoern A. Zeeb 		offset = 4;
18896c92544dSBjoern A. Zeeb 	}
18906c92544dSBjoern A. Zeeb 
18916c92544dSBjoern A. Zeeb 	for (i = offset; i < len; i++) {
18926c92544dSBjoern A. Zeeb 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
18936c92544dSBjoern A. Zeeb 			return i;
18946c92544dSBjoern A. Zeeb 	}
18956c92544dSBjoern A. Zeeb 
18966c92544dSBjoern A. Zeeb 	return 0;
18976c92544dSBjoern A. Zeeb }
18986c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_rate);
18996c92544dSBjoern A. Zeeb 
mt76_sw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * mac)19006c92544dSBjoern A. Zeeb void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
19016c92544dSBjoern A. Zeeb 		  const u8 *mac)
19026c92544dSBjoern A. Zeeb {
19036c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
19046c92544dSBjoern A. Zeeb 
19056c92544dSBjoern A. Zeeb 	set_bit(MT76_SCANNING, &phy->state);
19066c92544dSBjoern A. Zeeb }
19076c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan);
19086c92544dSBjoern A. Zeeb 
mt76_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)19096c92544dSBjoern A. Zeeb void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
19106c92544dSBjoern A. Zeeb {
19116c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
19126c92544dSBjoern A. Zeeb 
19136c92544dSBjoern A. Zeeb 	clear_bit(MT76_SCANNING, &phy->state);
19146c92544dSBjoern A. Zeeb }
19156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
19166c92544dSBjoern A. Zeeb 
mt76_get_antenna(struct ieee80211_hw * hw,u32 * tx_ant,u32 * rx_ant)19176c92544dSBjoern A. Zeeb int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
19186c92544dSBjoern A. Zeeb {
19196c92544dSBjoern A. Zeeb 	struct mt76_phy *phy = hw->priv;
19206c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
1921*8ba4d145SBjoern A. Zeeb 	int i;
19226c92544dSBjoern A. Zeeb 
19236c92544dSBjoern A. Zeeb 	mutex_lock(&dev->mutex);
1924*8ba4d145SBjoern A. Zeeb 	*tx_ant = 0;
1925*8ba4d145SBjoern A. Zeeb 	for (i = 0; i < ARRAY_SIZE(dev->phys); i++)
1926*8ba4d145SBjoern A. Zeeb 		if (dev->phys[i] && dev->phys[i]->hw == hw)
1927*8ba4d145SBjoern A. Zeeb 			*tx_ant |= dev->phys[i]->chainmask;
1928*8ba4d145SBjoern A. Zeeb 	*rx_ant = *tx_ant;
19296c92544dSBjoern A. Zeeb 	mutex_unlock(&dev->mutex);
19306c92544dSBjoern A. Zeeb 
19316c92544dSBjoern A. Zeeb 	return 0;
19326c92544dSBjoern A. Zeeb }
19336c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_antenna);
19346c92544dSBjoern A. Zeeb 
19356c92544dSBjoern A. Zeeb struct mt76_queue *
mt76_init_queue(struct mt76_dev * dev,int qid,int idx,int n_desc,int ring_base,void * wed,u32 flags)19366c92544dSBjoern A. Zeeb mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1937*8ba4d145SBjoern A. Zeeb 		int ring_base, void *wed, u32 flags)
19386c92544dSBjoern A. Zeeb {
19396c92544dSBjoern A. Zeeb 	struct mt76_queue *hwq;
19406c92544dSBjoern A. Zeeb 	int err;
19416c92544dSBjoern A. Zeeb 
19426c92544dSBjoern A. Zeeb 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
19436c92544dSBjoern A. Zeeb 	if (!hwq)
19446c92544dSBjoern A. Zeeb 		return ERR_PTR(-ENOMEM);
19456c92544dSBjoern A. Zeeb 
19466c92544dSBjoern A. Zeeb 	hwq->flags = flags;
1947*8ba4d145SBjoern A. Zeeb 	hwq->wed = wed;
19486c92544dSBjoern A. Zeeb 
19496c92544dSBjoern A. Zeeb 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
19506c92544dSBjoern A. Zeeb 	if (err < 0)
19516c92544dSBjoern A. Zeeb 		return ERR_PTR(err);
19526c92544dSBjoern A. Zeeb 
19536c92544dSBjoern A. Zeeb 	return hwq;
19546c92544dSBjoern A. Zeeb }
19556c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_queue);
19566c92544dSBjoern A. Zeeb 
mt76_ethtool_worker(struct mt76_ethtool_worker_info * wi,struct mt76_sta_stats * stats,bool eht)19576c92544dSBjoern A. Zeeb void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1958cbb3ec25SBjoern A. Zeeb 			 struct mt76_sta_stats *stats, bool eht)
19596c92544dSBjoern A. Zeeb {
19606c92544dSBjoern A. Zeeb 	int i, ei = wi->initial_stat_idx;
19616c92544dSBjoern A. Zeeb 	u64 *data = wi->data;
19626c92544dSBjoern A. Zeeb 
19636c92544dSBjoern A. Zeeb 	wi->sta_count++;
19646c92544dSBjoern A. Zeeb 
19656c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
19666c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
19676c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
19686c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
19696c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
19706c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
19716c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
19726c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
19736c92544dSBjoern A. Zeeb 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1974cbb3ec25SBjoern A. Zeeb 	if (eht) {
1975cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1976cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1977cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1978cbb3ec25SBjoern A. Zeeb 	}
19796c92544dSBjoern A. Zeeb 
1980cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
19816c92544dSBjoern A. Zeeb 		data[ei++] += stats->tx_bw[i];
19826c92544dSBjoern A. Zeeb 
1983cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < (eht ? 14 : 12); i++)
19846c92544dSBjoern A. Zeeb 		data[ei++] += stats->tx_mcs[i];
19856c92544dSBjoern A. Zeeb 
1986cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < 4; i++)
1987cbb3ec25SBjoern A. Zeeb 		data[ei++] += stats->tx_nss[i];
1988cbb3ec25SBjoern A. Zeeb 
19896c92544dSBjoern A. Zeeb 	wi->worker_stat_count = ei - wi->initial_stat_idx;
19906c92544dSBjoern A. Zeeb }
19916c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
19926c92544dSBjoern A. Zeeb 
mt76_ethtool_page_pool_stats(struct mt76_dev * dev,u64 * data,int * index)1993cbb3ec25SBjoern A. Zeeb void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1994cbb3ec25SBjoern A. Zeeb {
1995cbb3ec25SBjoern A. Zeeb #ifdef CONFIG_PAGE_POOL_STATS
1996cbb3ec25SBjoern A. Zeeb 	struct page_pool_stats stats = {};
1997cbb3ec25SBjoern A. Zeeb 	int i;
1998cbb3ec25SBjoern A. Zeeb 
1999cbb3ec25SBjoern A. Zeeb 	mt76_for_each_q_rx(dev, i)
2000cbb3ec25SBjoern A. Zeeb 		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
2001cbb3ec25SBjoern A. Zeeb 
2002cbb3ec25SBjoern A. Zeeb 	page_pool_ethtool_stats_get(data, &stats);
2003cbb3ec25SBjoern A. Zeeb 	*index += page_pool_ethtool_stats_get_count();
2004cbb3ec25SBjoern A. Zeeb #endif
2005cbb3ec25SBjoern A. Zeeb }
2006cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
2007cbb3ec25SBjoern A. Zeeb 
mt76_phy_dfs_state(struct mt76_phy * phy)20086c92544dSBjoern A. Zeeb enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
20096c92544dSBjoern A. Zeeb {
20106c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = phy->hw;
20116c92544dSBjoern A. Zeeb 	struct mt76_dev *dev = phy->dev;
20126c92544dSBjoern A. Zeeb 
20136c92544dSBjoern A. Zeeb 	if (dev->region == NL80211_DFS_UNSET ||
20146c92544dSBjoern A. Zeeb 	    test_bit(MT76_SCANNING, &phy->state))
20156c92544dSBjoern A. Zeeb 		return MT_DFS_STATE_DISABLED;
20166c92544dSBjoern A. Zeeb 
2017*8ba4d145SBjoern A. Zeeb 	if (!phy->radar_enabled) {
20186c92544dSBjoern A. Zeeb 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
20196c92544dSBjoern A. Zeeb 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
20206c92544dSBjoern A. Zeeb 			return MT_DFS_STATE_ACTIVE;
20216c92544dSBjoern A. Zeeb 
20226c92544dSBjoern A. Zeeb 		return MT_DFS_STATE_DISABLED;
20236c92544dSBjoern A. Zeeb 	}
20246c92544dSBjoern A. Zeeb 
20256c92544dSBjoern A. Zeeb 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
20266c92544dSBjoern A. Zeeb 		return MT_DFS_STATE_CAC;
20276c92544dSBjoern A. Zeeb 
20286c92544dSBjoern A. Zeeb 	return MT_DFS_STATE_ACTIVE;
20296c92544dSBjoern A. Zeeb }
20306c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
2031*8ba4d145SBjoern A. Zeeb 
mt76_vif_cleanup(struct mt76_dev * dev,struct ieee80211_vif * vif)2032*8ba4d145SBjoern A. Zeeb void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
2033*8ba4d145SBjoern A. Zeeb {
2034*8ba4d145SBjoern A. Zeeb 	struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
2035*8ba4d145SBjoern A. Zeeb 	struct mt76_vif_data *mvif = mlink->mvif;
2036*8ba4d145SBjoern A. Zeeb 
2037*8ba4d145SBjoern A. Zeeb 	rcu_assign_pointer(mvif->link[0], NULL);
2038*8ba4d145SBjoern A. Zeeb 	mt76_abort_scan(dev);
2039*8ba4d145SBjoern A. Zeeb 	if (mvif->roc_phy)
2040*8ba4d145SBjoern A. Zeeb 		mt76_abort_roc(mvif->roc_phy);
2041*8ba4d145SBjoern A. Zeeb }
2042*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_vif_cleanup);
2043