xref: /openbmc/linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
5781eef5bSFelix Fietkau #include <linux/sched.h>
617f1de56SFelix Fietkau #include <linux/of.h>
717f1de56SFelix Fietkau #include "mt76.h"
817f1de56SFelix Fietkau 
917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
1017f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1117f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1217f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1317f1de56SFelix Fietkau 	.max_power = 30,			\
1417f1de56SFelix Fietkau }
1517f1de56SFelix Fietkau 
1617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1717f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1817f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1917f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2017f1de56SFelix Fietkau 	.max_power = 30,			\
2117f1de56SFelix Fietkau }
2217f1de56SFelix Fietkau 
23edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) {			\
24edf9dab8SLorenzo Bianconi 	.band = NL80211_BAND_6GHZ,		\
25edf9dab8SLorenzo Bianconi 	.center_freq = (_freq),			\
26edf9dab8SLorenzo Bianconi 	.hw_value = (_idx),			\
27edf9dab8SLorenzo Bianconi 	.max_power = 30,			\
28edf9dab8SLorenzo Bianconi }
29edf9dab8SLorenzo Bianconi 
3017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3117f1de56SFelix Fietkau 	CHAN2G(1, 2412),
3217f1de56SFelix Fietkau 	CHAN2G(2, 2417),
3317f1de56SFelix Fietkau 	CHAN2G(3, 2422),
3417f1de56SFelix Fietkau 	CHAN2G(4, 2427),
3517f1de56SFelix Fietkau 	CHAN2G(5, 2432),
3617f1de56SFelix Fietkau 	CHAN2G(6, 2437),
3717f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3817f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3917f1de56SFelix Fietkau 	CHAN2G(9, 2452),
4017f1de56SFelix Fietkau 	CHAN2G(10, 2457),
4117f1de56SFelix Fietkau 	CHAN2G(11, 2462),
4217f1de56SFelix Fietkau 	CHAN2G(12, 2467),
4317f1de56SFelix Fietkau 	CHAN2G(13, 2472),
4417f1de56SFelix Fietkau 	CHAN2G(14, 2484),
4517f1de56SFelix Fietkau };
4617f1de56SFelix Fietkau 
4717f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4817f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4917f1de56SFelix Fietkau 	CHAN5G(40, 5200),
5017f1de56SFelix Fietkau 	CHAN5G(44, 5220),
5117f1de56SFelix Fietkau 	CHAN5G(48, 5240),
5217f1de56SFelix Fietkau 
5317f1de56SFelix Fietkau 	CHAN5G(52, 5260),
5417f1de56SFelix Fietkau 	CHAN5G(56, 5280),
5517f1de56SFelix Fietkau 	CHAN5G(60, 5300),
5617f1de56SFelix Fietkau 	CHAN5G(64, 5320),
5717f1de56SFelix Fietkau 
5817f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5917f1de56SFelix Fietkau 	CHAN5G(104, 5520),
6017f1de56SFelix Fietkau 	CHAN5G(108, 5540),
6117f1de56SFelix Fietkau 	CHAN5G(112, 5560),
6217f1de56SFelix Fietkau 	CHAN5G(116, 5580),
6317f1de56SFelix Fietkau 	CHAN5G(120, 5600),
6417f1de56SFelix Fietkau 	CHAN5G(124, 5620),
6517f1de56SFelix Fietkau 	CHAN5G(128, 5640),
6617f1de56SFelix Fietkau 	CHAN5G(132, 5660),
6717f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6817f1de56SFelix Fietkau 	CHAN5G(140, 5700),
699da82fb7SMarkus Theil 	CHAN5G(144, 5720),
7017f1de56SFelix Fietkau 
7117f1de56SFelix Fietkau 	CHAN5G(149, 5745),
7217f1de56SFelix Fietkau 	CHAN5G(153, 5765),
7317f1de56SFelix Fietkau 	CHAN5G(157, 5785),
7417f1de56SFelix Fietkau 	CHAN5G(161, 5805),
7517f1de56SFelix Fietkau 	CHAN5G(165, 5825),
769da82fb7SMarkus Theil 	CHAN5G(169, 5845),
779da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7862561a47SRyder Lee 	CHAN5G(177, 5885),
7917f1de56SFelix Fietkau };
8017f1de56SFelix Fietkau 
81edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = {
82edf9dab8SLorenzo Bianconi 	/* UNII-5 */
83edf9dab8SLorenzo Bianconi 	CHAN6G(1, 5955),
84edf9dab8SLorenzo Bianconi 	CHAN6G(5, 5975),
85edf9dab8SLorenzo Bianconi 	CHAN6G(9, 5995),
86edf9dab8SLorenzo Bianconi 	CHAN6G(13, 6015),
87edf9dab8SLorenzo Bianconi 	CHAN6G(17, 6035),
88edf9dab8SLorenzo Bianconi 	CHAN6G(21, 6055),
89edf9dab8SLorenzo Bianconi 	CHAN6G(25, 6075),
90edf9dab8SLorenzo Bianconi 	CHAN6G(29, 6095),
91edf9dab8SLorenzo Bianconi 	CHAN6G(33, 6115),
92edf9dab8SLorenzo Bianconi 	CHAN6G(37, 6135),
93edf9dab8SLorenzo Bianconi 	CHAN6G(41, 6155),
94edf9dab8SLorenzo Bianconi 	CHAN6G(45, 6175),
95edf9dab8SLorenzo Bianconi 	CHAN6G(49, 6195),
96edf9dab8SLorenzo Bianconi 	CHAN6G(53, 6215),
97edf9dab8SLorenzo Bianconi 	CHAN6G(57, 6235),
98edf9dab8SLorenzo Bianconi 	CHAN6G(61, 6255),
99edf9dab8SLorenzo Bianconi 	CHAN6G(65, 6275),
100edf9dab8SLorenzo Bianconi 	CHAN6G(69, 6295),
101edf9dab8SLorenzo Bianconi 	CHAN6G(73, 6315),
102edf9dab8SLorenzo Bianconi 	CHAN6G(77, 6335),
103edf9dab8SLorenzo Bianconi 	CHAN6G(81, 6355),
104edf9dab8SLorenzo Bianconi 	CHAN6G(85, 6375),
105edf9dab8SLorenzo Bianconi 	CHAN6G(89, 6395),
106edf9dab8SLorenzo Bianconi 	CHAN6G(93, 6415),
107edf9dab8SLorenzo Bianconi 	/* UNII-6 */
108edf9dab8SLorenzo Bianconi 	CHAN6G(97, 6435),
109edf9dab8SLorenzo Bianconi 	CHAN6G(101, 6455),
110edf9dab8SLorenzo Bianconi 	CHAN6G(105, 6475),
111edf9dab8SLorenzo Bianconi 	CHAN6G(109, 6495),
112edf9dab8SLorenzo Bianconi 	CHAN6G(113, 6515),
113edf9dab8SLorenzo Bianconi 	CHAN6G(117, 6535),
114edf9dab8SLorenzo Bianconi 	/* UNII-7 */
115edf9dab8SLorenzo Bianconi 	CHAN6G(121, 6555),
116edf9dab8SLorenzo Bianconi 	CHAN6G(125, 6575),
117edf9dab8SLorenzo Bianconi 	CHAN6G(129, 6595),
118edf9dab8SLorenzo Bianconi 	CHAN6G(133, 6615),
119edf9dab8SLorenzo Bianconi 	CHAN6G(137, 6635),
120edf9dab8SLorenzo Bianconi 	CHAN6G(141, 6655),
121edf9dab8SLorenzo Bianconi 	CHAN6G(145, 6675),
122edf9dab8SLorenzo Bianconi 	CHAN6G(149, 6695),
123edf9dab8SLorenzo Bianconi 	CHAN6G(153, 6715),
124edf9dab8SLorenzo Bianconi 	CHAN6G(157, 6735),
125edf9dab8SLorenzo Bianconi 	CHAN6G(161, 6755),
126edf9dab8SLorenzo Bianconi 	CHAN6G(165, 6775),
127edf9dab8SLorenzo Bianconi 	CHAN6G(169, 6795),
128edf9dab8SLorenzo Bianconi 	CHAN6G(173, 6815),
129edf9dab8SLorenzo Bianconi 	CHAN6G(177, 6835),
130edf9dab8SLorenzo Bianconi 	CHAN6G(181, 6855),
131edf9dab8SLorenzo Bianconi 	CHAN6G(185, 6875),
132edf9dab8SLorenzo Bianconi 	/* UNII-8 */
133edf9dab8SLorenzo Bianconi 	CHAN6G(189, 6895),
134edf9dab8SLorenzo Bianconi 	CHAN6G(193, 6915),
135edf9dab8SLorenzo Bianconi 	CHAN6G(197, 6935),
136edf9dab8SLorenzo Bianconi 	CHAN6G(201, 6955),
137edf9dab8SLorenzo Bianconi 	CHAN6G(205, 6975),
138edf9dab8SLorenzo Bianconi 	CHAN6G(209, 6995),
139edf9dab8SLorenzo Bianconi 	CHAN6G(213, 7015),
140edf9dab8SLorenzo Bianconi 	CHAN6G(217, 7035),
141edf9dab8SLorenzo Bianconi 	CHAN6G(221, 7055),
142edf9dab8SLorenzo Bianconi 	CHAN6G(225, 7075),
143edf9dab8SLorenzo Bianconi 	CHAN6G(229, 7095),
144edf9dab8SLorenzo Bianconi 	CHAN6G(233, 7115),
145edf9dab8SLorenzo Bianconi };
146edf9dab8SLorenzo Bianconi 
14717f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
14817f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
14917f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
15017f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
15117f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
15217f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
15317f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
15417f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
15517f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
15617f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
15717f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
15817f1de56SFelix Fietkau };
15917f1de56SFelix Fietkau 
16054b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = {
16154b8fdebSLorenzo Bianconi 	CCK_RATE(0, 10),
16254b8fdebSLorenzo Bianconi 	CCK_RATE(1, 20),
16354b8fdebSLorenzo Bianconi 	CCK_RATE(2, 55),
16454b8fdebSLorenzo Bianconi 	CCK_RATE(3, 110),
16554b8fdebSLorenzo Bianconi 	OFDM_RATE(11, 60),
16654b8fdebSLorenzo Bianconi 	OFDM_RATE(15, 90),
16754b8fdebSLorenzo Bianconi 	OFDM_RATE(10, 120),
16854b8fdebSLorenzo Bianconi 	OFDM_RATE(14, 180),
16954b8fdebSLorenzo Bianconi 	OFDM_RATE(9,  240),
17054b8fdebSLorenzo Bianconi 	OFDM_RATE(13, 360),
17154b8fdebSLorenzo Bianconi 	OFDM_RATE(8,  480),
17254b8fdebSLorenzo Bianconi 	OFDM_RATE(12, 540),
17354b8fdebSLorenzo Bianconi };
17454b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates);
17554b8fdebSLorenzo Bianconi 
176502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
177502604f5SYN Chen 	{ .start_freq = 2402, .end_freq = 2494, },
178502604f5SYN Chen 	{ .start_freq = 5150, .end_freq = 5350, },
179502604f5SYN Chen 	{ .start_freq = 5350, .end_freq = 5470, },
180502604f5SYN Chen 	{ .start_freq = 5470, .end_freq = 5725, },
181502604f5SYN Chen 	{ .start_freq = 5725, .end_freq = 5950, },
182162d5c14SDeren Wu 	{ .start_freq = 5945, .end_freq = 6165, },
183162d5c14SDeren Wu 	{ .start_freq = 6165, .end_freq = 6405, },
184162d5c14SDeren Wu 	{ .start_freq = 6405, .end_freq = 6525, },
185162d5c14SDeren Wu 	{ .start_freq = 6525, .end_freq = 6705, },
186162d5c14SDeren Wu 	{ .start_freq = 6705, .end_freq = 6865, },
187162d5c14SDeren Wu 	{ .start_freq = 6865, .end_freq = 7125, },
188502604f5SYN Chen };
189502604f5SYN Chen 
19097f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = {
191502604f5SYN Chen 	.type = NL80211_SAR_TYPE_POWER,
192502604f5SYN Chen 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
193502604f5SYN Chen 	.freq_ranges = &mt76_sar_freq_ranges[0],
194502604f5SYN Chen };
195502604f5SYN Chen 
mt76_led_init(struct mt76_phy * phy)1963abd46ddSLorenzo Bianconi static int mt76_led_init(struct mt76_phy *phy)
19717f1de56SFelix Fietkau {
1983abd46ddSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1993abd46ddSLorenzo Bianconi 	struct ieee80211_hw *hw = phy->hw;
20017f1de56SFelix Fietkau 
2013abd46ddSLorenzo Bianconi 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
20217f1de56SFelix Fietkau 		return 0;
20317f1de56SFelix Fietkau 
2043abd46ddSLorenzo Bianconi 	snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
2053abd46ddSLorenzo Bianconi 		 wiphy_name(hw->wiphy));
20617f1de56SFelix Fietkau 
2073abd46ddSLorenzo Bianconi 	phy->leds.cdev.name = phy->leds.name;
2083abd46ddSLorenzo Bianconi 	phy->leds.cdev.default_trigger =
20917f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
21017f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
21117f1de56SFelix Fietkau 					mt76_tpt_blink,
21217f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
21317f1de56SFelix Fietkau 
2143abd46ddSLorenzo Bianconi 	if (phy == &dev->phy) {
2153abd46ddSLorenzo Bianconi 		struct device_node *np = dev->dev->of_node;
2163abd46ddSLorenzo Bianconi 
21717f1de56SFelix Fietkau 		np = of_get_child_by_name(np, "led");
21817f1de56SFelix Fietkau 		if (np) {
2193abd46ddSLorenzo Bianconi 			int led_pin;
2203abd46ddSLorenzo Bianconi 
22117f1de56SFelix Fietkau 			if (!of_property_read_u32(np, "led-sources", &led_pin))
2223abd46ddSLorenzo Bianconi 				phy->leds.pin = led_pin;
2233abd46ddSLorenzo Bianconi 			phy->leds.al = of_property_read_bool(np,
2243abd46ddSLorenzo Bianconi 							     "led-active-low");
2250a14c1d0SLiang He 			of_node_put(np);
22617f1de56SFelix Fietkau 		}
22736f7e2b2SFelix Fietkau 	}
22836f7e2b2SFelix Fietkau 
2293abd46ddSLorenzo Bianconi 	return led_classdev_register(dev->dev, &phy->leds.cdev);
2303abd46ddSLorenzo Bianconi }
2313abd46ddSLorenzo Bianconi 
mt76_led_cleanup(struct mt76_phy * phy)2323abd46ddSLorenzo Bianconi static void mt76_led_cleanup(struct mt76_phy *phy)
23336f7e2b2SFelix Fietkau {
2343abd46ddSLorenzo Bianconi 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
23536f7e2b2SFelix Fietkau 		return;
23636f7e2b2SFelix Fietkau 
2373abd46ddSLorenzo Bianconi 	led_classdev_unregister(&phy->leds.cdev);
23817f1de56SFelix Fietkau }
23917f1de56SFelix Fietkau 
mt76_init_stream_cap(struct mt76_phy * phy,struct ieee80211_supported_band * sband,bool vht)240bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
241551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
242551e1ef4SLorenzo Bianconi 				 bool vht)
243551e1ef4SLorenzo Bianconi {
244551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
245bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
246551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
247551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
248551e1ef4SLorenzo Bianconi 
249551e1ef4SLorenzo Bianconi 	if (nstream > 1)
250551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
251551e1ef4SLorenzo Bianconi 	else
252551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
253551e1ef4SLorenzo Bianconi 
254551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
255551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
256551e1ef4SLorenzo Bianconi 
257551e1ef4SLorenzo Bianconi 	if (!vht)
258551e1ef4SLorenzo Bianconi 		return;
259551e1ef4SLorenzo Bianconi 
260551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
261551e1ef4SLorenzo Bianconi 	if (nstream > 1)
262551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
263551e1ef4SLorenzo Bianconi 	else
264551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
265abba3453SDeren Wu 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
266abba3453SDeren Wu 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
267551e1ef4SLorenzo Bianconi 
268551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
269551e1ef4SLorenzo Bianconi 		if (i < nstream)
270551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
271551e1ef4SLorenzo Bianconi 		else
272551e1ef4SLorenzo Bianconi 			mcs_map |=
273551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
274551e1ef4SLorenzo Bianconi 	}
275551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
276551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
277781b80f4SFelix Fietkau 	if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
278d9fcfc14SDeren Wu 		vht_cap->vht_mcs.tx_highest |=
279d9fcfc14SDeren Wu 				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
280551e1ef4SLorenzo Bianconi }
281551e1ef4SLorenzo Bianconi 
mt76_set_stream_caps(struct mt76_phy * phy,bool vht)282bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2835ebdc3e0SLorenzo Bianconi {
28448dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
285bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
28648dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
287bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
288edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz)
289edf9dab8SLorenzo Bianconi 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
2905ebdc3e0SLorenzo Bianconi }
2915ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
2925ebdc3e0SLorenzo Bianconi 
29317f1de56SFelix Fietkau 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)29477af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
29517f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
296edf9dab8SLorenzo Bianconi 		struct ieee80211_rate *rates, int n_rates,
297edf9dab8SLorenzo Bianconi 		bool ht, bool vht)
29817f1de56SFelix Fietkau {
29917f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
30017f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
30177af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
30277af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
30317f1de56SFelix Fietkau 	void *chanlist;
30417f1de56SFelix Fietkau 	int size;
30517f1de56SFelix Fietkau 
30617f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
30717f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
30817f1de56SFelix Fietkau 	if (!chanlist)
30917f1de56SFelix Fietkau 		return -ENOMEM;
31017f1de56SFelix Fietkau 
311a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
31217f1de56SFelix Fietkau 				    GFP_KERNEL);
31317f1de56SFelix Fietkau 	if (!msband->chan)
31417f1de56SFelix Fietkau 		return -ENOMEM;
31517f1de56SFelix Fietkau 
31617f1de56SFelix Fietkau 	sband->channels = chanlist;
31717f1de56SFelix Fietkau 	sband->n_channels = n_chan;
31817f1de56SFelix Fietkau 	sband->bitrates = rates;
31917f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
32017f1de56SFelix Fietkau 
321edf9dab8SLorenzo Bianconi 	if (!ht)
322edf9dab8SLorenzo Bianconi 		return 0;
323edf9dab8SLorenzo Bianconi 
32417f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
32517f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
32617f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
32717f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
32817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
32917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
33017f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
33117f1de56SFelix Fietkau 
33217f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
33317f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
33417f1de56SFelix Fietkau 
33577af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
336551e1ef4SLorenzo Bianconi 
33717f1de56SFelix Fietkau 	if (!vht)
33817f1de56SFelix Fietkau 		return 0;
33917f1de56SFelix Fietkau 
34017f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
34117f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
34217f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
34317f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
34449149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
34549149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
34617f1de56SFelix Fietkau 
34717f1de56SFelix Fietkau 	return 0;
34817f1de56SFelix Fietkau }
34917f1de56SFelix Fietkau 
35017f1de56SFelix Fietkau static int
mt76_init_sband_2g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)35177af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
35217f1de56SFelix Fietkau 		   int n_rates)
35317f1de56SFelix Fietkau {
35477af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
35517f1de56SFelix Fietkau 
35677af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
35777af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
358edf9dab8SLorenzo Bianconi 			       n_rates, true, false);
35917f1de56SFelix Fietkau }
36017f1de56SFelix Fietkau 
36117f1de56SFelix Fietkau static int
mt76_init_sband_5g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates,bool vht)36277af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
36317f1de56SFelix Fietkau 		   int n_rates, bool vht)
36417f1de56SFelix Fietkau {
36577af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
36617f1de56SFelix Fietkau 
36777af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
36877af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
369edf9dab8SLorenzo Bianconi 			       n_rates, true, vht);
370edf9dab8SLorenzo Bianconi }
371edf9dab8SLorenzo Bianconi 
372edf9dab8SLorenzo Bianconi static int
mt76_init_sband_6g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)373edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
374edf9dab8SLorenzo Bianconi 		   int n_rates)
375edf9dab8SLorenzo Bianconi {
376edf9dab8SLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
377edf9dab8SLorenzo Bianconi 
378edf9dab8SLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
379edf9dab8SLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
380edf9dab8SLorenzo Bianconi 			       n_rates, false, false);
38117f1de56SFelix Fietkau }
38217f1de56SFelix Fietkau 
38317f1de56SFelix Fietkau static void
mt76_check_sband(struct mt76_phy * phy,struct mt76_sband * msband,enum nl80211_band band)384c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
385c89d3625SFelix Fietkau 		 enum nl80211_band band)
38617f1de56SFelix Fietkau {
387c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
38817f1de56SFelix Fietkau 	bool found = false;
38917f1de56SFelix Fietkau 	int i;
39017f1de56SFelix Fietkau 
39117f1de56SFelix Fietkau 	if (!sband)
39217f1de56SFelix Fietkau 		return;
39317f1de56SFelix Fietkau 
39417f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
39517f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
39617f1de56SFelix Fietkau 			continue;
39717f1de56SFelix Fietkau 
39817f1de56SFelix Fietkau 		found = true;
39917f1de56SFelix Fietkau 		break;
40017f1de56SFelix Fietkau 	}
40117f1de56SFelix Fietkau 
402c89d3625SFelix Fietkau 	if (found) {
403c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
404c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
40517f1de56SFelix Fietkau 		return;
406c89d3625SFelix Fietkau 	}
40717f1de56SFelix Fietkau 
40817f1de56SFelix Fietkau 	sband->n_channels = 0;
409c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
41017f1de56SFelix Fietkau }
41117f1de56SFelix Fietkau 
412d43de9cfSLorenzo Bianconi static int
mt76_phy_init(struct mt76_phy * phy,struct ieee80211_hw * hw)41398df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
414c89d3625SFelix Fietkau {
41598df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
416c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
417c89d3625SFelix Fietkau 
418d2defcddSFelix Fietkau 	INIT_LIST_HEAD(&phy->tx_list);
419d2defcddSFelix Fietkau 	spin_lock_init(&phy->tx_lock);
420d2defcddSFelix Fietkau 
421c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
42298df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
423c89d3625SFelix Fietkau 
424c278a64aSRyder Lee 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
425c278a64aSRyder Lee 			   NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
426dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
427b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
428b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
429c89d3625SFelix Fietkau 
430c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
431c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
432d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
433c89d3625SFelix Fietkau 
4340a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4350a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
436c89d3625SFelix Fietkau 
437d43de9cfSLorenzo Bianconi 	wiphy->sar_capa = &mt76_sar_capa;
438d43de9cfSLorenzo Bianconi 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
439d43de9cfSLorenzo Bianconi 				sizeof(struct mt76_freq_range_power),
440d43de9cfSLorenzo Bianconi 				GFP_KERNEL);
441d43de9cfSLorenzo Bianconi 	if (!phy->frp)
442d43de9cfSLorenzo Bianconi 		return -ENOMEM;
443d43de9cfSLorenzo Bianconi 
444c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
445b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
446c9619dfaSShayne Chen 
447c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
448c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
449c89d3625SFelix Fietkau 
450c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
451c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
452c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
453c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
454c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
455c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
456ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
4575b0fb852SBen Greear 
4585b0fb852SBen Greear 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
459c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
460c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
4615b0fb852SBen Greear 	}
4625b0fb852SBen Greear 
463c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
464c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
465c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
466d43de9cfSLorenzo Bianconi 
467d43de9cfSLorenzo Bianconi 	return 0;
468c89d3625SFelix Fietkau }
469c89d3625SFelix Fietkau 
470c89d3625SFelix Fietkau struct mt76_phy *
mt76_alloc_phy(struct mt76_dev * dev,unsigned int size,const struct ieee80211_ops * ops,u8 band_idx)471c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
472dc44c45cSLorenzo Bianconi 	       const struct ieee80211_ops *ops, u8 band_idx)
473c89d3625SFelix Fietkau {
474c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
475db78a791SLorenzo Bianconi 	unsigned int phy_size;
476c89d3625SFelix Fietkau 	struct mt76_phy *phy;
477c89d3625SFelix Fietkau 
478c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
479db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
480c89d3625SFelix Fietkau 	if (!hw)
481c89d3625SFelix Fietkau 		return NULL;
482c89d3625SFelix Fietkau 
483c89d3625SFelix Fietkau 	phy = hw->priv;
484c89d3625SFelix Fietkau 	phy->dev = dev;
485c89d3625SFelix Fietkau 	phy->hw = hw;
486db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
487dc44c45cSLorenzo Bianconi 	phy->band_idx = band_idx;
488c89d3625SFelix Fietkau 
4898af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4908af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4918af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4928af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4938af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4948af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4958af414e8SLorenzo Bianconi #endif
4968af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4978af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4988af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4998af414e8SLorenzo Bianconi 
500c89d3625SFelix Fietkau 	return phy;
501c89d3625SFelix Fietkau }
502c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
503c89d3625SFelix Fietkau 
mt76_register_phy(struct mt76_phy * phy,bool vht,struct ieee80211_rate * rates,int n_rates)504db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
505db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
506c89d3625SFelix Fietkau {
507c89d3625SFelix Fietkau 	int ret;
508c89d3625SFelix Fietkau 
509d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
510d43de9cfSLorenzo Bianconi 	if (ret)
511d43de9cfSLorenzo Bianconi 		return ret;
512db78a791SLorenzo Bianconi 
513db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
514db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
515db78a791SLorenzo Bianconi 		if (ret)
516db78a791SLorenzo Bianconi 			return ret;
517db78a791SLorenzo Bianconi 	}
518db78a791SLorenzo Bianconi 
519db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
520db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
521db78a791SLorenzo Bianconi 		if (ret)
522db78a791SLorenzo Bianconi 			return ret;
523db78a791SLorenzo Bianconi 	}
524db78a791SLorenzo Bianconi 
525edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
526edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
527edf9dab8SLorenzo Bianconi 		if (ret)
528edf9dab8SLorenzo Bianconi 			return ret;
529edf9dab8SLorenzo Bianconi 	}
530edf9dab8SLorenzo Bianconi 
5319e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
5329e81c2c7SLorenzo Bianconi 		ret = mt76_led_init(phy);
5339e81c2c7SLorenzo Bianconi 		if (ret)
5349e81c2c7SLorenzo Bianconi 			return ret;
5359e81c2c7SLorenzo Bianconi 	}
5369e81c2c7SLorenzo Bianconi 
537db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
538db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
539db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
540edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
541db78a791SLorenzo Bianconi 
542c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
543c89d3625SFelix Fietkau 	if (ret)
544c89d3625SFelix Fietkau 		return ret;
545c89d3625SFelix Fietkau 
54641130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
547dc44c45cSLorenzo Bianconi 	phy->dev->phys[phy->band_idx] = phy;
548db78a791SLorenzo Bianconi 
549c89d3625SFelix Fietkau 	return 0;
550c89d3625SFelix Fietkau }
551c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
552c89d3625SFelix Fietkau 
mt76_unregister_phy(struct mt76_phy * phy)553db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
554c89d3625SFelix Fietkau {
555c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
556c89d3625SFelix Fietkau 
55741130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
55841130c32SLorenzo Bianconi 		return;
55941130c32SLorenzo Bianconi 
5609e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS))
5619e81c2c7SLorenzo Bianconi 		mt76_led_cleanup(phy);
562c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
563c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
564dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = NULL;
565c89d3625SFelix Fietkau }
566c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
567c89d3625SFelix Fietkau 
mt76_create_page_pool(struct mt76_dev * dev,struct mt76_queue * q)5682f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
5692f5c3c77SLorenzo Bianconi {
5702f5c3c77SLorenzo Bianconi 	struct page_pool_params pp_params = {
5712f5c3c77SLorenzo Bianconi 		.order = 0,
5722f5c3c77SLorenzo Bianconi 		.flags = PP_FLAG_PAGE_FRAG,
5732f5c3c77SLorenzo Bianconi 		.nid = NUMA_NO_NODE,
5742f5c3c77SLorenzo Bianconi 		.dev = dev->dma_dev,
5752f5c3c77SLorenzo Bianconi 	};
5762f5c3c77SLorenzo Bianconi 	int idx = q - dev->q_rx;
5772f5c3c77SLorenzo Bianconi 
5782f5c3c77SLorenzo Bianconi 	switch (idx) {
5792f5c3c77SLorenzo Bianconi 	case MT_RXQ_MAIN:
5802f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND1:
5812f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND2:
5822f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 256;
5832f5c3c77SLorenzo Bianconi 		break;
5842f5c3c77SLorenzo Bianconi 	default:
5852f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 16;
5862f5c3c77SLorenzo Bianconi 		break;
5872f5c3c77SLorenzo Bianconi 	}
5882f5c3c77SLorenzo Bianconi 
5892f5c3c77SLorenzo Bianconi 	if (mt76_is_mmio(dev)) {
5902f5c3c77SLorenzo Bianconi 		/* rely on page_pool for DMA mapping */
5912f5c3c77SLorenzo Bianconi 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
5922f5c3c77SLorenzo Bianconi 		pp_params.dma_dir = DMA_FROM_DEVICE;
5932f5c3c77SLorenzo Bianconi 		pp_params.max_len = PAGE_SIZE;
5942f5c3c77SLorenzo Bianconi 		pp_params.offset = 0;
5952f5c3c77SLorenzo Bianconi 	}
5962f5c3c77SLorenzo Bianconi 
5972f5c3c77SLorenzo Bianconi 	q->page_pool = page_pool_create(&pp_params);
5982f5c3c77SLorenzo Bianconi 	if (IS_ERR(q->page_pool)) {
5992f5c3c77SLorenzo Bianconi 		int err = PTR_ERR(q->page_pool);
6002f5c3c77SLorenzo Bianconi 
6012f5c3c77SLorenzo Bianconi 		q->page_pool = NULL;
6022f5c3c77SLorenzo Bianconi 		return err;
6032f5c3c77SLorenzo Bianconi 	}
6042f5c3c77SLorenzo Bianconi 
6052f5c3c77SLorenzo Bianconi 	return 0;
6062f5c3c77SLorenzo Bianconi }
6072f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool);
6082f5c3c77SLorenzo Bianconi 
609a85b590cSFelix Fietkau struct mt76_dev *
mt76_alloc_device(struct device * pdev,unsigned int size,const struct ieee80211_ops * ops,const struct mt76_driver_ops * drv_ops)610c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
611c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
612c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
613a85b590cSFelix Fietkau {
614a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
615ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
616a85b590cSFelix Fietkau 	struct mt76_dev *dev;
617e5443256SFelix Fietkau 	int i;
618a85b590cSFelix Fietkau 
619a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
620a85b590cSFelix Fietkau 	if (!hw)
621a85b590cSFelix Fietkau 		return NULL;
622a85b590cSFelix Fietkau 
623a85b590cSFelix Fietkau 	dev = hw->priv;
624a85b590cSFelix Fietkau 	dev->hw = hw;
625c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
626c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
627d1ddc536SFelix Fietkau 	dev->dma_dev = pdev;
628c0f7b25aSLorenzo Bianconi 
629ac24dd35SFelix Fietkau 	phy = &dev->phy;
630ac24dd35SFelix Fietkau 	phy->dev = dev;
631ac24dd35SFelix Fietkau 	phy->hw = hw;
632dc44c45cSLorenzo Bianconi 	phy->band_idx = MT_BAND0;
633dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = phy;
634ac24dd35SFelix Fietkau 
635a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
636a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
637a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
638c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
6392666beceSSujuan Chen 	spin_lock_init(&dev->wed_lock);
640108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
64126e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
642a85b590cSFelix Fietkau 
64309872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
64409872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
64509872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
646781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
64709872957SLorenzo Bianconi 
6488af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6498af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
6508af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
6518af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
6528af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
6538af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
6548af414e8SLorenzo Bianconi #endif
6558af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
6568af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
6578af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
6588af414e8SLorenzo Bianconi 
65951252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
66051252cc5SLorenzo Bianconi 	idr_init(&dev->token);
66151252cc5SLorenzo Bianconi 
6622666beceSSujuan Chen 	spin_lock_init(&dev->rx_token_lock);
6632666beceSSujuan Chen 	idr_init(&dev->rx_token);
6642666beceSSujuan Chen 
665bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
666fbba711cSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->sta_poll_list);
667fbba711cSLorenzo Bianconi 	spin_lock_init(&dev->sta_poll_lock);
668bd1e3e7bSLorenzo Bianconi 
669e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
6702666beceSSujuan Chen 	INIT_LIST_HEAD(&dev->rxwi_cache);
67161b5156bSFelix Fietkau 	dev->token_size = dev->drv->token_size;
672e5443256SFelix Fietkau 
673e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
674e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
675e5443256SFelix Fietkau 
676a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
677a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
678a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
679a86f1d01SLorenzo Bianconi 		return NULL;
680a86f1d01SLorenzo Bianconi 	}
681a86f1d01SLorenzo Bianconi 
682a85b590cSFelix Fietkau 	return dev;
683a85b590cSFelix Fietkau }
684a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
685a85b590cSFelix Fietkau 
mt76_register_device(struct mt76_dev * dev,bool vht,struct ieee80211_rate * rates,int n_rates)68617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
68717f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
68817f1de56SFelix Fietkau {
68917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
690c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
69117f1de56SFelix Fietkau 	int ret;
69217f1de56SFelix Fietkau 
69317f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
694d2defcddSFelix Fietkau 	mt76_wcid_init(&dev->global_wcid);
695d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
696d43de9cfSLorenzo Bianconi 	if (ret)
697d43de9cfSLorenzo Bianconi 		return ret;
69817f1de56SFelix Fietkau 
69948dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
70077af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
70117f1de56SFelix Fietkau 		if (ret)
70217f1de56SFelix Fietkau 			return ret;
70317f1de56SFelix Fietkau 	}
70417f1de56SFelix Fietkau 
70548dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
70677af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
70717f1de56SFelix Fietkau 		if (ret)
70817f1de56SFelix Fietkau 			return ret;
70917f1de56SFelix Fietkau 	}
71017f1de56SFelix Fietkau 
711edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
712edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
713edf9dab8SLorenzo Bianconi 		if (ret)
714edf9dab8SLorenzo Bianconi 			return ret;
715edf9dab8SLorenzo Bianconi 	}
716edf9dab8SLorenzo Bianconi 
717c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
718c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
719c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
720edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
72117f1de56SFelix Fietkau 
722b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
7233abd46ddSLorenzo Bianconi 		ret = mt76_led_init(phy);
72417f1de56SFelix Fietkau 		if (ret)
72517f1de56SFelix Fietkau 			return ret;
726b374e868SArnd Bergmann 	}
72717f1de56SFelix Fietkau 
728781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
729781eef5bSFelix Fietkau 	if (ret)
730781eef5bSFelix Fietkau 		return ret;
731781eef5bSFelix Fietkau 
732781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
73341130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
734781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
735781eef5bSFelix Fietkau 
736781eef5bSFelix Fietkau 	return 0;
73717f1de56SFelix Fietkau }
73817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
73917f1de56SFelix Fietkau 
mt76_unregister_device(struct mt76_dev * dev)74017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
74117f1de56SFelix Fietkau {
74217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
74317f1de56SFelix Fietkau 
74441130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
74541130c32SLorenzo Bianconi 		return;
74641130c32SLorenzo Bianconi 
747d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
7483abd46ddSLorenzo Bianconi 		mt76_led_cleanup(&dev->phy);
749c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
750d2defcddSFelix Fietkau 	mt76_wcid_cleanup(dev, &dev->global_wcid);
75117f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
75217f1de56SFelix Fietkau }
75317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
75417f1de56SFelix Fietkau 
mt76_free_device(struct mt76_dev * dev)755def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
756def34a2fSLorenzo Bianconi {
757781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
758a86f1d01SLorenzo Bianconi 	if (dev->wq) {
759a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
760a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
761a86f1d01SLorenzo Bianconi 	}
762def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
763def34a2fSLorenzo Bianconi }
764def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
765def34a2fSLorenzo Bianconi 
mt76_rx_release_amsdu(struct mt76_phy * phy,enum mt76_rxq_id q)766cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
767cc4b3c13SLorenzo Bianconi {
768cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
7692c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
770cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
771cc4b3c13SLorenzo Bianconi 
772cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
773cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
7742c2bdd23SFelix Fietkau 
7752c2bdd23SFelix Fietkau 	/*
7762c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
7772c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7782c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
7792c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
7802c2bdd23SFelix Fietkau 	 * address.
7812c2bdd23SFelix Fietkau 	 */
7822c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
7832c2bdd23SFelix Fietkau 		int offset = 0;
7842c2bdd23SFelix Fietkau 
7852c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
7862c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
7872c2bdd23SFelix Fietkau 
7882c2bdd23SFelix Fietkau 			if ((status->flag &
7892c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
7902c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
7912c2bdd23SFelix Fietkau 				offset += 8;
7922c2bdd23SFelix Fietkau 		}
7932c2bdd23SFelix Fietkau 
7942c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
7952c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
7962c2bdd23SFelix Fietkau 			return;
7972c2bdd23SFelix Fietkau 		}
7982c2bdd23SFelix Fietkau 	}
799cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
800cc4b3c13SLorenzo Bianconi }
801cc4b3c13SLorenzo Bianconi 
mt76_rx_release_burst(struct mt76_phy * phy,enum mt76_rxq_id q,struct sk_buff * skb)802cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
803cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
804cc4b3c13SLorenzo Bianconi {
805cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
806cc4b3c13SLorenzo Bianconi 
807cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
808cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
809cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
810cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
811cc4b3c13SLorenzo Bianconi 
812cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
813cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
814cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
815cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
816cc4b3c13SLorenzo Bianconi 	} else {
817cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
818cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
819cc4b3c13SLorenzo Bianconi 	}
820cc4b3c13SLorenzo Bianconi 
821cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
822cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
823cc4b3c13SLorenzo Bianconi }
824cc4b3c13SLorenzo Bianconi 
mt76_rx(struct mt76_dev * dev,enum mt76_rxq_id q,struct sk_buff * skb)82517f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
82617f1de56SFelix Fietkau {
827011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
828128c9b7dSLorenzo Bianconi 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
829011849e0SFelix Fietkau 
830011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
83117f1de56SFelix Fietkau 		dev_kfree_skb(skb);
83217f1de56SFelix Fietkau 		return;
83317f1de56SFelix Fietkau 	}
83417f1de56SFelix Fietkau 
835f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
836c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
837c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
838f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
839c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
840f0efa862SFelix Fietkau 	}
841f0efa862SFelix Fietkau #endif
842cc4b3c13SLorenzo Bianconi 
843cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
84417f1de56SFelix Fietkau }
84517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
84617f1de56SFelix Fietkau 
mt76_has_tx_pending(struct mt76_phy * phy)8475a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
84826e40d4cSFelix Fietkau {
849af005f26SLorenzo Bianconi 	struct mt76_queue *q;
85091990519SLorenzo Bianconi 	int i;
8515a95ca41SFelix Fietkau 
8525a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
85391990519SLorenzo Bianconi 		q = phy->q_tx[i];
854af005f26SLorenzo Bianconi 		if (q && q->queued)
85526e40d4cSFelix Fietkau 			return true;
85626e40d4cSFelix Fietkau 	}
85726e40d4cSFelix Fietkau 
85826e40d4cSFelix Fietkau 	return false;
85926e40d4cSFelix Fietkau }
86039d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
86126e40d4cSFelix Fietkau 
8620fd0eb54SFelix Fietkau static struct mt76_channel_state *
mt76_channel_state(struct mt76_phy * phy,struct ieee80211_channel * c)86396747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8640fd0eb54SFelix Fietkau {
8650fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
8660fd0eb54SFelix Fietkau 	int idx;
8670fd0eb54SFelix Fietkau 
8680fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
86996747a51SFelix Fietkau 		msband = &phy->sband_2g;
870edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
871edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
8720fd0eb54SFelix Fietkau 	else
87396747a51SFelix Fietkau 		msband = &phy->sband_5g;
8740fd0eb54SFelix Fietkau 
8750fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
8760fd0eb54SFelix Fietkau 	return &msband->chan[idx];
8770fd0eb54SFelix Fietkau }
8780fd0eb54SFelix Fietkau 
mt76_update_survey_active_time(struct mt76_phy * phy,ktime_t time)87904414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
88096747a51SFelix Fietkau {
88196747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
88296747a51SFelix Fietkau 
88396747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
88496747a51SFelix Fietkau 						  phy->survey_time));
88596747a51SFelix Fietkau 	phy->survey_time = time;
88696747a51SFelix Fietkau }
88704414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
88896747a51SFelix Fietkau 
mt76_update_survey(struct mt76_phy * phy)889c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
8905ce09c1aSFelix Fietkau {
891c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
892aec65e48SFelix Fietkau 	ktime_t cur_time;
893aec65e48SFelix Fietkau 
8945ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
895c560b137SRyder Lee 		dev->drv->update_survey(phy);
8965ce09c1aSFelix Fietkau 
897aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
898c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
899aec65e48SFelix Fietkau 
9005ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
901c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
90296747a51SFelix Fietkau 
903237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
9045ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
9055ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
906237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
9075ce09c1aSFelix Fietkau 	}
9085ce09c1aSFelix Fietkau }
9095ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
9105ce09c1aSFelix Fietkau 
mt76_set_channel(struct mt76_phy * phy)91196747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
91217f1de56SFelix Fietkau {
91396747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
91496747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
91517f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
91617f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
91726e40d4cSFelix Fietkau 	int timeout = HZ / 5;
91817f1de56SFelix Fietkau 
9195a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
920c560b137SRyder Lee 	mt76_update_survey(phy);
92117f1de56SFelix Fietkau 
9223f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9233f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
9243f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9253f306448SFelix Fietkau 
92696747a51SFelix Fietkau 	phy->chandef = *chandef;
92796747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
92817f1de56SFelix Fietkau 
92917f1de56SFelix Fietkau 	if (!offchannel)
93096747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
93117f1de56SFelix Fietkau 
93296747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
93396747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
93417f1de56SFelix Fietkau }
93517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
93617f1de56SFelix Fietkau 
mt76_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)93717f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
93817f1de56SFelix Fietkau 		    struct survey_info *survey)
93917f1de56SFelix Fietkau {
94096747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
94196747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
94217f1de56SFelix Fietkau 	struct mt76_sband *sband;
94317f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
94417f1de56SFelix Fietkau 	struct mt76_channel_state *state;
94517f1de56SFelix Fietkau 	int ret = 0;
94617f1de56SFelix Fietkau 
947237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
94817f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
949c560b137SRyder Lee 		mt76_update_survey(phy);
95017f1de56SFelix Fietkau 
951edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
952edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
953edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
954edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
955edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
956edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
957edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
95896747a51SFelix Fietkau 		sband = &phy->sband_5g;
959edf9dab8SLorenzo Bianconi 	} else {
960edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
96117f1de56SFelix Fietkau 	}
96217f1de56SFelix Fietkau 
963237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
964237312c5SLorenzo Bianconi 		ret = -ENOENT;
965237312c5SLorenzo Bianconi 		goto out;
966237312c5SLorenzo Bianconi 	}
96717f1de56SFelix Fietkau 
96817f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
96996747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
97017f1de56SFelix Fietkau 
97117f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
97217f1de56SFelix Fietkau 	survey->channel = chan;
97317f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
974ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
975e5051965SFelix Fietkau 	if (state->noise)
976e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
977e5051965SFelix Fietkau 
97896747a51SFelix Fietkau 	if (chan == phy->main_chan) {
97917f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
98017f1de56SFelix Fietkau 
9815ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
9825ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
9835ce09c1aSFelix Fietkau 	}
9845ce09c1aSFelix Fietkau 
98517f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
9866bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
987237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
988e5051965SFelix Fietkau 	survey->noise = state->noise;
989237312c5SLorenzo Bianconi 
990237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
991237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
992ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
99317f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
99417f1de56SFelix Fietkau 
995237312c5SLorenzo Bianconi out:
996237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
997237312c5SLorenzo Bianconi 
99817f1de56SFelix Fietkau 	return ret;
99917f1de56SFelix Fietkau }
100017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
100117f1de56SFelix Fietkau 
mt76_wcid_key_setup(struct mt76_dev * dev,struct mt76_wcid * wcid,struct ieee80211_key_conf * key)100230ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
100330ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
100430ce7f44SFelix Fietkau {
100530ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
100630ce7f44SFelix Fietkau 	int i;
100730ce7f44SFelix Fietkau 
100830ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
100930ce7f44SFelix Fietkau 
101030ce7f44SFelix Fietkau 	if (!key)
101130ce7f44SFelix Fietkau 		return;
101230ce7f44SFelix Fietkau 
101301cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
101401cfc1b4SLorenzo Bianconi 		return;
101530ce7f44SFelix Fietkau 
101601cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
1017a1b0bbd4SXing Song 
1018a1b0bbd4SXing Song 	/* data frame */
101930ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
102030ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
102130ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
102230ce7f44SFelix Fietkau 	}
1023a1b0bbd4SXing Song 
1024a1b0bbd4SXing Song 	/* robust management frame */
1025a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
1026a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
1027a1b0bbd4SXing Song 
102830ce7f44SFelix Fietkau }
102930ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
103030ce7f44SFelix Fietkau 
mt76_rx_signal(u8 chain_mask,s8 * chain_signal)1031a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10324550fb9eSFelix Fietkau {
10334550fb9eSFelix Fietkau 	int signal = -128;
10344550fb9eSFelix Fietkau 	u8 chains;
10354550fb9eSFelix Fietkau 
1036a71b648eSRyder Lee 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10374550fb9eSFelix Fietkau 		int cur, diff;
10384550fb9eSFelix Fietkau 
10396450b133SDeren Wu 		cur = *chain_signal;
10406450b133SDeren Wu 		if (!(chains & BIT(0)) ||
10416450b133SDeren Wu 		    cur > 0)
10424550fb9eSFelix Fietkau 			continue;
10434550fb9eSFelix Fietkau 
10444550fb9eSFelix Fietkau 		if (cur > signal)
10454550fb9eSFelix Fietkau 			swap(cur, signal);
10464550fb9eSFelix Fietkau 
10474550fb9eSFelix Fietkau 		diff = signal - cur;
10484550fb9eSFelix Fietkau 		if (diff == 0)
10494550fb9eSFelix Fietkau 			signal += 3;
10504550fb9eSFelix Fietkau 		else if (diff <= 2)
10514550fb9eSFelix Fietkau 			signal += 2;
10524550fb9eSFelix Fietkau 		else if (diff <= 6)
10534550fb9eSFelix Fietkau 			signal += 1;
10544550fb9eSFelix Fietkau 	}
10554550fb9eSFelix Fietkau 
10564550fb9eSFelix Fietkau 	return signal;
10574550fb9eSFelix Fietkau }
1058a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
10594550fb9eSFelix Fietkau 
1060bfc394ddSFelix Fietkau static void
mt76_rx_convert(struct mt76_dev * dev,struct sk_buff * skb,struct ieee80211_hw ** hw,struct ieee80211_sta ** sta)1061bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
1062bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
1063bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
10644e34249eSFelix Fietkau {
10654e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1066abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
10674e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
10684e34249eSFelix Fietkau 
10694e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
10704e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
10714e34249eSFelix Fietkau 
10724e34249eSFelix Fietkau 	status->flag = mstat.flag;
10734e34249eSFelix Fietkau 	status->freq = mstat.freq;
10744e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
10754e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
10764e34249eSFelix Fietkau 	status->bw = mstat.bw;
1077021af945SShayne Chen 	if (status->encoding == RX_ENC_EHT) {
1078021af945SShayne Chen 		status->eht.ru = mstat.eht.ru;
1079021af945SShayne Chen 		status->eht.gi = mstat.eht.gi;
1080021af945SShayne Chen 	} else {
1081af4a2f2fSRyder Lee 		status->he_ru = mstat.he_ru;
1082af4a2f2fSRyder Lee 		status->he_gi = mstat.he_gi;
1083af4a2f2fSRyder Lee 		status->he_dcm = mstat.he_dcm;
1084021af945SShayne Chen 	}
10854e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
10864e34249eSFelix Fietkau 	status->nss = mstat.nss;
10874e34249eSFelix Fietkau 	status->band = mstat.band;
10884e34249eSFelix Fietkau 	status->signal = mstat.signal;
10894e34249eSFelix Fietkau 	status->chains = mstat.chains;
1090d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
10910fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
10920fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
1093a71b648eSRyder Lee 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
10944550fb9eSFelix Fietkau 	if (status->signal <= -128)
10954550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
10964e34249eSFelix Fietkau 
1097abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
1098abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
1099abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1100abe3f3daSRyder Lee 
11014e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
110213381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
110313381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
110413381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
110513381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
11069c68a57bSFelix Fietkau 
1107bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1108128c9b7dSLorenzo Bianconi 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
11094e34249eSFelix Fietkau }
11104e34249eSFelix Fietkau 
11113c1032e1SFelix Fietkau static void
mt76_check_ccmp_pn(struct sk_buff * skb)111230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
111330ce7f44SFelix Fietkau {
111430ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
111530ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
111630ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1117a1b0bbd4SXing Song 	int security_idx;
111830ce7f44SFelix Fietkau 	int ret;
111930ce7f44SFelix Fietkau 
112030ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
11213c1032e1SFelix Fietkau 		return;
112230ce7f44SFelix Fietkau 
11231858e4fcSMeiChia Chiu 	if (status->flag & RX_FLAG_ONLY_MONITOR)
11243c1032e1SFelix Fietkau 		return;
11251858e4fcSMeiChia Chiu 
112630ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
11273c1032e1SFelix Fietkau 		return;
112830ce7f44SFelix Fietkau 
11297360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11307360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
11317360cdecSFelix Fietkau 		goto skip_hdr_check;
11327360cdecSFelix Fietkau 
1133a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
113430ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
113530ce7f44SFelix Fietkau 		/*
113630ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
113730ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
113830ce7f44SFelix Fietkau 		 */
113930ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
114030ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
11413c1032e1SFelix Fietkau 			return;
114230ce7f44SFelix Fietkau 	}
114330ce7f44SFelix Fietkau 
1144a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1145a1b0bbd4SXing Song 	 *
1146a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1147a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1148a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1149a1b0bbd4SXing Song 	 */
1150a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1151a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1152a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1153a1b0bbd4SXing Song 
11547360cdecSFelix Fietkau skip_hdr_check:
115530ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1156a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
115730ce7f44SFelix Fietkau 		     sizeof(status->iv));
11583c1032e1SFelix Fietkau 	if (ret <= 0) {
11593c1032e1SFelix Fietkau 		status->flag |= RX_FLAG_ONLY_MONITOR;
11603c1032e1SFelix Fietkau 		return;
11613c1032e1SFelix Fietkau 	}
116230ce7f44SFelix Fietkau 
1163a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
116430ce7f44SFelix Fietkau 
116530ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
116630ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
116730ce7f44SFelix Fietkau }
116830ce7f44SFelix Fietkau 
1169d71ef286SFelix Fietkau static void
mt76_airtime_report(struct mt76_dev * dev,struct mt76_rx_status * status,int len)11705ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
11715ce09c1aSFelix Fietkau 		    int len)
11725ce09c1aSFelix Fietkau {
11735ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
117485b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
117585b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
117685b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
117785b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
117885b7a5d0SLorenzo Bianconi 		.band = status->band,
117985b7a5d0SLorenzo Bianconi 		.nss = status->nss,
118085b7a5d0SLorenzo Bianconi 		.bw = status->bw,
118185b7a5d0SLorenzo Bianconi 	};
11825ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
11835ce09c1aSFelix Fietkau 	u32 airtime;
1184e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11855ce09c1aSFelix Fietkau 
118685b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1187237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
11885ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1189237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
11905ce09c1aSFelix Fietkau 
11915ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
11925ce09c1aSFelix Fietkau 		return;
11935ce09c1aSFelix Fietkau 
11945ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1195e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
11965ce09c1aSFelix Fietkau }
11975ce09c1aSFelix Fietkau 
11985ce09c1aSFelix Fietkau static void
mt76_airtime_flush_ampdu(struct mt76_dev * dev)11995ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
12005ce09c1aSFelix Fietkau {
12015ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
12025ce09c1aSFelix Fietkau 	int wcid_idx;
12035ce09c1aSFelix Fietkau 
12045ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
12055ce09c1aSFelix Fietkau 		return;
12065ce09c1aSFelix Fietkau 
12075ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1208bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
12095ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
12105ce09c1aSFelix Fietkau 	else
12115ce09c1aSFelix Fietkau 		wcid = NULL;
12125ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
12135ce09c1aSFelix Fietkau 
12145ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
12155ce09c1aSFelix Fietkau 
12165ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
12175ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
12185ce09c1aSFelix Fietkau }
12195ce09c1aSFelix Fietkau 
12205ce09c1aSFelix Fietkau static void
mt76_airtime_check(struct mt76_dev * dev,struct sk_buff * skb)12215ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12225ce09c1aSFelix Fietkau {
12235ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12245ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
12255ce09c1aSFelix Fietkau 
12265ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12275ce09c1aSFelix Fietkau 		return;
12285ce09c1aSFelix Fietkau 
12295ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1230e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1231e195dad1SFelix Fietkau 
1232e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1233e195dad1SFelix Fietkau 			return;
1234e195dad1SFelix Fietkau 
123598df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12365ce09c1aSFelix Fietkau 			return;
12375ce09c1aSFelix Fietkau 
12385ce09c1aSFelix Fietkau 		wcid = NULL;
12395ce09c1aSFelix Fietkau 	}
12405ce09c1aSFelix Fietkau 
12415ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12425ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
12435ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
12445ce09c1aSFelix Fietkau 
12455ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12465ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
12475ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
12485ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
12495ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
12505ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
12515ce09c1aSFelix Fietkau 		}
12525ce09c1aSFelix Fietkau 
12535ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
12545ce09c1aSFelix Fietkau 		return;
12555ce09c1aSFelix Fietkau 	}
12565ce09c1aSFelix Fietkau 
12575ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
12585ce09c1aSFelix Fietkau }
12595ce09c1aSFelix Fietkau 
12605ce09c1aSFelix Fietkau static void
mt76_check_sta(struct mt76_dev * dev,struct sk_buff * skb)1261ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1262d71ef286SFelix Fietkau {
1263d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
126477ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1265d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1266bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1267d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1268e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1269d71ef286SFelix Fietkau 	bool ps;
1270d71ef286SFelix Fietkau 
1271128c9b7dSLorenzo Bianconi 	hw = mt76_phy_hw(dev, status->phy_idx);
1272e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1273e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1274bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
127536d91096SFelix Fietkau 		if (sta)
127636d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
127736d91096SFelix Fietkau 	}
127836d91096SFelix Fietkau 
12795ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
12805ce09c1aSFelix Fietkau 
1281d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1282d71ef286SFelix Fietkau 		return;
1283d71ef286SFelix Fietkau 
1284d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1285d71ef286SFelix Fietkau 
128602e5a769SFelix Fietkau 	if (status->signal <= 0)
128702e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
128802e5a769SFelix Fietkau 
1289ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1290ef13edc0SFelix Fietkau 
1291e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1292e195dad1SFelix Fietkau 		return;
1293e195dad1SFelix Fietkau 
1294d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1295d71ef286SFelix Fietkau 		return;
1296d71ef286SFelix Fietkau 
1297d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1298d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1299d71ef286SFelix Fietkau 		return;
1300d71ef286SFelix Fietkau 	}
1301d71ef286SFelix Fietkau 
1302d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1303d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1304d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1305d71ef286SFelix Fietkau 		return;
1306d71ef286SFelix Fietkau 
1307d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1308d71ef286SFelix Fietkau 
1309d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1310d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1311e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1312d71ef286SFelix Fietkau 
1313d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1314d71ef286SFelix Fietkau 		return;
1315d71ef286SFelix Fietkau 
131611b2a25fSFelix Fietkau 	if (ps)
1317d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1318d71ef286SFelix Fietkau 
1319f28c3139SLorenzo Bianconi 	if (dev->drv->sta_ps)
1320d71ef286SFelix Fietkau 		dev->drv->sta_ps(dev, sta, ps);
1321608f7c47SFelix Fietkau 
1322608f7c47SFelix Fietkau 	if (!ps)
1323608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1324608f7c47SFelix Fietkau 
13259f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1326d71ef286SFelix Fietkau }
1327d71ef286SFelix Fietkau 
mt76_rx_complete(struct mt76_dev * dev,struct sk_buff_head * frames,struct napi_struct * napi)13289d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
132981e850efSLorenzo Bianconi 		      struct napi_struct *napi)
133017f1de56SFelix Fietkau {
13319c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1332bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
13333298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
13343298b1f8SFelix Fietkau 	LIST_HEAD(list);
13359d9d738bSFelix Fietkau 
1336c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
13379d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1338cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1339cc4b3c13SLorenzo Bianconi 
13403c1032e1SFelix Fietkau 		mt76_check_ccmp_pn(skb);
1341cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1342bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
13433298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1344cc4b3c13SLorenzo Bianconi 
1345cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1346cc4b3c13SLorenzo Bianconi 		while (nskb) {
1347cc4b3c13SLorenzo Bianconi 			skb = nskb;
1348cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1349cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1350cc4b3c13SLorenzo Bianconi 
1351cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1352cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1353cc4b3c13SLorenzo Bianconi 		}
13549d9d738bSFelix Fietkau 	}
1355c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
13563298b1f8SFelix Fietkau 
13573298b1f8SFelix Fietkau 	if (!napi) {
13583298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
13593298b1f8SFelix Fietkau 		return;
13603298b1f8SFelix Fietkau 	}
13613298b1f8SFelix Fietkau 
13623298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
13633298b1f8SFelix Fietkau 		skb_list_del_init(skb);
13643298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
13653298b1f8SFelix Fietkau 	}
13669d9d738bSFelix Fietkau }
13679d9d738bSFelix Fietkau 
mt76_rx_poll_complete(struct mt76_dev * dev,enum mt76_rxq_id q,struct napi_struct * napi)136881e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
136981e850efSLorenzo Bianconi 			   struct napi_struct *napi)
13709d9d738bSFelix Fietkau {
1371aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
137217f1de56SFelix Fietkau 	struct sk_buff *skb;
137317f1de56SFelix Fietkau 
1374aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1375aee5b8cfSFelix Fietkau 
1376d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1377ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
13784f831d18SLorenzo Bianconi 		if (mtk_wed_device_active(&dev->mmio.wed))
13794f831d18SLorenzo Bianconi 			__skb_queue_tail(&frames, skb);
13804f831d18SLorenzo Bianconi 		else
1381aee5b8cfSFelix Fietkau 			mt76_rx_aggr_reorder(skb, &frames);
1382d71ef286SFelix Fietkau 	}
1383aee5b8cfSFelix Fietkau 
138481e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
13854e34249eSFelix Fietkau }
138681e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1387723b90dcSFelix Fietkau 
1388e28487eaSFelix Fietkau static int
mt76_sta_add(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1389a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1390a1a99d7bSLorenzo Bianconi 	     struct ieee80211_sta *sta)
1391e28487eaSFelix Fietkau {
1392e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1393a1a99d7bSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1394e28487eaSFelix Fietkau 	int ret;
1395e28487eaSFelix Fietkau 	int i;
1396e28487eaSFelix Fietkau 
1397e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1398e28487eaSFelix Fietkau 
1399e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1400e28487eaSFelix Fietkau 	if (ret)
1401e28487eaSFelix Fietkau 		goto out;
1402e28487eaSFelix Fietkau 
1403e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1404e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1405e28487eaSFelix Fietkau 
1406e28487eaSFelix Fietkau 		if (!sta->txq[i])
1407e28487eaSFelix Fietkau 			continue;
1408e28487eaSFelix Fietkau 
1409e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
141051fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1411e28487eaSFelix Fietkau 	}
1412e28487eaSFelix Fietkau 
1413ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1414a1a99d7bSLorenzo Bianconi 	if (phy->band_idx == MT_BAND1)
1415426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1416a1a99d7bSLorenzo Bianconi 	wcid->phy_idx = phy->band_idx;
1417e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1418e28487eaSFelix Fietkau 
1419d2defcddSFelix Fietkau 	mt76_wcid_init(wcid);
1420e28487eaSFelix Fietkau out:
1421e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1422e28487eaSFelix Fietkau 
1423e28487eaSFelix Fietkau 	return ret;
1424e28487eaSFelix Fietkau }
1425e28487eaSFelix Fietkau 
__mt76_sta_remove(struct mt76_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)142613f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1427723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1428723b90dcSFelix Fietkau {
1429723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
143013f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1431723b90dcSFelix Fietkau 
143258bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
143358bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
143458bab0d4SFelix Fietkau 
1435e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1436e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1437e28487eaSFelix Fietkau 
1438d2defcddSFelix Fietkau 	mt76_wcid_cleanup(dev, wcid);
1439bd1e3e7bSLorenzo Bianconi 
1440426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1441426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
144213f61dfcSLorenzo Bianconi }
144313f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1444e28487eaSFelix Fietkau 
144513f61dfcSLorenzo Bianconi static void
mt76_sta_remove(struct mt76_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)144613f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
144713f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
144813f61dfcSLorenzo Bianconi {
144913f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
145013f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1451723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1452723b90dcSFelix Fietkau }
1453e28487eaSFelix Fietkau 
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)1454e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1455e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1456e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1457e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1458e28487eaSFelix Fietkau {
1459426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1460426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1461e28487eaSFelix Fietkau 
1462e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1463e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1464a1a99d7bSLorenzo Bianconi 		return mt76_sta_add(phy, vif, sta);
1465e28487eaSFelix Fietkau 
14669c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
14679c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
14689c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
14699c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
14709c193de5SFelix Fietkau 
1471e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1472e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1473e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1474e28487eaSFelix Fietkau 
1475e28487eaSFelix Fietkau 	return 0;
1476e28487eaSFelix Fietkau }
1477e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
14789313faacSFelix Fietkau 
mt76_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)147943ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
148043ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
148143ba1922SFelix Fietkau {
148243ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
148343ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
148443ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
148543ba1922SFelix Fietkau 
148643ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1487fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
148843ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1489fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
149043ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
149143ba1922SFelix Fietkau }
149243ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
149343ba1922SFelix Fietkau 
mt76_wcid_init(struct mt76_wcid * wcid)1494d2defcddSFelix Fietkau void mt76_wcid_init(struct mt76_wcid *wcid)
1495d2defcddSFelix Fietkau {
1496d2defcddSFelix Fietkau 	INIT_LIST_HEAD(&wcid->tx_list);
1497d2defcddSFelix Fietkau 	skb_queue_head_init(&wcid->tx_pending);
1498d2defcddSFelix Fietkau 
1499d2defcddSFelix Fietkau 	INIT_LIST_HEAD(&wcid->list);
1500d2defcddSFelix Fietkau 	idr_init(&wcid->pktid);
1501d2defcddSFelix Fietkau }
1502d2defcddSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_init);
1503d2defcddSFelix Fietkau 
mt76_wcid_cleanup(struct mt76_dev * dev,struct mt76_wcid * wcid)1504d2defcddSFelix Fietkau void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
1505d2defcddSFelix Fietkau {
1506*818dd118SBjørn Mork 	struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx);
1507d2defcddSFelix Fietkau 	struct ieee80211_hw *hw;
1508d2defcddSFelix Fietkau 	struct sk_buff_head list;
1509d2defcddSFelix Fietkau 	struct sk_buff *skb;
1510d2defcddSFelix Fietkau 
1511d2defcddSFelix Fietkau 	mt76_tx_status_lock(dev, &list);
1512d2defcddSFelix Fietkau 	mt76_tx_status_skb_get(dev, wcid, -1, &list);
1513d2defcddSFelix Fietkau 	mt76_tx_status_unlock(dev, &list);
1514d2defcddSFelix Fietkau 
1515d2defcddSFelix Fietkau 	idr_destroy(&wcid->pktid);
1516d2defcddSFelix Fietkau 
1517d2defcddSFelix Fietkau 	spin_lock_bh(&phy->tx_lock);
1518d2defcddSFelix Fietkau 
1519d2defcddSFelix Fietkau 	if (!list_empty(&wcid->tx_list))
1520d2defcddSFelix Fietkau 		list_del_init(&wcid->tx_list);
1521d2defcddSFelix Fietkau 
1522d2defcddSFelix Fietkau 	spin_lock(&wcid->tx_pending.lock);
1523d2defcddSFelix Fietkau 	skb_queue_splice_tail_init(&wcid->tx_pending, &list);
1524d2defcddSFelix Fietkau 	spin_unlock(&wcid->tx_pending.lock);
1525d2defcddSFelix Fietkau 
1526d2defcddSFelix Fietkau 	spin_unlock_bh(&phy->tx_lock);
1527d2defcddSFelix Fietkau 
1528d2defcddSFelix Fietkau 	while ((skb = __skb_dequeue(&list)) != NULL) {
1529d2defcddSFelix Fietkau 		hw = mt76_tx_status_get_hw(dev, skb);
1530d2defcddSFelix Fietkau 		ieee80211_free_txskb(hw, skb);
1531d2defcddSFelix Fietkau 	}
1532d2defcddSFelix Fietkau }
1533d2defcddSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
1534d2defcddSFelix Fietkau 
mt76_get_txpower(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int * dbm)15359313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15369313faacSFelix Fietkau 		     int *dbm)
15379313faacSFelix Fietkau {
1538beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1539beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
154007cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
15419313faacSFelix Fietkau 
154207cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
15439313faacSFelix Fietkau 
15449313faacSFelix Fietkau 	return 0;
15459313faacSFelix Fietkau }
15469313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1547e7173858SFelix Fietkau 
mt76_init_sar_power(struct ieee80211_hw * hw,const struct cfg80211_sar_specs * sar)1548b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1549b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1550b3cb885eSLorenzo Bianconi {
1551b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1552b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1553b3cb885eSLorenzo Bianconi 	int i;
1554b3cb885eSLorenzo Bianconi 
1555b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1556b3cb885eSLorenzo Bianconi 		return -EINVAL;
1557b3cb885eSLorenzo Bianconi 
1558b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1559b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1560b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1561b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1562b3cb885eSLorenzo Bianconi 
1563b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1564b3cb885eSLorenzo Bianconi 			power = 127;
1565b3cb885eSLorenzo Bianconi 
1566b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1567b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1568b3cb885eSLorenzo Bianconi 	}
1569b3cb885eSLorenzo Bianconi 
1570b3cb885eSLorenzo Bianconi 	return 0;
1571b3cb885eSLorenzo Bianconi }
1572b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1573b3cb885eSLorenzo Bianconi 
mt76_get_sar_power(struct mt76_phy * phy,struct ieee80211_channel * chan,int power)1574b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1575b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1576b3cb885eSLorenzo Bianconi 		       int power)
1577b3cb885eSLorenzo Bianconi {
1578b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1579b3cb885eSLorenzo Bianconi 	int freq, i;
1580b3cb885eSLorenzo Bianconi 
1581b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1582b3cb885eSLorenzo Bianconi 		return power;
1583b3cb885eSLorenzo Bianconi 
1584b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1585b3cb885eSLorenzo Bianconi 		power = 127;
1586b3cb885eSLorenzo Bianconi 
1587b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1588b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1589b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1590b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1591b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1592b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1593b3cb885eSLorenzo Bianconi 			break;
1594b3cb885eSLorenzo Bianconi 		}
1595b3cb885eSLorenzo Bianconi 	}
1596b3cb885eSLorenzo Bianconi 
1597b3cb885eSLorenzo Bianconi 	return power;
1598b3cb885eSLorenzo Bianconi }
1599b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1600b3cb885eSLorenzo Bianconi 
1601e7173858SFelix Fietkau static void
__mt76_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)1602e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1603e7173858SFelix Fietkau {
1604d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1605e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1606e7173858SFelix Fietkau }
1607e7173858SFelix Fietkau 
mt76_csa_finish(struct mt76_dev * dev)1608e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1609e7173858SFelix Fietkau {
1610e7173858SFelix Fietkau 	if (!dev->csa_complete)
1611e7173858SFelix Fietkau 		return;
1612e7173858SFelix Fietkau 
1613e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1614e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1615e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1616e7173858SFelix Fietkau 
1617e7173858SFelix Fietkau 	dev->csa_complete = 0;
1618e7173858SFelix Fietkau }
1619e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1620e7173858SFelix Fietkau 
1621e7173858SFelix Fietkau static void
__mt76_csa_check(void * priv,u8 * mac,struct ieee80211_vif * vif)1622e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1623e7173858SFelix Fietkau {
1624e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1625e7173858SFelix Fietkau 
1626d0a9123eSJohannes Berg 	if (!vif->bss_conf.csa_active)
1627e7173858SFelix Fietkau 		return;
1628e7173858SFelix Fietkau 
16298552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1630e7173858SFelix Fietkau }
1631e7173858SFelix Fietkau 
mt76_csa_check(struct mt76_dev * dev)1632e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1633e7173858SFelix Fietkau {
1634e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1635e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1636e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1637e7173858SFelix Fietkau }
1638e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
163987d53103SStanislaw Gruszka 
164087d53103SStanislaw Gruszka int
mt76_set_tim(struct ieee80211_hw * hw,struct ieee80211_sta * sta,bool set)164187d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
164287d53103SStanislaw Gruszka {
164387d53103SStanislaw Gruszka 	return 0;
164487d53103SStanislaw Gruszka }
164587d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1646eadfd98fSLorenzo Bianconi 
mt76_insert_ccmp_hdr(struct sk_buff * skb,u8 key_id)1647eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1648eadfd98fSLorenzo Bianconi {
1649eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1650eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1651eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1652eadfd98fSLorenzo Bianconi 
1653eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1654eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1655eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1656eadfd98fSLorenzo Bianconi 
1657eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1658eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1659eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1660eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1661eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1662eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1663eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1664eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1665eadfd98fSLorenzo Bianconi 
1666eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1667eadfd98fSLorenzo Bianconi }
1668eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1669d2679d65SLorenzo Bianconi 
mt76_get_rate(struct mt76_dev * dev,struct ieee80211_supported_band * sband,int idx,bool cck)1670d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1671d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1672d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1673d2679d65SLorenzo Bianconi {
1674d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1675d2679d65SLorenzo Bianconi 
1676d2679d65SLorenzo Bianconi 	if (cck) {
1677edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1678d2679d65SLorenzo Bianconi 			return 0;
1679d2679d65SLorenzo Bianconi 
1680d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
168196747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1682d2679d65SLorenzo Bianconi 		offset = 4;
1683d2679d65SLorenzo Bianconi 	}
1684d2679d65SLorenzo Bianconi 
1685d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1686d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1687d2679d65SLorenzo Bianconi 			return i;
1688d2679d65SLorenzo Bianconi 	}
1689d2679d65SLorenzo Bianconi 
1690d2679d65SLorenzo Bianconi 	return 0;
1691d2679d65SLorenzo Bianconi }
1692d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
16938b8ab5c2SLorenzo Bianconi 
mt76_sw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * mac)16948b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16958b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
16968b8ab5c2SLorenzo Bianconi {
1697011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
16988b8ab5c2SLorenzo Bianconi 
1699011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
17008b8ab5c2SLorenzo Bianconi }
17018b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
17028b8ab5c2SLorenzo Bianconi 
mt76_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)17038b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
17048b8ab5c2SLorenzo Bianconi {
1705011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
17068b8ab5c2SLorenzo Bianconi 
1707011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
17088b8ab5c2SLorenzo Bianconi }
17098b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1710e49c76d4SLorenzo Bianconi 
mt76_get_antenna(struct ieee80211_hw * hw,u32 * tx_ant,u32 * rx_ant)1711e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1712e49c76d4SLorenzo Bianconi {
1713beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1714beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1715e49c76d4SLorenzo Bianconi 
1716e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1717beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1718beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1719e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1720e49c76d4SLorenzo Bianconi 
1721e49c76d4SLorenzo Bianconi 	return 0;
1722e49c76d4SLorenzo Bianconi }
1723e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1724b671da33SLorenzo Bianconi 
1725b1cb42adSLorenzo Bianconi struct mt76_queue *
mt76_init_queue(struct mt76_dev * dev,int qid,int idx,int n_desc,int ring_base,u32 flags)1726b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1727f68d6762SFelix Fietkau 		int ring_base, u32 flags)
1728b671da33SLorenzo Bianconi {
1729b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1730b671da33SLorenzo Bianconi 	int err;
1731b671da33SLorenzo Bianconi 
1732b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1733b671da33SLorenzo Bianconi 	if (!hwq)
1734b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1735b671da33SLorenzo Bianconi 
1736f68d6762SFelix Fietkau 	hwq->flags = flags;
1737f68d6762SFelix Fietkau 
1738b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1739b671da33SLorenzo Bianconi 	if (err < 0)
1740b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1741b671da33SLorenzo Bianconi 
1742b1cb42adSLorenzo Bianconi 	return hwq;
1743b671da33SLorenzo Bianconi }
1744b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1745e4867225SSean Wang 
mt76_calculate_default_rate(struct mt76_phy * phy,struct ieee80211_vif * vif,int rateidx)1746e1d9e0e7SSean Wang u16 mt76_calculate_default_rate(struct mt76_phy *phy,
1747e1d9e0e7SSean Wang 				struct ieee80211_vif *vif, int rateidx)
1748e4867225SSean Wang {
1749e1d9e0e7SSean Wang 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
1750e1d9e0e7SSean Wang 	struct cfg80211_chan_def *chandef = mvif->ctx ?
1751e1d9e0e7SSean Wang 					    &mvif->ctx->def :
1752e1d9e0e7SSean Wang 					    &phy->chandef;
175333920b2bSRyder Lee 	int offset = 0;
1754e4867225SSean Wang 
1755e1d9e0e7SSean Wang 	if (chandef->chan->band != NL80211_BAND_2GHZ)
1756e4867225SSean Wang 		offset = 4;
1757e4867225SSean Wang 
175833920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
175933920b2bSRyder Lee 	if (rateidx < 0)
176033920b2bSRyder Lee 		rateidx = 0;
176133920b2bSRyder Lee 
1762d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1763d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1764d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1765e4867225SSean Wang 
1766d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1767e4867225SSean Wang }
176833920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
176954ae98ffSLorenzo Bianconi 
mt76_ethtool_worker(struct mt76_ethtool_worker_info * wi,struct mt76_sta_stats * stats,bool eht)177054ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1771731425f3SShayne Chen 			 struct mt76_sta_stats *stats, bool eht)
177254ae98ffSLorenzo Bianconi {
177354ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
177454ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
177554ae98ffSLorenzo Bianconi 
177654ae98ffSLorenzo Bianconi 	wi->sta_count++;
177754ae98ffSLorenzo Bianconi 
177854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
177954ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
178054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
178154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
178254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
178354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
178454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
178554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
178654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1787731425f3SShayne Chen 	if (eht) {
1788731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1789731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1790731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1791731425f3SShayne Chen 	}
179254ae98ffSLorenzo Bianconi 
1793731425f3SShayne Chen 	for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
179454ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
179554ae98ffSLorenzo Bianconi 
1796731425f3SShayne Chen 	for (i = 0; i < (eht ? 14 : 12); i++)
179754ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
179854ae98ffSLorenzo Bianconi 
1799749c2c2bSRyder Lee 	for (i = 0; i < 4; i++)
1800749c2c2bSRyder Lee 		data[ei++] += stats->tx_nss[i];
1801749c2c2bSRyder Lee 
180254ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
180354ae98ffSLorenzo Bianconi }
180454ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
18053f306448SFelix Fietkau 
mt76_ethtool_page_pool_stats(struct mt76_dev * dev,u64 * data,int * index)1806192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1807192ad406SLorenzo Bianconi {
1808192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS
1809192ad406SLorenzo Bianconi 	struct page_pool_stats stats = {};
1810192ad406SLorenzo Bianconi 	int i;
1811192ad406SLorenzo Bianconi 
1812192ad406SLorenzo Bianconi 	mt76_for_each_q_rx(dev, i)
1813192ad406SLorenzo Bianconi 		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
1814192ad406SLorenzo Bianconi 
1815192ad406SLorenzo Bianconi 	page_pool_ethtool_stats_get(data, &stats);
1816192ad406SLorenzo Bianconi 	*index += page_pool_ethtool_stats_get_count();
1817192ad406SLorenzo Bianconi #endif
1818192ad406SLorenzo Bianconi }
1819192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
1820192ad406SLorenzo Bianconi 
mt76_phy_dfs_state(struct mt76_phy * phy)18213f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
18223f306448SFelix Fietkau {
18233f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
18243f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
18253f306448SFelix Fietkau 
18263f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
18273f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
18283f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
18293f306448SFelix Fietkau 
18303f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
18313f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
18323f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
18333f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
18343f306448SFelix Fietkau 
18353f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
18363f306448SFelix Fietkau 	}
18373f306448SFelix Fietkau 
183800a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
18393f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
18403f306448SFelix Fietkau 
18413f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
18423f306448SFelix Fietkau }
18433f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1844