xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 14cdeaf9504cd37589e8acfedf644d32fb29a429)
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 
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;
200*14cdeaf9SRyder Lee 	struct device_node *np = dev->dev->of_node;
20117f1de56SFelix Fietkau 
2023abd46ddSLorenzo Bianconi 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
20317f1de56SFelix Fietkau 		return 0;
20417f1de56SFelix Fietkau 
205*14cdeaf9SRyder Lee 	np = of_get_child_by_name(np, "led");
206*14cdeaf9SRyder Lee 	if (np) {
207*14cdeaf9SRyder Lee 		if (!of_device_is_available(np)) {
208*14cdeaf9SRyder Lee 			of_node_put(np);
209*14cdeaf9SRyder Lee 			dev_info(dev->dev,
210*14cdeaf9SRyder Lee 				"led registration was explicitly disabled by dts\n");
211*14cdeaf9SRyder Lee 			return 0;
212*14cdeaf9SRyder Lee 		}
213*14cdeaf9SRyder Lee 
214*14cdeaf9SRyder Lee 		if (phy == &dev->phy) {
215*14cdeaf9SRyder Lee 			int led_pin;
216*14cdeaf9SRyder Lee 
217*14cdeaf9SRyder Lee 			if (!of_property_read_u32(np, "led-sources", &led_pin))
218*14cdeaf9SRyder Lee 				phy->leds.pin = led_pin;
219*14cdeaf9SRyder Lee 
220*14cdeaf9SRyder Lee 			phy->leds.al =
221*14cdeaf9SRyder Lee 				of_property_read_bool(np, "led-active-low");
222*14cdeaf9SRyder Lee 		}
223*14cdeaf9SRyder Lee 
224*14cdeaf9SRyder Lee 		of_node_put(np);
225*14cdeaf9SRyder Lee 	}
226*14cdeaf9SRyder Lee 
2273abd46ddSLorenzo Bianconi 	snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
2283abd46ddSLorenzo Bianconi 		 wiphy_name(hw->wiphy));
22917f1de56SFelix Fietkau 
2303abd46ddSLorenzo Bianconi 	phy->leds.cdev.name = phy->leds.name;
2313abd46ddSLorenzo Bianconi 	phy->leds.cdev.default_trigger =
23217f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
23317f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
23417f1de56SFelix Fietkau 					mt76_tpt_blink,
23517f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
23617f1de56SFelix Fietkau 
237*14cdeaf9SRyder Lee 	dev_info(dev->dev,
238*14cdeaf9SRyder Lee 		"registering led '%s'\n", phy->leds.name);
23936f7e2b2SFelix Fietkau 
2403abd46ddSLorenzo Bianconi 	return led_classdev_register(dev->dev, &phy->leds.cdev);
2413abd46ddSLorenzo Bianconi }
2423abd46ddSLorenzo Bianconi 
2433abd46ddSLorenzo Bianconi static void mt76_led_cleanup(struct mt76_phy *phy)
24436f7e2b2SFelix Fietkau {
2453abd46ddSLorenzo Bianconi 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
24636f7e2b2SFelix Fietkau 		return;
24736f7e2b2SFelix Fietkau 
2483abd46ddSLorenzo Bianconi 	led_classdev_unregister(&phy->leds.cdev);
24917f1de56SFelix Fietkau }
25017f1de56SFelix Fietkau 
251bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
252551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
253551e1ef4SLorenzo Bianconi 				 bool vht)
254551e1ef4SLorenzo Bianconi {
255551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
256bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
257551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
258551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
259551e1ef4SLorenzo Bianconi 
260551e1ef4SLorenzo Bianconi 	if (nstream > 1)
261551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
262551e1ef4SLorenzo Bianconi 	else
263551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
264551e1ef4SLorenzo Bianconi 
265551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
266551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
267551e1ef4SLorenzo Bianconi 
268551e1ef4SLorenzo Bianconi 	if (!vht)
269551e1ef4SLorenzo Bianconi 		return;
270551e1ef4SLorenzo Bianconi 
271551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
272551e1ef4SLorenzo Bianconi 	if (nstream > 1)
273551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
274551e1ef4SLorenzo Bianconi 	else
275551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
276abba3453SDeren Wu 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
277abba3453SDeren Wu 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
278551e1ef4SLorenzo Bianconi 
279551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
280551e1ef4SLorenzo Bianconi 		if (i < nstream)
281551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
282551e1ef4SLorenzo Bianconi 		else
283551e1ef4SLorenzo Bianconi 			mcs_map |=
284551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
285551e1ef4SLorenzo Bianconi 	}
286551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
287551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
288781b80f4SFelix Fietkau 	if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
289d9fcfc14SDeren Wu 		vht_cap->vht_mcs.tx_highest |=
290d9fcfc14SDeren Wu 				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
291551e1ef4SLorenzo Bianconi }
292551e1ef4SLorenzo Bianconi 
293bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2945ebdc3e0SLorenzo Bianconi {
29548dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
296bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
29748dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
298bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
299edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz)
300edf9dab8SLorenzo Bianconi 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
3015ebdc3e0SLorenzo Bianconi }
3025ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
3035ebdc3e0SLorenzo Bianconi 
30417f1de56SFelix Fietkau static int
30577af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
30617f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
307edf9dab8SLorenzo Bianconi 		struct ieee80211_rate *rates, int n_rates,
308edf9dab8SLorenzo Bianconi 		bool ht, bool vht)
30917f1de56SFelix Fietkau {
31017f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
31117f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
31277af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
31377af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
31417f1de56SFelix Fietkau 	void *chanlist;
31517f1de56SFelix Fietkau 	int size;
31617f1de56SFelix Fietkau 
31717f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
31817f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
31917f1de56SFelix Fietkau 	if (!chanlist)
32017f1de56SFelix Fietkau 		return -ENOMEM;
32117f1de56SFelix Fietkau 
322a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
32317f1de56SFelix Fietkau 				    GFP_KERNEL);
32417f1de56SFelix Fietkau 	if (!msband->chan)
32517f1de56SFelix Fietkau 		return -ENOMEM;
32617f1de56SFelix Fietkau 
32717f1de56SFelix Fietkau 	sband->channels = chanlist;
32817f1de56SFelix Fietkau 	sband->n_channels = n_chan;
32917f1de56SFelix Fietkau 	sband->bitrates = rates;
33017f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
33117f1de56SFelix Fietkau 
332edf9dab8SLorenzo Bianconi 	if (!ht)
333edf9dab8SLorenzo Bianconi 		return 0;
334edf9dab8SLorenzo Bianconi 
33517f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
33617f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
33717f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
33817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
33917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
34017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
34117f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
34217f1de56SFelix Fietkau 
34317f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
34417f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
34517f1de56SFelix Fietkau 
34677af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
347551e1ef4SLorenzo Bianconi 
34817f1de56SFelix Fietkau 	if (!vht)
34917f1de56SFelix Fietkau 		return 0;
35017f1de56SFelix Fietkau 
35117f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
35217f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
35317f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
35417f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
35549149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
35649149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
35717f1de56SFelix Fietkau 
35817f1de56SFelix Fietkau 	return 0;
35917f1de56SFelix Fietkau }
36017f1de56SFelix Fietkau 
36117f1de56SFelix Fietkau static int
36277af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
36317f1de56SFelix Fietkau 		   int n_rates)
36417f1de56SFelix Fietkau {
36577af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
36617f1de56SFelix Fietkau 
36777af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
36877af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
369edf9dab8SLorenzo Bianconi 			       n_rates, true, false);
37017f1de56SFelix Fietkau }
37117f1de56SFelix Fietkau 
37217f1de56SFelix Fietkau static int
37377af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
37417f1de56SFelix Fietkau 		   int n_rates, bool vht)
37517f1de56SFelix Fietkau {
37677af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
37717f1de56SFelix Fietkau 
37877af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
37977af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
380edf9dab8SLorenzo Bianconi 			       n_rates, true, vht);
381edf9dab8SLorenzo Bianconi }
382edf9dab8SLorenzo Bianconi 
383edf9dab8SLorenzo Bianconi static int
384edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
385edf9dab8SLorenzo Bianconi 		   int n_rates)
386edf9dab8SLorenzo Bianconi {
387edf9dab8SLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
388edf9dab8SLorenzo Bianconi 
389edf9dab8SLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
390edf9dab8SLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
391edf9dab8SLorenzo Bianconi 			       n_rates, false, false);
39217f1de56SFelix Fietkau }
39317f1de56SFelix Fietkau 
39417f1de56SFelix Fietkau static void
395c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
396c89d3625SFelix Fietkau 		 enum nl80211_band band)
39717f1de56SFelix Fietkau {
398c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
39917f1de56SFelix Fietkau 	bool found = false;
40017f1de56SFelix Fietkau 	int i;
40117f1de56SFelix Fietkau 
40217f1de56SFelix Fietkau 	if (!sband)
40317f1de56SFelix Fietkau 		return;
40417f1de56SFelix Fietkau 
40517f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
40617f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
40717f1de56SFelix Fietkau 			continue;
40817f1de56SFelix Fietkau 
40917f1de56SFelix Fietkau 		found = true;
41017f1de56SFelix Fietkau 		break;
41117f1de56SFelix Fietkau 	}
41217f1de56SFelix Fietkau 
413c89d3625SFelix Fietkau 	if (found) {
414c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
415c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
41617f1de56SFelix Fietkau 		return;
417c89d3625SFelix Fietkau 	}
41817f1de56SFelix Fietkau 
41917f1de56SFelix Fietkau 	sband->n_channels = 0;
420c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
42117f1de56SFelix Fietkau }
42217f1de56SFelix Fietkau 
423d43de9cfSLorenzo Bianconi static int
42498df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
425c89d3625SFelix Fietkau {
42698df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
427c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
428c89d3625SFelix Fietkau 
4290335c034SFelix Fietkau 	INIT_LIST_HEAD(&phy->tx_list);
4300335c034SFelix Fietkau 	spin_lock_init(&phy->tx_lock);
4310335c034SFelix Fietkau 
432c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
43398df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
434c89d3625SFelix Fietkau 
435c278a64aSRyder Lee 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
436c278a64aSRyder Lee 			   NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
437dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
438b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
439b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
440c89d3625SFelix Fietkau 
441c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
442c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
443d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
444c89d3625SFelix Fietkau 
4450a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4460a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
447c89d3625SFelix Fietkau 
448d43de9cfSLorenzo Bianconi 	wiphy->sar_capa = &mt76_sar_capa;
449d43de9cfSLorenzo Bianconi 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
450d43de9cfSLorenzo Bianconi 				sizeof(struct mt76_freq_range_power),
451d43de9cfSLorenzo Bianconi 				GFP_KERNEL);
452d43de9cfSLorenzo Bianconi 	if (!phy->frp)
453d43de9cfSLorenzo Bianconi 		return -ENOMEM;
454d43de9cfSLorenzo Bianconi 
455c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
456b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
457c9619dfaSShayne Chen 
458c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
459c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
460c89d3625SFelix Fietkau 
461c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
462c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
463c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
464c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
465c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
466c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
467ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
4685b0fb852SBen Greear 
469c2fcc83bSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD) &&
470c2fcc83bSFelix Fietkau 	    hw->max_tx_fragments > 1) {
471c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
472c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
4735b0fb852SBen Greear 	}
4745b0fb852SBen Greear 
475c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
476c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
477c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
478d43de9cfSLorenzo Bianconi 
479d43de9cfSLorenzo Bianconi 	return 0;
480c89d3625SFelix Fietkau }
481c89d3625SFelix Fietkau 
482c89d3625SFelix Fietkau struct mt76_phy *
483c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
484dc44c45cSLorenzo Bianconi 	       const struct ieee80211_ops *ops, u8 band_idx)
485c89d3625SFelix Fietkau {
486c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
487db78a791SLorenzo Bianconi 	unsigned int phy_size;
488c89d3625SFelix Fietkau 	struct mt76_phy *phy;
489c89d3625SFelix Fietkau 
490c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
491db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
492c89d3625SFelix Fietkau 	if (!hw)
493c89d3625SFelix Fietkau 		return NULL;
494c89d3625SFelix Fietkau 
495c89d3625SFelix Fietkau 	phy = hw->priv;
496c89d3625SFelix Fietkau 	phy->dev = dev;
497c89d3625SFelix Fietkau 	phy->hw = hw;
498db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
499dc44c45cSLorenzo Bianconi 	phy->band_idx = band_idx;
500c89d3625SFelix Fietkau 
5018af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5028af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
5038af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
5048af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
5058af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
5068af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
5078af414e8SLorenzo Bianconi #endif
5088af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5098af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
5108af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
5118af414e8SLorenzo Bianconi 
512c89d3625SFelix Fietkau 	return phy;
513c89d3625SFelix Fietkau }
514c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
515c89d3625SFelix Fietkau 
516db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
517db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
518c89d3625SFelix Fietkau {
519c89d3625SFelix Fietkau 	int ret;
520c89d3625SFelix Fietkau 
521d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
522d43de9cfSLorenzo Bianconi 	if (ret)
523d43de9cfSLorenzo Bianconi 		return ret;
524db78a791SLorenzo Bianconi 
525db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
526db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
527db78a791SLorenzo Bianconi 		if (ret)
528db78a791SLorenzo Bianconi 			return ret;
529db78a791SLorenzo Bianconi 	}
530db78a791SLorenzo Bianconi 
531db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
532db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
533db78a791SLorenzo Bianconi 		if (ret)
534db78a791SLorenzo Bianconi 			return ret;
535db78a791SLorenzo Bianconi 	}
536db78a791SLorenzo Bianconi 
537edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
538edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
539edf9dab8SLorenzo Bianconi 		if (ret)
540edf9dab8SLorenzo Bianconi 			return ret;
541edf9dab8SLorenzo Bianconi 	}
542edf9dab8SLorenzo Bianconi 
5439e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
5449e81c2c7SLorenzo Bianconi 		ret = mt76_led_init(phy);
5459e81c2c7SLorenzo Bianconi 		if (ret)
5469e81c2c7SLorenzo Bianconi 			return ret;
5479e81c2c7SLorenzo Bianconi 	}
5489e81c2c7SLorenzo Bianconi 
549db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
550db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
551db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
552edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
553db78a791SLorenzo Bianconi 
554c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
555c89d3625SFelix Fietkau 	if (ret)
556c89d3625SFelix Fietkau 		return ret;
557c89d3625SFelix Fietkau 
55841130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
559dc44c45cSLorenzo Bianconi 	phy->dev->phys[phy->band_idx] = phy;
560db78a791SLorenzo Bianconi 
561c89d3625SFelix Fietkau 	return 0;
562c89d3625SFelix Fietkau }
563c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
564c89d3625SFelix Fietkau 
565db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
566c89d3625SFelix Fietkau {
567c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
568c89d3625SFelix Fietkau 
56941130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
57041130c32SLorenzo Bianconi 		return;
57141130c32SLorenzo Bianconi 
5729e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS))
5739e81c2c7SLorenzo Bianconi 		mt76_led_cleanup(phy);
574c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
575c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
576dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = NULL;
577c89d3625SFelix Fietkau }
578c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
579c89d3625SFelix Fietkau 
5802f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
5812f5c3c77SLorenzo Bianconi {
5822f5c3c77SLorenzo Bianconi 	struct page_pool_params pp_params = {
5832f5c3c77SLorenzo Bianconi 		.order = 0,
58409d96ee5SYunsheng Lin 		.flags = 0,
5852f5c3c77SLorenzo Bianconi 		.nid = NUMA_NO_NODE,
5862f5c3c77SLorenzo Bianconi 		.dev = dev->dma_dev,
5872f5c3c77SLorenzo Bianconi 	};
5882f5c3c77SLorenzo Bianconi 	int idx = q - dev->q_rx;
5892f5c3c77SLorenzo Bianconi 
5902f5c3c77SLorenzo Bianconi 	switch (idx) {
5912f5c3c77SLorenzo Bianconi 	case MT_RXQ_MAIN:
5922f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND1:
5932f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND2:
5942f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 256;
5952f5c3c77SLorenzo Bianconi 		break;
5962f5c3c77SLorenzo Bianconi 	default:
5972f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 16;
5982f5c3c77SLorenzo Bianconi 		break;
5992f5c3c77SLorenzo Bianconi 	}
6002f5c3c77SLorenzo Bianconi 
6012f5c3c77SLorenzo Bianconi 	if (mt76_is_mmio(dev)) {
6022f5c3c77SLorenzo Bianconi 		/* rely on page_pool for DMA mapping */
6032f5c3c77SLorenzo Bianconi 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
6042f5c3c77SLorenzo Bianconi 		pp_params.dma_dir = DMA_FROM_DEVICE;
6052f5c3c77SLorenzo Bianconi 		pp_params.max_len = PAGE_SIZE;
6062f5c3c77SLorenzo Bianconi 		pp_params.offset = 0;
6072f5c3c77SLorenzo Bianconi 	}
6082f5c3c77SLorenzo Bianconi 
6092f5c3c77SLorenzo Bianconi 	q->page_pool = page_pool_create(&pp_params);
6102f5c3c77SLorenzo Bianconi 	if (IS_ERR(q->page_pool)) {
6112f5c3c77SLorenzo Bianconi 		int err = PTR_ERR(q->page_pool);
6122f5c3c77SLorenzo Bianconi 
6132f5c3c77SLorenzo Bianconi 		q->page_pool = NULL;
6142f5c3c77SLorenzo Bianconi 		return err;
6152f5c3c77SLorenzo Bianconi 	}
6162f5c3c77SLorenzo Bianconi 
6172f5c3c77SLorenzo Bianconi 	return 0;
6182f5c3c77SLorenzo Bianconi }
6192f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool);
6202f5c3c77SLorenzo Bianconi 
621a85b590cSFelix Fietkau struct mt76_dev *
622c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
623c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
624c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
625a85b590cSFelix Fietkau {
626a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
627ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
628a85b590cSFelix Fietkau 	struct mt76_dev *dev;
629e5443256SFelix Fietkau 	int i;
630a85b590cSFelix Fietkau 
631a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
632a85b590cSFelix Fietkau 	if (!hw)
633a85b590cSFelix Fietkau 		return NULL;
634a85b590cSFelix Fietkau 
635a85b590cSFelix Fietkau 	dev = hw->priv;
636a85b590cSFelix Fietkau 	dev->hw = hw;
637c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
638c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
639d1ddc536SFelix Fietkau 	dev->dma_dev = pdev;
640c0f7b25aSLorenzo Bianconi 
641ac24dd35SFelix Fietkau 	phy = &dev->phy;
642ac24dd35SFelix Fietkau 	phy->dev = dev;
643ac24dd35SFelix Fietkau 	phy->hw = hw;
644dc44c45cSLorenzo Bianconi 	phy->band_idx = MT_BAND0;
645dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = phy;
646ac24dd35SFelix Fietkau 
647a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
648a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
649a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
650c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
6512666beceSSujuan Chen 	spin_lock_init(&dev->wed_lock);
652108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
65326e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
654a85b590cSFelix Fietkau 
65509872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
65609872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
65709872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
658781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
65909872957SLorenzo Bianconi 
6608af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6618af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
6628af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
6638af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
6648af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
6658af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
6668af414e8SLorenzo Bianconi #endif
6678af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
6688af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
6698af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
6708af414e8SLorenzo Bianconi 
67151252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
67251252cc5SLorenzo Bianconi 	idr_init(&dev->token);
67351252cc5SLorenzo Bianconi 
6742666beceSSujuan Chen 	spin_lock_init(&dev->rx_token_lock);
6752666beceSSujuan Chen 	idr_init(&dev->rx_token);
6762666beceSSujuan Chen 
677bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
678fbba711cSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->sta_poll_list);
679fbba711cSLorenzo Bianconi 	spin_lock_init(&dev->sta_poll_lock);
680bd1e3e7bSLorenzo Bianconi 
681e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
6822666beceSSujuan Chen 	INIT_LIST_HEAD(&dev->rxwi_cache);
68361b5156bSFelix Fietkau 	dev->token_size = dev->drv->token_size;
684e5443256SFelix Fietkau 
685e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
686e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
687e5443256SFelix Fietkau 
688a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
689a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
690a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
691a86f1d01SLorenzo Bianconi 		return NULL;
692a86f1d01SLorenzo Bianconi 	}
693a86f1d01SLorenzo Bianconi 
694a85b590cSFelix Fietkau 	return dev;
695a85b590cSFelix Fietkau }
696a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
697a85b590cSFelix Fietkau 
69817f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
69917f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
70017f1de56SFelix Fietkau {
70117f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
702c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
70317f1de56SFelix Fietkau 	int ret;
70417f1de56SFelix Fietkau 
70517f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
7060335c034SFelix Fietkau 	mt76_wcid_init(&dev->global_wcid);
707d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
708d43de9cfSLorenzo Bianconi 	if (ret)
709d43de9cfSLorenzo Bianconi 		return ret;
71017f1de56SFelix Fietkau 
71148dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
71277af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
71317f1de56SFelix Fietkau 		if (ret)
71417f1de56SFelix Fietkau 			return ret;
71517f1de56SFelix Fietkau 	}
71617f1de56SFelix Fietkau 
71748dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
71877af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
71917f1de56SFelix Fietkau 		if (ret)
72017f1de56SFelix Fietkau 			return ret;
72117f1de56SFelix Fietkau 	}
72217f1de56SFelix Fietkau 
723edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
724edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
725edf9dab8SLorenzo Bianconi 		if (ret)
726edf9dab8SLorenzo Bianconi 			return ret;
727edf9dab8SLorenzo Bianconi 	}
728edf9dab8SLorenzo Bianconi 
729c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
730c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
731c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
732edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
73317f1de56SFelix Fietkau 
734b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
7353abd46ddSLorenzo Bianconi 		ret = mt76_led_init(phy);
73617f1de56SFelix Fietkau 		if (ret)
73717f1de56SFelix Fietkau 			return ret;
738b374e868SArnd Bergmann 	}
73917f1de56SFelix Fietkau 
740781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
741781eef5bSFelix Fietkau 	if (ret)
742781eef5bSFelix Fietkau 		return ret;
743781eef5bSFelix Fietkau 
744781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
74541130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
746781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
747781eef5bSFelix Fietkau 
748781eef5bSFelix Fietkau 	return 0;
74917f1de56SFelix Fietkau }
75017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
75117f1de56SFelix Fietkau 
75217f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
75317f1de56SFelix Fietkau {
75417f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
75517f1de56SFelix Fietkau 
75641130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
75741130c32SLorenzo Bianconi 		return;
75841130c32SLorenzo Bianconi 
759d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
7603abd46ddSLorenzo Bianconi 		mt76_led_cleanup(&dev->phy);
761c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
7620335c034SFelix Fietkau 	mt76_wcid_cleanup(dev, &dev->global_wcid);
76317f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
76417f1de56SFelix Fietkau }
76517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
76617f1de56SFelix Fietkau 
767def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
768def34a2fSLorenzo Bianconi {
769781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
770a86f1d01SLorenzo Bianconi 	if (dev->wq) {
771a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
772a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
773a86f1d01SLorenzo Bianconi 	}
774def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
775def34a2fSLorenzo Bianconi }
776def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
777def34a2fSLorenzo Bianconi 
778cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
779cc4b3c13SLorenzo Bianconi {
780cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
7812c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
782cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
783cc4b3c13SLorenzo Bianconi 
784cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
785cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
7862c2bdd23SFelix Fietkau 
7872c2bdd23SFelix Fietkau 	/*
7882c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
7892c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7902c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
7912c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
7922c2bdd23SFelix Fietkau 	 * address.
7932c2bdd23SFelix Fietkau 	 */
7942c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
7952c2bdd23SFelix Fietkau 		int offset = 0;
7962c2bdd23SFelix Fietkau 
7972c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
7982c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
7992c2bdd23SFelix Fietkau 
8002c2bdd23SFelix Fietkau 			if ((status->flag &
8012c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
8022c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
8032c2bdd23SFelix Fietkau 				offset += 8;
8042c2bdd23SFelix Fietkau 		}
8052c2bdd23SFelix Fietkau 
8062c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
8072c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
8082c2bdd23SFelix Fietkau 			return;
8092c2bdd23SFelix Fietkau 		}
8102c2bdd23SFelix Fietkau 	}
811cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
812cc4b3c13SLorenzo Bianconi }
813cc4b3c13SLorenzo Bianconi 
814cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
815cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
816cc4b3c13SLorenzo Bianconi {
817cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
818cc4b3c13SLorenzo Bianconi 
819cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
820cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
821cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
822cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
823cc4b3c13SLorenzo Bianconi 
824cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
825cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
826cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
827cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
828cc4b3c13SLorenzo Bianconi 	} else {
829cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
830cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
831cc4b3c13SLorenzo Bianconi 	}
832cc4b3c13SLorenzo Bianconi 
833cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
834cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
835cc4b3c13SLorenzo Bianconi }
836cc4b3c13SLorenzo Bianconi 
83717f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
83817f1de56SFelix Fietkau {
839011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
840128c9b7dSLorenzo Bianconi 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
841011849e0SFelix Fietkau 
842011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
84317f1de56SFelix Fietkau 		dev_kfree_skb(skb);
84417f1de56SFelix Fietkau 		return;
84517f1de56SFelix Fietkau 	}
84617f1de56SFelix Fietkau 
847f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
848c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
849c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
850f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
851c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
852f0efa862SFelix Fietkau 	}
853f0efa862SFelix Fietkau #endif
854cc4b3c13SLorenzo Bianconi 
855cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
85617f1de56SFelix Fietkau }
85717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
85817f1de56SFelix Fietkau 
8595a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
86026e40d4cSFelix Fietkau {
861af005f26SLorenzo Bianconi 	struct mt76_queue *q;
86291990519SLorenzo Bianconi 	int i;
8635a95ca41SFelix Fietkau 
8645a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
86591990519SLorenzo Bianconi 		q = phy->q_tx[i];
866af005f26SLorenzo Bianconi 		if (q && q->queued)
86726e40d4cSFelix Fietkau 			return true;
86826e40d4cSFelix Fietkau 	}
86926e40d4cSFelix Fietkau 
87026e40d4cSFelix Fietkau 	return false;
87126e40d4cSFelix Fietkau }
87239d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
87326e40d4cSFelix Fietkau 
8740fd0eb54SFelix Fietkau static struct mt76_channel_state *
87596747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8760fd0eb54SFelix Fietkau {
8770fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
8780fd0eb54SFelix Fietkau 	int idx;
8790fd0eb54SFelix Fietkau 
8800fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
88196747a51SFelix Fietkau 		msband = &phy->sband_2g;
882edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
883edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
8840fd0eb54SFelix Fietkau 	else
88596747a51SFelix Fietkau 		msband = &phy->sband_5g;
8860fd0eb54SFelix Fietkau 
8870fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
8880fd0eb54SFelix Fietkau 	return &msband->chan[idx];
8890fd0eb54SFelix Fietkau }
8900fd0eb54SFelix Fietkau 
89104414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
89296747a51SFelix Fietkau {
89396747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
89496747a51SFelix Fietkau 
89596747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
89696747a51SFelix Fietkau 						  phy->survey_time));
89796747a51SFelix Fietkau 	phy->survey_time = time;
89896747a51SFelix Fietkau }
89904414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
90096747a51SFelix Fietkau 
901c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
9025ce09c1aSFelix Fietkau {
903c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
904aec65e48SFelix Fietkau 	ktime_t cur_time;
905aec65e48SFelix Fietkau 
9065ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
907c560b137SRyder Lee 		dev->drv->update_survey(phy);
9085ce09c1aSFelix Fietkau 
909aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
910c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
911aec65e48SFelix Fietkau 
9125ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
913c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
91496747a51SFelix Fietkau 
915237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
9165ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
9175ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
918237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
9195ce09c1aSFelix Fietkau 	}
9205ce09c1aSFelix Fietkau }
9215ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
9225ce09c1aSFelix Fietkau 
92396747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
92417f1de56SFelix Fietkau {
92596747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
92696747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
92717f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
92817f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
92926e40d4cSFelix Fietkau 	int timeout = HZ / 5;
93017f1de56SFelix Fietkau 
9315a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
932c560b137SRyder Lee 	mt76_update_survey(phy);
93317f1de56SFelix Fietkau 
9343f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9353f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
9363f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9373f306448SFelix Fietkau 
93896747a51SFelix Fietkau 	phy->chandef = *chandef;
93996747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
94017f1de56SFelix Fietkau 
94117f1de56SFelix Fietkau 	if (!offchannel)
94296747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
94317f1de56SFelix Fietkau 
94496747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
94596747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
94617f1de56SFelix Fietkau }
94717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
94817f1de56SFelix Fietkau 
94917f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
95017f1de56SFelix Fietkau 		    struct survey_info *survey)
95117f1de56SFelix Fietkau {
95296747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
95396747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
95417f1de56SFelix Fietkau 	struct mt76_sband *sband;
95517f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
95617f1de56SFelix Fietkau 	struct mt76_channel_state *state;
95717f1de56SFelix Fietkau 	int ret = 0;
95817f1de56SFelix Fietkau 
959237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
96017f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
961c560b137SRyder Lee 		mt76_update_survey(phy);
96217f1de56SFelix Fietkau 
963edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
964edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
965edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
966edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
967edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
968edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
969edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
97096747a51SFelix Fietkau 		sband = &phy->sband_5g;
971edf9dab8SLorenzo Bianconi 	} else {
972edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
97317f1de56SFelix Fietkau 	}
97417f1de56SFelix Fietkau 
975237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
976237312c5SLorenzo Bianconi 		ret = -ENOENT;
977237312c5SLorenzo Bianconi 		goto out;
978237312c5SLorenzo Bianconi 	}
97917f1de56SFelix Fietkau 
98017f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
98196747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
98217f1de56SFelix Fietkau 
98317f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
98417f1de56SFelix Fietkau 	survey->channel = chan;
98517f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
986ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
987e5051965SFelix Fietkau 	if (state->noise)
988e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
989e5051965SFelix Fietkau 
99096747a51SFelix Fietkau 	if (chan == phy->main_chan) {
99117f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
99217f1de56SFelix Fietkau 
9935ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
9945ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
9955ce09c1aSFelix Fietkau 	}
9965ce09c1aSFelix Fietkau 
99717f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
9986bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
999237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
1000e5051965SFelix Fietkau 	survey->noise = state->noise;
1001237312c5SLorenzo Bianconi 
1002237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
1003237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
1004ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
100517f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
100617f1de56SFelix Fietkau 
1007237312c5SLorenzo Bianconi out:
1008237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1009237312c5SLorenzo Bianconi 
101017f1de56SFelix Fietkau 	return ret;
101117f1de56SFelix Fietkau }
101217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
101317f1de56SFelix Fietkau 
101430ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
101530ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
101630ce7f44SFelix Fietkau {
101730ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
101830ce7f44SFelix Fietkau 	int i;
101930ce7f44SFelix Fietkau 
102030ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
102130ce7f44SFelix Fietkau 
102230ce7f44SFelix Fietkau 	if (!key)
102330ce7f44SFelix Fietkau 		return;
102430ce7f44SFelix Fietkau 
102501cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
102601cfc1b4SLorenzo Bianconi 		return;
102730ce7f44SFelix Fietkau 
102801cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
1029a1b0bbd4SXing Song 
1030a1b0bbd4SXing Song 	/* data frame */
103130ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
103230ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
103330ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
103430ce7f44SFelix Fietkau 	}
1035a1b0bbd4SXing Song 
1036a1b0bbd4SXing Song 	/* robust management frame */
1037a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
1038a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
1039a1b0bbd4SXing Song 
104030ce7f44SFelix Fietkau }
104130ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
104230ce7f44SFelix Fietkau 
1043a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10444550fb9eSFelix Fietkau {
10454550fb9eSFelix Fietkau 	int signal = -128;
10464550fb9eSFelix Fietkau 	u8 chains;
10474550fb9eSFelix Fietkau 
1048a71b648eSRyder Lee 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10494550fb9eSFelix Fietkau 		int cur, diff;
10504550fb9eSFelix Fietkau 
10516450b133SDeren Wu 		cur = *chain_signal;
10526450b133SDeren Wu 		if (!(chains & BIT(0)) ||
10536450b133SDeren Wu 		    cur > 0)
10544550fb9eSFelix Fietkau 			continue;
10554550fb9eSFelix Fietkau 
10564550fb9eSFelix Fietkau 		if (cur > signal)
10574550fb9eSFelix Fietkau 			swap(cur, signal);
10584550fb9eSFelix Fietkau 
10594550fb9eSFelix Fietkau 		diff = signal - cur;
10604550fb9eSFelix Fietkau 		if (diff == 0)
10614550fb9eSFelix Fietkau 			signal += 3;
10624550fb9eSFelix Fietkau 		else if (diff <= 2)
10634550fb9eSFelix Fietkau 			signal += 2;
10644550fb9eSFelix Fietkau 		else if (diff <= 6)
10654550fb9eSFelix Fietkau 			signal += 1;
10664550fb9eSFelix Fietkau 	}
10674550fb9eSFelix Fietkau 
10684550fb9eSFelix Fietkau 	return signal;
10694550fb9eSFelix Fietkau }
1070a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
10714550fb9eSFelix Fietkau 
1072bfc394ddSFelix Fietkau static void
1073bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
1074bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
1075bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
10764e34249eSFelix Fietkau {
10774e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1078abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
10794e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
10804e34249eSFelix Fietkau 
10814e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
10824e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
10834e34249eSFelix Fietkau 
10844e34249eSFelix Fietkau 	status->flag = mstat.flag;
10854e34249eSFelix Fietkau 	status->freq = mstat.freq;
10864e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
10874e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
10884e34249eSFelix Fietkau 	status->bw = mstat.bw;
1089021af945SShayne Chen 	if (status->encoding == RX_ENC_EHT) {
1090021af945SShayne Chen 		status->eht.ru = mstat.eht.ru;
1091021af945SShayne Chen 		status->eht.gi = mstat.eht.gi;
1092021af945SShayne Chen 	} else {
1093af4a2f2fSRyder Lee 		status->he_ru = mstat.he_ru;
1094af4a2f2fSRyder Lee 		status->he_gi = mstat.he_gi;
1095af4a2f2fSRyder Lee 		status->he_dcm = mstat.he_dcm;
1096021af945SShayne Chen 	}
10974e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
10984e34249eSFelix Fietkau 	status->nss = mstat.nss;
10994e34249eSFelix Fietkau 	status->band = mstat.band;
11004e34249eSFelix Fietkau 	status->signal = mstat.signal;
11014e34249eSFelix Fietkau 	status->chains = mstat.chains;
1102d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
11030fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
11040fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
1105a71b648eSRyder Lee 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
11064550fb9eSFelix Fietkau 	if (status->signal <= -128)
11074550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
11084e34249eSFelix Fietkau 
1109abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
1110abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
1111abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1112abe3f3daSRyder Lee 
11134e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
111413381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
111513381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
111613381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
111713381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
11189c68a57bSFelix Fietkau 
1119bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1120128c9b7dSLorenzo Bianconi 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
11214e34249eSFelix Fietkau }
11224e34249eSFelix Fietkau 
11233c1032e1SFelix Fietkau static void
112430ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
112530ce7f44SFelix Fietkau {
112630ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
112730ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
112830ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1129a1b0bbd4SXing Song 	int security_idx;
113030ce7f44SFelix Fietkau 	int ret;
113130ce7f44SFelix Fietkau 
113230ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
11333c1032e1SFelix Fietkau 		return;
113430ce7f44SFelix Fietkau 
11351858e4fcSMeiChia Chiu 	if (status->flag & RX_FLAG_ONLY_MONITOR)
11363c1032e1SFelix Fietkau 		return;
11371858e4fcSMeiChia Chiu 
113830ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
11393c1032e1SFelix Fietkau 		return;
114030ce7f44SFelix Fietkau 
11417360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11427360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
11437360cdecSFelix Fietkau 		goto skip_hdr_check;
11447360cdecSFelix Fietkau 
1145a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
114630ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
114730ce7f44SFelix Fietkau 		/*
114830ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
114930ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
115030ce7f44SFelix Fietkau 		 */
115130ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
115230ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
11533c1032e1SFelix Fietkau 			return;
115430ce7f44SFelix Fietkau 	}
115530ce7f44SFelix Fietkau 
1156a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1157a1b0bbd4SXing Song 	 *
1158a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1159a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1160a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1161a1b0bbd4SXing Song 	 */
1162a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1163a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1164a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1165a1b0bbd4SXing Song 
11667360cdecSFelix Fietkau skip_hdr_check:
116730ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1168a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
116930ce7f44SFelix Fietkau 		     sizeof(status->iv));
11703c1032e1SFelix Fietkau 	if (ret <= 0) {
11713c1032e1SFelix Fietkau 		status->flag |= RX_FLAG_ONLY_MONITOR;
11723c1032e1SFelix Fietkau 		return;
11733c1032e1SFelix Fietkau 	}
117430ce7f44SFelix Fietkau 
1175a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
117630ce7f44SFelix Fietkau 
117730ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
117830ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
117930ce7f44SFelix Fietkau }
118030ce7f44SFelix Fietkau 
1181d71ef286SFelix Fietkau static void
11825ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
11835ce09c1aSFelix Fietkau 		    int len)
11845ce09c1aSFelix Fietkau {
11855ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
118685b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
118785b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
118885b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
118985b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
119085b7a5d0SLorenzo Bianconi 		.band = status->band,
119185b7a5d0SLorenzo Bianconi 		.nss = status->nss,
119285b7a5d0SLorenzo Bianconi 		.bw = status->bw,
119385b7a5d0SLorenzo Bianconi 	};
11945ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
11955ce09c1aSFelix Fietkau 	u32 airtime;
1196e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11975ce09c1aSFelix Fietkau 
119885b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1199237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
12005ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1201237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
12025ce09c1aSFelix Fietkau 
12035ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
12045ce09c1aSFelix Fietkau 		return;
12055ce09c1aSFelix Fietkau 
12065ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1207e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
12085ce09c1aSFelix Fietkau }
12095ce09c1aSFelix Fietkau 
12105ce09c1aSFelix Fietkau static void
12115ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
12125ce09c1aSFelix Fietkau {
12135ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
12145ce09c1aSFelix Fietkau 	int wcid_idx;
12155ce09c1aSFelix Fietkau 
12165ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
12175ce09c1aSFelix Fietkau 		return;
12185ce09c1aSFelix Fietkau 
12195ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1220bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
12215ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
12225ce09c1aSFelix Fietkau 	else
12235ce09c1aSFelix Fietkau 		wcid = NULL;
12245ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
12255ce09c1aSFelix Fietkau 
12265ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
12275ce09c1aSFelix Fietkau 
12285ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
12295ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
12305ce09c1aSFelix Fietkau }
12315ce09c1aSFelix Fietkau 
12325ce09c1aSFelix Fietkau static void
12335ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12345ce09c1aSFelix Fietkau {
12355ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12365ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
12375ce09c1aSFelix Fietkau 
12385ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12395ce09c1aSFelix Fietkau 		return;
12405ce09c1aSFelix Fietkau 
12415ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1242e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1243e195dad1SFelix Fietkau 
1244e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1245e195dad1SFelix Fietkau 			return;
1246e195dad1SFelix Fietkau 
124798df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12485ce09c1aSFelix Fietkau 			return;
12495ce09c1aSFelix Fietkau 
12505ce09c1aSFelix Fietkau 		wcid = NULL;
12515ce09c1aSFelix Fietkau 	}
12525ce09c1aSFelix Fietkau 
12535ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12545ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
12555ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
12565ce09c1aSFelix Fietkau 
12575ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12585ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
12595ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
12605ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
12615ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
12625ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
12635ce09c1aSFelix Fietkau 		}
12645ce09c1aSFelix Fietkau 
12655ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
12665ce09c1aSFelix Fietkau 		return;
12675ce09c1aSFelix Fietkau 	}
12685ce09c1aSFelix Fietkau 
12695ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
12705ce09c1aSFelix Fietkau }
12715ce09c1aSFelix Fietkau 
12725ce09c1aSFelix Fietkau static void
1273ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1274d71ef286SFelix Fietkau {
1275d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
127677ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1277d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1278bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1279d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1280e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1281d71ef286SFelix Fietkau 	bool ps;
1282d71ef286SFelix Fietkau 
1283128c9b7dSLorenzo Bianconi 	hw = mt76_phy_hw(dev, status->phy_idx);
1284e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1285e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1286bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
128736d91096SFelix Fietkau 		if (sta)
128836d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
128936d91096SFelix Fietkau 	}
129036d91096SFelix Fietkau 
12915ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
12925ce09c1aSFelix Fietkau 
1293d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1294d71ef286SFelix Fietkau 		return;
1295d71ef286SFelix Fietkau 
1296d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1297d71ef286SFelix Fietkau 
129802e5a769SFelix Fietkau 	if (status->signal <= 0)
129902e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
130002e5a769SFelix Fietkau 
1301ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1302ef13edc0SFelix Fietkau 
1303e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1304e195dad1SFelix Fietkau 		return;
1305e195dad1SFelix Fietkau 
1306d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1307d71ef286SFelix Fietkau 		return;
1308d71ef286SFelix Fietkau 
1309d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1310d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1311d71ef286SFelix Fietkau 		return;
1312d71ef286SFelix Fietkau 	}
1313d71ef286SFelix Fietkau 
1314d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1315d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1316d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1317d71ef286SFelix Fietkau 		return;
1318d71ef286SFelix Fietkau 
1319d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1320d71ef286SFelix Fietkau 
1321d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1322d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1323e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1324d71ef286SFelix Fietkau 
1325d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1326d71ef286SFelix Fietkau 		return;
1327d71ef286SFelix Fietkau 
132811b2a25fSFelix Fietkau 	if (ps)
1329d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1330d71ef286SFelix Fietkau 
1331f28c3139SLorenzo Bianconi 	if (dev->drv->sta_ps)
1332d71ef286SFelix Fietkau 		dev->drv->sta_ps(dev, sta, ps);
1333608f7c47SFelix Fietkau 
1334608f7c47SFelix Fietkau 	if (!ps)
1335608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1336608f7c47SFelix Fietkau 
13379f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1338d71ef286SFelix Fietkau }
1339d71ef286SFelix Fietkau 
13409d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
134181e850efSLorenzo Bianconi 		      struct napi_struct *napi)
134217f1de56SFelix Fietkau {
13439c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1344bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
13453298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
13463298b1f8SFelix Fietkau 	LIST_HEAD(list);
13479d9d738bSFelix Fietkau 
1348c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
13499d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1350cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1351cc4b3c13SLorenzo Bianconi 
13523c1032e1SFelix Fietkau 		mt76_check_ccmp_pn(skb);
1353cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1354bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
13553298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1356cc4b3c13SLorenzo Bianconi 
1357cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1358cc4b3c13SLorenzo Bianconi 		while (nskb) {
1359cc4b3c13SLorenzo Bianconi 			skb = nskb;
1360cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1361cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1362cc4b3c13SLorenzo Bianconi 
1363cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1364cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1365cc4b3c13SLorenzo Bianconi 		}
13669d9d738bSFelix Fietkau 	}
1367c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
13683298b1f8SFelix Fietkau 
13693298b1f8SFelix Fietkau 	if (!napi) {
13703298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
13713298b1f8SFelix Fietkau 		return;
13723298b1f8SFelix Fietkau 	}
13733298b1f8SFelix Fietkau 
13743298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
13753298b1f8SFelix Fietkau 		skb_list_del_init(skb);
13763298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
13773298b1f8SFelix Fietkau 	}
13789d9d738bSFelix Fietkau }
13799d9d738bSFelix Fietkau 
138081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
138181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
13829d9d738bSFelix Fietkau {
1383aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
138417f1de56SFelix Fietkau 	struct sk_buff *skb;
138517f1de56SFelix Fietkau 
1386aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1387aee5b8cfSFelix Fietkau 
1388d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1389ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
13904f831d18SLorenzo Bianconi 		if (mtk_wed_device_active(&dev->mmio.wed))
13914f831d18SLorenzo Bianconi 			__skb_queue_tail(&frames, skb);
13924f831d18SLorenzo Bianconi 		else
1393aee5b8cfSFelix Fietkau 			mt76_rx_aggr_reorder(skb, &frames);
1394d71ef286SFelix Fietkau 	}
1395aee5b8cfSFelix Fietkau 
139681e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
13974e34249eSFelix Fietkau }
139881e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1399723b90dcSFelix Fietkau 
1400e28487eaSFelix Fietkau static int
1401a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1402a1a99d7bSLorenzo Bianconi 	     struct ieee80211_sta *sta)
1403e28487eaSFelix Fietkau {
1404e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1405a1a99d7bSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1406e28487eaSFelix Fietkau 	int ret;
1407e28487eaSFelix Fietkau 	int i;
1408e28487eaSFelix Fietkau 
1409e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1410e28487eaSFelix Fietkau 
1411e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1412e28487eaSFelix Fietkau 	if (ret)
1413e28487eaSFelix Fietkau 		goto out;
1414e28487eaSFelix Fietkau 
1415e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1416e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1417e28487eaSFelix Fietkau 
1418e28487eaSFelix Fietkau 		if (!sta->txq[i])
1419e28487eaSFelix Fietkau 			continue;
1420e28487eaSFelix Fietkau 
1421e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
142251fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1423e28487eaSFelix Fietkau 	}
1424e28487eaSFelix Fietkau 
1425ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1426a1a99d7bSLorenzo Bianconi 	if (phy->band_idx == MT_BAND1)
1427426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1428a1a99d7bSLorenzo Bianconi 	wcid->phy_idx = phy->band_idx;
1429e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1430e28487eaSFelix Fietkau 
14310335c034SFelix Fietkau 	mt76_wcid_init(wcid);
1432e28487eaSFelix Fietkau out:
1433e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1434e28487eaSFelix Fietkau 
1435e28487eaSFelix Fietkau 	return ret;
1436e28487eaSFelix Fietkau }
1437e28487eaSFelix Fietkau 
143813f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1439723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1440723b90dcSFelix Fietkau {
1441723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
144213f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1443723b90dcSFelix Fietkau 
144458bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
144558bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
144658bab0d4SFelix Fietkau 
1447e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1448e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1449e28487eaSFelix Fietkau 
14500335c034SFelix Fietkau 	mt76_wcid_cleanup(dev, wcid);
1451bd1e3e7bSLorenzo Bianconi 
1452426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1453426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
145413f61dfcSLorenzo Bianconi }
145513f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1456e28487eaSFelix Fietkau 
145713f61dfcSLorenzo Bianconi static void
145813f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
145913f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
146013f61dfcSLorenzo Bianconi {
146113f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
146213f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1463723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1464723b90dcSFelix Fietkau }
1465e28487eaSFelix Fietkau 
1466e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1467e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1468e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1469e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1470e28487eaSFelix Fietkau {
1471426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1472426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1473e28487eaSFelix Fietkau 
1474e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1475e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1476a1a99d7bSLorenzo Bianconi 		return mt76_sta_add(phy, vif, sta);
1477e28487eaSFelix Fietkau 
14789c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
14799c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
14809c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
14819c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
14829c193de5SFelix Fietkau 
1483e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1484e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1485e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1486e28487eaSFelix Fietkau 
1487e28487eaSFelix Fietkau 	return 0;
1488e28487eaSFelix Fietkau }
1489e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
14909313faacSFelix Fietkau 
149143ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
149243ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
149343ba1922SFelix Fietkau {
149443ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
149543ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
149643ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
149743ba1922SFelix Fietkau 
149843ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1499fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
150043ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1501fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
150243ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
150343ba1922SFelix Fietkau }
150443ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
150543ba1922SFelix Fietkau 
15060335c034SFelix Fietkau void mt76_wcid_init(struct mt76_wcid *wcid)
15070335c034SFelix Fietkau {
15080335c034SFelix Fietkau 	INIT_LIST_HEAD(&wcid->tx_list);
15090335c034SFelix Fietkau 	skb_queue_head_init(&wcid->tx_pending);
15100335c034SFelix Fietkau 
15110335c034SFelix Fietkau 	INIT_LIST_HEAD(&wcid->list);
15120335c034SFelix Fietkau 	idr_init(&wcid->pktid);
15130335c034SFelix Fietkau }
15140335c034SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_init);
15150335c034SFelix Fietkau 
15160335c034SFelix Fietkau void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
15170335c034SFelix Fietkau {
15180335c034SFelix Fietkau 	struct mt76_phy *phy = dev->phys[wcid->phy_idx];
15190335c034SFelix Fietkau 	struct ieee80211_hw *hw;
15200335c034SFelix Fietkau 	struct sk_buff_head list;
15210335c034SFelix Fietkau 	struct sk_buff *skb;
15220335c034SFelix Fietkau 
15230335c034SFelix Fietkau 	mt76_tx_status_lock(dev, &list);
15240335c034SFelix Fietkau 	mt76_tx_status_skb_get(dev, wcid, -1, &list);
15250335c034SFelix Fietkau 	mt76_tx_status_unlock(dev, &list);
15260335c034SFelix Fietkau 
15270335c034SFelix Fietkau 	idr_destroy(&wcid->pktid);
15280335c034SFelix Fietkau 
15290335c034SFelix Fietkau 	spin_lock_bh(&phy->tx_lock);
15300335c034SFelix Fietkau 
15310335c034SFelix Fietkau 	if (!list_empty(&wcid->tx_list))
15320335c034SFelix Fietkau 		list_del_init(&wcid->tx_list);
15330335c034SFelix Fietkau 
15340335c034SFelix Fietkau 	spin_lock(&wcid->tx_pending.lock);
15350335c034SFelix Fietkau 	skb_queue_splice_tail_init(&wcid->tx_pending, &list);
15360335c034SFelix Fietkau 	spin_unlock(&wcid->tx_pending.lock);
15370335c034SFelix Fietkau 
15380335c034SFelix Fietkau 	spin_unlock_bh(&phy->tx_lock);
15390335c034SFelix Fietkau 
15400335c034SFelix Fietkau 	while ((skb = __skb_dequeue(&list)) != NULL) {
15410335c034SFelix Fietkau 		hw = mt76_tx_status_get_hw(dev, skb);
15420335c034SFelix Fietkau 		ieee80211_free_txskb(hw, skb);
15430335c034SFelix Fietkau 	}
15440335c034SFelix Fietkau }
15450335c034SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
15460335c034SFelix Fietkau 
15479313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15489313faacSFelix Fietkau 		     int *dbm)
15499313faacSFelix Fietkau {
1550beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1551beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
155207cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
15539313faacSFelix Fietkau 
155407cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
15559313faacSFelix Fietkau 
15569313faacSFelix Fietkau 	return 0;
15579313faacSFelix Fietkau }
15589313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1559e7173858SFelix Fietkau 
1560b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1561b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1562b3cb885eSLorenzo Bianconi {
1563b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1564b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1565b3cb885eSLorenzo Bianconi 	int i;
1566b3cb885eSLorenzo Bianconi 
1567b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1568b3cb885eSLorenzo Bianconi 		return -EINVAL;
1569b3cb885eSLorenzo Bianconi 
1570b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1571b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1572b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1573b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1574b3cb885eSLorenzo Bianconi 
1575b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1576b3cb885eSLorenzo Bianconi 			power = 127;
1577b3cb885eSLorenzo Bianconi 
1578b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1579b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1580b3cb885eSLorenzo Bianconi 	}
1581b3cb885eSLorenzo Bianconi 
1582b3cb885eSLorenzo Bianconi 	return 0;
1583b3cb885eSLorenzo Bianconi }
1584b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1585b3cb885eSLorenzo Bianconi 
1586b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1587b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1588b3cb885eSLorenzo Bianconi 		       int power)
1589b3cb885eSLorenzo Bianconi {
1590b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1591b3cb885eSLorenzo Bianconi 	int freq, i;
1592b3cb885eSLorenzo Bianconi 
1593b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1594b3cb885eSLorenzo Bianconi 		return power;
1595b3cb885eSLorenzo Bianconi 
1596b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1597b3cb885eSLorenzo Bianconi 		power = 127;
1598b3cb885eSLorenzo Bianconi 
1599b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1600b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1601b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1602b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1603b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1604b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1605b3cb885eSLorenzo Bianconi 			break;
1606b3cb885eSLorenzo Bianconi 		}
1607b3cb885eSLorenzo Bianconi 	}
1608b3cb885eSLorenzo Bianconi 
1609b3cb885eSLorenzo Bianconi 	return power;
1610b3cb885eSLorenzo Bianconi }
1611b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1612b3cb885eSLorenzo Bianconi 
1613e7173858SFelix Fietkau static void
1614e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1615e7173858SFelix Fietkau {
1616d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1617e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1618e7173858SFelix Fietkau }
1619e7173858SFelix Fietkau 
1620e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1621e7173858SFelix Fietkau {
1622e7173858SFelix Fietkau 	if (!dev->csa_complete)
1623e7173858SFelix Fietkau 		return;
1624e7173858SFelix Fietkau 
1625e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1626e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1627e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1628e7173858SFelix Fietkau 
1629e7173858SFelix Fietkau 	dev->csa_complete = 0;
1630e7173858SFelix Fietkau }
1631e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1632e7173858SFelix Fietkau 
1633e7173858SFelix Fietkau static void
1634e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1635e7173858SFelix Fietkau {
1636e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1637e7173858SFelix Fietkau 
1638d0a9123eSJohannes Berg 	if (!vif->bss_conf.csa_active)
1639e7173858SFelix Fietkau 		return;
1640e7173858SFelix Fietkau 
16418552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1642e7173858SFelix Fietkau }
1643e7173858SFelix Fietkau 
1644e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1645e7173858SFelix Fietkau {
1646e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1647e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1648e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1649e7173858SFelix Fietkau }
1650e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
165187d53103SStanislaw Gruszka 
165287d53103SStanislaw Gruszka int
165387d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
165487d53103SStanislaw Gruszka {
165587d53103SStanislaw Gruszka 	return 0;
165687d53103SStanislaw Gruszka }
165787d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1658eadfd98fSLorenzo Bianconi 
1659eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1660eadfd98fSLorenzo Bianconi {
1661eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1662eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1663eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1664eadfd98fSLorenzo Bianconi 
1665eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1666eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1667eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1668eadfd98fSLorenzo Bianconi 
1669eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1670eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1671eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1672eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1673eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1674eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1675eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1676eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1677eadfd98fSLorenzo Bianconi 
1678eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1679eadfd98fSLorenzo Bianconi }
1680eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1681d2679d65SLorenzo Bianconi 
1682d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1683d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1684d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1685d2679d65SLorenzo Bianconi {
1686d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1687d2679d65SLorenzo Bianconi 
1688d2679d65SLorenzo Bianconi 	if (cck) {
1689edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1690d2679d65SLorenzo Bianconi 			return 0;
1691d2679d65SLorenzo Bianconi 
1692d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
169396747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1694d2679d65SLorenzo Bianconi 		offset = 4;
1695d2679d65SLorenzo Bianconi 	}
1696d2679d65SLorenzo Bianconi 
1697d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1698d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1699d2679d65SLorenzo Bianconi 			return i;
1700d2679d65SLorenzo Bianconi 	}
1701d2679d65SLorenzo Bianconi 
1702d2679d65SLorenzo Bianconi 	return 0;
1703d2679d65SLorenzo Bianconi }
1704d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
17058b8ab5c2SLorenzo Bianconi 
17068b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
17078b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
17088b8ab5c2SLorenzo Bianconi {
1709011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
17108b8ab5c2SLorenzo Bianconi 
1711011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
17128b8ab5c2SLorenzo Bianconi }
17138b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
17148b8ab5c2SLorenzo Bianconi 
17158b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
17168b8ab5c2SLorenzo Bianconi {
1717011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
17188b8ab5c2SLorenzo Bianconi 
1719011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
17208b8ab5c2SLorenzo Bianconi }
17218b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1722e49c76d4SLorenzo Bianconi 
1723e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1724e49c76d4SLorenzo Bianconi {
1725beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1726beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1727e49c76d4SLorenzo Bianconi 
1728e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1729beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1730beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1731e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1732e49c76d4SLorenzo Bianconi 
1733e49c76d4SLorenzo Bianconi 	return 0;
1734e49c76d4SLorenzo Bianconi }
1735e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1736b671da33SLorenzo Bianconi 
1737b1cb42adSLorenzo Bianconi struct mt76_queue *
1738b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1739f68d6762SFelix Fietkau 		int ring_base, u32 flags)
1740b671da33SLorenzo Bianconi {
1741b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1742b671da33SLorenzo Bianconi 	int err;
1743b671da33SLorenzo Bianconi 
1744b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1745b671da33SLorenzo Bianconi 	if (!hwq)
1746b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1747b671da33SLorenzo Bianconi 
1748f68d6762SFelix Fietkau 	hwq->flags = flags;
1749f68d6762SFelix Fietkau 
1750b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1751b671da33SLorenzo Bianconi 	if (err < 0)
1752b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1753b671da33SLorenzo Bianconi 
1754b1cb42adSLorenzo Bianconi 	return hwq;
1755b671da33SLorenzo Bianconi }
1756b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1757e4867225SSean Wang 
175832b1000dSSean Wang u16 mt76_calculate_default_rate(struct mt76_phy *phy,
175932b1000dSSean Wang 				struct ieee80211_vif *vif, int rateidx)
1760e4867225SSean Wang {
176132b1000dSSean Wang 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
176232b1000dSSean Wang 	struct cfg80211_chan_def *chandef = mvif->ctx ?
176332b1000dSSean Wang 					    &mvif->ctx->def :
176432b1000dSSean Wang 					    &phy->chandef;
176533920b2bSRyder Lee 	int offset = 0;
1766e4867225SSean Wang 
176732b1000dSSean Wang 	if (chandef->chan->band != NL80211_BAND_2GHZ)
1768e4867225SSean Wang 		offset = 4;
1769e4867225SSean Wang 
177033920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
177133920b2bSRyder Lee 	if (rateidx < 0)
177233920b2bSRyder Lee 		rateidx = 0;
177333920b2bSRyder Lee 
1774d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1775d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1776d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1777e4867225SSean Wang 
1778d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1779e4867225SSean Wang }
178033920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
178154ae98ffSLorenzo Bianconi 
178254ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1783731425f3SShayne Chen 			 struct mt76_sta_stats *stats, bool eht)
178454ae98ffSLorenzo Bianconi {
178554ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
178654ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
178754ae98ffSLorenzo Bianconi 
178854ae98ffSLorenzo Bianconi 	wi->sta_count++;
178954ae98ffSLorenzo Bianconi 
179054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
179154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
179254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
179354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
179454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
179554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
179654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
179754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
179854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1799731425f3SShayne Chen 	if (eht) {
1800731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1801731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1802731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1803731425f3SShayne Chen 	}
180454ae98ffSLorenzo Bianconi 
1805731425f3SShayne Chen 	for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
180654ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
180754ae98ffSLorenzo Bianconi 
1808731425f3SShayne Chen 	for (i = 0; i < (eht ? 14 : 12); i++)
180954ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
181054ae98ffSLorenzo Bianconi 
1811749c2c2bSRyder Lee 	for (i = 0; i < 4; i++)
1812749c2c2bSRyder Lee 		data[ei++] += stats->tx_nss[i];
1813749c2c2bSRyder Lee 
181454ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
181554ae98ffSLorenzo Bianconi }
181654ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
18173f306448SFelix Fietkau 
1818192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1819192ad406SLorenzo Bianconi {
1820192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS
1821192ad406SLorenzo Bianconi 	struct page_pool_stats stats = {};
1822192ad406SLorenzo Bianconi 	int i;
1823192ad406SLorenzo Bianconi 
1824192ad406SLorenzo Bianconi 	mt76_for_each_q_rx(dev, i)
1825192ad406SLorenzo Bianconi 		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
1826192ad406SLorenzo Bianconi 
1827192ad406SLorenzo Bianconi 	page_pool_ethtool_stats_get(data, &stats);
1828192ad406SLorenzo Bianconi 	*index += page_pool_ethtool_stats_get_count();
1829192ad406SLorenzo Bianconi #endif
1830192ad406SLorenzo Bianconi }
1831192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
1832192ad406SLorenzo Bianconi 
18333f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
18343f306448SFelix Fietkau {
18353f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
18363f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
18373f306448SFelix Fietkau 
18383f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
18393f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
18403f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
18413f306448SFelix Fietkau 
18423f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
18433f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
18443f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
18453f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
18463f306448SFelix Fietkau 
18473f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
18483f306448SFelix Fietkau 	}
18493f306448SFelix Fietkau 
185000a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
18513f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
18523f306448SFelix Fietkau 
18533f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
18543f306448SFelix Fietkau }
18553f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1856