xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 2f5c3c77fc9b6a34b68b97231bfa970e1194ec28)
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>
7*2f5c3c77SLorenzo 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 
421c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
422dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
423b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
424b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
425c89d3625SFelix Fietkau 
426c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
427c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
428d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
429c89d3625SFelix Fietkau 
4300a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4310a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
432c89d3625SFelix Fietkau 
433d43de9cfSLorenzo Bianconi 	wiphy->sar_capa = &mt76_sar_capa;
434d43de9cfSLorenzo Bianconi 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
435d43de9cfSLorenzo Bianconi 				sizeof(struct mt76_freq_range_power),
436d43de9cfSLorenzo Bianconi 				GFP_KERNEL);
437d43de9cfSLorenzo Bianconi 	if (!phy->frp)
438d43de9cfSLorenzo Bianconi 		return -ENOMEM;
439d43de9cfSLorenzo Bianconi 
440c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
441b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
442c9619dfaSShayne Chen 
443c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
444c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
445c89d3625SFelix Fietkau 
446c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
447c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
448c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
449c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
450c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
451c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
452ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
4535b0fb852SBen Greear 
4545b0fb852SBen Greear 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
455c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
456c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
4575b0fb852SBen Greear 	}
4585b0fb852SBen Greear 
459c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
460c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
461c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
462d43de9cfSLorenzo Bianconi 
463d43de9cfSLorenzo Bianconi 	return 0;
464c89d3625SFelix Fietkau }
465c89d3625SFelix Fietkau 
466c89d3625SFelix Fietkau struct mt76_phy *
467c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
468dc44c45cSLorenzo Bianconi 	       const struct ieee80211_ops *ops, u8 band_idx)
469c89d3625SFelix Fietkau {
470c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
471db78a791SLorenzo Bianconi 	unsigned int phy_size;
472c89d3625SFelix Fietkau 	struct mt76_phy *phy;
473c89d3625SFelix Fietkau 
474c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
475db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
476c89d3625SFelix Fietkau 	if (!hw)
477c89d3625SFelix Fietkau 		return NULL;
478c89d3625SFelix Fietkau 
479c89d3625SFelix Fietkau 	phy = hw->priv;
480c89d3625SFelix Fietkau 	phy->dev = dev;
481c89d3625SFelix Fietkau 	phy->hw = hw;
482db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
483dc44c45cSLorenzo Bianconi 	phy->band_idx = band_idx;
484c89d3625SFelix Fietkau 
4858af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4868af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4878af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4888af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4898af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4908af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4918af414e8SLorenzo Bianconi #endif
4928af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4938af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4948af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4958af414e8SLorenzo Bianconi 
496c89d3625SFelix Fietkau 	return phy;
497c89d3625SFelix Fietkau }
498c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
499c89d3625SFelix Fietkau 
500db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
501db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
502c89d3625SFelix Fietkau {
503c89d3625SFelix Fietkau 	int ret;
504c89d3625SFelix Fietkau 
505d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
506d43de9cfSLorenzo Bianconi 	if (ret)
507d43de9cfSLorenzo Bianconi 		return ret;
508db78a791SLorenzo Bianconi 
509db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
510db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
511db78a791SLorenzo Bianconi 		if (ret)
512db78a791SLorenzo Bianconi 			return ret;
513db78a791SLorenzo Bianconi 	}
514db78a791SLorenzo Bianconi 
515db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
516db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
517db78a791SLorenzo Bianconi 		if (ret)
518db78a791SLorenzo Bianconi 			return ret;
519db78a791SLorenzo Bianconi 	}
520db78a791SLorenzo Bianconi 
521edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
522edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
523edf9dab8SLorenzo Bianconi 		if (ret)
524edf9dab8SLorenzo Bianconi 			return ret;
525edf9dab8SLorenzo Bianconi 	}
526edf9dab8SLorenzo Bianconi 
5279e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
5289e81c2c7SLorenzo Bianconi 		ret = mt76_led_init(phy);
5299e81c2c7SLorenzo Bianconi 		if (ret)
5309e81c2c7SLorenzo Bianconi 			return ret;
5319e81c2c7SLorenzo Bianconi 	}
5329e81c2c7SLorenzo Bianconi 
533db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
534db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
535db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
536edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
537db78a791SLorenzo Bianconi 
538c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
539c89d3625SFelix Fietkau 	if (ret)
540c89d3625SFelix Fietkau 		return ret;
541c89d3625SFelix Fietkau 
542dc44c45cSLorenzo Bianconi 	phy->dev->phys[phy->band_idx] = phy;
543db78a791SLorenzo Bianconi 
544c89d3625SFelix Fietkau 	return 0;
545c89d3625SFelix Fietkau }
546c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
547c89d3625SFelix Fietkau 
548db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
549c89d3625SFelix Fietkau {
550c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
551c89d3625SFelix Fietkau 
5529e81c2c7SLorenzo Bianconi 	if (IS_ENABLED(CONFIG_MT76_LEDS))
5539e81c2c7SLorenzo Bianconi 		mt76_led_cleanup(phy);
554c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
555c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
556dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = NULL;
557c89d3625SFelix Fietkau }
558c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
559c89d3625SFelix Fietkau 
560*2f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
561*2f5c3c77SLorenzo Bianconi {
562*2f5c3c77SLorenzo Bianconi 	struct page_pool_params pp_params = {
563*2f5c3c77SLorenzo Bianconi 		.order = 0,
564*2f5c3c77SLorenzo Bianconi 		.flags = PP_FLAG_PAGE_FRAG,
565*2f5c3c77SLorenzo Bianconi 		.nid = NUMA_NO_NODE,
566*2f5c3c77SLorenzo Bianconi 		.dev = dev->dma_dev,
567*2f5c3c77SLorenzo Bianconi 	};
568*2f5c3c77SLorenzo Bianconi 	int idx = q - dev->q_rx;
569*2f5c3c77SLorenzo Bianconi 
570*2f5c3c77SLorenzo Bianconi 	switch (idx) {
571*2f5c3c77SLorenzo Bianconi 	case MT_RXQ_MAIN:
572*2f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND1:
573*2f5c3c77SLorenzo Bianconi 	case MT_RXQ_BAND2:
574*2f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 256;
575*2f5c3c77SLorenzo Bianconi 		break;
576*2f5c3c77SLorenzo Bianconi 	default:
577*2f5c3c77SLorenzo Bianconi 		pp_params.pool_size = 16;
578*2f5c3c77SLorenzo Bianconi 		break;
579*2f5c3c77SLorenzo Bianconi 	}
580*2f5c3c77SLorenzo Bianconi 
581*2f5c3c77SLorenzo Bianconi 	if (mt76_is_mmio(dev)) {
582*2f5c3c77SLorenzo Bianconi 		/* rely on page_pool for DMA mapping */
583*2f5c3c77SLorenzo Bianconi 		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
584*2f5c3c77SLorenzo Bianconi 		pp_params.dma_dir = DMA_FROM_DEVICE;
585*2f5c3c77SLorenzo Bianconi 		pp_params.max_len = PAGE_SIZE;
586*2f5c3c77SLorenzo Bianconi 		pp_params.offset = 0;
587*2f5c3c77SLorenzo Bianconi 	}
588*2f5c3c77SLorenzo Bianconi 
589*2f5c3c77SLorenzo Bianconi 	q->page_pool = page_pool_create(&pp_params);
590*2f5c3c77SLorenzo Bianconi 	if (IS_ERR(q->page_pool)) {
591*2f5c3c77SLorenzo Bianconi 		int err = PTR_ERR(q->page_pool);
592*2f5c3c77SLorenzo Bianconi 
593*2f5c3c77SLorenzo Bianconi 		q->page_pool = NULL;
594*2f5c3c77SLorenzo Bianconi 		return err;
595*2f5c3c77SLorenzo Bianconi 	}
596*2f5c3c77SLorenzo Bianconi 
597*2f5c3c77SLorenzo Bianconi 	return 0;
598*2f5c3c77SLorenzo Bianconi }
599*2f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool);
600*2f5c3c77SLorenzo Bianconi 
601a85b590cSFelix Fietkau struct mt76_dev *
602c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
603c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
604c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
605a85b590cSFelix Fietkau {
606a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
607ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
608a85b590cSFelix Fietkau 	struct mt76_dev *dev;
609e5443256SFelix Fietkau 	int i;
610a85b590cSFelix Fietkau 
611a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
612a85b590cSFelix Fietkau 	if (!hw)
613a85b590cSFelix Fietkau 		return NULL;
614a85b590cSFelix Fietkau 
615a85b590cSFelix Fietkau 	dev = hw->priv;
616a85b590cSFelix Fietkau 	dev->hw = hw;
617c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
618c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
619d1ddc536SFelix Fietkau 	dev->dma_dev = pdev;
620c0f7b25aSLorenzo Bianconi 
621ac24dd35SFelix Fietkau 	phy = &dev->phy;
622ac24dd35SFelix Fietkau 	phy->dev = dev;
623ac24dd35SFelix Fietkau 	phy->hw = hw;
624dc44c45cSLorenzo Bianconi 	phy->band_idx = MT_BAND0;
625dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = phy;
626ac24dd35SFelix Fietkau 
627a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
628a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
629a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
630c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
6312666beceSSujuan Chen 	spin_lock_init(&dev->wed_lock);
632108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
63326e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
634a85b590cSFelix Fietkau 
63509872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
63609872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
63709872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
638781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
63909872957SLorenzo Bianconi 
6408af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6418af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
6428af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
6438af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
6448af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
6458af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
6468af414e8SLorenzo Bianconi #endif
6478af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
6488af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
6498af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
6508af414e8SLorenzo Bianconi 
65151252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
65251252cc5SLorenzo Bianconi 	idr_init(&dev->token);
65351252cc5SLorenzo Bianconi 
6542666beceSSujuan Chen 	spin_lock_init(&dev->rx_token_lock);
6552666beceSSujuan Chen 	idr_init(&dev->rx_token);
6562666beceSSujuan Chen 
657bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
658bd1e3e7bSLorenzo Bianconi 
659e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
6602666beceSSujuan Chen 	INIT_LIST_HEAD(&dev->rxwi_cache);
66161b5156bSFelix Fietkau 	dev->token_size = dev->drv->token_size;
662e5443256SFelix Fietkau 
663e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
664e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
665e5443256SFelix Fietkau 
666a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
667a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
668a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
669a86f1d01SLorenzo Bianconi 		return NULL;
670a86f1d01SLorenzo Bianconi 	}
671a86f1d01SLorenzo Bianconi 
672a85b590cSFelix Fietkau 	return dev;
673a85b590cSFelix Fietkau }
674a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
675a85b590cSFelix Fietkau 
67617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
67717f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
67817f1de56SFelix Fietkau {
67917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
680c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
68117f1de56SFelix Fietkau 	int ret;
68217f1de56SFelix Fietkau 
68317f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
684d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
685d43de9cfSLorenzo Bianconi 	if (ret)
686d43de9cfSLorenzo Bianconi 		return ret;
68717f1de56SFelix Fietkau 
68848dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
68977af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
69017f1de56SFelix Fietkau 		if (ret)
69117f1de56SFelix Fietkau 			return ret;
69217f1de56SFelix Fietkau 	}
69317f1de56SFelix Fietkau 
69448dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
69577af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
69617f1de56SFelix Fietkau 		if (ret)
69717f1de56SFelix Fietkau 			return ret;
69817f1de56SFelix Fietkau 	}
69917f1de56SFelix Fietkau 
700edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
701edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
702edf9dab8SLorenzo Bianconi 		if (ret)
703edf9dab8SLorenzo Bianconi 			return ret;
704edf9dab8SLorenzo Bianconi 	}
705edf9dab8SLorenzo Bianconi 
706c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
707c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
708c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
709edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
71017f1de56SFelix Fietkau 
711b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
7123abd46ddSLorenzo Bianconi 		ret = mt76_led_init(phy);
71317f1de56SFelix Fietkau 		if (ret)
71417f1de56SFelix Fietkau 			return ret;
715b374e868SArnd Bergmann 	}
71617f1de56SFelix Fietkau 
717781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
718781eef5bSFelix Fietkau 	if (ret)
719781eef5bSFelix Fietkau 		return ret;
720781eef5bSFelix Fietkau 
721781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
722781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
723781eef5bSFelix Fietkau 
724781eef5bSFelix Fietkau 	return 0;
72517f1de56SFelix Fietkau }
72617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
72717f1de56SFelix Fietkau 
72817f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
72917f1de56SFelix Fietkau {
73017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
73117f1de56SFelix Fietkau 
732d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
7333abd46ddSLorenzo Bianconi 		mt76_led_cleanup(&dev->phy);
734c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
73517f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
73617f1de56SFelix Fietkau }
73717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
73817f1de56SFelix Fietkau 
739def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
740def34a2fSLorenzo Bianconi {
741781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
742a86f1d01SLorenzo Bianconi 	if (dev->wq) {
743a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
744a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
745a86f1d01SLorenzo Bianconi 	}
746def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
747def34a2fSLorenzo Bianconi }
748def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
749def34a2fSLorenzo Bianconi 
750cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
751cc4b3c13SLorenzo Bianconi {
752cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
7532c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
754cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
755cc4b3c13SLorenzo Bianconi 
756cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
757cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
7582c2bdd23SFelix Fietkau 
7592c2bdd23SFelix Fietkau 	/*
7602c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
7612c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7622c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
7632c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
7642c2bdd23SFelix Fietkau 	 * address.
7652c2bdd23SFelix Fietkau 	 */
7662c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
7672c2bdd23SFelix Fietkau 		int offset = 0;
7682c2bdd23SFelix Fietkau 
7692c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
7702c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
7712c2bdd23SFelix Fietkau 
7722c2bdd23SFelix Fietkau 			if ((status->flag &
7732c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
7742c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
7752c2bdd23SFelix Fietkau 				offset += 8;
7762c2bdd23SFelix Fietkau 		}
7772c2bdd23SFelix Fietkau 
7782c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
7792c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
7802c2bdd23SFelix Fietkau 			return;
7812c2bdd23SFelix Fietkau 		}
7822c2bdd23SFelix Fietkau 	}
783cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
784cc4b3c13SLorenzo Bianconi }
785cc4b3c13SLorenzo Bianconi 
786cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
787cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
788cc4b3c13SLorenzo Bianconi {
789cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
790cc4b3c13SLorenzo Bianconi 
791cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
792cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
793cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
794cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
795cc4b3c13SLorenzo Bianconi 
796cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
797cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
798cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
799cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
800cc4b3c13SLorenzo Bianconi 	} else {
801cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
802cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
803cc4b3c13SLorenzo Bianconi 	}
804cc4b3c13SLorenzo Bianconi 
805cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
806cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
807cc4b3c13SLorenzo Bianconi }
808cc4b3c13SLorenzo Bianconi 
80917f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
81017f1de56SFelix Fietkau {
811011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
812128c9b7dSLorenzo Bianconi 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
813011849e0SFelix Fietkau 
814011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
81517f1de56SFelix Fietkau 		dev_kfree_skb(skb);
81617f1de56SFelix Fietkau 		return;
81717f1de56SFelix Fietkau 	}
81817f1de56SFelix Fietkau 
819f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
820c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
821c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
822f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
823c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
824f0efa862SFelix Fietkau 	}
825f0efa862SFelix Fietkau #endif
826cc4b3c13SLorenzo Bianconi 
827cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
82817f1de56SFelix Fietkau }
82917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
83017f1de56SFelix Fietkau 
8315a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
83226e40d4cSFelix Fietkau {
833af005f26SLorenzo Bianconi 	struct mt76_queue *q;
83491990519SLorenzo Bianconi 	int i;
8355a95ca41SFelix Fietkau 
8365a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
83791990519SLorenzo Bianconi 		q = phy->q_tx[i];
838af005f26SLorenzo Bianconi 		if (q && q->queued)
83926e40d4cSFelix Fietkau 			return true;
84026e40d4cSFelix Fietkau 	}
84126e40d4cSFelix Fietkau 
84226e40d4cSFelix Fietkau 	return false;
84326e40d4cSFelix Fietkau }
84439d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
84526e40d4cSFelix Fietkau 
8460fd0eb54SFelix Fietkau static struct mt76_channel_state *
84796747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8480fd0eb54SFelix Fietkau {
8490fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
8500fd0eb54SFelix Fietkau 	int idx;
8510fd0eb54SFelix Fietkau 
8520fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
85396747a51SFelix Fietkau 		msband = &phy->sband_2g;
854edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
855edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
8560fd0eb54SFelix Fietkau 	else
85796747a51SFelix Fietkau 		msband = &phy->sband_5g;
8580fd0eb54SFelix Fietkau 
8590fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
8600fd0eb54SFelix Fietkau 	return &msband->chan[idx];
8610fd0eb54SFelix Fietkau }
8620fd0eb54SFelix Fietkau 
86304414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
86496747a51SFelix Fietkau {
86596747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
86696747a51SFelix Fietkau 
86796747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
86896747a51SFelix Fietkau 						  phy->survey_time));
86996747a51SFelix Fietkau 	phy->survey_time = time;
87096747a51SFelix Fietkau }
87104414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
87296747a51SFelix Fietkau 
873c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
8745ce09c1aSFelix Fietkau {
875c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
876aec65e48SFelix Fietkau 	ktime_t cur_time;
877aec65e48SFelix Fietkau 
8785ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
879c560b137SRyder Lee 		dev->drv->update_survey(phy);
8805ce09c1aSFelix Fietkau 
881aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
882c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
883aec65e48SFelix Fietkau 
8845ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
885c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
88696747a51SFelix Fietkau 
887237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
8885ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
8895ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
890237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
8915ce09c1aSFelix Fietkau 	}
8925ce09c1aSFelix Fietkau }
8935ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
8945ce09c1aSFelix Fietkau 
89596747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
89617f1de56SFelix Fietkau {
89796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
89896747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
89917f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
90017f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
90126e40d4cSFelix Fietkau 	int timeout = HZ / 5;
90217f1de56SFelix Fietkau 
9035a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
904c560b137SRyder Lee 	mt76_update_survey(phy);
90517f1de56SFelix Fietkau 
9063f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9073f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
9083f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9093f306448SFelix Fietkau 
91096747a51SFelix Fietkau 	phy->chandef = *chandef;
91196747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
91217f1de56SFelix Fietkau 
91317f1de56SFelix Fietkau 	if (!offchannel)
91496747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
91517f1de56SFelix Fietkau 
91696747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
91796747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
91817f1de56SFelix Fietkau }
91917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
92017f1de56SFelix Fietkau 
92117f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
92217f1de56SFelix Fietkau 		    struct survey_info *survey)
92317f1de56SFelix Fietkau {
92496747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
92596747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
92617f1de56SFelix Fietkau 	struct mt76_sband *sband;
92717f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
92817f1de56SFelix Fietkau 	struct mt76_channel_state *state;
92917f1de56SFelix Fietkau 	int ret = 0;
93017f1de56SFelix Fietkau 
931237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
93217f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
933c560b137SRyder Lee 		mt76_update_survey(phy);
93417f1de56SFelix Fietkau 
935edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
936edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
937edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
938edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
939edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
940edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
941edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
94296747a51SFelix Fietkau 		sband = &phy->sband_5g;
943edf9dab8SLorenzo Bianconi 	} else {
944edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
94517f1de56SFelix Fietkau 	}
94617f1de56SFelix Fietkau 
947237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
948237312c5SLorenzo Bianconi 		ret = -ENOENT;
949237312c5SLorenzo Bianconi 		goto out;
950237312c5SLorenzo Bianconi 	}
95117f1de56SFelix Fietkau 
95217f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
95396747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
95417f1de56SFelix Fietkau 
95517f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
95617f1de56SFelix Fietkau 	survey->channel = chan;
95717f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
958ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
959e5051965SFelix Fietkau 	if (state->noise)
960e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
961e5051965SFelix Fietkau 
96296747a51SFelix Fietkau 	if (chan == phy->main_chan) {
96317f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
96417f1de56SFelix Fietkau 
9655ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
9665ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
9675ce09c1aSFelix Fietkau 	}
9685ce09c1aSFelix Fietkau 
96917f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
9706bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
971237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
972e5051965SFelix Fietkau 	survey->noise = state->noise;
973237312c5SLorenzo Bianconi 
974237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
975237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
976ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
97717f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
97817f1de56SFelix Fietkau 
979237312c5SLorenzo Bianconi out:
980237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
981237312c5SLorenzo Bianconi 
98217f1de56SFelix Fietkau 	return ret;
98317f1de56SFelix Fietkau }
98417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
98517f1de56SFelix Fietkau 
98630ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
98730ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
98830ce7f44SFelix Fietkau {
98930ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
99030ce7f44SFelix Fietkau 	int i;
99130ce7f44SFelix Fietkau 
99230ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
99330ce7f44SFelix Fietkau 
99430ce7f44SFelix Fietkau 	if (!key)
99530ce7f44SFelix Fietkau 		return;
99630ce7f44SFelix Fietkau 
99701cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
99801cfc1b4SLorenzo Bianconi 		return;
99930ce7f44SFelix Fietkau 
100001cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
1001a1b0bbd4SXing Song 
1002a1b0bbd4SXing Song 	/* data frame */
100330ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
100430ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
100530ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
100630ce7f44SFelix Fietkau 	}
1007a1b0bbd4SXing Song 
1008a1b0bbd4SXing Song 	/* robust management frame */
1009a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
1010a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
1011a1b0bbd4SXing Song 
101230ce7f44SFelix Fietkau }
101330ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
101430ce7f44SFelix Fietkau 
1015a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10164550fb9eSFelix Fietkau {
10174550fb9eSFelix Fietkau 	int signal = -128;
10184550fb9eSFelix Fietkau 	u8 chains;
10194550fb9eSFelix Fietkau 
1020a71b648eSRyder Lee 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10214550fb9eSFelix Fietkau 		int cur, diff;
10224550fb9eSFelix Fietkau 
10236450b133SDeren Wu 		cur = *chain_signal;
10246450b133SDeren Wu 		if (!(chains & BIT(0)) ||
10256450b133SDeren Wu 		    cur > 0)
10264550fb9eSFelix Fietkau 			continue;
10274550fb9eSFelix Fietkau 
10284550fb9eSFelix Fietkau 		if (cur > signal)
10294550fb9eSFelix Fietkau 			swap(cur, signal);
10304550fb9eSFelix Fietkau 
10314550fb9eSFelix Fietkau 		diff = signal - cur;
10324550fb9eSFelix Fietkau 		if (diff == 0)
10334550fb9eSFelix Fietkau 			signal += 3;
10344550fb9eSFelix Fietkau 		else if (diff <= 2)
10354550fb9eSFelix Fietkau 			signal += 2;
10364550fb9eSFelix Fietkau 		else if (diff <= 6)
10374550fb9eSFelix Fietkau 			signal += 1;
10384550fb9eSFelix Fietkau 	}
10394550fb9eSFelix Fietkau 
10404550fb9eSFelix Fietkau 	return signal;
10414550fb9eSFelix Fietkau }
1042a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
10434550fb9eSFelix Fietkau 
1044bfc394ddSFelix Fietkau static void
1045bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
1046bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
1047bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
10484e34249eSFelix Fietkau {
10494e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1050abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
10514e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
10524e34249eSFelix Fietkau 
10534e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
10544e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
10554e34249eSFelix Fietkau 
10564e34249eSFelix Fietkau 	status->flag = mstat.flag;
10574e34249eSFelix Fietkau 	status->freq = mstat.freq;
10584e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
10594e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
10604e34249eSFelix Fietkau 	status->bw = mstat.bw;
1061af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
1062af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
1063af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
10644e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
10654e34249eSFelix Fietkau 	status->nss = mstat.nss;
10664e34249eSFelix Fietkau 	status->band = mstat.band;
10674e34249eSFelix Fietkau 	status->signal = mstat.signal;
10684e34249eSFelix Fietkau 	status->chains = mstat.chains;
1069d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
10700fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
10710fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
1072a71b648eSRyder Lee 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
10734550fb9eSFelix Fietkau 	if (status->signal <= -128)
10744550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
10754e34249eSFelix Fietkau 
1076abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
1077abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
1078abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1079abe3f3daSRyder Lee 
10804e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
108113381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
108213381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
108313381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
108413381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
10859c68a57bSFelix Fietkau 
1086bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1087128c9b7dSLorenzo Bianconi 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
10884e34249eSFelix Fietkau }
10894e34249eSFelix Fietkau 
10903c1032e1SFelix Fietkau static void
109130ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
109230ce7f44SFelix Fietkau {
109330ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
109430ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
109530ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1096a1b0bbd4SXing Song 	int security_idx;
109730ce7f44SFelix Fietkau 	int ret;
109830ce7f44SFelix Fietkau 
109930ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
11003c1032e1SFelix Fietkau 		return;
110130ce7f44SFelix Fietkau 
11021858e4fcSMeiChia Chiu 	if (status->flag & RX_FLAG_ONLY_MONITOR)
11033c1032e1SFelix Fietkau 		return;
11041858e4fcSMeiChia Chiu 
110530ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
11063c1032e1SFelix Fietkau 		return;
110730ce7f44SFelix Fietkau 
11087360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11097360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
11107360cdecSFelix Fietkau 		goto skip_hdr_check;
11117360cdecSFelix Fietkau 
1112a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
111330ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
111430ce7f44SFelix Fietkau 		/*
111530ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
111630ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
111730ce7f44SFelix Fietkau 		 */
111830ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
111930ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
11203c1032e1SFelix Fietkau 			return;
112130ce7f44SFelix Fietkau 	}
112230ce7f44SFelix Fietkau 
1123a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1124a1b0bbd4SXing Song 	 *
1125a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1126a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1127a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1128a1b0bbd4SXing Song 	 */
1129a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1130a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1131a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1132a1b0bbd4SXing Song 
11337360cdecSFelix Fietkau skip_hdr_check:
113430ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1135a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
113630ce7f44SFelix Fietkau 		     sizeof(status->iv));
11373c1032e1SFelix Fietkau 	if (ret <= 0) {
11383c1032e1SFelix Fietkau 		status->flag |= RX_FLAG_ONLY_MONITOR;
11393c1032e1SFelix Fietkau 		return;
11403c1032e1SFelix Fietkau 	}
114130ce7f44SFelix Fietkau 
1142a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
114330ce7f44SFelix Fietkau 
114430ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
114530ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
114630ce7f44SFelix Fietkau }
114730ce7f44SFelix Fietkau 
1148d71ef286SFelix Fietkau static void
11495ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
11505ce09c1aSFelix Fietkau 		    int len)
11515ce09c1aSFelix Fietkau {
11525ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
115385b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
115485b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
115585b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
115685b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
115785b7a5d0SLorenzo Bianconi 		.band = status->band,
115885b7a5d0SLorenzo Bianconi 		.nss = status->nss,
115985b7a5d0SLorenzo Bianconi 		.bw = status->bw,
116085b7a5d0SLorenzo Bianconi 	};
11615ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
11625ce09c1aSFelix Fietkau 	u32 airtime;
1163e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11645ce09c1aSFelix Fietkau 
116585b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1166237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
11675ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1168237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
11695ce09c1aSFelix Fietkau 
11705ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
11715ce09c1aSFelix Fietkau 		return;
11725ce09c1aSFelix Fietkau 
11735ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1174e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
11755ce09c1aSFelix Fietkau }
11765ce09c1aSFelix Fietkau 
11775ce09c1aSFelix Fietkau static void
11785ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
11795ce09c1aSFelix Fietkau {
11805ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
11815ce09c1aSFelix Fietkau 	int wcid_idx;
11825ce09c1aSFelix Fietkau 
11835ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
11845ce09c1aSFelix Fietkau 		return;
11855ce09c1aSFelix Fietkau 
11865ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1187bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
11885ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
11895ce09c1aSFelix Fietkau 	else
11905ce09c1aSFelix Fietkau 		wcid = NULL;
11915ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
11925ce09c1aSFelix Fietkau 
11935ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
11945ce09c1aSFelix Fietkau 
11955ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
11965ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
11975ce09c1aSFelix Fietkau }
11985ce09c1aSFelix Fietkau 
11995ce09c1aSFelix Fietkau static void
12005ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12015ce09c1aSFelix Fietkau {
12025ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12035ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
12045ce09c1aSFelix Fietkau 
12055ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12065ce09c1aSFelix Fietkau 		return;
12075ce09c1aSFelix Fietkau 
12085ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1209e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1210e195dad1SFelix Fietkau 
1211e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1212e195dad1SFelix Fietkau 			return;
1213e195dad1SFelix Fietkau 
121498df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12155ce09c1aSFelix Fietkau 			return;
12165ce09c1aSFelix Fietkau 
12175ce09c1aSFelix Fietkau 		wcid = NULL;
12185ce09c1aSFelix Fietkau 	}
12195ce09c1aSFelix Fietkau 
12205ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12215ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
12225ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
12235ce09c1aSFelix Fietkau 
12245ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12255ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
12265ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
12275ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
12285ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
12295ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
12305ce09c1aSFelix Fietkau 		}
12315ce09c1aSFelix Fietkau 
12325ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
12335ce09c1aSFelix Fietkau 		return;
12345ce09c1aSFelix Fietkau 	}
12355ce09c1aSFelix Fietkau 
12365ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
12375ce09c1aSFelix Fietkau }
12385ce09c1aSFelix Fietkau 
12395ce09c1aSFelix Fietkau static void
1240ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1241d71ef286SFelix Fietkau {
1242d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
124377ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1244d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1245bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1246d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1247e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1248d71ef286SFelix Fietkau 	bool ps;
1249d71ef286SFelix Fietkau 
1250128c9b7dSLorenzo Bianconi 	hw = mt76_phy_hw(dev, status->phy_idx);
1251e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1252e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1253bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
125436d91096SFelix Fietkau 		if (sta)
125536d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
125636d91096SFelix Fietkau 	}
125736d91096SFelix Fietkau 
12585ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
12595ce09c1aSFelix Fietkau 
1260d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1261d71ef286SFelix Fietkau 		return;
1262d71ef286SFelix Fietkau 
1263d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1264d71ef286SFelix Fietkau 
126502e5a769SFelix Fietkau 	if (status->signal <= 0)
126602e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
126702e5a769SFelix Fietkau 
1268ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1269ef13edc0SFelix Fietkau 
1270e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1271e195dad1SFelix Fietkau 		return;
1272e195dad1SFelix Fietkau 
1273d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1274d71ef286SFelix Fietkau 		return;
1275d71ef286SFelix Fietkau 
1276d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1277d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1278d71ef286SFelix Fietkau 		return;
1279d71ef286SFelix Fietkau 	}
1280d71ef286SFelix Fietkau 
1281d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1282d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1283d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1284d71ef286SFelix Fietkau 		return;
1285d71ef286SFelix Fietkau 
1286d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1287d71ef286SFelix Fietkau 
1288d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1289d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1290e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1291d71ef286SFelix Fietkau 
1292d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1293d71ef286SFelix Fietkau 		return;
1294d71ef286SFelix Fietkau 
129511b2a25fSFelix Fietkau 	if (ps)
1296d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1297d71ef286SFelix Fietkau 
1298d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
1299608f7c47SFelix Fietkau 
1300608f7c47SFelix Fietkau 	if (!ps)
1301608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1302608f7c47SFelix Fietkau 
13039f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1304d71ef286SFelix Fietkau }
1305d71ef286SFelix Fietkau 
13069d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
130781e850efSLorenzo Bianconi 		      struct napi_struct *napi)
130817f1de56SFelix Fietkau {
13099c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1310bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
13113298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
13123298b1f8SFelix Fietkau 	LIST_HEAD(list);
13139d9d738bSFelix Fietkau 
1314c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
13159d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1316cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1317cc4b3c13SLorenzo Bianconi 
13183c1032e1SFelix Fietkau 		mt76_check_ccmp_pn(skb);
1319cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1320bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
13213298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1322cc4b3c13SLorenzo Bianconi 
1323cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1324cc4b3c13SLorenzo Bianconi 		while (nskb) {
1325cc4b3c13SLorenzo Bianconi 			skb = nskb;
1326cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1327cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1328cc4b3c13SLorenzo Bianconi 
1329cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1330cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1331cc4b3c13SLorenzo Bianconi 		}
13329d9d738bSFelix Fietkau 	}
1333c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
13343298b1f8SFelix Fietkau 
13353298b1f8SFelix Fietkau 	if (!napi) {
13363298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
13373298b1f8SFelix Fietkau 		return;
13383298b1f8SFelix Fietkau 	}
13393298b1f8SFelix Fietkau 
13403298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
13413298b1f8SFelix Fietkau 		skb_list_del_init(skb);
13423298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
13433298b1f8SFelix Fietkau 	}
13449d9d738bSFelix Fietkau }
13459d9d738bSFelix Fietkau 
134681e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
134781e850efSLorenzo Bianconi 			   struct napi_struct *napi)
13489d9d738bSFelix Fietkau {
1349aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
135017f1de56SFelix Fietkau 	struct sk_buff *skb;
135117f1de56SFelix Fietkau 
1352aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1353aee5b8cfSFelix Fietkau 
1354d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1355ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
13564f831d18SLorenzo Bianconi 		if (mtk_wed_device_active(&dev->mmio.wed))
13574f831d18SLorenzo Bianconi 			__skb_queue_tail(&frames, skb);
13584f831d18SLorenzo Bianconi 		else
1359aee5b8cfSFelix Fietkau 			mt76_rx_aggr_reorder(skb, &frames);
1360d71ef286SFelix Fietkau 	}
1361aee5b8cfSFelix Fietkau 
136281e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
13634e34249eSFelix Fietkau }
136481e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1365723b90dcSFelix Fietkau 
1366e28487eaSFelix Fietkau static int
1367a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1368a1a99d7bSLorenzo Bianconi 	     struct ieee80211_sta *sta)
1369e28487eaSFelix Fietkau {
1370e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1371a1a99d7bSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1372e28487eaSFelix Fietkau 	int ret;
1373e28487eaSFelix Fietkau 	int i;
1374e28487eaSFelix Fietkau 
1375e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1376e28487eaSFelix Fietkau 
1377e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1378e28487eaSFelix Fietkau 	if (ret)
1379e28487eaSFelix Fietkau 		goto out;
1380e28487eaSFelix Fietkau 
1381e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1382e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1383e28487eaSFelix Fietkau 
1384e28487eaSFelix Fietkau 		if (!sta->txq[i])
1385e28487eaSFelix Fietkau 			continue;
1386e28487eaSFelix Fietkau 
1387e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
138851fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1389e28487eaSFelix Fietkau 	}
1390e28487eaSFelix Fietkau 
1391ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1392a1a99d7bSLorenzo Bianconi 	if (phy->band_idx == MT_BAND1)
1393426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1394a1a99d7bSLorenzo Bianconi 	wcid->phy_idx = phy->band_idx;
1395e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1396e28487eaSFelix Fietkau 
1397bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_init(wcid);
1398e28487eaSFelix Fietkau out:
1399e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1400e28487eaSFelix Fietkau 
1401e28487eaSFelix Fietkau 	return ret;
1402e28487eaSFelix Fietkau }
1403e28487eaSFelix Fietkau 
140413f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1405723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1406723b90dcSFelix Fietkau {
1407723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
140813f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1409723b90dcSFelix Fietkau 
141058bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
141158bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
141258bab0d4SFelix Fietkau 
1413e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1414e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1415e28487eaSFelix Fietkau 
1416bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_flush(dev, wcid);
1417bd1e3e7bSLorenzo Bianconi 
1418426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1419426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
142013f61dfcSLorenzo Bianconi }
142113f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1422e28487eaSFelix Fietkau 
142313f61dfcSLorenzo Bianconi static void
142413f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
142513f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
142613f61dfcSLorenzo Bianconi {
142713f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
142813f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1429723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1430723b90dcSFelix Fietkau }
1431e28487eaSFelix Fietkau 
1432e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1433e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1434e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1435e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1436e28487eaSFelix Fietkau {
1437426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1438426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1439e28487eaSFelix Fietkau 
1440e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1441e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1442a1a99d7bSLorenzo Bianconi 		return mt76_sta_add(phy, vif, sta);
1443e28487eaSFelix Fietkau 
14449c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
14459c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
14469c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
14479c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
14489c193de5SFelix Fietkau 
1449e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1450e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1451e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1452e28487eaSFelix Fietkau 
1453e28487eaSFelix Fietkau 	return 0;
1454e28487eaSFelix Fietkau }
1455e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
14569313faacSFelix Fietkau 
145743ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
145843ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
145943ba1922SFelix Fietkau {
146043ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
146143ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
146243ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
146343ba1922SFelix Fietkau 
146443ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1465fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
146643ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1467fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
146843ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
146943ba1922SFelix Fietkau }
147043ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
147143ba1922SFelix Fietkau 
14729313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
14739313faacSFelix Fietkau 		     int *dbm)
14749313faacSFelix Fietkau {
1475beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1476beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
147707cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
14789313faacSFelix Fietkau 
147907cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
14809313faacSFelix Fietkau 
14819313faacSFelix Fietkau 	return 0;
14829313faacSFelix Fietkau }
14839313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1484e7173858SFelix Fietkau 
1485b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1486b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1487b3cb885eSLorenzo Bianconi {
1488b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1489b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1490b3cb885eSLorenzo Bianconi 	int i;
1491b3cb885eSLorenzo Bianconi 
1492b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1493b3cb885eSLorenzo Bianconi 		return -EINVAL;
1494b3cb885eSLorenzo Bianconi 
1495b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1496b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1497b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1498b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1499b3cb885eSLorenzo Bianconi 
1500b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1501b3cb885eSLorenzo Bianconi 			power = 127;
1502b3cb885eSLorenzo Bianconi 
1503b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1504b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1505b3cb885eSLorenzo Bianconi 	}
1506b3cb885eSLorenzo Bianconi 
1507b3cb885eSLorenzo Bianconi 	return 0;
1508b3cb885eSLorenzo Bianconi }
1509b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1510b3cb885eSLorenzo Bianconi 
1511b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1512b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1513b3cb885eSLorenzo Bianconi 		       int power)
1514b3cb885eSLorenzo Bianconi {
1515b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1516b3cb885eSLorenzo Bianconi 	int freq, i;
1517b3cb885eSLorenzo Bianconi 
1518b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1519b3cb885eSLorenzo Bianconi 		return power;
1520b3cb885eSLorenzo Bianconi 
1521b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1522b3cb885eSLorenzo Bianconi 		power = 127;
1523b3cb885eSLorenzo Bianconi 
1524b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1525b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1526b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1527b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1528b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1529b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1530b3cb885eSLorenzo Bianconi 			break;
1531b3cb885eSLorenzo Bianconi 		}
1532b3cb885eSLorenzo Bianconi 	}
1533b3cb885eSLorenzo Bianconi 
1534b3cb885eSLorenzo Bianconi 	return power;
1535b3cb885eSLorenzo Bianconi }
1536b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1537b3cb885eSLorenzo Bianconi 
1538e7173858SFelix Fietkau static void
1539e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1540e7173858SFelix Fietkau {
1541d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1542e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1543e7173858SFelix Fietkau }
1544e7173858SFelix Fietkau 
1545e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1546e7173858SFelix Fietkau {
1547e7173858SFelix Fietkau 	if (!dev->csa_complete)
1548e7173858SFelix Fietkau 		return;
1549e7173858SFelix Fietkau 
1550e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1551e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1552e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1553e7173858SFelix Fietkau 
1554e7173858SFelix Fietkau 	dev->csa_complete = 0;
1555e7173858SFelix Fietkau }
1556e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1557e7173858SFelix Fietkau 
1558e7173858SFelix Fietkau static void
1559e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1560e7173858SFelix Fietkau {
1561e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1562e7173858SFelix Fietkau 
1563d0a9123eSJohannes Berg 	if (!vif->bss_conf.csa_active)
1564e7173858SFelix Fietkau 		return;
1565e7173858SFelix Fietkau 
15668552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1567e7173858SFelix Fietkau }
1568e7173858SFelix Fietkau 
1569e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1570e7173858SFelix Fietkau {
1571e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1572e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1573e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1574e7173858SFelix Fietkau }
1575e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
157687d53103SStanislaw Gruszka 
157787d53103SStanislaw Gruszka int
157887d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
157987d53103SStanislaw Gruszka {
158087d53103SStanislaw Gruszka 	return 0;
158187d53103SStanislaw Gruszka }
158287d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1583eadfd98fSLorenzo Bianconi 
1584eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1585eadfd98fSLorenzo Bianconi {
1586eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1587eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1588eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1589eadfd98fSLorenzo Bianconi 
1590eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1591eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1592eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1593eadfd98fSLorenzo Bianconi 
1594eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1595eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1596eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1597eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1598eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1599eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1600eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1601eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1602eadfd98fSLorenzo Bianconi 
1603eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1604eadfd98fSLorenzo Bianconi }
1605eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1606d2679d65SLorenzo Bianconi 
1607d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1608d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1609d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1610d2679d65SLorenzo Bianconi {
1611d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1612d2679d65SLorenzo Bianconi 
1613d2679d65SLorenzo Bianconi 	if (cck) {
1614edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1615d2679d65SLorenzo Bianconi 			return 0;
1616d2679d65SLorenzo Bianconi 
1617d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
161896747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1619d2679d65SLorenzo Bianconi 		offset = 4;
1620d2679d65SLorenzo Bianconi 	}
1621d2679d65SLorenzo Bianconi 
1622d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1623d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1624d2679d65SLorenzo Bianconi 			return i;
1625d2679d65SLorenzo Bianconi 	}
1626d2679d65SLorenzo Bianconi 
1627d2679d65SLorenzo Bianconi 	return 0;
1628d2679d65SLorenzo Bianconi }
1629d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
16308b8ab5c2SLorenzo Bianconi 
16318b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16328b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
16338b8ab5c2SLorenzo Bianconi {
1634011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
16358b8ab5c2SLorenzo Bianconi 
1636011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
16378b8ab5c2SLorenzo Bianconi }
16388b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
16398b8ab5c2SLorenzo Bianconi 
16408b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
16418b8ab5c2SLorenzo Bianconi {
1642011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
16438b8ab5c2SLorenzo Bianconi 
1644011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
16458b8ab5c2SLorenzo Bianconi }
16468b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1647e49c76d4SLorenzo Bianconi 
1648e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1649e49c76d4SLorenzo Bianconi {
1650beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1651beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1652e49c76d4SLorenzo Bianconi 
1653e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1654beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1655beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1656e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1657e49c76d4SLorenzo Bianconi 
1658e49c76d4SLorenzo Bianconi 	return 0;
1659e49c76d4SLorenzo Bianconi }
1660e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1661b671da33SLorenzo Bianconi 
1662b1cb42adSLorenzo Bianconi struct mt76_queue *
1663b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1664f68d6762SFelix Fietkau 		int ring_base, u32 flags)
1665b671da33SLorenzo Bianconi {
1666b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1667b671da33SLorenzo Bianconi 	int err;
1668b671da33SLorenzo Bianconi 
1669b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1670b671da33SLorenzo Bianconi 	if (!hwq)
1671b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1672b671da33SLorenzo Bianconi 
1673f68d6762SFelix Fietkau 	hwq->flags = flags;
1674f68d6762SFelix Fietkau 
1675b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1676b671da33SLorenzo Bianconi 	if (err < 0)
1677b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1678b671da33SLorenzo Bianconi 
1679b1cb42adSLorenzo Bianconi 	return hwq;
1680b671da33SLorenzo Bianconi }
1681b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1682e4867225SSean Wang 
168333920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
1684e4867225SSean Wang {
168533920b2bSRyder Lee 	int offset = 0;
1686e4867225SSean Wang 
1687edf9dab8SLorenzo Bianconi 	if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
1688e4867225SSean Wang 		offset = 4;
1689e4867225SSean Wang 
169033920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
169133920b2bSRyder Lee 	if (rateidx < 0)
169233920b2bSRyder Lee 		rateidx = 0;
169333920b2bSRyder Lee 
1694d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1695d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1696d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1697e4867225SSean Wang 
1698d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1699e4867225SSean Wang }
170033920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
170154ae98ffSLorenzo Bianconi 
170254ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
170354ae98ffSLorenzo Bianconi 			 struct mt76_sta_stats *stats)
170454ae98ffSLorenzo Bianconi {
170554ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
170654ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
170754ae98ffSLorenzo Bianconi 
170854ae98ffSLorenzo Bianconi 	wi->sta_count++;
170954ae98ffSLorenzo Bianconi 
171054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
171154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
171254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
171354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
171454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
171554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
171654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
171754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
171854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
171954ae98ffSLorenzo Bianconi 
172054ae98ffSLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++)
172154ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
172254ae98ffSLorenzo Bianconi 
172354ae98ffSLorenzo Bianconi 	for (i = 0; i < 12; i++)
172454ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
172554ae98ffSLorenzo Bianconi 
172654ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
172754ae98ffSLorenzo Bianconi }
172854ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
17293f306448SFelix Fietkau 
17303f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
17313f306448SFelix Fietkau {
17323f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
17333f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
17343f306448SFelix Fietkau 
17353f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
17363f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
17373f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
17383f306448SFelix Fietkau 
17393f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
17403f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
17413f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
17423f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
17433f306448SFelix Fietkau 
17443f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
17453f306448SFelix Fietkau 	}
17463f306448SFelix Fietkau 
174700a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
17483f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
17493f306448SFelix Fietkau 
17503f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
17513f306448SFelix Fietkau }
17523f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1753