xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 9410645520e9b820069761f3450ef6661418e279)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
5781eef5bSFelix Fietkau #include <linux/sched.h>
617f1de56SFelix Fietkau #include <linux/of.h>
717f1de56SFelix Fietkau #include "mt76.h"
817f1de56SFelix Fietkau 
917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
1017f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1117f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1217f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1317f1de56SFelix Fietkau 	.max_power = 30,			\
1417f1de56SFelix Fietkau }
1517f1de56SFelix Fietkau 
1617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1717f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1817f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1917f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2017f1de56SFelix Fietkau 	.max_power = 30,			\
2117f1de56SFelix Fietkau }
2217f1de56SFelix Fietkau 
23edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) {			\
24edf9dab8SLorenzo Bianconi 	.band = NL80211_BAND_6GHZ,		\
25edf9dab8SLorenzo Bianconi 	.center_freq = (_freq),			\
26edf9dab8SLorenzo Bianconi 	.hw_value = (_idx),			\
27edf9dab8SLorenzo Bianconi 	.max_power = 30,			\
28edf9dab8SLorenzo Bianconi }
29edf9dab8SLorenzo Bianconi 
3017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3117f1de56SFelix Fietkau 	CHAN2G(1, 2412),
3217f1de56SFelix Fietkau 	CHAN2G(2, 2417),
3317f1de56SFelix Fietkau 	CHAN2G(3, 2422),
3417f1de56SFelix Fietkau 	CHAN2G(4, 2427),
3517f1de56SFelix Fietkau 	CHAN2G(5, 2432),
3617f1de56SFelix Fietkau 	CHAN2G(6, 2437),
3717f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3817f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3917f1de56SFelix Fietkau 	CHAN2G(9, 2452),
4017f1de56SFelix Fietkau 	CHAN2G(10, 2457),
4117f1de56SFelix Fietkau 	CHAN2G(11, 2462),
4217f1de56SFelix Fietkau 	CHAN2G(12, 2467),
4317f1de56SFelix Fietkau 	CHAN2G(13, 2472),
4417f1de56SFelix Fietkau 	CHAN2G(14, 2484),
4517f1de56SFelix Fietkau };
4617f1de56SFelix Fietkau 
4717f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4817f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4917f1de56SFelix Fietkau 	CHAN5G(40, 5200),
5017f1de56SFelix Fietkau 	CHAN5G(44, 5220),
5117f1de56SFelix Fietkau 	CHAN5G(48, 5240),
5217f1de56SFelix Fietkau 
5317f1de56SFelix Fietkau 	CHAN5G(52, 5260),
5417f1de56SFelix Fietkau 	CHAN5G(56, 5280),
5517f1de56SFelix Fietkau 	CHAN5G(60, 5300),
5617f1de56SFelix Fietkau 	CHAN5G(64, 5320),
5717f1de56SFelix Fietkau 
5817f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5917f1de56SFelix Fietkau 	CHAN5G(104, 5520),
6017f1de56SFelix Fietkau 	CHAN5G(108, 5540),
6117f1de56SFelix Fietkau 	CHAN5G(112, 5560),
6217f1de56SFelix Fietkau 	CHAN5G(116, 5580),
6317f1de56SFelix Fietkau 	CHAN5G(120, 5600),
6417f1de56SFelix Fietkau 	CHAN5G(124, 5620),
6517f1de56SFelix Fietkau 	CHAN5G(128, 5640),
6617f1de56SFelix Fietkau 	CHAN5G(132, 5660),
6717f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6817f1de56SFelix Fietkau 	CHAN5G(140, 5700),
699da82fb7SMarkus Theil 	CHAN5G(144, 5720),
7017f1de56SFelix Fietkau 
7117f1de56SFelix Fietkau 	CHAN5G(149, 5745),
7217f1de56SFelix Fietkau 	CHAN5G(153, 5765),
7317f1de56SFelix Fietkau 	CHAN5G(157, 5785),
7417f1de56SFelix Fietkau 	CHAN5G(161, 5805),
7517f1de56SFelix Fietkau 	CHAN5G(165, 5825),
769da82fb7SMarkus Theil 	CHAN5G(169, 5845),
779da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7862561a47SRyder Lee 	CHAN5G(177, 5885),
7917f1de56SFelix Fietkau };
8017f1de56SFelix Fietkau 
81edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = {
82edf9dab8SLorenzo Bianconi 	/* UNII-5 */
83edf9dab8SLorenzo Bianconi 	CHAN6G(1, 5955),
84edf9dab8SLorenzo Bianconi 	CHAN6G(5, 5975),
85edf9dab8SLorenzo Bianconi 	CHAN6G(9, 5995),
86edf9dab8SLorenzo Bianconi 	CHAN6G(13, 6015),
87edf9dab8SLorenzo Bianconi 	CHAN6G(17, 6035),
88edf9dab8SLorenzo Bianconi 	CHAN6G(21, 6055),
89edf9dab8SLorenzo Bianconi 	CHAN6G(25, 6075),
90edf9dab8SLorenzo Bianconi 	CHAN6G(29, 6095),
91edf9dab8SLorenzo Bianconi 	CHAN6G(33, 6115),
92edf9dab8SLorenzo Bianconi 	CHAN6G(37, 6135),
93edf9dab8SLorenzo Bianconi 	CHAN6G(41, 6155),
94edf9dab8SLorenzo Bianconi 	CHAN6G(45, 6175),
95edf9dab8SLorenzo Bianconi 	CHAN6G(49, 6195),
96edf9dab8SLorenzo Bianconi 	CHAN6G(53, 6215),
97edf9dab8SLorenzo Bianconi 	CHAN6G(57, 6235),
98edf9dab8SLorenzo Bianconi 	CHAN6G(61, 6255),
99edf9dab8SLorenzo Bianconi 	CHAN6G(65, 6275),
100edf9dab8SLorenzo Bianconi 	CHAN6G(69, 6295),
101edf9dab8SLorenzo Bianconi 	CHAN6G(73, 6315),
102edf9dab8SLorenzo Bianconi 	CHAN6G(77, 6335),
103edf9dab8SLorenzo Bianconi 	CHAN6G(81, 6355),
104edf9dab8SLorenzo Bianconi 	CHAN6G(85, 6375),
105edf9dab8SLorenzo Bianconi 	CHAN6G(89, 6395),
106edf9dab8SLorenzo Bianconi 	CHAN6G(93, 6415),
107edf9dab8SLorenzo Bianconi 	/* UNII-6 */
108edf9dab8SLorenzo Bianconi 	CHAN6G(97, 6435),
109edf9dab8SLorenzo Bianconi 	CHAN6G(101, 6455),
110edf9dab8SLorenzo Bianconi 	CHAN6G(105, 6475),
111edf9dab8SLorenzo Bianconi 	CHAN6G(109, 6495),
112edf9dab8SLorenzo Bianconi 	CHAN6G(113, 6515),
113edf9dab8SLorenzo Bianconi 	CHAN6G(117, 6535),
114edf9dab8SLorenzo Bianconi 	/* UNII-7 */
115edf9dab8SLorenzo Bianconi 	CHAN6G(121, 6555),
116edf9dab8SLorenzo Bianconi 	CHAN6G(125, 6575),
117edf9dab8SLorenzo Bianconi 	CHAN6G(129, 6595),
118edf9dab8SLorenzo Bianconi 	CHAN6G(133, 6615),
119edf9dab8SLorenzo Bianconi 	CHAN6G(137, 6635),
120edf9dab8SLorenzo Bianconi 	CHAN6G(141, 6655),
121edf9dab8SLorenzo Bianconi 	CHAN6G(145, 6675),
122edf9dab8SLorenzo Bianconi 	CHAN6G(149, 6695),
123edf9dab8SLorenzo Bianconi 	CHAN6G(153, 6715),
124edf9dab8SLorenzo Bianconi 	CHAN6G(157, 6735),
125edf9dab8SLorenzo Bianconi 	CHAN6G(161, 6755),
126edf9dab8SLorenzo Bianconi 	CHAN6G(165, 6775),
127edf9dab8SLorenzo Bianconi 	CHAN6G(169, 6795),
128edf9dab8SLorenzo Bianconi 	CHAN6G(173, 6815),
129edf9dab8SLorenzo Bianconi 	CHAN6G(177, 6835),
130edf9dab8SLorenzo Bianconi 	CHAN6G(181, 6855),
131edf9dab8SLorenzo Bianconi 	CHAN6G(185, 6875),
132edf9dab8SLorenzo Bianconi 	/* UNII-8 */
133edf9dab8SLorenzo Bianconi 	CHAN6G(189, 6895),
134edf9dab8SLorenzo Bianconi 	CHAN6G(193, 6915),
135edf9dab8SLorenzo Bianconi 	CHAN6G(197, 6935),
136edf9dab8SLorenzo Bianconi 	CHAN6G(201, 6955),
137edf9dab8SLorenzo Bianconi 	CHAN6G(205, 6975),
138edf9dab8SLorenzo Bianconi 	CHAN6G(209, 6995),
139edf9dab8SLorenzo Bianconi 	CHAN6G(213, 7015),
140edf9dab8SLorenzo Bianconi 	CHAN6G(217, 7035),
141edf9dab8SLorenzo Bianconi 	CHAN6G(221, 7055),
142edf9dab8SLorenzo Bianconi 	CHAN6G(225, 7075),
143edf9dab8SLorenzo Bianconi 	CHAN6G(229, 7095),
144edf9dab8SLorenzo Bianconi 	CHAN6G(233, 7115),
145edf9dab8SLorenzo Bianconi };
146edf9dab8SLorenzo Bianconi 
14717f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
14817f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
14917f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
15017f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
15117f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
15217f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
15317f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
15417f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
15517f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
15617f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
15717f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
15817f1de56SFelix Fietkau };
15917f1de56SFelix Fietkau 
16054b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = {
16154b8fdebSLorenzo Bianconi 	CCK_RATE(0, 10),
16254b8fdebSLorenzo Bianconi 	CCK_RATE(1, 20),
16354b8fdebSLorenzo Bianconi 	CCK_RATE(2, 55),
16454b8fdebSLorenzo Bianconi 	CCK_RATE(3, 110),
16554b8fdebSLorenzo Bianconi 	OFDM_RATE(11, 60),
16654b8fdebSLorenzo Bianconi 	OFDM_RATE(15, 90),
16754b8fdebSLorenzo Bianconi 	OFDM_RATE(10, 120),
16854b8fdebSLorenzo Bianconi 	OFDM_RATE(14, 180),
16954b8fdebSLorenzo Bianconi 	OFDM_RATE(9,  240),
17054b8fdebSLorenzo Bianconi 	OFDM_RATE(13, 360),
17154b8fdebSLorenzo Bianconi 	OFDM_RATE(8,  480),
17254b8fdebSLorenzo Bianconi 	OFDM_RATE(12, 540),
17354b8fdebSLorenzo Bianconi };
17454b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates);
17554b8fdebSLorenzo Bianconi 
176502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
177502604f5SYN Chen 	{ .start_freq = 2402, .end_freq = 2494, },
178502604f5SYN Chen 	{ .start_freq = 5150, .end_freq = 5350, },
179502604f5SYN Chen 	{ .start_freq = 5350, .end_freq = 5470, },
180502604f5SYN Chen 	{ .start_freq = 5470, .end_freq = 5725, },
181502604f5SYN Chen 	{ .start_freq = 5725, .end_freq = 5950, },
182162d5c14SDeren Wu 	{ .start_freq = 5945, .end_freq = 6165, },
183162d5c14SDeren Wu 	{ .start_freq = 6165, .end_freq = 6405, },
184162d5c14SDeren Wu 	{ .start_freq = 6405, .end_freq = 6525, },
185162d5c14SDeren Wu 	{ .start_freq = 6525, .end_freq = 6705, },
186162d5c14SDeren Wu 	{ .start_freq = 6705, .end_freq = 6865, },
187162d5c14SDeren Wu 	{ .start_freq = 6865, .end_freq = 7125, },
188502604f5SYN Chen };
189502604f5SYN Chen 
19097f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = {
191502604f5SYN Chen 	.type = NL80211_SAR_TYPE_POWER,
192502604f5SYN Chen 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
193502604f5SYN Chen 	.freq_ranges = &mt76_sar_freq_ranges[0],
194502604f5SYN Chen };
195502604f5SYN Chen 
mt76_led_init(struct mt76_phy * phy)1963abd46ddSLorenzo Bianconi static int mt76_led_init(struct mt76_phy *phy)
19717f1de56SFelix Fietkau {
1983abd46ddSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1993abd46ddSLorenzo Bianconi 	struct ieee80211_hw *hw = phy->hw;
20014cdeaf9SRyder 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 
20514cdeaf9SRyder Lee 	np = of_get_child_by_name(np, "led");
20614cdeaf9SRyder Lee 	if (np) {
20714cdeaf9SRyder Lee 		if (!of_device_is_available(np)) {
20814cdeaf9SRyder Lee 			of_node_put(np);
20914cdeaf9SRyder Lee 			dev_info(dev->dev,
21014cdeaf9SRyder Lee 				"led registration was explicitly disabled by dts\n");
21114cdeaf9SRyder Lee 			return 0;
21214cdeaf9SRyder Lee 		}
21314cdeaf9SRyder Lee 
21414cdeaf9SRyder Lee 		if (phy == &dev->phy) {
21514cdeaf9SRyder Lee 			int led_pin;
21614cdeaf9SRyder Lee 
21714cdeaf9SRyder Lee 			if (!of_property_read_u32(np, "led-sources", &led_pin))
21814cdeaf9SRyder Lee 				phy->leds.pin = led_pin;
21914cdeaf9SRyder Lee 
22014cdeaf9SRyder Lee 			phy->leds.al =
22114cdeaf9SRyder Lee 				of_property_read_bool(np, "led-active-low");
22214cdeaf9SRyder Lee 		}
22314cdeaf9SRyder Lee 
22414cdeaf9SRyder Lee 		of_node_put(np);
22514cdeaf9SRyder Lee 	}
22614cdeaf9SRyder 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 
23714cdeaf9SRyder Lee 	dev_info(dev->dev,
23814cdeaf9SRyder 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 
mt76_led_cleanup(struct mt76_phy * phy)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 
mt76_init_stream_cap(struct mt76_phy * phy,struct ieee80211_supported_band * sband,bool vht)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 
mt76_set_stream_caps(struct mt76_phy * phy,bool vht)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
mt76_init_sband(struct mt76_phy * phy,struct mt76_sband * msband,const struct ieee80211_channel * chan,int n_chan,struct ieee80211_rate * rates,int n_rates,bool ht,bool vht)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
mt76_init_sband_2g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)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
mt76_init_sband_5g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates,bool vht)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
mt76_init_sband_6g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)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
mt76_check_sband(struct mt76_phy * phy,struct mt76_sband * msband,enum nl80211_band band)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
mt76_phy_init(struct mt76_phy * phy,struct ieee80211_hw * hw)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);
46859f4c573SFelix Fietkau 	ieee80211_hw_set(hw, SPECTRUM_MGMT);
4695b0fb852SBen Greear 
470c2fcc83bSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD) &&
471c2fcc83bSFelix Fietkau 	    hw->max_tx_fragments > 1) {
472c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
473c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
4745b0fb852SBen Greear 	}
4755b0fb852SBen Greear 
476c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
477c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
478c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
479d43de9cfSLorenzo Bianconi 
480d43de9cfSLorenzo Bianconi 	return 0;
481c89d3625SFelix Fietkau }
482c89d3625SFelix Fietkau 
483c89d3625SFelix Fietkau struct mt76_phy *
mt76_alloc_phy(struct mt76_dev * dev,unsigned int size,const struct ieee80211_ops * ops,u8 band_idx)484c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
485dc44c45cSLorenzo Bianconi 	       const struct ieee80211_ops *ops, u8 band_idx)
486c89d3625SFelix Fietkau {
487c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
488db78a791SLorenzo Bianconi 	unsigned int phy_size;
489c89d3625SFelix Fietkau 	struct mt76_phy *phy;
490c89d3625SFelix Fietkau 
491c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
492db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
493c89d3625SFelix Fietkau 	if (!hw)
494c89d3625SFelix Fietkau 		return NULL;
495c89d3625SFelix Fietkau 
496c89d3625SFelix Fietkau 	phy = hw->priv;
497c89d3625SFelix Fietkau 	phy->dev = dev;
498c89d3625SFelix Fietkau 	phy->hw = hw;
499db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
500dc44c45cSLorenzo Bianconi 	phy->band_idx = band_idx;
501c89d3625SFelix Fietkau 
5028af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5038af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
5048af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
5058af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
5068af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
5078af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
5088af414e8SLorenzo Bianconi #endif
5098af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5108af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
5118af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
5128af414e8SLorenzo Bianconi 
513c89d3625SFelix Fietkau 	return phy;
514c89d3625SFelix Fietkau }
515c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
516c89d3625SFelix Fietkau 
mt76_register_phy(struct mt76_phy * phy,bool vht,struct ieee80211_rate * rates,int n_rates)517db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
518db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
519c89d3625SFelix Fietkau {
520c89d3625SFelix Fietkau 	int ret;
521c89d3625SFelix Fietkau 
522d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
523d43de9cfSLorenzo Bianconi 	if (ret)
524d43de9cfSLorenzo Bianconi 		return ret;
525db78a791SLorenzo Bianconi 
526db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
527db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
528db78a791SLorenzo Bianconi 		if (ret)
529db78a791SLorenzo Bianconi 			return ret;
530db78a791SLorenzo Bianconi 	}
531db78a791SLorenzo Bianconi 
532db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
533db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
534db78a791SLorenzo Bianconi 		if (ret)
535db78a791SLorenzo Bianconi 			return ret;
536db78a791SLorenzo Bianconi 	}
537db78a791SLorenzo Bianconi 
538edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
539edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
540edf9dab8SLorenzo Bianconi 		if (ret)
541edf9dab8SLorenzo Bianconi 			return ret;
542edf9dab8SLorenzo Bianconi 	}
543edf9dab8SLorenzo Bianconi 
5449e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
5459e81c2c7SLorenzo Bianconi 		ret = mt76_led_init(phy);
5469e81c2c7SLorenzo Bianconi 		if (ret)
5479e81c2c7SLorenzo Bianconi 			return ret;
5489e81c2c7SLorenzo Bianconi 	}
5499e81c2c7SLorenzo Bianconi 
550db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
551db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
552db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
553edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
554db78a791SLorenzo Bianconi 
555c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
556c89d3625SFelix Fietkau 	if (ret)
557c89d3625SFelix Fietkau 		return ret;
558c89d3625SFelix Fietkau 
55941130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
560dc44c45cSLorenzo Bianconi 	phy->dev->phys[phy->band_idx] = phy;
561db78a791SLorenzo Bianconi 
562c89d3625SFelix Fietkau 	return 0;
563c89d3625SFelix Fietkau }
564c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
565c89d3625SFelix Fietkau 
mt76_unregister_phy(struct mt76_phy * phy)566db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
567c89d3625SFelix Fietkau {
568c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
569c89d3625SFelix Fietkau 
57041130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
57141130c32SLorenzo Bianconi 		return;
57241130c32SLorenzo Bianconi 
5739e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS))
5749e81c2c7SLorenzo Bianconi 		mt76_led_cleanup(phy);
575c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
576c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
577dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = NULL;
578c89d3625SFelix Fietkau }
579c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
580c89d3625SFelix Fietkau 
mt76_create_page_pool(struct mt76_dev * dev,struct mt76_queue * q)5812f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
5822f5c3c77SLorenzo Bianconi {
5833c37da57SLorenzo Bianconi 	bool is_qrx = mt76_queue_is_rx(dev, q);
5842f5c3c77SLorenzo Bianconi 	struct page_pool_params pp_params = {
5852f5c3c77SLorenzo Bianconi 		.order = 0,
58609d96ee5SYunsheng Lin 		.flags = 0,
5872f5c3c77SLorenzo Bianconi 		.nid = NUMA_NO_NODE,
5882f5c3c77SLorenzo Bianconi 		.dev = dev->dma_dev,
5892f5c3c77SLorenzo Bianconi 	};
5903c37da57SLorenzo Bianconi 	int idx = is_qrx ? q - dev->q_rx : -1;
5913c37da57SLorenzo Bianconi 
5923c37da57SLorenzo Bianconi 	/* Allocate page_pools just for rx/wed_tx_free queues */
5933c37da57SLorenzo Bianconi 	if (!is_qrx && !mt76_queue_is_wed_tx_free(q))
5943c37da57SLorenzo Bianconi 		return 0;
5952f5c3c77SLorenzo Bianconi 
5962f5c3c77SLorenzo Bianconi 	switch (idx) {
5972f5c3c77SLorenzo Bianconi 	case MT_RXQ_MAIN:
5982f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND1:
5992f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND2:
6002f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 256;
6012f5c3c77SLorenzo Bianconi 		break;
6022f5c3c77SLorenzo Bianconi 	default:
6032f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 16;
6042f5c3c77SLorenzo Bianconi 		break;
6052f5c3c77SLorenzo Bianconi 	}
6062f5c3c77SLorenzo Bianconi 
6072f5c3c77SLorenzo Bianconi 	if (mt76_is_mmio(dev)) {
6082f5c3c77SLorenzo Bianconi 		/* rely on page_pool for DMA mapping */
6092f5c3c77SLorenzo Bianconi 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
6102f5c3c77SLorenzo Bianconi 		pp_params.dma_dir = DMA_FROM_DEVICE;
6112f5c3c77SLorenzo Bianconi 		pp_params.max_len = PAGE_SIZE;
6122f5c3c77SLorenzo Bianconi 		pp_params.offset = 0;
6133c37da57SLorenzo Bianconi 		/* NAPI is available just for rx queues */
6143c37da57SLorenzo Bianconi 		if (idx >= 0 && idx < ARRAY_SIZE(dev->napi))
6153c37da57SLorenzo Bianconi 			pp_params.napi = &dev->napi[idx];
6162f5c3c77SLorenzo Bianconi 	}
6172f5c3c77SLorenzo Bianconi 
6182f5c3c77SLorenzo Bianconi 	q->page_pool = page_pool_create(&pp_params);
6192f5c3c77SLorenzo Bianconi 	if (IS_ERR(q->page_pool)) {
6202f5c3c77SLorenzo Bianconi 		int err = PTR_ERR(q->page_pool);
6212f5c3c77SLorenzo Bianconi 
6222f5c3c77SLorenzo Bianconi 		q->page_pool = NULL;
6232f5c3c77SLorenzo Bianconi 		return err;
6242f5c3c77SLorenzo Bianconi 	}
6252f5c3c77SLorenzo Bianconi 
6262f5c3c77SLorenzo Bianconi 	return 0;
6272f5c3c77SLorenzo Bianconi }
6282f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool);
6292f5c3c77SLorenzo Bianconi 
630a85b590cSFelix Fietkau struct mt76_dev *
mt76_alloc_device(struct device * pdev,unsigned int size,const struct ieee80211_ops * ops,const struct mt76_driver_ops * drv_ops)631c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
632c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
633c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
634a85b590cSFelix Fietkau {
635a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
636ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
637a85b590cSFelix Fietkau 	struct mt76_dev *dev;
638e5443256SFelix Fietkau 	int i;
639a85b590cSFelix Fietkau 
640a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
641a85b590cSFelix Fietkau 	if (!hw)
642a85b590cSFelix Fietkau 		return NULL;
643a85b590cSFelix Fietkau 
644a85b590cSFelix Fietkau 	dev = hw->priv;
645a85b590cSFelix Fietkau 	dev->hw = hw;
646c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
647c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
648d1ddc536SFelix Fietkau 	dev->dma_dev = pdev;
649c0f7b25aSLorenzo Bianconi 
650ac24dd35SFelix Fietkau 	phy = &dev->phy;
651ac24dd35SFelix Fietkau 	phy->dev = dev;
652ac24dd35SFelix Fietkau 	phy->hw = hw;
653dc44c45cSLorenzo Bianconi 	phy->band_idx = MT_BAND0;
654dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = phy;
655ac24dd35SFelix Fietkau 
656a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
657a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
658a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
659c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
6602666beceSSujuan Chen 	spin_lock_init(&dev->wed_lock);
661108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
66226e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
663a85b590cSFelix Fietkau 
66409872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
66509872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
66609872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
667781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
66809872957SLorenzo Bianconi 
6698af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6708af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
6718af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
6728af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
6738af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
6748af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
6758af414e8SLorenzo Bianconi #endif
6768af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
6778af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
6788af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
6798af414e8SLorenzo Bianconi 
68051252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
68151252cc5SLorenzo Bianconi 	idr_init(&dev->token);
68251252cc5SLorenzo Bianconi 
6832666beceSSujuan Chen 	spin_lock_init(&dev->rx_token_lock);
6842666beceSSujuan Chen 	idr_init(&dev->rx_token);
6852666beceSSujuan Chen 
686bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
687fbba711cSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->sta_poll_list);
688fbba711cSLorenzo Bianconi 	spin_lock_init(&dev->sta_poll_lock);
689bd1e3e7bSLorenzo Bianconi 
690e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
6912666beceSSujuan Chen 	INIT_LIST_HEAD(&dev->rxwi_cache);
69261b5156bSFelix Fietkau 	dev->token_size = dev->drv->token_size;
693e5443256SFelix Fietkau 
694e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
695e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
696e5443256SFelix Fietkau 
697a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
698a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
699a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
700a86f1d01SLorenzo Bianconi 		return NULL;
701a86f1d01SLorenzo Bianconi 	}
702a86f1d01SLorenzo Bianconi 
703a85b590cSFelix Fietkau 	return dev;
704a85b590cSFelix Fietkau }
705a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
706a85b590cSFelix Fietkau 
mt76_register_device(struct mt76_dev * dev,bool vht,struct ieee80211_rate * rates,int n_rates)70717f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
70817f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
70917f1de56SFelix Fietkau {
71017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
711c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
71217f1de56SFelix Fietkau 	int ret;
71317f1de56SFelix Fietkau 
71417f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
7150335c034SFelix Fietkau 	mt76_wcid_init(&dev->global_wcid);
716d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
717d43de9cfSLorenzo Bianconi 	if (ret)
718d43de9cfSLorenzo Bianconi 		return ret;
71917f1de56SFelix Fietkau 
72048dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
72177af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
72217f1de56SFelix Fietkau 		if (ret)
72317f1de56SFelix Fietkau 			return ret;
72417f1de56SFelix Fietkau 	}
72517f1de56SFelix Fietkau 
72648dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
72777af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
72817f1de56SFelix Fietkau 		if (ret)
72917f1de56SFelix Fietkau 			return ret;
73017f1de56SFelix Fietkau 	}
73117f1de56SFelix Fietkau 
732edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
733edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
734edf9dab8SLorenzo Bianconi 		if (ret)
735edf9dab8SLorenzo Bianconi 			return ret;
736edf9dab8SLorenzo Bianconi 	}
737edf9dab8SLorenzo Bianconi 
738c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
739c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
740c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
741edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
74217f1de56SFelix Fietkau 
743b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
7443abd46ddSLorenzo Bianconi 		ret = mt76_led_init(phy);
74517f1de56SFelix Fietkau 		if (ret)
74617f1de56SFelix Fietkau 			return ret;
747b374e868SArnd Bergmann 	}
74817f1de56SFelix Fietkau 
749781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
750781eef5bSFelix Fietkau 	if (ret)
751781eef5bSFelix Fietkau 		return ret;
752781eef5bSFelix Fietkau 
753781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
75441130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
755781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
756781eef5bSFelix Fietkau 
757781eef5bSFelix Fietkau 	return 0;
75817f1de56SFelix Fietkau }
75917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
76017f1de56SFelix Fietkau 
mt76_unregister_device(struct mt76_dev * dev)76117f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
76217f1de56SFelix Fietkau {
76317f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
76417f1de56SFelix Fietkau 
76541130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
76641130c32SLorenzo Bianconi 		return;
76741130c32SLorenzo Bianconi 
768d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
7693abd46ddSLorenzo Bianconi 		mt76_led_cleanup(&dev->phy);
770c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
7710335c034SFelix Fietkau 	mt76_wcid_cleanup(dev, &dev->global_wcid);
77217f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
77317f1de56SFelix Fietkau }
77417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
77517f1de56SFelix Fietkau 
mt76_free_device(struct mt76_dev * dev)776def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
777def34a2fSLorenzo Bianconi {
778781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
779a86f1d01SLorenzo Bianconi 	if (dev->wq) {
780a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
781a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
782a86f1d01SLorenzo Bianconi 	}
783def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
784def34a2fSLorenzo Bianconi }
785def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
786def34a2fSLorenzo Bianconi 
mt76_rx_release_amsdu(struct mt76_phy * phy,enum mt76_rxq_id q)787cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
788cc4b3c13SLorenzo Bianconi {
789cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
7902c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
791cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
792cc4b3c13SLorenzo Bianconi 
793cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
794cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
7952c2bdd23SFelix Fietkau 
7962c2bdd23SFelix Fietkau 	/*
7972c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
7982c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7992c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
8002c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
8012c2bdd23SFelix Fietkau 	 * address.
8022c2bdd23SFelix Fietkau 	 */
8032c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
8042c2bdd23SFelix Fietkau 		int offset = 0;
8052c2bdd23SFelix Fietkau 
8062c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
8072c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
8082c2bdd23SFelix Fietkau 
8092c2bdd23SFelix Fietkau 			if ((status->flag &
8102c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
8112c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
8122c2bdd23SFelix Fietkau 				offset += 8;
8132c2bdd23SFelix Fietkau 		}
8142c2bdd23SFelix Fietkau 
8152c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
8162c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
8172c2bdd23SFelix Fietkau 			return;
8182c2bdd23SFelix Fietkau 		}
8192c2bdd23SFelix Fietkau 	}
820cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
821cc4b3c13SLorenzo Bianconi }
822cc4b3c13SLorenzo Bianconi 
mt76_rx_release_burst(struct mt76_phy * phy,enum mt76_rxq_id q,struct sk_buff * skb)823cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
824cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
825cc4b3c13SLorenzo Bianconi {
826cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
827cc4b3c13SLorenzo Bianconi 
828cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
829cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
830cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
831cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
832cc4b3c13SLorenzo Bianconi 
833cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
834cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
835cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
836cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
837cc4b3c13SLorenzo Bianconi 	} else {
838cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
839cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
840cc4b3c13SLorenzo Bianconi 	}
841cc4b3c13SLorenzo Bianconi 
842cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
843cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
844cc4b3c13SLorenzo Bianconi }
845cc4b3c13SLorenzo Bianconi 
mt76_rx(struct mt76_dev * dev,enum mt76_rxq_id q,struct sk_buff * skb)84617f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
84717f1de56SFelix Fietkau {
848011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
849128c9b7dSLorenzo Bianconi 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
850011849e0SFelix Fietkau 
851011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
85217f1de56SFelix Fietkau 		dev_kfree_skb(skb);
85317f1de56SFelix Fietkau 		return;
85417f1de56SFelix Fietkau 	}
85517f1de56SFelix Fietkau 
856f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
857c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
858c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
859f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
860c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
861f0efa862SFelix Fietkau 	}
862f0efa862SFelix Fietkau #endif
863cc4b3c13SLorenzo Bianconi 
864cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
86517f1de56SFelix Fietkau }
86617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
86717f1de56SFelix Fietkau 
mt76_has_tx_pending(struct mt76_phy * phy)8685a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
86926e40d4cSFelix Fietkau {
870af005f26SLorenzo Bianconi 	struct mt76_queue *q;
87191990519SLorenzo Bianconi 	int i;
8725a95ca41SFelix Fietkau 
8735a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
87491990519SLorenzo Bianconi 		q = phy->q_tx[i];
875af005f26SLorenzo Bianconi 		if (q && q->queued)
87626e40d4cSFelix Fietkau 			return true;
87726e40d4cSFelix Fietkau 	}
87826e40d4cSFelix Fietkau 
87926e40d4cSFelix Fietkau 	return false;
88026e40d4cSFelix Fietkau }
88139d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
88226e40d4cSFelix Fietkau 
8830fd0eb54SFelix Fietkau static struct mt76_channel_state *
mt76_channel_state(struct mt76_phy * phy,struct ieee80211_channel * c)88496747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8850fd0eb54SFelix Fietkau {
8860fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
8870fd0eb54SFelix Fietkau 	int idx;
8880fd0eb54SFelix Fietkau 
8890fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
89096747a51SFelix Fietkau 		msband = &phy->sband_2g;
891edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
892edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
8930fd0eb54SFelix Fietkau 	else
89496747a51SFelix Fietkau 		msband = &phy->sband_5g;
8950fd0eb54SFelix Fietkau 
8960fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
8970fd0eb54SFelix Fietkau 	return &msband->chan[idx];
8980fd0eb54SFelix Fietkau }
8990fd0eb54SFelix Fietkau 
mt76_update_survey_active_time(struct mt76_phy * phy,ktime_t time)90004414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
90196747a51SFelix Fietkau {
90296747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
90396747a51SFelix Fietkau 
90496747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
90596747a51SFelix Fietkau 						  phy->survey_time));
90696747a51SFelix Fietkau 	phy->survey_time = time;
90796747a51SFelix Fietkau }
90804414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
90996747a51SFelix Fietkau 
mt76_update_survey(struct mt76_phy * phy)910c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
9115ce09c1aSFelix Fietkau {
912c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
913aec65e48SFelix Fietkau 	ktime_t cur_time;
914aec65e48SFelix Fietkau 
9155ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
916c560b137SRyder Lee 		dev->drv->update_survey(phy);
9175ce09c1aSFelix Fietkau 
918aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
919c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
920aec65e48SFelix Fietkau 
9215ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
922c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
92396747a51SFelix Fietkau 
924237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
9255ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
9265ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
927237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
9285ce09c1aSFelix Fietkau 	}
9295ce09c1aSFelix Fietkau }
9305ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
9315ce09c1aSFelix Fietkau 
mt76_set_channel(struct mt76_phy * phy,struct cfg80211_chan_def * chandef,bool offchannel)932f4fdd771SFelix Fietkau int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
933f4fdd771SFelix Fietkau 		     bool offchannel)
93417f1de56SFelix Fietkau {
93596747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
93626e40d4cSFelix Fietkau 	int timeout = HZ / 5;
937f4fdd771SFelix Fietkau 	int ret;
938f4fdd771SFelix Fietkau 
939f4fdd771SFelix Fietkau 	cancel_delayed_work_sync(&phy->mac_work);
940f4fdd771SFelix Fietkau 
941f4fdd771SFelix Fietkau 	mutex_lock(&dev->mutex);
942f4fdd771SFelix Fietkau 	set_bit(MT76_RESET, &phy->state);
943f4fdd771SFelix Fietkau 
9440b3be9d1SFelix Fietkau 	mt76_worker_disable(&dev->tx_worker);
9455a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
946c560b137SRyder Lee 	mt76_update_survey(phy);
94717f1de56SFelix Fietkau 
9483f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9493f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
9503f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9513f306448SFelix Fietkau 
95296747a51SFelix Fietkau 	phy->chandef = *chandef;
95396747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
954f4fdd771SFelix Fietkau 	phy->offchannel = offchannel;
95517f1de56SFelix Fietkau 
95617f1de56SFelix Fietkau 	if (!offchannel)
95796747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
95817f1de56SFelix Fietkau 
95996747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
96096747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
9610b3be9d1SFelix Fietkau 	mt76_worker_enable(&dev->tx_worker);
962f4fdd771SFelix Fietkau 
963f4fdd771SFelix Fietkau 	ret = dev->drv->set_channel(phy);
964f4fdd771SFelix Fietkau 
965f4fdd771SFelix Fietkau 	clear_bit(MT76_RESET, &phy->state);
966f4fdd771SFelix Fietkau 	mt76_worker_schedule(&dev->tx_worker);
967f4fdd771SFelix Fietkau 
968f4fdd771SFelix Fietkau 	mutex_unlock(&dev->mutex);
969f4fdd771SFelix Fietkau 
970f4fdd771SFelix Fietkau 	return ret;
97117f1de56SFelix Fietkau }
972f4fdd771SFelix Fietkau 
mt76_update_channel(struct mt76_phy * phy)973f4fdd771SFelix Fietkau int mt76_update_channel(struct mt76_phy *phy)
974f4fdd771SFelix Fietkau {
975f4fdd771SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
976f4fdd771SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
977f4fdd771SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
978f4fdd771SFelix Fietkau 
979f4fdd771SFelix Fietkau 	return mt76_set_channel(phy, chandef, offchannel);
980f4fdd771SFelix Fietkau }
981f4fdd771SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_channel);
98217f1de56SFelix Fietkau 
mt76_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)98317f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
98417f1de56SFelix Fietkau 		    struct survey_info *survey)
98517f1de56SFelix Fietkau {
98696747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
98796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
98817f1de56SFelix Fietkau 	struct mt76_sband *sband;
98917f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
99017f1de56SFelix Fietkau 	struct mt76_channel_state *state;
99117f1de56SFelix Fietkau 	int ret = 0;
99217f1de56SFelix Fietkau 
993237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
99417f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
995c560b137SRyder Lee 		mt76_update_survey(phy);
99617f1de56SFelix Fietkau 
997edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
998edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
999edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
1000edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
1001edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
1002edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
1003edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
100496747a51SFelix Fietkau 		sband = &phy->sband_5g;
1005edf9dab8SLorenzo Bianconi 	} else {
1006edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
100717f1de56SFelix Fietkau 	}
100817f1de56SFelix Fietkau 
1009237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
1010237312c5SLorenzo Bianconi 		ret = -ENOENT;
1011237312c5SLorenzo Bianconi 		goto out;
1012237312c5SLorenzo Bianconi 	}
101317f1de56SFelix Fietkau 
101417f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
101596747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
101617f1de56SFelix Fietkau 
101717f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
101817f1de56SFelix Fietkau 	survey->channel = chan;
101917f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
1020ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
1021e5051965SFelix Fietkau 	if (state->noise)
1022e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
1023e5051965SFelix Fietkau 
102496747a51SFelix Fietkau 	if (chan == phy->main_chan) {
102517f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
102617f1de56SFelix Fietkau 
10275ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
10285ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
10295ce09c1aSFelix Fietkau 	}
10305ce09c1aSFelix Fietkau 
103117f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
10326bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
1033237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
1034e5051965SFelix Fietkau 	survey->noise = state->noise;
1035237312c5SLorenzo Bianconi 
1036237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
1037237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
1038ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
103917f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
104017f1de56SFelix Fietkau 
1041237312c5SLorenzo Bianconi out:
1042237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1043237312c5SLorenzo Bianconi 
104417f1de56SFelix Fietkau 	return ret;
104517f1de56SFelix Fietkau }
104617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
104717f1de56SFelix Fietkau 
mt76_wcid_key_setup(struct mt76_dev * dev,struct mt76_wcid * wcid,struct ieee80211_key_conf * key)104830ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
104930ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
105030ce7f44SFelix Fietkau {
105130ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
105230ce7f44SFelix Fietkau 	int i;
105330ce7f44SFelix Fietkau 
105430ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
105530ce7f44SFelix Fietkau 
105630ce7f44SFelix Fietkau 	if (!key)
105730ce7f44SFelix Fietkau 		return;
105830ce7f44SFelix Fietkau 
105901cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
106001cfc1b4SLorenzo Bianconi 		return;
106130ce7f44SFelix Fietkau 
106201cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
1063a1b0bbd4SXing Song 
1064a1b0bbd4SXing Song 	/* data frame */
106530ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
106630ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
106730ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
106830ce7f44SFelix Fietkau 	}
1069a1b0bbd4SXing Song 
1070a1b0bbd4SXing Song 	/* robust management frame */
1071a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
1072a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
1073a1b0bbd4SXing Song 
107430ce7f44SFelix Fietkau }
107530ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
107630ce7f44SFelix Fietkau 
mt76_rx_signal(u8 chain_mask,s8 * chain_signal)1077a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10784550fb9eSFelix Fietkau {
10794550fb9eSFelix Fietkau 	int signal = -128;
10804550fb9eSFelix Fietkau 	u8 chains;
10814550fb9eSFelix Fietkau 
1082a71b648eSRyder Lee 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10834550fb9eSFelix Fietkau 		int cur, diff;
10844550fb9eSFelix Fietkau 
10856450b133SDeren Wu 		cur = *chain_signal;
10866450b133SDeren Wu 		if (!(chains & BIT(0)) ||
10876450b133SDeren Wu 		    cur > 0)
10884550fb9eSFelix Fietkau 			continue;
10894550fb9eSFelix Fietkau 
10904550fb9eSFelix Fietkau 		if (cur > signal)
10914550fb9eSFelix Fietkau 			swap(cur, signal);
10924550fb9eSFelix Fietkau 
10934550fb9eSFelix Fietkau 		diff = signal - cur;
10944550fb9eSFelix Fietkau 		if (diff == 0)
10954550fb9eSFelix Fietkau 			signal += 3;
10964550fb9eSFelix Fietkau 		else if (diff <= 2)
10974550fb9eSFelix Fietkau 			signal += 2;
10984550fb9eSFelix Fietkau 		else if (diff <= 6)
10994550fb9eSFelix Fietkau 			signal += 1;
11004550fb9eSFelix Fietkau 	}
11014550fb9eSFelix Fietkau 
11024550fb9eSFelix Fietkau 	return signal;
11034550fb9eSFelix Fietkau }
1104a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
11054550fb9eSFelix Fietkau 
1106bfc394ddSFelix Fietkau static void
mt76_rx_convert(struct mt76_dev * dev,struct sk_buff * skb,struct ieee80211_hw ** hw,struct ieee80211_sta ** sta)1107bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
1108bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
1109bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
11104e34249eSFelix Fietkau {
11114e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1112abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
11134e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
11144e34249eSFelix Fietkau 
11154e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
11164e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
11174e34249eSFelix Fietkau 
11184e34249eSFelix Fietkau 	status->flag = mstat.flag;
11194e34249eSFelix Fietkau 	status->freq = mstat.freq;
11204e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
11214e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
11224e34249eSFelix Fietkau 	status->bw = mstat.bw;
1123021af945SShayne Chen 	if (status->encoding == RX_ENC_EHT) {
1124021af945SShayne Chen 		status->eht.ru = mstat.eht.ru;
1125021af945SShayne Chen 		status->eht.gi = mstat.eht.gi;
1126021af945SShayne Chen 	} else {
1127af4a2f2fSRyder Lee 		status->he_ru = mstat.he_ru;
1128af4a2f2fSRyder Lee 		status->he_gi = mstat.he_gi;
1129af4a2f2fSRyder Lee 		status->he_dcm = mstat.he_dcm;
1130021af945SShayne Chen 	}
11314e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
11324e34249eSFelix Fietkau 	status->nss = mstat.nss;
11334e34249eSFelix Fietkau 	status->band = mstat.band;
11344e34249eSFelix Fietkau 	status->signal = mstat.signal;
11354e34249eSFelix Fietkau 	status->chains = mstat.chains;
1136d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
11370fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
11380fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
1139a71b648eSRyder Lee 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
11404550fb9eSFelix Fietkau 	if (status->signal <= -128)
11414550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
11424e34249eSFelix Fietkau 
1143abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
1144abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
1145abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1146abe3f3daSRyder Lee 
11474e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
114813381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
114913381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
115013381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
115113381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
11529c68a57bSFelix Fietkau 
11534f0f33d2SSean Wang 	if (mstat.wcid) {
11544f0f33d2SSean Wang 		status->link_valid = mstat.wcid->link_valid;
11554f0f33d2SSean Wang 		status->link_id = mstat.wcid->link_id;
11564f0f33d2SSean Wang 	}
11574f0f33d2SSean Wang 
1158bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1159128c9b7dSLorenzo Bianconi 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
11604e34249eSFelix Fietkau }
11614e34249eSFelix Fietkau 
11623c1032e1SFelix Fietkau static void
mt76_check_ccmp_pn(struct sk_buff * skb)116330ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
116430ce7f44SFelix Fietkau {
116530ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
116630ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
116730ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1168a1b0bbd4SXing Song 	int security_idx;
116930ce7f44SFelix Fietkau 	int ret;
117030ce7f44SFelix Fietkau 
117130ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
11723c1032e1SFelix Fietkau 		return;
117330ce7f44SFelix Fietkau 
11741858e4fcSMeiChia Chiu 	if (status->flag & RX_FLAG_ONLY_MONITOR)
11753c1032e1SFelix Fietkau 		return;
11761858e4fcSMeiChia Chiu 
117730ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
11783c1032e1SFelix Fietkau 		return;
117930ce7f44SFelix Fietkau 
11807360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11817360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
11827360cdecSFelix Fietkau 		goto skip_hdr_check;
11837360cdecSFelix Fietkau 
1184a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
118530ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
118630ce7f44SFelix Fietkau 		/*
118730ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
118830ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
118930ce7f44SFelix Fietkau 		 */
119030ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
119130ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
11923c1032e1SFelix Fietkau 			return;
119330ce7f44SFelix Fietkau 	}
119430ce7f44SFelix Fietkau 
1195a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1196a1b0bbd4SXing Song 	 *
1197a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1198a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1199a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1200a1b0bbd4SXing Song 	 */
1201a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1202a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1203a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1204a1b0bbd4SXing Song 
12057360cdecSFelix Fietkau skip_hdr_check:
120630ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1207a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
120830ce7f44SFelix Fietkau 		     sizeof(status->iv));
12093c1032e1SFelix Fietkau 	if (ret <= 0) {
12103c1032e1SFelix Fietkau 		status->flag |= RX_FLAG_ONLY_MONITOR;
12113c1032e1SFelix Fietkau 		return;
12123c1032e1SFelix Fietkau 	}
121330ce7f44SFelix Fietkau 
1214a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
121530ce7f44SFelix Fietkau 
121630ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
121730ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
121830ce7f44SFelix Fietkau }
121930ce7f44SFelix Fietkau 
1220d71ef286SFelix Fietkau static void
mt76_airtime_report(struct mt76_dev * dev,struct mt76_rx_status * status,int len)12215ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
12225ce09c1aSFelix Fietkau 		    int len)
12235ce09c1aSFelix Fietkau {
12245ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
122585b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
122685b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
122785b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
122885b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
122985b7a5d0SLorenzo Bianconi 		.band = status->band,
123085b7a5d0SLorenzo Bianconi 		.nss = status->nss,
123185b7a5d0SLorenzo Bianconi 		.bw = status->bw,
123285b7a5d0SLorenzo Bianconi 	};
12335ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
12345ce09c1aSFelix Fietkau 	u32 airtime;
1235e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
12365ce09c1aSFelix Fietkau 
123785b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1238237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
12395ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1240237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
12415ce09c1aSFelix Fietkau 
12425ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
12435ce09c1aSFelix Fietkau 		return;
12445ce09c1aSFelix Fietkau 
12455ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1246e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
12475ce09c1aSFelix Fietkau }
12485ce09c1aSFelix Fietkau 
12495ce09c1aSFelix Fietkau static void
mt76_airtime_flush_ampdu(struct mt76_dev * dev)12505ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
12515ce09c1aSFelix Fietkau {
12525ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
12535ce09c1aSFelix Fietkau 	int wcid_idx;
12545ce09c1aSFelix Fietkau 
12555ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
12565ce09c1aSFelix Fietkau 		return;
12575ce09c1aSFelix Fietkau 
12585ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1259bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
12605ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
12615ce09c1aSFelix Fietkau 	else
12625ce09c1aSFelix Fietkau 		wcid = NULL;
12635ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
12645ce09c1aSFelix Fietkau 
12655ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
12665ce09c1aSFelix Fietkau 
12675ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
12685ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
12695ce09c1aSFelix Fietkau }
12705ce09c1aSFelix Fietkau 
12715ce09c1aSFelix Fietkau static void
mt76_airtime_check(struct mt76_dev * dev,struct sk_buff * skb)12725ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12735ce09c1aSFelix Fietkau {
12745ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12755ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
12765ce09c1aSFelix Fietkau 
12775ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12785ce09c1aSFelix Fietkau 		return;
12795ce09c1aSFelix Fietkau 
12805ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1281e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1282e195dad1SFelix Fietkau 
1283e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1284e195dad1SFelix Fietkau 			return;
1285e195dad1SFelix Fietkau 
128698df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12875ce09c1aSFelix Fietkau 			return;
12885ce09c1aSFelix Fietkau 
12895ce09c1aSFelix Fietkau 		wcid = NULL;
12905ce09c1aSFelix Fietkau 	}
12915ce09c1aSFelix Fietkau 
12925ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12935ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
12945ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
12955ce09c1aSFelix Fietkau 
12965ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12975ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
12985ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
12995ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
13005ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
13015ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
13025ce09c1aSFelix Fietkau 		}
13035ce09c1aSFelix Fietkau 
13045ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
13055ce09c1aSFelix Fietkau 		return;
13065ce09c1aSFelix Fietkau 	}
13075ce09c1aSFelix Fietkau 
13085ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
13095ce09c1aSFelix Fietkau }
13105ce09c1aSFelix Fietkau 
13115ce09c1aSFelix Fietkau static void
mt76_check_sta(struct mt76_dev * dev,struct sk_buff * skb)1312ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1313d71ef286SFelix Fietkau {
1314d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
131577ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1316d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1317bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1318d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1319e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1320d71ef286SFelix Fietkau 	bool ps;
1321d71ef286SFelix Fietkau 
1322128c9b7dSLorenzo Bianconi 	hw = mt76_phy_hw(dev, status->phy_idx);
1323e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1324e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1325bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
132636d91096SFelix Fietkau 		if (sta)
132736d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
132836d91096SFelix Fietkau 	}
132936d91096SFelix Fietkau 
13305ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
13315ce09c1aSFelix Fietkau 
1332d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1333d71ef286SFelix Fietkau 		return;
1334d71ef286SFelix Fietkau 
1335d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1336d71ef286SFelix Fietkau 
133702e5a769SFelix Fietkau 	if (status->signal <= 0)
133802e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
133902e5a769SFelix Fietkau 
1340ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1341ef13edc0SFelix Fietkau 
1342e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1343e195dad1SFelix Fietkau 		return;
1344e195dad1SFelix Fietkau 
1345d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1346d71ef286SFelix Fietkau 		return;
1347d71ef286SFelix Fietkau 
1348d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1349d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1350d71ef286SFelix Fietkau 		return;
1351d71ef286SFelix Fietkau 	}
1352d71ef286SFelix Fietkau 
1353d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1354d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1355d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1356d71ef286SFelix Fietkau 		return;
1357d71ef286SFelix Fietkau 
1358d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1359d71ef286SFelix Fietkau 
1360d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1361d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1362e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1363d71ef286SFelix Fietkau 
1364d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1365d71ef286SFelix Fietkau 		return;
1366d71ef286SFelix Fietkau 
136711b2a25fSFelix Fietkau 	if (ps)
1368d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1369d71ef286SFelix Fietkau 
1370f28c3139SLorenzo Bianconi 	if (dev->drv->sta_ps)
1371d71ef286SFelix Fietkau 		dev->drv->sta_ps(dev, sta, ps);
1372608f7c47SFelix Fietkau 
1373608f7c47SFelix Fietkau 	if (!ps)
1374608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1375608f7c47SFelix Fietkau 
13769f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1377d71ef286SFelix Fietkau }
1378d71ef286SFelix Fietkau 
mt76_rx_complete(struct mt76_dev * dev,struct sk_buff_head * frames,struct napi_struct * napi)13799d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
138081e850efSLorenzo Bianconi 		      struct napi_struct *napi)
138117f1de56SFelix Fietkau {
13829c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1383bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
13843298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
13853298b1f8SFelix Fietkau 	LIST_HEAD(list);
13869d9d738bSFelix Fietkau 
1387c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
13889d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1389cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1390cc4b3c13SLorenzo Bianconi 
13913c1032e1SFelix Fietkau 		mt76_check_ccmp_pn(skb);
1392cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1393bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
13943298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1395cc4b3c13SLorenzo Bianconi 
1396cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1397cc4b3c13SLorenzo Bianconi 		while (nskb) {
1398cc4b3c13SLorenzo Bianconi 			skb = nskb;
1399cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1400cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1401cc4b3c13SLorenzo Bianconi 
1402cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1403cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1404cc4b3c13SLorenzo Bianconi 		}
14059d9d738bSFelix Fietkau 	}
1406c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
14073298b1f8SFelix Fietkau 
14083298b1f8SFelix Fietkau 	if (!napi) {
14093298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
14103298b1f8SFelix Fietkau 		return;
14113298b1f8SFelix Fietkau 	}
14123298b1f8SFelix Fietkau 
14133298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
14143298b1f8SFelix Fietkau 		skb_list_del_init(skb);
14153298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
14163298b1f8SFelix Fietkau 	}
14179d9d738bSFelix Fietkau }
14189d9d738bSFelix Fietkau 
mt76_rx_poll_complete(struct mt76_dev * dev,enum mt76_rxq_id q,struct napi_struct * napi)141981e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
142081e850efSLorenzo Bianconi 			   struct napi_struct *napi)
14219d9d738bSFelix Fietkau {
1422aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
142317f1de56SFelix Fietkau 	struct sk_buff *skb;
142417f1de56SFelix Fietkau 
1425aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1426aee5b8cfSFelix Fietkau 
1427d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1428ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
14294f831d18SLorenzo Bianconi 		if (mtk_wed_device_active(&dev->mmio.wed))
14304f831d18SLorenzo Bianconi 			__skb_queue_tail(&frames, skb);
14314f831d18SLorenzo Bianconi 		else
1432aee5b8cfSFelix Fietkau 			mt76_rx_aggr_reorder(skb, &frames);
1433d71ef286SFelix Fietkau 	}
1434aee5b8cfSFelix Fietkau 
143581e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
14364e34249eSFelix Fietkau }
143781e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1438723b90dcSFelix Fietkau 
1439e28487eaSFelix Fietkau static int
mt76_sta_add(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1440a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1441a1a99d7bSLorenzo Bianconi 	     struct ieee80211_sta *sta)
1442e28487eaSFelix Fietkau {
1443e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1444a1a99d7bSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1445e28487eaSFelix Fietkau 	int ret;
1446e28487eaSFelix Fietkau 	int i;
1447e28487eaSFelix Fietkau 
1448e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1449e28487eaSFelix Fietkau 
1450e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1451e28487eaSFelix Fietkau 	if (ret)
1452e28487eaSFelix Fietkau 		goto out;
1453e28487eaSFelix Fietkau 
1454e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1455e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1456e28487eaSFelix Fietkau 
1457e28487eaSFelix Fietkau 		if (!sta->txq[i])
1458e28487eaSFelix Fietkau 			continue;
1459e28487eaSFelix Fietkau 
1460e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
146151fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1462e28487eaSFelix Fietkau 	}
1463e28487eaSFelix Fietkau 
1464ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1465a1a99d7bSLorenzo Bianconi 	if (phy->band_idx == MT_BAND1)
1466426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1467a1a99d7bSLorenzo Bianconi 	wcid->phy_idx = phy->band_idx;
1468e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1469e28487eaSFelix Fietkau 
14700335c034SFelix Fietkau 	mt76_wcid_init(wcid);
1471e28487eaSFelix Fietkau out:
1472e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1473e28487eaSFelix Fietkau 
1474e28487eaSFelix Fietkau 	return ret;
1475e28487eaSFelix Fietkau }
1476e28487eaSFelix Fietkau 
__mt76_sta_remove(struct mt76_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)147713f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1478723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1479723b90dcSFelix Fietkau {
1480723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
148113f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1482723b90dcSFelix Fietkau 
148358bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
148458bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
148558bab0d4SFelix Fietkau 
1486e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1487e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1488e28487eaSFelix Fietkau 
14890335c034SFelix Fietkau 	mt76_wcid_cleanup(dev, wcid);
1490bd1e3e7bSLorenzo Bianconi 
1491426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1492426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
149313f61dfcSLorenzo Bianconi }
149413f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1495e28487eaSFelix Fietkau 
149613f61dfcSLorenzo Bianconi static void
mt76_sta_remove(struct mt76_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)149713f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
149813f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
149913f61dfcSLorenzo Bianconi {
150013f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
150113f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1502723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1503723b90dcSFelix Fietkau }
1504e28487eaSFelix Fietkau 
mt76_sta_state(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,enum ieee80211_sta_state old_state,enum ieee80211_sta_state new_state)1505e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1506e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1507e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1508e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1509e28487eaSFelix Fietkau {
1510426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1511426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1512*17b0f68aSFelix Fietkau 	enum mt76_sta_event ev;
1513e28487eaSFelix Fietkau 
1514e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1515e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1516a1a99d7bSLorenzo Bianconi 		return mt76_sta_add(phy, vif, sta);
1517e28487eaSFelix Fietkau 
1518e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1519e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1520e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1521e28487eaSFelix Fietkau 
1522*17b0f68aSFelix Fietkau 	if (!dev->drv->sta_event)
1523e28487eaSFelix Fietkau 		return 0;
1524*17b0f68aSFelix Fietkau 
1525*17b0f68aSFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
1526*17b0f68aSFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC)
1527*17b0f68aSFelix Fietkau 		ev = MT76_STA_EVENT_ASSOC;
1528*17b0f68aSFelix Fietkau 	else if (old_state == IEEE80211_STA_ASSOC &&
1529*17b0f68aSFelix Fietkau 		 new_state == IEEE80211_STA_AUTHORIZED)
1530*17b0f68aSFelix Fietkau 		ev = MT76_STA_EVENT_AUTHORIZE;
1531*17b0f68aSFelix Fietkau 	else if (old_state == IEEE80211_STA_ASSOC &&
1532*17b0f68aSFelix Fietkau 		 new_state == IEEE80211_STA_AUTH)
1533*17b0f68aSFelix Fietkau 		ev = MT76_STA_EVENT_DISASSOC;
1534*17b0f68aSFelix Fietkau 	else
1535*17b0f68aSFelix Fietkau 		return 0;
1536*17b0f68aSFelix Fietkau 
1537*17b0f68aSFelix Fietkau 	return dev->drv->sta_event(dev, vif, sta, ev);
1538e28487eaSFelix Fietkau }
1539e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
15409313faacSFelix Fietkau 
mt76_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)154143ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
154243ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
154343ba1922SFelix Fietkau {
154443ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
154543ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
154643ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
154743ba1922SFelix Fietkau 
154843ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1549fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
155043ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1551fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
155243ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
155343ba1922SFelix Fietkau }
155443ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
155543ba1922SFelix Fietkau 
mt76_wcid_init(struct mt76_wcid * wcid)15560335c034SFelix Fietkau void mt76_wcid_init(struct mt76_wcid *wcid)
15570335c034SFelix Fietkau {
15580335c034SFelix Fietkau 	INIT_LIST_HEAD(&wcid->tx_list);
15590335c034SFelix Fietkau 	skb_queue_head_init(&wcid->tx_pending);
15600b3be9d1SFelix Fietkau 	skb_queue_head_init(&wcid->tx_offchannel);
15610335c034SFelix Fietkau 
15620335c034SFelix Fietkau 	INIT_LIST_HEAD(&wcid->list);
15630335c034SFelix Fietkau 	idr_init(&wcid->pktid);
15640335c034SFelix Fietkau }
15650335c034SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_init);
15660335c034SFelix Fietkau 
mt76_wcid_cleanup(struct mt76_dev * dev,struct mt76_wcid * wcid)15670335c034SFelix Fietkau void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
15680335c034SFelix Fietkau {
1569862bf7cbSBjørn Mork 	struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx);
15700335c034SFelix Fietkau 	struct ieee80211_hw *hw;
15710335c034SFelix Fietkau 	struct sk_buff_head list;
15720335c034SFelix Fietkau 	struct sk_buff *skb;
15730335c034SFelix Fietkau 
15740335c034SFelix Fietkau 	mt76_tx_status_lock(dev, &list);
15750335c034SFelix Fietkau 	mt76_tx_status_skb_get(dev, wcid, -1, &list);
15760335c034SFelix Fietkau 	mt76_tx_status_unlock(dev, &list);
15770335c034SFelix Fietkau 
15780335c034SFelix Fietkau 	idr_destroy(&wcid->pktid);
15790335c034SFelix Fietkau 
15800335c034SFelix Fietkau 	spin_lock_bh(&phy->tx_lock);
15810335c034SFelix Fietkau 
15820335c034SFelix Fietkau 	if (!list_empty(&wcid->tx_list))
15830335c034SFelix Fietkau 		list_del_init(&wcid->tx_list);
15840335c034SFelix Fietkau 
15850335c034SFelix Fietkau 	spin_lock(&wcid->tx_pending.lock);
15860335c034SFelix Fietkau 	skb_queue_splice_tail_init(&wcid->tx_pending, &list);
15870335c034SFelix Fietkau 	spin_unlock(&wcid->tx_pending.lock);
15880335c034SFelix Fietkau 
15890335c034SFelix Fietkau 	spin_unlock_bh(&phy->tx_lock);
15900335c034SFelix Fietkau 
15910335c034SFelix Fietkau 	while ((skb = __skb_dequeue(&list)) != NULL) {
15920335c034SFelix Fietkau 		hw = mt76_tx_status_get_hw(dev, skb);
15930335c034SFelix Fietkau 		ieee80211_free_txskb(hw, skb);
15940335c034SFelix Fietkau 	}
15950335c034SFelix Fietkau }
15960335c034SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
15970335c034SFelix Fietkau 
mt76_get_txpower(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int * dbm)15989313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15999313faacSFelix Fietkau 		     int *dbm)
16009313faacSFelix Fietkau {
1601beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
16021e12f0f8SAllen Ye 	int n_chains = hweight16(phy->chainmask);
160307cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
16049313faacSFelix Fietkau 
160507cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
16069313faacSFelix Fietkau 
16079313faacSFelix Fietkau 	return 0;
16089313faacSFelix Fietkau }
16099313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1610e7173858SFelix Fietkau 
mt76_init_sar_power(struct ieee80211_hw * hw,const struct cfg80211_sar_specs * sar)1611b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1612b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1613b3cb885eSLorenzo Bianconi {
1614b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1615b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1616b3cb885eSLorenzo Bianconi 	int i;
1617b3cb885eSLorenzo Bianconi 
1618b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1619b3cb885eSLorenzo Bianconi 		return -EINVAL;
1620b3cb885eSLorenzo Bianconi 
1621b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1622b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1623b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1624b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1625b3cb885eSLorenzo Bianconi 
1626b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1627b3cb885eSLorenzo Bianconi 			power = 127;
1628b3cb885eSLorenzo Bianconi 
1629b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1630b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1631b3cb885eSLorenzo Bianconi 	}
1632b3cb885eSLorenzo Bianconi 
1633b3cb885eSLorenzo Bianconi 	return 0;
1634b3cb885eSLorenzo Bianconi }
1635b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1636b3cb885eSLorenzo Bianconi 
mt76_get_sar_power(struct mt76_phy * phy,struct ieee80211_channel * chan,int power)1637b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1638b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1639b3cb885eSLorenzo Bianconi 		       int power)
1640b3cb885eSLorenzo Bianconi {
1641b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1642b3cb885eSLorenzo Bianconi 	int freq, i;
1643b3cb885eSLorenzo Bianconi 
1644b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1645b3cb885eSLorenzo Bianconi 		return power;
1646b3cb885eSLorenzo Bianconi 
1647b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1648b3cb885eSLorenzo Bianconi 		power = 127;
1649b3cb885eSLorenzo Bianconi 
1650b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1651b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1652b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1653b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1654b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1655b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1656b3cb885eSLorenzo Bianconi 			break;
1657b3cb885eSLorenzo Bianconi 		}
1658b3cb885eSLorenzo Bianconi 	}
1659b3cb885eSLorenzo Bianconi 
1660b3cb885eSLorenzo Bianconi 	return power;
1661b3cb885eSLorenzo Bianconi }
1662b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1663b3cb885eSLorenzo Bianconi 
1664e7173858SFelix Fietkau static void
__mt76_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)1665e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1666e7173858SFelix Fietkau {
16676030b3a4SAditya Kumar Singh 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0))
166804ada859SAditya Kumar Singh 		ieee80211_csa_finish(vif, 0);
1669e7173858SFelix Fietkau }
1670e7173858SFelix Fietkau 
mt76_csa_finish(struct mt76_dev * dev)1671e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1672e7173858SFelix Fietkau {
1673e7173858SFelix Fietkau 	if (!dev->csa_complete)
1674e7173858SFelix Fietkau 		return;
1675e7173858SFelix Fietkau 
1676e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1677e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1678e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1679e7173858SFelix Fietkau 
1680e7173858SFelix Fietkau 	dev->csa_complete = 0;
1681e7173858SFelix Fietkau }
1682e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1683e7173858SFelix Fietkau 
1684e7173858SFelix Fietkau static void
__mt76_csa_check(void * priv,u8 * mac,struct ieee80211_vif * vif)1685e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1686e7173858SFelix Fietkau {
1687e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1688e7173858SFelix Fietkau 
1689d0a9123eSJohannes Berg 	if (!vif->bss_conf.csa_active)
1690e7173858SFelix Fietkau 		return;
1691e7173858SFelix Fietkau 
16926030b3a4SAditya Kumar Singh 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0);
1693e7173858SFelix Fietkau }
1694e7173858SFelix Fietkau 
mt76_csa_check(struct mt76_dev * dev)1695e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1696e7173858SFelix Fietkau {
1697e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1698e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1699e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1700e7173858SFelix Fietkau }
1701e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
170287d53103SStanislaw Gruszka 
170387d53103SStanislaw Gruszka int
mt76_set_tim(struct ieee80211_hw * hw,struct ieee80211_sta * sta,bool set)170487d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
170587d53103SStanislaw Gruszka {
170687d53103SStanislaw Gruszka 	return 0;
170787d53103SStanislaw Gruszka }
170887d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1709eadfd98fSLorenzo Bianconi 
mt76_insert_ccmp_hdr(struct sk_buff * skb,u8 key_id)1710eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1711eadfd98fSLorenzo Bianconi {
1712eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1713eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1714eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1715eadfd98fSLorenzo Bianconi 
1716eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1717eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1718eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1719eadfd98fSLorenzo Bianconi 
1720eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1721eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1722eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1723eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1724eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1725eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1726eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1727eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1728eadfd98fSLorenzo Bianconi 
1729eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1730eadfd98fSLorenzo Bianconi }
1731eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1732d2679d65SLorenzo Bianconi 
mt76_get_rate(struct mt76_dev * dev,struct ieee80211_supported_band * sband,int idx,bool cck)1733d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1734d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1735d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1736d2679d65SLorenzo Bianconi {
1737e43b87f6SFelix Fietkau 	bool is_2g = sband->band == NL80211_BAND_2GHZ;
1738d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1739d2679d65SLorenzo Bianconi 
1740d2679d65SLorenzo Bianconi 	if (cck) {
1741e43b87f6SFelix Fietkau 		if (!is_2g)
1742d2679d65SLorenzo Bianconi 			return 0;
1743d2679d65SLorenzo Bianconi 
1744d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
1745e43b87f6SFelix Fietkau 	} else if (is_2g) {
1746d2679d65SLorenzo Bianconi 		offset = 4;
1747d2679d65SLorenzo Bianconi 	}
1748d2679d65SLorenzo Bianconi 
1749d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1750d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1751d2679d65SLorenzo Bianconi 			return i;
1752d2679d65SLorenzo Bianconi 	}
1753d2679d65SLorenzo Bianconi 
1754d2679d65SLorenzo Bianconi 	return 0;
1755d2679d65SLorenzo Bianconi }
1756d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
17578b8ab5c2SLorenzo Bianconi 
mt76_sw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * mac)17588b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
17598b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
17608b8ab5c2SLorenzo Bianconi {
1761011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
17628b8ab5c2SLorenzo Bianconi 
1763011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
17648b8ab5c2SLorenzo Bianconi }
17658b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
17668b8ab5c2SLorenzo Bianconi 
mt76_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)17678b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
17688b8ab5c2SLorenzo Bianconi {
1769011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
17708b8ab5c2SLorenzo Bianconi 
1771011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
17728b8ab5c2SLorenzo Bianconi }
17738b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1774e49c76d4SLorenzo Bianconi 
mt76_get_antenna(struct ieee80211_hw * hw,u32 * tx_ant,u32 * rx_ant)1775e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1776e49c76d4SLorenzo Bianconi {
1777beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1778beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1779e49c76d4SLorenzo Bianconi 
1780e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1781beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1782beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1783e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1784e49c76d4SLorenzo Bianconi 
1785e49c76d4SLorenzo Bianconi 	return 0;
1786e49c76d4SLorenzo Bianconi }
1787e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1788b671da33SLorenzo Bianconi 
1789b1cb42adSLorenzo Bianconi struct mt76_queue *
mt76_init_queue(struct mt76_dev * dev,int qid,int idx,int n_desc,int ring_base,void * wed,u32 flags)1790b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
17912e420b88SLorenzo Bianconi 		int ring_base, void *wed, u32 flags)
1792b671da33SLorenzo Bianconi {
1793b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1794b671da33SLorenzo Bianconi 	int err;
1795b671da33SLorenzo Bianconi 
1796b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1797b671da33SLorenzo Bianconi 	if (!hwq)
1798b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1799b671da33SLorenzo Bianconi 
1800f68d6762SFelix Fietkau 	hwq->flags = flags;
18012e420b88SLorenzo Bianconi 	hwq->wed = wed;
1802f68d6762SFelix Fietkau 
1803b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1804b671da33SLorenzo Bianconi 	if (err < 0)
1805b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1806b671da33SLorenzo Bianconi 
1807b1cb42adSLorenzo Bianconi 	return hwq;
1808b671da33SLorenzo Bianconi }
1809b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1810e4867225SSean Wang 
mt76_calculate_default_rate(struct mt76_phy * phy,struct ieee80211_vif * vif,int rateidx)181132b1000dSSean Wang u16 mt76_calculate_default_rate(struct mt76_phy *phy,
181232b1000dSSean Wang 				struct ieee80211_vif *vif, int rateidx)
1813e4867225SSean Wang {
181432b1000dSSean Wang 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
181532b1000dSSean Wang 	struct cfg80211_chan_def *chandef = mvif->ctx ?
181632b1000dSSean Wang 					    &mvif->ctx->def :
181732b1000dSSean Wang 					    &phy->chandef;
181833920b2bSRyder Lee 	int offset = 0;
1819e4867225SSean Wang 
182032b1000dSSean Wang 	if (chandef->chan->band != NL80211_BAND_2GHZ)
1821e4867225SSean Wang 		offset = 4;
1822e4867225SSean Wang 
182333920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
182433920b2bSRyder Lee 	if (rateidx < 0)
182533920b2bSRyder Lee 		rateidx = 0;
182633920b2bSRyder Lee 
1827d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1828d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1829d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1830e4867225SSean Wang 
1831d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1832e4867225SSean Wang }
183333920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
183454ae98ffSLorenzo Bianconi 
mt76_ethtool_worker(struct mt76_ethtool_worker_info * wi,struct mt76_sta_stats * stats,bool eht)183554ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1836731425f3SShayne Chen 			 struct mt76_sta_stats *stats, bool eht)
183754ae98ffSLorenzo Bianconi {
183854ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
183954ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
184054ae98ffSLorenzo Bianconi 
184154ae98ffSLorenzo Bianconi 	wi->sta_count++;
184254ae98ffSLorenzo Bianconi 
184354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
184454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
184554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
184654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
184754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
184854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
184954ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
185054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
185154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1852731425f3SShayne Chen 	if (eht) {
1853731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1854731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1855731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1856731425f3SShayne Chen 	}
185754ae98ffSLorenzo Bianconi 
1858731425f3SShayne Chen 	for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
185954ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
186054ae98ffSLorenzo Bianconi 
1861731425f3SShayne Chen 	for (i = 0; i < (eht ? 14 : 12); i++)
186254ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
186354ae98ffSLorenzo Bianconi 
1864749c2c2bSRyder Lee 	for (i = 0; i < 4; i++)
1865749c2c2bSRyder Lee 		data[ei++] += stats->tx_nss[i];
1866749c2c2bSRyder Lee 
186754ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
186854ae98ffSLorenzo Bianconi }
186954ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
18703f306448SFelix Fietkau 
mt76_ethtool_page_pool_stats(struct mt76_dev * dev,u64 * data,int * index)1871192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1872192ad406SLorenzo Bianconi {
1873192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS
1874192ad406SLorenzo Bianconi 	struct page_pool_stats stats = {};
1875192ad406SLorenzo Bianconi 	int i;
1876192ad406SLorenzo Bianconi 
1877192ad406SLorenzo Bianconi 	mt76_for_each_q_rx(dev, i)
1878192ad406SLorenzo Bianconi 		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
1879192ad406SLorenzo Bianconi 
1880192ad406SLorenzo Bianconi 	page_pool_ethtool_stats_get(data, &stats);
1881192ad406SLorenzo Bianconi 	*index += page_pool_ethtool_stats_get_count();
1882192ad406SLorenzo Bianconi #endif
1883192ad406SLorenzo Bianconi }
1884192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
1885192ad406SLorenzo Bianconi 
mt76_phy_dfs_state(struct mt76_phy * phy)18863f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
18873f306448SFelix Fietkau {
18883f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
18893f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
18903f306448SFelix Fietkau 
18913f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
18923f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
18933f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
18943f306448SFelix Fietkau 
18953f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
18963f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
18973f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
18983f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
18993f306448SFelix Fietkau 
19003f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
19013f306448SFelix Fietkau 	}
19023f306448SFelix Fietkau 
190300a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
19043f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
19053f306448SFelix Fietkau 
19063f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
19073f306448SFelix Fietkau }
19083f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1909