xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision c278a64a9375b5410a25d3e17317c36ee9e2fd02)
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>
72f5c3c77SLorenzo Bianconi #include <net/page_pool.h>
817f1de56SFelix Fietkau #include "mt76.h"
917f1de56SFelix Fietkau 
1017f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
1117f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1217f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1317f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1417f1de56SFelix Fietkau 	.max_power = 30,			\
1517f1de56SFelix Fietkau }
1617f1de56SFelix Fietkau 
1717f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1817f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1917f1de56SFelix Fietkau 	.center_freq = (_freq),			\
2017f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2117f1de56SFelix Fietkau 	.max_power = 30,			\
2217f1de56SFelix Fietkau }
2317f1de56SFelix Fietkau 
24edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) {			\
25edf9dab8SLorenzo Bianconi 	.band = NL80211_BAND_6GHZ,		\
26edf9dab8SLorenzo Bianconi 	.center_freq = (_freq),			\
27edf9dab8SLorenzo Bianconi 	.hw_value = (_idx),			\
28edf9dab8SLorenzo Bianconi 	.max_power = 30,			\
29edf9dab8SLorenzo Bianconi }
30edf9dab8SLorenzo Bianconi 
3117f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3217f1de56SFelix Fietkau 	CHAN2G(1, 2412),
3317f1de56SFelix Fietkau 	CHAN2G(2, 2417),
3417f1de56SFelix Fietkau 	CHAN2G(3, 2422),
3517f1de56SFelix Fietkau 	CHAN2G(4, 2427),
3617f1de56SFelix Fietkau 	CHAN2G(5, 2432),
3717f1de56SFelix Fietkau 	CHAN2G(6, 2437),
3817f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3917f1de56SFelix Fietkau 	CHAN2G(8, 2447),
4017f1de56SFelix Fietkau 	CHAN2G(9, 2452),
4117f1de56SFelix Fietkau 	CHAN2G(10, 2457),
4217f1de56SFelix Fietkau 	CHAN2G(11, 2462),
4317f1de56SFelix Fietkau 	CHAN2G(12, 2467),
4417f1de56SFelix Fietkau 	CHAN2G(13, 2472),
4517f1de56SFelix Fietkau 	CHAN2G(14, 2484),
4617f1de56SFelix Fietkau };
4717f1de56SFelix Fietkau 
4817f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4917f1de56SFelix Fietkau 	CHAN5G(36, 5180),
5017f1de56SFelix Fietkau 	CHAN5G(40, 5200),
5117f1de56SFelix Fietkau 	CHAN5G(44, 5220),
5217f1de56SFelix Fietkau 	CHAN5G(48, 5240),
5317f1de56SFelix Fietkau 
5417f1de56SFelix Fietkau 	CHAN5G(52, 5260),
5517f1de56SFelix Fietkau 	CHAN5G(56, 5280),
5617f1de56SFelix Fietkau 	CHAN5G(60, 5300),
5717f1de56SFelix Fietkau 	CHAN5G(64, 5320),
5817f1de56SFelix Fietkau 
5917f1de56SFelix Fietkau 	CHAN5G(100, 5500),
6017f1de56SFelix Fietkau 	CHAN5G(104, 5520),
6117f1de56SFelix Fietkau 	CHAN5G(108, 5540),
6217f1de56SFelix Fietkau 	CHAN5G(112, 5560),
6317f1de56SFelix Fietkau 	CHAN5G(116, 5580),
6417f1de56SFelix Fietkau 	CHAN5G(120, 5600),
6517f1de56SFelix Fietkau 	CHAN5G(124, 5620),
6617f1de56SFelix Fietkau 	CHAN5G(128, 5640),
6717f1de56SFelix Fietkau 	CHAN5G(132, 5660),
6817f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6917f1de56SFelix Fietkau 	CHAN5G(140, 5700),
709da82fb7SMarkus Theil 	CHAN5G(144, 5720),
7117f1de56SFelix Fietkau 
7217f1de56SFelix Fietkau 	CHAN5G(149, 5745),
7317f1de56SFelix Fietkau 	CHAN5G(153, 5765),
7417f1de56SFelix Fietkau 	CHAN5G(157, 5785),
7517f1de56SFelix Fietkau 	CHAN5G(161, 5805),
7617f1de56SFelix Fietkau 	CHAN5G(165, 5825),
779da82fb7SMarkus Theil 	CHAN5G(169, 5845),
789da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7917f1de56SFelix Fietkau };
8017f1de56SFelix Fietkau 
81edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = {
82edf9dab8SLorenzo Bianconi 	/* UNII-5 */
83edf9dab8SLorenzo Bianconi 	CHAN6G(1, 5955),
84edf9dab8SLorenzo Bianconi 	CHAN6G(5, 5975),
85edf9dab8SLorenzo Bianconi 	CHAN6G(9, 5995),
86edf9dab8SLorenzo Bianconi 	CHAN6G(13, 6015),
87edf9dab8SLorenzo Bianconi 	CHAN6G(17, 6035),
88edf9dab8SLorenzo Bianconi 	CHAN6G(21, 6055),
89edf9dab8SLorenzo Bianconi 	CHAN6G(25, 6075),
90edf9dab8SLorenzo Bianconi 	CHAN6G(29, 6095),
91edf9dab8SLorenzo Bianconi 	CHAN6G(33, 6115),
92edf9dab8SLorenzo Bianconi 	CHAN6G(37, 6135),
93edf9dab8SLorenzo Bianconi 	CHAN6G(41, 6155),
94edf9dab8SLorenzo Bianconi 	CHAN6G(45, 6175),
95edf9dab8SLorenzo Bianconi 	CHAN6G(49, 6195),
96edf9dab8SLorenzo Bianconi 	CHAN6G(53, 6215),
97edf9dab8SLorenzo Bianconi 	CHAN6G(57, 6235),
98edf9dab8SLorenzo Bianconi 	CHAN6G(61, 6255),
99edf9dab8SLorenzo Bianconi 	CHAN6G(65, 6275),
100edf9dab8SLorenzo Bianconi 	CHAN6G(69, 6295),
101edf9dab8SLorenzo Bianconi 	CHAN6G(73, 6315),
102edf9dab8SLorenzo Bianconi 	CHAN6G(77, 6335),
103edf9dab8SLorenzo Bianconi 	CHAN6G(81, 6355),
104edf9dab8SLorenzo Bianconi 	CHAN6G(85, 6375),
105edf9dab8SLorenzo Bianconi 	CHAN6G(89, 6395),
106edf9dab8SLorenzo Bianconi 	CHAN6G(93, 6415),
107edf9dab8SLorenzo Bianconi 	/* UNII-6 */
108edf9dab8SLorenzo Bianconi 	CHAN6G(97, 6435),
109edf9dab8SLorenzo Bianconi 	CHAN6G(101, 6455),
110edf9dab8SLorenzo Bianconi 	CHAN6G(105, 6475),
111edf9dab8SLorenzo Bianconi 	CHAN6G(109, 6495),
112edf9dab8SLorenzo Bianconi 	CHAN6G(113, 6515),
113edf9dab8SLorenzo Bianconi 	CHAN6G(117, 6535),
114edf9dab8SLorenzo Bianconi 	/* UNII-7 */
115edf9dab8SLorenzo Bianconi 	CHAN6G(121, 6555),
116edf9dab8SLorenzo Bianconi 	CHAN6G(125, 6575),
117edf9dab8SLorenzo Bianconi 	CHAN6G(129, 6595),
118edf9dab8SLorenzo Bianconi 	CHAN6G(133, 6615),
119edf9dab8SLorenzo Bianconi 	CHAN6G(137, 6635),
120edf9dab8SLorenzo Bianconi 	CHAN6G(141, 6655),
121edf9dab8SLorenzo Bianconi 	CHAN6G(145, 6675),
122edf9dab8SLorenzo Bianconi 	CHAN6G(149, 6695),
123edf9dab8SLorenzo Bianconi 	CHAN6G(153, 6715),
124edf9dab8SLorenzo Bianconi 	CHAN6G(157, 6735),
125edf9dab8SLorenzo Bianconi 	CHAN6G(161, 6755),
126edf9dab8SLorenzo Bianconi 	CHAN6G(165, 6775),
127edf9dab8SLorenzo Bianconi 	CHAN6G(169, 6795),
128edf9dab8SLorenzo Bianconi 	CHAN6G(173, 6815),
129edf9dab8SLorenzo Bianconi 	CHAN6G(177, 6835),
130edf9dab8SLorenzo Bianconi 	CHAN6G(181, 6855),
131edf9dab8SLorenzo Bianconi 	CHAN6G(185, 6875),
132edf9dab8SLorenzo Bianconi 	/* UNII-8 */
133edf9dab8SLorenzo Bianconi 	CHAN6G(189, 6895),
134edf9dab8SLorenzo Bianconi 	CHAN6G(193, 6915),
135edf9dab8SLorenzo Bianconi 	CHAN6G(197, 6935),
136edf9dab8SLorenzo Bianconi 	CHAN6G(201, 6955),
137edf9dab8SLorenzo Bianconi 	CHAN6G(205, 6975),
138edf9dab8SLorenzo Bianconi 	CHAN6G(209, 6995),
139edf9dab8SLorenzo Bianconi 	CHAN6G(213, 7015),
140edf9dab8SLorenzo Bianconi 	CHAN6G(217, 7035),
141edf9dab8SLorenzo Bianconi 	CHAN6G(221, 7055),
142edf9dab8SLorenzo Bianconi 	CHAN6G(225, 7075),
143edf9dab8SLorenzo Bianconi 	CHAN6G(229, 7095),
144edf9dab8SLorenzo Bianconi 	CHAN6G(233, 7115),
145edf9dab8SLorenzo Bianconi };
146edf9dab8SLorenzo Bianconi 
14717f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
14817f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
14917f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
15017f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
15117f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
15217f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
15317f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
15417f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
15517f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
15617f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
15717f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
15817f1de56SFelix Fietkau };
15917f1de56SFelix Fietkau 
16054b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = {
16154b8fdebSLorenzo Bianconi 	CCK_RATE(0, 10),
16254b8fdebSLorenzo Bianconi 	CCK_RATE(1, 20),
16354b8fdebSLorenzo Bianconi 	CCK_RATE(2, 55),
16454b8fdebSLorenzo Bianconi 	CCK_RATE(3, 110),
16554b8fdebSLorenzo Bianconi 	OFDM_RATE(11, 60),
16654b8fdebSLorenzo Bianconi 	OFDM_RATE(15, 90),
16754b8fdebSLorenzo Bianconi 	OFDM_RATE(10, 120),
16854b8fdebSLorenzo Bianconi 	OFDM_RATE(14, 180),
16954b8fdebSLorenzo Bianconi 	OFDM_RATE(9,  240),
17054b8fdebSLorenzo Bianconi 	OFDM_RATE(13, 360),
17154b8fdebSLorenzo Bianconi 	OFDM_RATE(8,  480),
17254b8fdebSLorenzo Bianconi 	OFDM_RATE(12, 540),
17354b8fdebSLorenzo Bianconi };
17454b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates);
17554b8fdebSLorenzo Bianconi 
176502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
177502604f5SYN Chen 	{ .start_freq = 2402, .end_freq = 2494, },
178502604f5SYN Chen 	{ .start_freq = 5150, .end_freq = 5350, },
179502604f5SYN Chen 	{ .start_freq = 5350, .end_freq = 5470, },
180502604f5SYN Chen 	{ .start_freq = 5470, .end_freq = 5725, },
181502604f5SYN Chen 	{ .start_freq = 5725, .end_freq = 5950, },
182162d5c14SDeren Wu 	{ .start_freq = 5945, .end_freq = 6165, },
183162d5c14SDeren Wu 	{ .start_freq = 6165, .end_freq = 6405, },
184162d5c14SDeren Wu 	{ .start_freq = 6405, .end_freq = 6525, },
185162d5c14SDeren Wu 	{ .start_freq = 6525, .end_freq = 6705, },
186162d5c14SDeren Wu 	{ .start_freq = 6705, .end_freq = 6865, },
187162d5c14SDeren Wu 	{ .start_freq = 6865, .end_freq = 7125, },
188502604f5SYN Chen };
189502604f5SYN Chen 
19097f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = {
191502604f5SYN Chen 	.type = NL80211_SAR_TYPE_POWER,
192502604f5SYN Chen 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
193502604f5SYN Chen 	.freq_ranges = &mt76_sar_freq_ranges[0],
194502604f5SYN Chen };
195502604f5SYN Chen 
1963abd46ddSLorenzo Bianconi static int mt76_led_init(struct mt76_phy *phy)
19717f1de56SFelix Fietkau {
1983abd46ddSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1993abd46ddSLorenzo Bianconi 	struct ieee80211_hw *hw = phy->hw;
20017f1de56SFelix Fietkau 
2013abd46ddSLorenzo Bianconi 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
20217f1de56SFelix Fietkau 		return 0;
20317f1de56SFelix Fietkau 
2043abd46ddSLorenzo Bianconi 	snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
2053abd46ddSLorenzo Bianconi 		 wiphy_name(hw->wiphy));
20617f1de56SFelix Fietkau 
2073abd46ddSLorenzo Bianconi 	phy->leds.cdev.name = phy->leds.name;
2083abd46ddSLorenzo Bianconi 	phy->leds.cdev.default_trigger =
20917f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
21017f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
21117f1de56SFelix Fietkau 					mt76_tpt_blink,
21217f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
21317f1de56SFelix Fietkau 
2143abd46ddSLorenzo Bianconi 	if (phy == &dev->phy) {
2153abd46ddSLorenzo Bianconi 		struct device_node *np = dev->dev->of_node;
2163abd46ddSLorenzo Bianconi 
21717f1de56SFelix Fietkau 		np = of_get_child_by_name(np, "led");
21817f1de56SFelix Fietkau 		if (np) {
2193abd46ddSLorenzo Bianconi 			int led_pin;
2203abd46ddSLorenzo Bianconi 
22117f1de56SFelix Fietkau 			if (!of_property_read_u32(np, "led-sources", &led_pin))
2223abd46ddSLorenzo Bianconi 				phy->leds.pin = led_pin;
2233abd46ddSLorenzo Bianconi 			phy->leds.al = of_property_read_bool(np,
2243abd46ddSLorenzo Bianconi 							     "led-active-low");
2250a14c1d0SLiang He 			of_node_put(np);
22617f1de56SFelix Fietkau 		}
22736f7e2b2SFelix Fietkau 	}
22836f7e2b2SFelix Fietkau 
2293abd46ddSLorenzo Bianconi 	return led_classdev_register(dev->dev, &phy->leds.cdev);
2303abd46ddSLorenzo Bianconi }
2313abd46ddSLorenzo Bianconi 
2323abd46ddSLorenzo Bianconi static void mt76_led_cleanup(struct mt76_phy *phy)
23336f7e2b2SFelix Fietkau {
2343abd46ddSLorenzo Bianconi 	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
23536f7e2b2SFelix Fietkau 		return;
23636f7e2b2SFelix Fietkau 
2373abd46ddSLorenzo Bianconi 	led_classdev_unregister(&phy->leds.cdev);
23817f1de56SFelix Fietkau }
23917f1de56SFelix Fietkau 
240bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
241551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
242551e1ef4SLorenzo Bianconi 				 bool vht)
243551e1ef4SLorenzo Bianconi {
244551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
245bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
246551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
247551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
248551e1ef4SLorenzo Bianconi 
249551e1ef4SLorenzo Bianconi 	if (nstream > 1)
250551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
251551e1ef4SLorenzo Bianconi 	else
252551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
253551e1ef4SLorenzo Bianconi 
254551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
255551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
256551e1ef4SLorenzo Bianconi 
257551e1ef4SLorenzo Bianconi 	if (!vht)
258551e1ef4SLorenzo Bianconi 		return;
259551e1ef4SLorenzo Bianconi 
260551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
261551e1ef4SLorenzo Bianconi 	if (nstream > 1)
262551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
263551e1ef4SLorenzo Bianconi 	else
264551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
265abba3453SDeren Wu 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
266abba3453SDeren Wu 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
267551e1ef4SLorenzo Bianconi 
268551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
269551e1ef4SLorenzo Bianconi 		if (i < nstream)
270551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
271551e1ef4SLorenzo Bianconi 		else
272551e1ef4SLorenzo Bianconi 			mcs_map |=
273551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
274551e1ef4SLorenzo Bianconi 	}
275551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
276551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
277781b80f4SFelix Fietkau 	if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
278d9fcfc14SDeren Wu 		vht_cap->vht_mcs.tx_highest |=
279d9fcfc14SDeren Wu 				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
280551e1ef4SLorenzo Bianconi }
281551e1ef4SLorenzo Bianconi 
282bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2835ebdc3e0SLorenzo Bianconi {
28448dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
285bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
28648dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
287bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
288edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz)
289edf9dab8SLorenzo Bianconi 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
2905ebdc3e0SLorenzo Bianconi }
2915ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
2925ebdc3e0SLorenzo Bianconi 
29317f1de56SFelix Fietkau static int
29477af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
29517f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
296edf9dab8SLorenzo Bianconi 		struct ieee80211_rate *rates, int n_rates,
297edf9dab8SLorenzo Bianconi 		bool ht, bool vht)
29817f1de56SFelix Fietkau {
29917f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
30017f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
30177af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
30277af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
30317f1de56SFelix Fietkau 	void *chanlist;
30417f1de56SFelix Fietkau 	int size;
30517f1de56SFelix Fietkau 
30617f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
30717f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
30817f1de56SFelix Fietkau 	if (!chanlist)
30917f1de56SFelix Fietkau 		return -ENOMEM;
31017f1de56SFelix Fietkau 
311a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
31217f1de56SFelix Fietkau 				    GFP_KERNEL);
31317f1de56SFelix Fietkau 	if (!msband->chan)
31417f1de56SFelix Fietkau 		return -ENOMEM;
31517f1de56SFelix Fietkau 
31617f1de56SFelix Fietkau 	sband->channels = chanlist;
31717f1de56SFelix Fietkau 	sband->n_channels = n_chan;
31817f1de56SFelix Fietkau 	sband->bitrates = rates;
31917f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
32017f1de56SFelix Fietkau 
321edf9dab8SLorenzo Bianconi 	if (!ht)
322edf9dab8SLorenzo Bianconi 		return 0;
323edf9dab8SLorenzo Bianconi 
32417f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
32517f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
32617f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
32717f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
32817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
32917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
33017f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
33117f1de56SFelix Fietkau 
33217f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
33317f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
33417f1de56SFelix Fietkau 
33577af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
336551e1ef4SLorenzo Bianconi 
33717f1de56SFelix Fietkau 	if (!vht)
33817f1de56SFelix Fietkau 		return 0;
33917f1de56SFelix Fietkau 
34017f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
34117f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
34217f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
34317f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
34449149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
34549149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
34617f1de56SFelix Fietkau 
34717f1de56SFelix Fietkau 	return 0;
34817f1de56SFelix Fietkau }
34917f1de56SFelix Fietkau 
35017f1de56SFelix Fietkau static int
35177af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
35217f1de56SFelix Fietkau 		   int n_rates)
35317f1de56SFelix Fietkau {
35477af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
35517f1de56SFelix Fietkau 
35677af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
35777af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
358edf9dab8SLorenzo Bianconi 			       n_rates, true, false);
35917f1de56SFelix Fietkau }
36017f1de56SFelix Fietkau 
36117f1de56SFelix Fietkau static int
36277af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
36317f1de56SFelix Fietkau 		   int n_rates, bool vht)
36417f1de56SFelix Fietkau {
36577af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
36617f1de56SFelix Fietkau 
36777af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
36877af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
369edf9dab8SLorenzo Bianconi 			       n_rates, true, vht);
370edf9dab8SLorenzo Bianconi }
371edf9dab8SLorenzo Bianconi 
372edf9dab8SLorenzo Bianconi static int
373edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
374edf9dab8SLorenzo Bianconi 		   int n_rates)
375edf9dab8SLorenzo Bianconi {
376edf9dab8SLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
377edf9dab8SLorenzo Bianconi 
378edf9dab8SLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
379edf9dab8SLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
380edf9dab8SLorenzo Bianconi 			       n_rates, false, false);
38117f1de56SFelix Fietkau }
38217f1de56SFelix Fietkau 
38317f1de56SFelix Fietkau static void
384c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
385c89d3625SFelix Fietkau 		 enum nl80211_band band)
38617f1de56SFelix Fietkau {
387c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
38817f1de56SFelix Fietkau 	bool found = false;
38917f1de56SFelix Fietkau 	int i;
39017f1de56SFelix Fietkau 
39117f1de56SFelix Fietkau 	if (!sband)
39217f1de56SFelix Fietkau 		return;
39317f1de56SFelix Fietkau 
39417f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
39517f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
39617f1de56SFelix Fietkau 			continue;
39717f1de56SFelix Fietkau 
39817f1de56SFelix Fietkau 		found = true;
39917f1de56SFelix Fietkau 		break;
40017f1de56SFelix Fietkau 	}
40117f1de56SFelix Fietkau 
402c89d3625SFelix Fietkau 	if (found) {
403c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
404c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
40517f1de56SFelix Fietkau 		return;
406c89d3625SFelix Fietkau 	}
40717f1de56SFelix Fietkau 
40817f1de56SFelix Fietkau 	sband->n_channels = 0;
409c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
41017f1de56SFelix Fietkau }
41117f1de56SFelix Fietkau 
412d43de9cfSLorenzo Bianconi static int
41398df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
414c89d3625SFelix Fietkau {
41598df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
416c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
417c89d3625SFelix Fietkau 
418c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
41998df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
420c89d3625SFelix Fietkau 
421*c278a64aSRyder Lee 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
422*c278a64aSRyder Lee 			   NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
423dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
424b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
425b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
426c89d3625SFelix Fietkau 
427c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
428c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
429d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
430c89d3625SFelix Fietkau 
4310a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4320a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
433c89d3625SFelix Fietkau 
434d43de9cfSLorenzo Bianconi 	wiphy->sar_capa = &mt76_sar_capa;
435d43de9cfSLorenzo Bianconi 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
436d43de9cfSLorenzo Bianconi 				sizeof(struct mt76_freq_range_power),
437d43de9cfSLorenzo Bianconi 				GFP_KERNEL);
438d43de9cfSLorenzo Bianconi 	if (!phy->frp)
439d43de9cfSLorenzo Bianconi 		return -ENOMEM;
440d43de9cfSLorenzo Bianconi 
441c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
442b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
443c9619dfaSShayne Chen 
444c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
445c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
446c89d3625SFelix Fietkau 
447c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
448c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
449c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
450c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
451c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
452c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
453ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
4545b0fb852SBen Greear 
4555b0fb852SBen Greear 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
456c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
457c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
4585b0fb852SBen Greear 	}
4595b0fb852SBen Greear 
460c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
461c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
462c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
463d43de9cfSLorenzo Bianconi 
464d43de9cfSLorenzo Bianconi 	return 0;
465c89d3625SFelix Fietkau }
466c89d3625SFelix Fietkau 
467c89d3625SFelix Fietkau struct mt76_phy *
468c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
469dc44c45cSLorenzo Bianconi 	       const struct ieee80211_ops *ops, u8 band_idx)
470c89d3625SFelix Fietkau {
471c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
472db78a791SLorenzo Bianconi 	unsigned int phy_size;
473c89d3625SFelix Fietkau 	struct mt76_phy *phy;
474c89d3625SFelix Fietkau 
475c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
476db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
477c89d3625SFelix Fietkau 	if (!hw)
478c89d3625SFelix Fietkau 		return NULL;
479c89d3625SFelix Fietkau 
480c89d3625SFelix Fietkau 	phy = hw->priv;
481c89d3625SFelix Fietkau 	phy->dev = dev;
482c89d3625SFelix Fietkau 	phy->hw = hw;
483db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
484dc44c45cSLorenzo Bianconi 	phy->band_idx = band_idx;
485c89d3625SFelix Fietkau 
4868af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4878af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4888af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4898af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4908af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4918af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4928af414e8SLorenzo Bianconi #endif
4938af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4948af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4958af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4968af414e8SLorenzo Bianconi 
497c89d3625SFelix Fietkau 	return phy;
498c89d3625SFelix Fietkau }
499c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
500c89d3625SFelix Fietkau 
501db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
502db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
503c89d3625SFelix Fietkau {
504c89d3625SFelix Fietkau 	int ret;
505c89d3625SFelix Fietkau 
506d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
507d43de9cfSLorenzo Bianconi 	if (ret)
508d43de9cfSLorenzo Bianconi 		return ret;
509db78a791SLorenzo Bianconi 
510db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
511db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
512db78a791SLorenzo Bianconi 		if (ret)
513db78a791SLorenzo Bianconi 			return ret;
514db78a791SLorenzo Bianconi 	}
515db78a791SLorenzo Bianconi 
516db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
517db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
518db78a791SLorenzo Bianconi 		if (ret)
519db78a791SLorenzo Bianconi 			return ret;
520db78a791SLorenzo Bianconi 	}
521db78a791SLorenzo Bianconi 
522edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
523edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
524edf9dab8SLorenzo Bianconi 		if (ret)
525edf9dab8SLorenzo Bianconi 			return ret;
526edf9dab8SLorenzo Bianconi 	}
527edf9dab8SLorenzo Bianconi 
5289e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
5299e81c2c7SLorenzo Bianconi 		ret = mt76_led_init(phy);
5309e81c2c7SLorenzo Bianconi 		if (ret)
5319e81c2c7SLorenzo Bianconi 			return ret;
5329e81c2c7SLorenzo Bianconi 	}
5339e81c2c7SLorenzo Bianconi 
534db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
535db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
536db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
537edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
538db78a791SLorenzo Bianconi 
539c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
540c89d3625SFelix Fietkau 	if (ret)
541c89d3625SFelix Fietkau 		return ret;
542c89d3625SFelix Fietkau 
54341130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
544dc44c45cSLorenzo Bianconi 	phy->dev->phys[phy->band_idx] = phy;
545db78a791SLorenzo Bianconi 
546c89d3625SFelix Fietkau 	return 0;
547c89d3625SFelix Fietkau }
548c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
549c89d3625SFelix Fietkau 
550db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
551c89d3625SFelix Fietkau {
552c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
553c89d3625SFelix Fietkau 
55441130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
55541130c32SLorenzo Bianconi 		return;
55641130c32SLorenzo Bianconi 
5579e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS))
5589e81c2c7SLorenzo Bianconi 		mt76_led_cleanup(phy);
559c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
560c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
561dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = NULL;
562c89d3625SFelix Fietkau }
563c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
564c89d3625SFelix Fietkau 
5652f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
5662f5c3c77SLorenzo Bianconi {
5672f5c3c77SLorenzo Bianconi 	struct page_pool_params pp_params = {
5682f5c3c77SLorenzo Bianconi 		.order = 0,
5692f5c3c77SLorenzo Bianconi 		.flags = PP_FLAG_PAGE_FRAG,
5702f5c3c77SLorenzo Bianconi 		.nid = NUMA_NO_NODE,
5712f5c3c77SLorenzo Bianconi 		.dev = dev->dma_dev,
5722f5c3c77SLorenzo Bianconi 	};
5732f5c3c77SLorenzo Bianconi 	int idx = q - dev->q_rx;
5742f5c3c77SLorenzo Bianconi 
5752f5c3c77SLorenzo Bianconi 	switch (idx) {
5762f5c3c77SLorenzo Bianconi 	case MT_RXQ_MAIN:
5772f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND1:
5782f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND2:
5792f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 256;
5802f5c3c77SLorenzo Bianconi 		break;
5812f5c3c77SLorenzo Bianconi 	default:
5822f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 16;
5832f5c3c77SLorenzo Bianconi 		break;
5842f5c3c77SLorenzo Bianconi 	}
5852f5c3c77SLorenzo Bianconi 
5862f5c3c77SLorenzo Bianconi 	if (mt76_is_mmio(dev)) {
5872f5c3c77SLorenzo Bianconi 		/* rely on page_pool for DMA mapping */
5882f5c3c77SLorenzo Bianconi 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
5892f5c3c77SLorenzo Bianconi 		pp_params.dma_dir = DMA_FROM_DEVICE;
5902f5c3c77SLorenzo Bianconi 		pp_params.max_len = PAGE_SIZE;
5912f5c3c77SLorenzo Bianconi 		pp_params.offset = 0;
5922f5c3c77SLorenzo Bianconi 	}
5932f5c3c77SLorenzo Bianconi 
5942f5c3c77SLorenzo Bianconi 	q->page_pool = page_pool_create(&pp_params);
5952f5c3c77SLorenzo Bianconi 	if (IS_ERR(q->page_pool)) {
5962f5c3c77SLorenzo Bianconi 		int err = PTR_ERR(q->page_pool);
5972f5c3c77SLorenzo Bianconi 
5982f5c3c77SLorenzo Bianconi 		q->page_pool = NULL;
5992f5c3c77SLorenzo Bianconi 		return err;
6002f5c3c77SLorenzo Bianconi 	}
6012f5c3c77SLorenzo Bianconi 
6022f5c3c77SLorenzo Bianconi 	return 0;
6032f5c3c77SLorenzo Bianconi }
6042f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool);
6052f5c3c77SLorenzo Bianconi 
606a85b590cSFelix Fietkau struct mt76_dev *
607c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
608c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
609c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
610a85b590cSFelix Fietkau {
611a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
612ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
613a85b590cSFelix Fietkau 	struct mt76_dev *dev;
614e5443256SFelix Fietkau 	int i;
615a85b590cSFelix Fietkau 
616a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
617a85b590cSFelix Fietkau 	if (!hw)
618a85b590cSFelix Fietkau 		return NULL;
619a85b590cSFelix Fietkau 
620a85b590cSFelix Fietkau 	dev = hw->priv;
621a85b590cSFelix Fietkau 	dev->hw = hw;
622c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
623c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
624d1ddc536SFelix Fietkau 	dev->dma_dev = pdev;
625c0f7b25aSLorenzo Bianconi 
626ac24dd35SFelix Fietkau 	phy = &dev->phy;
627ac24dd35SFelix Fietkau 	phy->dev = dev;
628ac24dd35SFelix Fietkau 	phy->hw = hw;
629dc44c45cSLorenzo Bianconi 	phy->band_idx = MT_BAND0;
630dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = phy;
631ac24dd35SFelix Fietkau 
632a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
633a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
634a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
635c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
6362666beceSSujuan Chen 	spin_lock_init(&dev->wed_lock);
637108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
63826e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
639a85b590cSFelix Fietkau 
64009872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
64109872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
64209872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
643781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
64409872957SLorenzo Bianconi 
6458af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6468af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
6478af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
6488af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
6498af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
6508af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
6518af414e8SLorenzo Bianconi #endif
6528af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
6538af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
6548af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
6558af414e8SLorenzo Bianconi 
65651252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
65751252cc5SLorenzo Bianconi 	idr_init(&dev->token);
65851252cc5SLorenzo Bianconi 
6592666beceSSujuan Chen 	spin_lock_init(&dev->rx_token_lock);
6602666beceSSujuan Chen 	idr_init(&dev->rx_token);
6612666beceSSujuan Chen 
662bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
663bd1e3e7bSLorenzo Bianconi 
664e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
6652666beceSSujuan Chen 	INIT_LIST_HEAD(&dev->rxwi_cache);
66661b5156bSFelix Fietkau 	dev->token_size = dev->drv->token_size;
667e5443256SFelix Fietkau 
668e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
669e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
670e5443256SFelix Fietkau 
671a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
672a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
673a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
674a86f1d01SLorenzo Bianconi 		return NULL;
675a86f1d01SLorenzo Bianconi 	}
676a86f1d01SLorenzo Bianconi 
677a85b590cSFelix Fietkau 	return dev;
678a85b590cSFelix Fietkau }
679a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
680a85b590cSFelix Fietkau 
68117f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
68217f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
68317f1de56SFelix Fietkau {
68417f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
685c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
68617f1de56SFelix Fietkau 	int ret;
68717f1de56SFelix Fietkau 
68817f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
689d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
690d43de9cfSLorenzo Bianconi 	if (ret)
691d43de9cfSLorenzo Bianconi 		return ret;
69217f1de56SFelix Fietkau 
69348dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
69477af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
69517f1de56SFelix Fietkau 		if (ret)
69617f1de56SFelix Fietkau 			return ret;
69717f1de56SFelix Fietkau 	}
69817f1de56SFelix Fietkau 
69948dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
70077af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
70117f1de56SFelix Fietkau 		if (ret)
70217f1de56SFelix Fietkau 			return ret;
70317f1de56SFelix Fietkau 	}
70417f1de56SFelix Fietkau 
705edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
706edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
707edf9dab8SLorenzo Bianconi 		if (ret)
708edf9dab8SLorenzo Bianconi 			return ret;
709edf9dab8SLorenzo Bianconi 	}
710edf9dab8SLorenzo Bianconi 
711c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
712c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
713c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
714edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
71517f1de56SFelix Fietkau 
716b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
7173abd46ddSLorenzo Bianconi 		ret = mt76_led_init(phy);
71817f1de56SFelix Fietkau 		if (ret)
71917f1de56SFelix Fietkau 			return ret;
720b374e868SArnd Bergmann 	}
72117f1de56SFelix Fietkau 
722781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
723781eef5bSFelix Fietkau 	if (ret)
724781eef5bSFelix Fietkau 		return ret;
725781eef5bSFelix Fietkau 
726781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
72741130c32SLorenzo Bianconi 	set_bit(MT76_STATE_REGISTERED, &phy->state);
728781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
729781eef5bSFelix Fietkau 
730781eef5bSFelix Fietkau 	return 0;
73117f1de56SFelix Fietkau }
73217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
73317f1de56SFelix Fietkau 
73417f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
73517f1de56SFelix Fietkau {
73617f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
73717f1de56SFelix Fietkau 
73841130c32SLorenzo Bianconi 	if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
73941130c32SLorenzo Bianconi 		return;
74041130c32SLorenzo Bianconi 
741d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
7423abd46ddSLorenzo Bianconi 		mt76_led_cleanup(&dev->phy);
743c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
74417f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
74517f1de56SFelix Fietkau }
74617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
74717f1de56SFelix Fietkau 
748def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
749def34a2fSLorenzo Bianconi {
750781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
751a86f1d01SLorenzo Bianconi 	if (dev->wq) {
752a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
753a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
754a86f1d01SLorenzo Bianconi 	}
755def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
756def34a2fSLorenzo Bianconi }
757def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
758def34a2fSLorenzo Bianconi 
759cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
760cc4b3c13SLorenzo Bianconi {
761cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
7622c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
763cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
764cc4b3c13SLorenzo Bianconi 
765cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
766cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
7672c2bdd23SFelix Fietkau 
7682c2bdd23SFelix Fietkau 	/*
7692c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
7702c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7712c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
7722c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
7732c2bdd23SFelix Fietkau 	 * address.
7742c2bdd23SFelix Fietkau 	 */
7752c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
7762c2bdd23SFelix Fietkau 		int offset = 0;
7772c2bdd23SFelix Fietkau 
7782c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
7792c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
7802c2bdd23SFelix Fietkau 
7812c2bdd23SFelix Fietkau 			if ((status->flag &
7822c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
7832c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
7842c2bdd23SFelix Fietkau 				offset += 8;
7852c2bdd23SFelix Fietkau 		}
7862c2bdd23SFelix Fietkau 
7872c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
7882c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
7892c2bdd23SFelix Fietkau 			return;
7902c2bdd23SFelix Fietkau 		}
7912c2bdd23SFelix Fietkau 	}
792cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
793cc4b3c13SLorenzo Bianconi }
794cc4b3c13SLorenzo Bianconi 
795cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
796cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
797cc4b3c13SLorenzo Bianconi {
798cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
799cc4b3c13SLorenzo Bianconi 
800cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
801cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
802cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
803cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
804cc4b3c13SLorenzo Bianconi 
805cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
806cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
807cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
808cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
809cc4b3c13SLorenzo Bianconi 	} else {
810cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
811cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
812cc4b3c13SLorenzo Bianconi 	}
813cc4b3c13SLorenzo Bianconi 
814cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
815cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
816cc4b3c13SLorenzo Bianconi }
817cc4b3c13SLorenzo Bianconi 
81817f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
81917f1de56SFelix Fietkau {
820011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
821128c9b7dSLorenzo Bianconi 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
822011849e0SFelix Fietkau 
823011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
82417f1de56SFelix Fietkau 		dev_kfree_skb(skb);
82517f1de56SFelix Fietkau 		return;
82617f1de56SFelix Fietkau 	}
82717f1de56SFelix Fietkau 
828f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
829c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
830c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
831f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
832c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
833f0efa862SFelix Fietkau 	}
834f0efa862SFelix Fietkau #endif
835cc4b3c13SLorenzo Bianconi 
836cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
83717f1de56SFelix Fietkau }
83817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
83917f1de56SFelix Fietkau 
8405a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
84126e40d4cSFelix Fietkau {
842af005f26SLorenzo Bianconi 	struct mt76_queue *q;
84391990519SLorenzo Bianconi 	int i;
8445a95ca41SFelix Fietkau 
8455a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
84691990519SLorenzo Bianconi 		q = phy->q_tx[i];
847af005f26SLorenzo Bianconi 		if (q && q->queued)
84826e40d4cSFelix Fietkau 			return true;
84926e40d4cSFelix Fietkau 	}
85026e40d4cSFelix Fietkau 
85126e40d4cSFelix Fietkau 	return false;
85226e40d4cSFelix Fietkau }
85339d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
85426e40d4cSFelix Fietkau 
8550fd0eb54SFelix Fietkau static struct mt76_channel_state *
85696747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8570fd0eb54SFelix Fietkau {
8580fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
8590fd0eb54SFelix Fietkau 	int idx;
8600fd0eb54SFelix Fietkau 
8610fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
86296747a51SFelix Fietkau 		msband = &phy->sband_2g;
863edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
864edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
8650fd0eb54SFelix Fietkau 	else
86696747a51SFelix Fietkau 		msband = &phy->sband_5g;
8670fd0eb54SFelix Fietkau 
8680fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
8690fd0eb54SFelix Fietkau 	return &msband->chan[idx];
8700fd0eb54SFelix Fietkau }
8710fd0eb54SFelix Fietkau 
87204414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
87396747a51SFelix Fietkau {
87496747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
87596747a51SFelix Fietkau 
87696747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
87796747a51SFelix Fietkau 						  phy->survey_time));
87896747a51SFelix Fietkau 	phy->survey_time = time;
87996747a51SFelix Fietkau }
88004414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
88196747a51SFelix Fietkau 
882c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
8835ce09c1aSFelix Fietkau {
884c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
885aec65e48SFelix Fietkau 	ktime_t cur_time;
886aec65e48SFelix Fietkau 
8875ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
888c560b137SRyder Lee 		dev->drv->update_survey(phy);
8895ce09c1aSFelix Fietkau 
890aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
891c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
892aec65e48SFelix Fietkau 
8935ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
894c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
89596747a51SFelix Fietkau 
896237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
8975ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
8985ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
899237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
9005ce09c1aSFelix Fietkau 	}
9015ce09c1aSFelix Fietkau }
9025ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
9035ce09c1aSFelix Fietkau 
90496747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
90517f1de56SFelix Fietkau {
90696747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
90796747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
90817f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
90917f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
91026e40d4cSFelix Fietkau 	int timeout = HZ / 5;
91117f1de56SFelix Fietkau 
9125a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
913c560b137SRyder Lee 	mt76_update_survey(phy);
91417f1de56SFelix Fietkau 
9153f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9163f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
9173f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9183f306448SFelix Fietkau 
91996747a51SFelix Fietkau 	phy->chandef = *chandef;
92096747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
92117f1de56SFelix Fietkau 
92217f1de56SFelix Fietkau 	if (!offchannel)
92396747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
92417f1de56SFelix Fietkau 
92596747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
92696747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
92717f1de56SFelix Fietkau }
92817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
92917f1de56SFelix Fietkau 
93017f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
93117f1de56SFelix Fietkau 		    struct survey_info *survey)
93217f1de56SFelix Fietkau {
93396747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
93496747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
93517f1de56SFelix Fietkau 	struct mt76_sband *sband;
93617f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
93717f1de56SFelix Fietkau 	struct mt76_channel_state *state;
93817f1de56SFelix Fietkau 	int ret = 0;
93917f1de56SFelix Fietkau 
940237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
94117f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
942c560b137SRyder Lee 		mt76_update_survey(phy);
94317f1de56SFelix Fietkau 
944edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
945edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
946edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
947edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
948edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
949edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
950edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
95196747a51SFelix Fietkau 		sband = &phy->sband_5g;
952edf9dab8SLorenzo Bianconi 	} else {
953edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
95417f1de56SFelix Fietkau 	}
95517f1de56SFelix Fietkau 
956237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
957237312c5SLorenzo Bianconi 		ret = -ENOENT;
958237312c5SLorenzo Bianconi 		goto out;
959237312c5SLorenzo Bianconi 	}
96017f1de56SFelix Fietkau 
96117f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
96296747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
96317f1de56SFelix Fietkau 
96417f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
96517f1de56SFelix Fietkau 	survey->channel = chan;
96617f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
967ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
968e5051965SFelix Fietkau 	if (state->noise)
969e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
970e5051965SFelix Fietkau 
97196747a51SFelix Fietkau 	if (chan == phy->main_chan) {
97217f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
97317f1de56SFelix Fietkau 
9745ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
9755ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
9765ce09c1aSFelix Fietkau 	}
9775ce09c1aSFelix Fietkau 
97817f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
9796bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
980237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
981e5051965SFelix Fietkau 	survey->noise = state->noise;
982237312c5SLorenzo Bianconi 
983237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
984237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
985ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
98617f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
98717f1de56SFelix Fietkau 
988237312c5SLorenzo Bianconi out:
989237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
990237312c5SLorenzo Bianconi 
99117f1de56SFelix Fietkau 	return ret;
99217f1de56SFelix Fietkau }
99317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
99417f1de56SFelix Fietkau 
99530ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
99630ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
99730ce7f44SFelix Fietkau {
99830ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
99930ce7f44SFelix Fietkau 	int i;
100030ce7f44SFelix Fietkau 
100130ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
100230ce7f44SFelix Fietkau 
100330ce7f44SFelix Fietkau 	if (!key)
100430ce7f44SFelix Fietkau 		return;
100530ce7f44SFelix Fietkau 
100601cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
100701cfc1b4SLorenzo Bianconi 		return;
100830ce7f44SFelix Fietkau 
100901cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
1010a1b0bbd4SXing Song 
1011a1b0bbd4SXing Song 	/* data frame */
101230ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
101330ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
101430ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
101530ce7f44SFelix Fietkau 	}
1016a1b0bbd4SXing Song 
1017a1b0bbd4SXing Song 	/* robust management frame */
1018a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
1019a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
1020a1b0bbd4SXing Song 
102130ce7f44SFelix Fietkau }
102230ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
102330ce7f44SFelix Fietkau 
1024a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10254550fb9eSFelix Fietkau {
10264550fb9eSFelix Fietkau 	int signal = -128;
10274550fb9eSFelix Fietkau 	u8 chains;
10284550fb9eSFelix Fietkau 
1029a71b648eSRyder Lee 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10304550fb9eSFelix Fietkau 		int cur, diff;
10314550fb9eSFelix Fietkau 
10326450b133SDeren Wu 		cur = *chain_signal;
10336450b133SDeren Wu 		if (!(chains & BIT(0)) ||
10346450b133SDeren Wu 		    cur > 0)
10354550fb9eSFelix Fietkau 			continue;
10364550fb9eSFelix Fietkau 
10374550fb9eSFelix Fietkau 		if (cur > signal)
10384550fb9eSFelix Fietkau 			swap(cur, signal);
10394550fb9eSFelix Fietkau 
10404550fb9eSFelix Fietkau 		diff = signal - cur;
10414550fb9eSFelix Fietkau 		if (diff == 0)
10424550fb9eSFelix Fietkau 			signal += 3;
10434550fb9eSFelix Fietkau 		else if (diff <= 2)
10444550fb9eSFelix Fietkau 			signal += 2;
10454550fb9eSFelix Fietkau 		else if (diff <= 6)
10464550fb9eSFelix Fietkau 			signal += 1;
10474550fb9eSFelix Fietkau 	}
10484550fb9eSFelix Fietkau 
10494550fb9eSFelix Fietkau 	return signal;
10504550fb9eSFelix Fietkau }
1051a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
10524550fb9eSFelix Fietkau 
1053bfc394ddSFelix Fietkau static void
1054bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
1055bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
1056bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
10574e34249eSFelix Fietkau {
10584e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1059abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
10604e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
10614e34249eSFelix Fietkau 
10624e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
10634e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
10644e34249eSFelix Fietkau 
10654e34249eSFelix Fietkau 	status->flag = mstat.flag;
10664e34249eSFelix Fietkau 	status->freq = mstat.freq;
10674e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
10684e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
10694e34249eSFelix Fietkau 	status->bw = mstat.bw;
1070af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
1071af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
1072af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
10734e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
10744e34249eSFelix Fietkau 	status->nss = mstat.nss;
10754e34249eSFelix Fietkau 	status->band = mstat.band;
10764e34249eSFelix Fietkau 	status->signal = mstat.signal;
10774e34249eSFelix Fietkau 	status->chains = mstat.chains;
1078d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
10790fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
10800fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
1081a71b648eSRyder Lee 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
10824550fb9eSFelix Fietkau 	if (status->signal <= -128)
10834550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
10844e34249eSFelix Fietkau 
1085abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
1086abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
1087abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1088abe3f3daSRyder Lee 
10894e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
109013381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
109113381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
109213381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
109313381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
10949c68a57bSFelix Fietkau 
1095bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1096128c9b7dSLorenzo Bianconi 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
10974e34249eSFelix Fietkau }
10984e34249eSFelix Fietkau 
10993c1032e1SFelix Fietkau static void
110030ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
110130ce7f44SFelix Fietkau {
110230ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
110330ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
110430ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1105a1b0bbd4SXing Song 	int security_idx;
110630ce7f44SFelix Fietkau 	int ret;
110730ce7f44SFelix Fietkau 
110830ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
11093c1032e1SFelix Fietkau 		return;
111030ce7f44SFelix Fietkau 
11111858e4fcSMeiChia Chiu 	if (status->flag & RX_FLAG_ONLY_MONITOR)
11123c1032e1SFelix Fietkau 		return;
11131858e4fcSMeiChia Chiu 
111430ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
11153c1032e1SFelix Fietkau 		return;
111630ce7f44SFelix Fietkau 
11177360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11187360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
11197360cdecSFelix Fietkau 		goto skip_hdr_check;
11207360cdecSFelix Fietkau 
1121a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
112230ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
112330ce7f44SFelix Fietkau 		/*
112430ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
112530ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
112630ce7f44SFelix Fietkau 		 */
112730ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
112830ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
11293c1032e1SFelix Fietkau 			return;
113030ce7f44SFelix Fietkau 	}
113130ce7f44SFelix Fietkau 
1132a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1133a1b0bbd4SXing Song 	 *
1134a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1135a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1136a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1137a1b0bbd4SXing Song 	 */
1138a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1139a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1140a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1141a1b0bbd4SXing Song 
11427360cdecSFelix Fietkau skip_hdr_check:
114330ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1144a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
114530ce7f44SFelix Fietkau 		     sizeof(status->iv));
11463c1032e1SFelix Fietkau 	if (ret <= 0) {
11473c1032e1SFelix Fietkau 		status->flag |= RX_FLAG_ONLY_MONITOR;
11483c1032e1SFelix Fietkau 		return;
11493c1032e1SFelix Fietkau 	}
115030ce7f44SFelix Fietkau 
1151a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
115230ce7f44SFelix Fietkau 
115330ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
115430ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
115530ce7f44SFelix Fietkau }
115630ce7f44SFelix Fietkau 
1157d71ef286SFelix Fietkau static void
11585ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
11595ce09c1aSFelix Fietkau 		    int len)
11605ce09c1aSFelix Fietkau {
11615ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
116285b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
116385b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
116485b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
116585b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
116685b7a5d0SLorenzo Bianconi 		.band = status->band,
116785b7a5d0SLorenzo Bianconi 		.nss = status->nss,
116885b7a5d0SLorenzo Bianconi 		.bw = status->bw,
116985b7a5d0SLorenzo Bianconi 	};
11705ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
11715ce09c1aSFelix Fietkau 	u32 airtime;
1172e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11735ce09c1aSFelix Fietkau 
117485b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1175237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
11765ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1177237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
11785ce09c1aSFelix Fietkau 
11795ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
11805ce09c1aSFelix Fietkau 		return;
11815ce09c1aSFelix Fietkau 
11825ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1183e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
11845ce09c1aSFelix Fietkau }
11855ce09c1aSFelix Fietkau 
11865ce09c1aSFelix Fietkau static void
11875ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
11885ce09c1aSFelix Fietkau {
11895ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
11905ce09c1aSFelix Fietkau 	int wcid_idx;
11915ce09c1aSFelix Fietkau 
11925ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
11935ce09c1aSFelix Fietkau 		return;
11945ce09c1aSFelix Fietkau 
11955ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1196bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
11975ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
11985ce09c1aSFelix Fietkau 	else
11995ce09c1aSFelix Fietkau 		wcid = NULL;
12005ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
12015ce09c1aSFelix Fietkau 
12025ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
12035ce09c1aSFelix Fietkau 
12045ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
12055ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
12065ce09c1aSFelix Fietkau }
12075ce09c1aSFelix Fietkau 
12085ce09c1aSFelix Fietkau static void
12095ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12105ce09c1aSFelix Fietkau {
12115ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12125ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
12135ce09c1aSFelix Fietkau 
12145ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12155ce09c1aSFelix Fietkau 		return;
12165ce09c1aSFelix Fietkau 
12175ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1218e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1219e195dad1SFelix Fietkau 
1220e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1221e195dad1SFelix Fietkau 			return;
1222e195dad1SFelix Fietkau 
122398df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12245ce09c1aSFelix Fietkau 			return;
12255ce09c1aSFelix Fietkau 
12265ce09c1aSFelix Fietkau 		wcid = NULL;
12275ce09c1aSFelix Fietkau 	}
12285ce09c1aSFelix Fietkau 
12295ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12305ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
12315ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
12325ce09c1aSFelix Fietkau 
12335ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12345ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
12355ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
12365ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
12375ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
12385ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
12395ce09c1aSFelix Fietkau 		}
12405ce09c1aSFelix Fietkau 
12415ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
12425ce09c1aSFelix Fietkau 		return;
12435ce09c1aSFelix Fietkau 	}
12445ce09c1aSFelix Fietkau 
12455ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
12465ce09c1aSFelix Fietkau }
12475ce09c1aSFelix Fietkau 
12485ce09c1aSFelix Fietkau static void
1249ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1250d71ef286SFelix Fietkau {
1251d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
125277ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1253d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1254bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1255d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1256e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1257d71ef286SFelix Fietkau 	bool ps;
1258d71ef286SFelix Fietkau 
1259128c9b7dSLorenzo Bianconi 	hw = mt76_phy_hw(dev, status->phy_idx);
1260e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1261e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1262bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
126336d91096SFelix Fietkau 		if (sta)
126436d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
126536d91096SFelix Fietkau 	}
126636d91096SFelix Fietkau 
12675ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
12685ce09c1aSFelix Fietkau 
1269d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1270d71ef286SFelix Fietkau 		return;
1271d71ef286SFelix Fietkau 
1272d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1273d71ef286SFelix Fietkau 
127402e5a769SFelix Fietkau 	if (status->signal <= 0)
127502e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
127602e5a769SFelix Fietkau 
1277ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1278ef13edc0SFelix Fietkau 
1279e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1280e195dad1SFelix Fietkau 		return;
1281e195dad1SFelix Fietkau 
1282d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1283d71ef286SFelix Fietkau 		return;
1284d71ef286SFelix Fietkau 
1285d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1286d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1287d71ef286SFelix Fietkau 		return;
1288d71ef286SFelix Fietkau 	}
1289d71ef286SFelix Fietkau 
1290d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1291d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1292d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1293d71ef286SFelix Fietkau 		return;
1294d71ef286SFelix Fietkau 
1295d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1296d71ef286SFelix Fietkau 
1297d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1298d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1299e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1300d71ef286SFelix Fietkau 
1301d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1302d71ef286SFelix Fietkau 		return;
1303d71ef286SFelix Fietkau 
130411b2a25fSFelix Fietkau 	if (ps)
1305d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1306d71ef286SFelix Fietkau 
1307d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
1308608f7c47SFelix Fietkau 
1309608f7c47SFelix Fietkau 	if (!ps)
1310608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1311608f7c47SFelix Fietkau 
13129f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1313d71ef286SFelix Fietkau }
1314d71ef286SFelix Fietkau 
13159d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
131681e850efSLorenzo Bianconi 		      struct napi_struct *napi)
131717f1de56SFelix Fietkau {
13189c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1319bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
13203298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
13213298b1f8SFelix Fietkau 	LIST_HEAD(list);
13229d9d738bSFelix Fietkau 
1323c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
13249d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1325cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1326cc4b3c13SLorenzo Bianconi 
13273c1032e1SFelix Fietkau 		mt76_check_ccmp_pn(skb);
1328cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1329bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
13303298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1331cc4b3c13SLorenzo Bianconi 
1332cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1333cc4b3c13SLorenzo Bianconi 		while (nskb) {
1334cc4b3c13SLorenzo Bianconi 			skb = nskb;
1335cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1336cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1337cc4b3c13SLorenzo Bianconi 
1338cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1339cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1340cc4b3c13SLorenzo Bianconi 		}
13419d9d738bSFelix Fietkau 	}
1342c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
13433298b1f8SFelix Fietkau 
13443298b1f8SFelix Fietkau 	if (!napi) {
13453298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
13463298b1f8SFelix Fietkau 		return;
13473298b1f8SFelix Fietkau 	}
13483298b1f8SFelix Fietkau 
13493298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
13503298b1f8SFelix Fietkau 		skb_list_del_init(skb);
13513298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
13523298b1f8SFelix Fietkau 	}
13539d9d738bSFelix Fietkau }
13549d9d738bSFelix Fietkau 
135581e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
135681e850efSLorenzo Bianconi 			   struct napi_struct *napi)
13579d9d738bSFelix Fietkau {
1358aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
135917f1de56SFelix Fietkau 	struct sk_buff *skb;
136017f1de56SFelix Fietkau 
1361aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1362aee5b8cfSFelix Fietkau 
1363d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1364ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
13654f831d18SLorenzo Bianconi 		if (mtk_wed_device_active(&dev->mmio.wed))
13664f831d18SLorenzo Bianconi 			__skb_queue_tail(&frames, skb);
13674f831d18SLorenzo Bianconi 		else
1368aee5b8cfSFelix Fietkau 			mt76_rx_aggr_reorder(skb, &frames);
1369d71ef286SFelix Fietkau 	}
1370aee5b8cfSFelix Fietkau 
137181e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
13724e34249eSFelix Fietkau }
137381e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1374723b90dcSFelix Fietkau 
1375e28487eaSFelix Fietkau static int
1376a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1377a1a99d7bSLorenzo Bianconi 	     struct ieee80211_sta *sta)
1378e28487eaSFelix Fietkau {
1379e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1380a1a99d7bSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1381e28487eaSFelix Fietkau 	int ret;
1382e28487eaSFelix Fietkau 	int i;
1383e28487eaSFelix Fietkau 
1384e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1385e28487eaSFelix Fietkau 
1386e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1387e28487eaSFelix Fietkau 	if (ret)
1388e28487eaSFelix Fietkau 		goto out;
1389e28487eaSFelix Fietkau 
1390e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1391e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1392e28487eaSFelix Fietkau 
1393e28487eaSFelix Fietkau 		if (!sta->txq[i])
1394e28487eaSFelix Fietkau 			continue;
1395e28487eaSFelix Fietkau 
1396e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
139751fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1398e28487eaSFelix Fietkau 	}
1399e28487eaSFelix Fietkau 
1400ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1401a1a99d7bSLorenzo Bianconi 	if (phy->band_idx == MT_BAND1)
1402426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1403a1a99d7bSLorenzo Bianconi 	wcid->phy_idx = phy->band_idx;
1404e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1405e28487eaSFelix Fietkau 
1406bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_init(wcid);
1407e28487eaSFelix Fietkau out:
1408e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1409e28487eaSFelix Fietkau 
1410e28487eaSFelix Fietkau 	return ret;
1411e28487eaSFelix Fietkau }
1412e28487eaSFelix Fietkau 
141313f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1414723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1415723b90dcSFelix Fietkau {
1416723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
141713f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1418723b90dcSFelix Fietkau 
141958bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
142058bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
142158bab0d4SFelix Fietkau 
1422e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1423e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1424e28487eaSFelix Fietkau 
1425bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_flush(dev, wcid);
1426bd1e3e7bSLorenzo Bianconi 
1427426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1428426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
142913f61dfcSLorenzo Bianconi }
143013f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1431e28487eaSFelix Fietkau 
143213f61dfcSLorenzo Bianconi static void
143313f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
143413f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
143513f61dfcSLorenzo Bianconi {
143613f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
143713f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1438723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1439723b90dcSFelix Fietkau }
1440e28487eaSFelix Fietkau 
1441e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1442e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1443e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1444e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1445e28487eaSFelix Fietkau {
1446426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1447426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1448e28487eaSFelix Fietkau 
1449e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1450e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1451a1a99d7bSLorenzo Bianconi 		return mt76_sta_add(phy, vif, sta);
1452e28487eaSFelix Fietkau 
14539c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
14549c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
14559c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
14569c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
14579c193de5SFelix Fietkau 
1458e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1459e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1460e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1461e28487eaSFelix Fietkau 
1462e28487eaSFelix Fietkau 	return 0;
1463e28487eaSFelix Fietkau }
1464e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
14659313faacSFelix Fietkau 
146643ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
146743ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
146843ba1922SFelix Fietkau {
146943ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
147043ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
147143ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
147243ba1922SFelix Fietkau 
147343ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1474fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
147543ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1476fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
147743ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
147843ba1922SFelix Fietkau }
147943ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
148043ba1922SFelix Fietkau 
14819313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
14829313faacSFelix Fietkau 		     int *dbm)
14839313faacSFelix Fietkau {
1484beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1485beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
148607cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
14879313faacSFelix Fietkau 
148807cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
14899313faacSFelix Fietkau 
14909313faacSFelix Fietkau 	return 0;
14919313faacSFelix Fietkau }
14929313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1493e7173858SFelix Fietkau 
1494b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1495b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1496b3cb885eSLorenzo Bianconi {
1497b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1498b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1499b3cb885eSLorenzo Bianconi 	int i;
1500b3cb885eSLorenzo Bianconi 
1501b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1502b3cb885eSLorenzo Bianconi 		return -EINVAL;
1503b3cb885eSLorenzo Bianconi 
1504b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1505b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1506b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1507b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1508b3cb885eSLorenzo Bianconi 
1509b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1510b3cb885eSLorenzo Bianconi 			power = 127;
1511b3cb885eSLorenzo Bianconi 
1512b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1513b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1514b3cb885eSLorenzo Bianconi 	}
1515b3cb885eSLorenzo Bianconi 
1516b3cb885eSLorenzo Bianconi 	return 0;
1517b3cb885eSLorenzo Bianconi }
1518b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1519b3cb885eSLorenzo Bianconi 
1520b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1521b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1522b3cb885eSLorenzo Bianconi 		       int power)
1523b3cb885eSLorenzo Bianconi {
1524b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1525b3cb885eSLorenzo Bianconi 	int freq, i;
1526b3cb885eSLorenzo Bianconi 
1527b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1528b3cb885eSLorenzo Bianconi 		return power;
1529b3cb885eSLorenzo Bianconi 
1530b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1531b3cb885eSLorenzo Bianconi 		power = 127;
1532b3cb885eSLorenzo Bianconi 
1533b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1534b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1535b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1536b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1537b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1538b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1539b3cb885eSLorenzo Bianconi 			break;
1540b3cb885eSLorenzo Bianconi 		}
1541b3cb885eSLorenzo Bianconi 	}
1542b3cb885eSLorenzo Bianconi 
1543b3cb885eSLorenzo Bianconi 	return power;
1544b3cb885eSLorenzo Bianconi }
1545b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1546b3cb885eSLorenzo Bianconi 
1547e7173858SFelix Fietkau static void
1548e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1549e7173858SFelix Fietkau {
1550d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1551e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1552e7173858SFelix Fietkau }
1553e7173858SFelix Fietkau 
1554e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1555e7173858SFelix Fietkau {
1556e7173858SFelix Fietkau 	if (!dev->csa_complete)
1557e7173858SFelix Fietkau 		return;
1558e7173858SFelix Fietkau 
1559e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1560e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1561e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1562e7173858SFelix Fietkau 
1563e7173858SFelix Fietkau 	dev->csa_complete = 0;
1564e7173858SFelix Fietkau }
1565e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1566e7173858SFelix Fietkau 
1567e7173858SFelix Fietkau static void
1568e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1569e7173858SFelix Fietkau {
1570e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1571e7173858SFelix Fietkau 
1572d0a9123eSJohannes Berg 	if (!vif->bss_conf.csa_active)
1573e7173858SFelix Fietkau 		return;
1574e7173858SFelix Fietkau 
15758552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1576e7173858SFelix Fietkau }
1577e7173858SFelix Fietkau 
1578e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1579e7173858SFelix Fietkau {
1580e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1581e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1582e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1583e7173858SFelix Fietkau }
1584e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
158587d53103SStanislaw Gruszka 
158687d53103SStanislaw Gruszka int
158787d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
158887d53103SStanislaw Gruszka {
158987d53103SStanislaw Gruszka 	return 0;
159087d53103SStanislaw Gruszka }
159187d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1592eadfd98fSLorenzo Bianconi 
1593eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1594eadfd98fSLorenzo Bianconi {
1595eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1596eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1597eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1598eadfd98fSLorenzo Bianconi 
1599eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1600eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1601eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1602eadfd98fSLorenzo Bianconi 
1603eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1604eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1605eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1606eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1607eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1608eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1609eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1610eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1611eadfd98fSLorenzo Bianconi 
1612eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1613eadfd98fSLorenzo Bianconi }
1614eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1615d2679d65SLorenzo Bianconi 
1616d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1617d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1618d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1619d2679d65SLorenzo Bianconi {
1620d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1621d2679d65SLorenzo Bianconi 
1622d2679d65SLorenzo Bianconi 	if (cck) {
1623edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1624d2679d65SLorenzo Bianconi 			return 0;
1625d2679d65SLorenzo Bianconi 
1626d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
162796747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1628d2679d65SLorenzo Bianconi 		offset = 4;
1629d2679d65SLorenzo Bianconi 	}
1630d2679d65SLorenzo Bianconi 
1631d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1632d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1633d2679d65SLorenzo Bianconi 			return i;
1634d2679d65SLorenzo Bianconi 	}
1635d2679d65SLorenzo Bianconi 
1636d2679d65SLorenzo Bianconi 	return 0;
1637d2679d65SLorenzo Bianconi }
1638d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
16398b8ab5c2SLorenzo Bianconi 
16408b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16418b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
16428b8ab5c2SLorenzo Bianconi {
1643011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
16448b8ab5c2SLorenzo Bianconi 
1645011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
16468b8ab5c2SLorenzo Bianconi }
16478b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
16488b8ab5c2SLorenzo Bianconi 
16498b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
16508b8ab5c2SLorenzo Bianconi {
1651011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
16528b8ab5c2SLorenzo Bianconi 
1653011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
16548b8ab5c2SLorenzo Bianconi }
16558b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1656e49c76d4SLorenzo Bianconi 
1657e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1658e49c76d4SLorenzo Bianconi {
1659beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1660beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1661e49c76d4SLorenzo Bianconi 
1662e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1663beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1664beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1665e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1666e49c76d4SLorenzo Bianconi 
1667e49c76d4SLorenzo Bianconi 	return 0;
1668e49c76d4SLorenzo Bianconi }
1669e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1670b671da33SLorenzo Bianconi 
1671b1cb42adSLorenzo Bianconi struct mt76_queue *
1672b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1673f68d6762SFelix Fietkau 		int ring_base, u32 flags)
1674b671da33SLorenzo Bianconi {
1675b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1676b671da33SLorenzo Bianconi 	int err;
1677b671da33SLorenzo Bianconi 
1678b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1679b671da33SLorenzo Bianconi 	if (!hwq)
1680b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1681b671da33SLorenzo Bianconi 
1682f68d6762SFelix Fietkau 	hwq->flags = flags;
1683f68d6762SFelix Fietkau 
1684b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1685b671da33SLorenzo Bianconi 	if (err < 0)
1686b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1687b671da33SLorenzo Bianconi 
1688b1cb42adSLorenzo Bianconi 	return hwq;
1689b671da33SLorenzo Bianconi }
1690b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1691e4867225SSean Wang 
169233920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
1693e4867225SSean Wang {
169433920b2bSRyder Lee 	int offset = 0;
1695e4867225SSean Wang 
1696edf9dab8SLorenzo Bianconi 	if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
1697e4867225SSean Wang 		offset = 4;
1698e4867225SSean Wang 
169933920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
170033920b2bSRyder Lee 	if (rateidx < 0)
170133920b2bSRyder Lee 		rateidx = 0;
170233920b2bSRyder Lee 
1703d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1704d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1705d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1706e4867225SSean Wang 
1707d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1708e4867225SSean Wang }
170933920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
171054ae98ffSLorenzo Bianconi 
171154ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1712731425f3SShayne Chen 			 struct mt76_sta_stats *stats, bool eht)
171354ae98ffSLorenzo Bianconi {
171454ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
171554ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
171654ae98ffSLorenzo Bianconi 
171754ae98ffSLorenzo Bianconi 	wi->sta_count++;
171854ae98ffSLorenzo Bianconi 
171954ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
172054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
172154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
172254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
172354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
172454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
172554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
172654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
172754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1728731425f3SShayne Chen 	if (eht) {
1729731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1730731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1731731425f3SShayne Chen 		data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1732731425f3SShayne Chen 	}
173354ae98ffSLorenzo Bianconi 
1734731425f3SShayne Chen 	for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
173554ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
173654ae98ffSLorenzo Bianconi 
1737731425f3SShayne Chen 	for (i = 0; i < (eht ? 14 : 12); i++)
173854ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
173954ae98ffSLorenzo Bianconi 
174054ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
174154ae98ffSLorenzo Bianconi }
174254ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
17433f306448SFelix Fietkau 
1744192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1745192ad406SLorenzo Bianconi {
1746192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS
1747192ad406SLorenzo Bianconi 	struct page_pool_stats stats = {};
1748192ad406SLorenzo Bianconi 	int i;
1749192ad406SLorenzo Bianconi 
1750192ad406SLorenzo Bianconi 	mt76_for_each_q_rx(dev, i)
1751192ad406SLorenzo Bianconi 		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
1752192ad406SLorenzo Bianconi 
1753192ad406SLorenzo Bianconi 	page_pool_ethtool_stats_get(data, &stats);
1754192ad406SLorenzo Bianconi 	*index += page_pool_ethtool_stats_get_count();
1755192ad406SLorenzo Bianconi #endif
1756192ad406SLorenzo Bianconi }
1757192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
1758192ad406SLorenzo Bianconi 
17593f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
17603f306448SFelix Fietkau {
17613f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
17623f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
17633f306448SFelix Fietkau 
17643f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
17653f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
17663f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
17673f306448SFelix Fietkau 
17683f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
17693f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
17703f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
17713f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
17723f306448SFelix Fietkau 
17733f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
17743f306448SFelix Fietkau 	}
17753f306448SFelix Fietkau 
177600a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
17773f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
17783f306448SFelix Fietkau 
17793f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
17803f306448SFelix Fietkau }
17813f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1782