xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision fcfe1b5e162bf473c1d47760962cec8523c00466)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
5781eef5bSFelix Fietkau #include <linux/sched.h>
617f1de56SFelix Fietkau #include <linux/of.h>
717f1de56SFelix Fietkau #include "mt76.h"
817f1de56SFelix Fietkau 
917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
1017f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1117f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1217f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1317f1de56SFelix Fietkau 	.max_power = 30,			\
1417f1de56SFelix Fietkau }
1517f1de56SFelix Fietkau 
1617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1717f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1817f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1917f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2017f1de56SFelix Fietkau 	.max_power = 30,			\
2117f1de56SFelix Fietkau }
2217f1de56SFelix Fietkau 
23edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) {			\
24edf9dab8SLorenzo Bianconi 	.band = NL80211_BAND_6GHZ,		\
25edf9dab8SLorenzo Bianconi 	.center_freq = (_freq),			\
26edf9dab8SLorenzo Bianconi 	.hw_value = (_idx),			\
27edf9dab8SLorenzo Bianconi 	.max_power = 30,			\
28edf9dab8SLorenzo Bianconi }
29edf9dab8SLorenzo Bianconi 
3017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3117f1de56SFelix Fietkau 	CHAN2G(1, 2412),
3217f1de56SFelix Fietkau 	CHAN2G(2, 2417),
3317f1de56SFelix Fietkau 	CHAN2G(3, 2422),
3417f1de56SFelix Fietkau 	CHAN2G(4, 2427),
3517f1de56SFelix Fietkau 	CHAN2G(5, 2432),
3617f1de56SFelix Fietkau 	CHAN2G(6, 2437),
3717f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3817f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3917f1de56SFelix Fietkau 	CHAN2G(9, 2452),
4017f1de56SFelix Fietkau 	CHAN2G(10, 2457),
4117f1de56SFelix Fietkau 	CHAN2G(11, 2462),
4217f1de56SFelix Fietkau 	CHAN2G(12, 2467),
4317f1de56SFelix Fietkau 	CHAN2G(13, 2472),
4417f1de56SFelix Fietkau 	CHAN2G(14, 2484),
4517f1de56SFelix Fietkau };
4617f1de56SFelix Fietkau 
4717f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4817f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4917f1de56SFelix Fietkau 	CHAN5G(40, 5200),
5017f1de56SFelix Fietkau 	CHAN5G(44, 5220),
5117f1de56SFelix Fietkau 	CHAN5G(48, 5240),
5217f1de56SFelix Fietkau 
5317f1de56SFelix Fietkau 	CHAN5G(52, 5260),
5417f1de56SFelix Fietkau 	CHAN5G(56, 5280),
5517f1de56SFelix Fietkau 	CHAN5G(60, 5300),
5617f1de56SFelix Fietkau 	CHAN5G(64, 5320),
5717f1de56SFelix Fietkau 
5817f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5917f1de56SFelix Fietkau 	CHAN5G(104, 5520),
6017f1de56SFelix Fietkau 	CHAN5G(108, 5540),
6117f1de56SFelix Fietkau 	CHAN5G(112, 5560),
6217f1de56SFelix Fietkau 	CHAN5G(116, 5580),
6317f1de56SFelix Fietkau 	CHAN5G(120, 5600),
6417f1de56SFelix Fietkau 	CHAN5G(124, 5620),
6517f1de56SFelix Fietkau 	CHAN5G(128, 5640),
6617f1de56SFelix Fietkau 	CHAN5G(132, 5660),
6717f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6817f1de56SFelix Fietkau 	CHAN5G(140, 5700),
699da82fb7SMarkus Theil 	CHAN5G(144, 5720),
7017f1de56SFelix Fietkau 
7117f1de56SFelix Fietkau 	CHAN5G(149, 5745),
7217f1de56SFelix Fietkau 	CHAN5G(153, 5765),
7317f1de56SFelix Fietkau 	CHAN5G(157, 5785),
7417f1de56SFelix Fietkau 	CHAN5G(161, 5805),
7517f1de56SFelix Fietkau 	CHAN5G(165, 5825),
769da82fb7SMarkus Theil 	CHAN5G(169, 5845),
779da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7817f1de56SFelix Fietkau };
7917f1de56SFelix Fietkau 
80edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = {
81edf9dab8SLorenzo Bianconi 	/* UNII-5 */
82edf9dab8SLorenzo Bianconi 	CHAN6G(1, 5955),
83edf9dab8SLorenzo Bianconi 	CHAN6G(5, 5975),
84edf9dab8SLorenzo Bianconi 	CHAN6G(9, 5995),
85edf9dab8SLorenzo Bianconi 	CHAN6G(13, 6015),
86edf9dab8SLorenzo Bianconi 	CHAN6G(17, 6035),
87edf9dab8SLorenzo Bianconi 	CHAN6G(21, 6055),
88edf9dab8SLorenzo Bianconi 	CHAN6G(25, 6075),
89edf9dab8SLorenzo Bianconi 	CHAN6G(29, 6095),
90edf9dab8SLorenzo Bianconi 	CHAN6G(33, 6115),
91edf9dab8SLorenzo Bianconi 	CHAN6G(37, 6135),
92edf9dab8SLorenzo Bianconi 	CHAN6G(41, 6155),
93edf9dab8SLorenzo Bianconi 	CHAN6G(45, 6175),
94edf9dab8SLorenzo Bianconi 	CHAN6G(49, 6195),
95edf9dab8SLorenzo Bianconi 	CHAN6G(53, 6215),
96edf9dab8SLorenzo Bianconi 	CHAN6G(57, 6235),
97edf9dab8SLorenzo Bianconi 	CHAN6G(61, 6255),
98edf9dab8SLorenzo Bianconi 	CHAN6G(65, 6275),
99edf9dab8SLorenzo Bianconi 	CHAN6G(69, 6295),
100edf9dab8SLorenzo Bianconi 	CHAN6G(73, 6315),
101edf9dab8SLorenzo Bianconi 	CHAN6G(77, 6335),
102edf9dab8SLorenzo Bianconi 	CHAN6G(81, 6355),
103edf9dab8SLorenzo Bianconi 	CHAN6G(85, 6375),
104edf9dab8SLorenzo Bianconi 	CHAN6G(89, 6395),
105edf9dab8SLorenzo Bianconi 	CHAN6G(93, 6415),
106edf9dab8SLorenzo Bianconi 	/* UNII-6 */
107edf9dab8SLorenzo Bianconi 	CHAN6G(97, 6435),
108edf9dab8SLorenzo Bianconi 	CHAN6G(101, 6455),
109edf9dab8SLorenzo Bianconi 	CHAN6G(105, 6475),
110edf9dab8SLorenzo Bianconi 	CHAN6G(109, 6495),
111edf9dab8SLorenzo Bianconi 	CHAN6G(113, 6515),
112edf9dab8SLorenzo Bianconi 	CHAN6G(117, 6535),
113edf9dab8SLorenzo Bianconi 	/* UNII-7 */
114edf9dab8SLorenzo Bianconi 	CHAN6G(121, 6555),
115edf9dab8SLorenzo Bianconi 	CHAN6G(125, 6575),
116edf9dab8SLorenzo Bianconi 	CHAN6G(129, 6595),
117edf9dab8SLorenzo Bianconi 	CHAN6G(133, 6615),
118edf9dab8SLorenzo Bianconi 	CHAN6G(137, 6635),
119edf9dab8SLorenzo Bianconi 	CHAN6G(141, 6655),
120edf9dab8SLorenzo Bianconi 	CHAN6G(145, 6675),
121edf9dab8SLorenzo Bianconi 	CHAN6G(149, 6695),
122edf9dab8SLorenzo Bianconi 	CHAN6G(153, 6715),
123edf9dab8SLorenzo Bianconi 	CHAN6G(157, 6735),
124edf9dab8SLorenzo Bianconi 	CHAN6G(161, 6755),
125edf9dab8SLorenzo Bianconi 	CHAN6G(165, 6775),
126edf9dab8SLorenzo Bianconi 	CHAN6G(169, 6795),
127edf9dab8SLorenzo Bianconi 	CHAN6G(173, 6815),
128edf9dab8SLorenzo Bianconi 	CHAN6G(177, 6835),
129edf9dab8SLorenzo Bianconi 	CHAN6G(181, 6855),
130edf9dab8SLorenzo Bianconi 	CHAN6G(185, 6875),
131edf9dab8SLorenzo Bianconi 	/* UNII-8 */
132edf9dab8SLorenzo Bianconi 	CHAN6G(189, 6895),
133edf9dab8SLorenzo Bianconi 	CHAN6G(193, 6915),
134edf9dab8SLorenzo Bianconi 	CHAN6G(197, 6935),
135edf9dab8SLorenzo Bianconi 	CHAN6G(201, 6955),
136edf9dab8SLorenzo Bianconi 	CHAN6G(205, 6975),
137edf9dab8SLorenzo Bianconi 	CHAN6G(209, 6995),
138edf9dab8SLorenzo Bianconi 	CHAN6G(213, 7015),
139edf9dab8SLorenzo Bianconi 	CHAN6G(217, 7035),
140edf9dab8SLorenzo Bianconi 	CHAN6G(221, 7055),
141edf9dab8SLorenzo Bianconi 	CHAN6G(225, 7075),
142edf9dab8SLorenzo Bianconi 	CHAN6G(229, 7095),
143edf9dab8SLorenzo Bianconi 	CHAN6G(233, 7115),
144edf9dab8SLorenzo Bianconi };
145edf9dab8SLorenzo Bianconi 
14617f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
14717f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
14817f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
14917f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
15017f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
15117f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
15217f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
15317f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
15417f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
15517f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
15617f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
15717f1de56SFelix Fietkau };
15817f1de56SFelix Fietkau 
15954b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = {
16054b8fdebSLorenzo Bianconi 	CCK_RATE(0, 10),
16154b8fdebSLorenzo Bianconi 	CCK_RATE(1, 20),
16254b8fdebSLorenzo Bianconi 	CCK_RATE(2, 55),
16354b8fdebSLorenzo Bianconi 	CCK_RATE(3, 110),
16454b8fdebSLorenzo Bianconi 	OFDM_RATE(11, 60),
16554b8fdebSLorenzo Bianconi 	OFDM_RATE(15, 90),
16654b8fdebSLorenzo Bianconi 	OFDM_RATE(10, 120),
16754b8fdebSLorenzo Bianconi 	OFDM_RATE(14, 180),
16854b8fdebSLorenzo Bianconi 	OFDM_RATE(9,  240),
16954b8fdebSLorenzo Bianconi 	OFDM_RATE(13, 360),
17054b8fdebSLorenzo Bianconi 	OFDM_RATE(8,  480),
17154b8fdebSLorenzo Bianconi 	OFDM_RATE(12, 540),
17254b8fdebSLorenzo Bianconi };
17354b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates);
17454b8fdebSLorenzo Bianconi 
175502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
176502604f5SYN Chen 	{ .start_freq = 2402, .end_freq = 2494, },
177502604f5SYN Chen 	{ .start_freq = 5150, .end_freq = 5350, },
178502604f5SYN Chen 	{ .start_freq = 5350, .end_freq = 5470, },
179502604f5SYN Chen 	{ .start_freq = 5470, .end_freq = 5725, },
180502604f5SYN Chen 	{ .start_freq = 5725, .end_freq = 5950, },
181502604f5SYN Chen };
182502604f5SYN Chen 
18397f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = {
184502604f5SYN Chen 	.type = NL80211_SAR_TYPE_POWER,
185502604f5SYN Chen 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
186502604f5SYN Chen 	.freq_ranges = &mt76_sar_freq_ranges[0],
187502604f5SYN Chen };
188502604f5SYN Chen 
18917f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
19017f1de56SFelix Fietkau {
19117f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
19217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
19317f1de56SFelix Fietkau 	int led_pin;
19417f1de56SFelix Fietkau 
19517f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
19617f1de56SFelix Fietkau 		return 0;
19717f1de56SFelix Fietkau 
19817f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
19917f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
20017f1de56SFelix Fietkau 
20117f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
20217f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
20317f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
20417f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
20517f1de56SFelix Fietkau 					mt76_tpt_blink,
20617f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
20717f1de56SFelix Fietkau 
20817f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
20917f1de56SFelix Fietkau 	if (np) {
21017f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
21117f1de56SFelix Fietkau 			dev->led_pin = led_pin;
21217f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
21317f1de56SFelix Fietkau 	}
21417f1de56SFelix Fietkau 
21536f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
21636f7e2b2SFelix Fietkau }
21736f7e2b2SFelix Fietkau 
21836f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
21936f7e2b2SFelix Fietkau {
22036f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
22136f7e2b2SFelix Fietkau 		return;
22236f7e2b2SFelix Fietkau 
22336f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
22417f1de56SFelix Fietkau }
22517f1de56SFelix Fietkau 
226bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
227551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
228551e1ef4SLorenzo Bianconi 				 bool vht)
229551e1ef4SLorenzo Bianconi {
230551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
231bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
232551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
233551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
234551e1ef4SLorenzo Bianconi 
235551e1ef4SLorenzo Bianconi 	if (nstream > 1)
236551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
237551e1ef4SLorenzo Bianconi 	else
238551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
239551e1ef4SLorenzo Bianconi 
240551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
241551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
242551e1ef4SLorenzo Bianconi 
243551e1ef4SLorenzo Bianconi 	if (!vht)
244551e1ef4SLorenzo Bianconi 		return;
245551e1ef4SLorenzo Bianconi 
246551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
247551e1ef4SLorenzo Bianconi 	if (nstream > 1)
248551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
249551e1ef4SLorenzo Bianconi 	else
250551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
251abba3453SDeren Wu 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
252abba3453SDeren Wu 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
253551e1ef4SLorenzo Bianconi 
254551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
255551e1ef4SLorenzo Bianconi 		if (i < nstream)
256551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
257551e1ef4SLorenzo Bianconi 		else
258551e1ef4SLorenzo Bianconi 			mcs_map |=
259551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
260551e1ef4SLorenzo Bianconi 	}
261551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
262551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
263551e1ef4SLorenzo Bianconi }
264551e1ef4SLorenzo Bianconi 
265bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2665ebdc3e0SLorenzo Bianconi {
26748dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
268bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
26948dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
270bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
271edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz)
272edf9dab8SLorenzo Bianconi 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
2735ebdc3e0SLorenzo Bianconi }
2745ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
2755ebdc3e0SLorenzo Bianconi 
27617f1de56SFelix Fietkau static int
27777af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
27817f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
279edf9dab8SLorenzo Bianconi 		struct ieee80211_rate *rates, int n_rates,
280edf9dab8SLorenzo Bianconi 		bool ht, bool vht)
28117f1de56SFelix Fietkau {
28217f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
28317f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
28477af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
28577af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
28617f1de56SFelix Fietkau 	void *chanlist;
28717f1de56SFelix Fietkau 	int size;
28817f1de56SFelix Fietkau 
28917f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
29017f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
29117f1de56SFelix Fietkau 	if (!chanlist)
29217f1de56SFelix Fietkau 		return -ENOMEM;
29317f1de56SFelix Fietkau 
294a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
29517f1de56SFelix Fietkau 				    GFP_KERNEL);
29617f1de56SFelix Fietkau 	if (!msband->chan)
29717f1de56SFelix Fietkau 		return -ENOMEM;
29817f1de56SFelix Fietkau 
29917f1de56SFelix Fietkau 	sband->channels = chanlist;
30017f1de56SFelix Fietkau 	sband->n_channels = n_chan;
30117f1de56SFelix Fietkau 	sband->bitrates = rates;
30217f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
30317f1de56SFelix Fietkau 
304edf9dab8SLorenzo Bianconi 	if (!ht)
305edf9dab8SLorenzo Bianconi 		return 0;
306edf9dab8SLorenzo Bianconi 
30717f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
30817f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
30917f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
31017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
31117f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
31217f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
31317f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
31417f1de56SFelix Fietkau 
31517f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
31617f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
31717f1de56SFelix Fietkau 
31877af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
319551e1ef4SLorenzo Bianconi 
32017f1de56SFelix Fietkau 	if (!vht)
32117f1de56SFelix Fietkau 		return 0;
32217f1de56SFelix Fietkau 
32317f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
32417f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
32517f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
32617f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
32749149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
32849149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
32917f1de56SFelix Fietkau 
33017f1de56SFelix Fietkau 	return 0;
33117f1de56SFelix Fietkau }
33217f1de56SFelix Fietkau 
33317f1de56SFelix Fietkau static int
33477af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
33517f1de56SFelix Fietkau 		   int n_rates)
33617f1de56SFelix Fietkau {
33777af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
33817f1de56SFelix Fietkau 
33977af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
34077af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
341edf9dab8SLorenzo Bianconi 			       n_rates, true, false);
34217f1de56SFelix Fietkau }
34317f1de56SFelix Fietkau 
34417f1de56SFelix Fietkau static int
34577af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
34617f1de56SFelix Fietkau 		   int n_rates, bool vht)
34717f1de56SFelix Fietkau {
34877af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
34917f1de56SFelix Fietkau 
35077af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
35177af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
352edf9dab8SLorenzo Bianconi 			       n_rates, true, vht);
353edf9dab8SLorenzo Bianconi }
354edf9dab8SLorenzo Bianconi 
355edf9dab8SLorenzo Bianconi static int
356edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
357edf9dab8SLorenzo Bianconi 		   int n_rates)
358edf9dab8SLorenzo Bianconi {
359edf9dab8SLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
360edf9dab8SLorenzo Bianconi 
361edf9dab8SLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
362edf9dab8SLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
363edf9dab8SLorenzo Bianconi 			       n_rates, false, false);
36417f1de56SFelix Fietkau }
36517f1de56SFelix Fietkau 
36617f1de56SFelix Fietkau static void
367c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
368c89d3625SFelix Fietkau 		 enum nl80211_band band)
36917f1de56SFelix Fietkau {
370c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
37117f1de56SFelix Fietkau 	bool found = false;
37217f1de56SFelix Fietkau 	int i;
37317f1de56SFelix Fietkau 
37417f1de56SFelix Fietkau 	if (!sband)
37517f1de56SFelix Fietkau 		return;
37617f1de56SFelix Fietkau 
37717f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
37817f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
37917f1de56SFelix Fietkau 			continue;
38017f1de56SFelix Fietkau 
38117f1de56SFelix Fietkau 		found = true;
38217f1de56SFelix Fietkau 		break;
38317f1de56SFelix Fietkau 	}
38417f1de56SFelix Fietkau 
385c89d3625SFelix Fietkau 	if (found) {
386c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
387c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
38817f1de56SFelix Fietkau 		return;
389c89d3625SFelix Fietkau 	}
39017f1de56SFelix Fietkau 
39117f1de56SFelix Fietkau 	sband->n_channels = 0;
392c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
39317f1de56SFelix Fietkau }
39417f1de56SFelix Fietkau 
395d43de9cfSLorenzo Bianconi static int
39698df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
397c89d3625SFelix Fietkau {
39898df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
399c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
400c89d3625SFelix Fietkau 
401c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
40298df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
403c89d3625SFelix Fietkau 
404c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
405dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
406b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
407b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
408c89d3625SFelix Fietkau 
409c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
410c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
411d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
412c89d3625SFelix Fietkau 
4130a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4140a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
415c89d3625SFelix Fietkau 
416d43de9cfSLorenzo Bianconi 	wiphy->sar_capa = &mt76_sar_capa;
417d43de9cfSLorenzo Bianconi 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
418d43de9cfSLorenzo Bianconi 				sizeof(struct mt76_freq_range_power),
419d43de9cfSLorenzo Bianconi 				GFP_KERNEL);
420d43de9cfSLorenzo Bianconi 	if (!phy->frp)
421d43de9cfSLorenzo Bianconi 		return -ENOMEM;
422d43de9cfSLorenzo Bianconi 
423c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
424b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
425c9619dfaSShayne Chen 
426c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
427c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
428c89d3625SFelix Fietkau 
429c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
430c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
431c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
432c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
433c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
434c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
435ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
436c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
437c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
438c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
439c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
440c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
441d43de9cfSLorenzo Bianconi 
442d43de9cfSLorenzo Bianconi 	return 0;
443c89d3625SFelix Fietkau }
444c89d3625SFelix Fietkau 
445c89d3625SFelix Fietkau struct mt76_phy *
446c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
447c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
448c89d3625SFelix Fietkau {
449c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
450db78a791SLorenzo Bianconi 	unsigned int phy_size;
451c89d3625SFelix Fietkau 	struct mt76_phy *phy;
452c89d3625SFelix Fietkau 
453c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
454db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
455c89d3625SFelix Fietkau 	if (!hw)
456c89d3625SFelix Fietkau 		return NULL;
457c89d3625SFelix Fietkau 
458c89d3625SFelix Fietkau 	phy = hw->priv;
459c89d3625SFelix Fietkau 	phy->dev = dev;
460c89d3625SFelix Fietkau 	phy->hw = hw;
461db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
462c89d3625SFelix Fietkau 
4638af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4648af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4658af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4668af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4678af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4688af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4698af414e8SLorenzo Bianconi #endif
4708af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4718af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4728af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4738af414e8SLorenzo Bianconi 
474c89d3625SFelix Fietkau 	return phy;
475c89d3625SFelix Fietkau }
476c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
477c89d3625SFelix Fietkau 
478db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
479db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
480c89d3625SFelix Fietkau {
481c89d3625SFelix Fietkau 	int ret;
482c89d3625SFelix Fietkau 
483d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
484d43de9cfSLorenzo Bianconi 	if (ret)
485d43de9cfSLorenzo Bianconi 		return ret;
486db78a791SLorenzo Bianconi 
487db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
488db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
489db78a791SLorenzo Bianconi 		if (ret)
490db78a791SLorenzo Bianconi 			return ret;
491db78a791SLorenzo Bianconi 	}
492db78a791SLorenzo Bianconi 
493db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
494db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
495db78a791SLorenzo Bianconi 		if (ret)
496db78a791SLorenzo Bianconi 			return ret;
497db78a791SLorenzo Bianconi 	}
498db78a791SLorenzo Bianconi 
499edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
500edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
501edf9dab8SLorenzo Bianconi 		if (ret)
502edf9dab8SLorenzo Bianconi 			return ret;
503edf9dab8SLorenzo Bianconi 	}
504edf9dab8SLorenzo Bianconi 
505db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
506db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
507db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
508edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
509db78a791SLorenzo Bianconi 
510c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
511c89d3625SFelix Fietkau 	if (ret)
512c89d3625SFelix Fietkau 		return ret;
513c89d3625SFelix Fietkau 
514c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
515db78a791SLorenzo Bianconi 
516c89d3625SFelix Fietkau 	return 0;
517c89d3625SFelix Fietkau }
518c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
519c89d3625SFelix Fietkau 
520db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
521c89d3625SFelix Fietkau {
522c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
523c89d3625SFelix Fietkau 
524c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
525c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
52694b6df08SFelix Fietkau 	dev->phy2 = NULL;
527c89d3625SFelix Fietkau }
528c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
529c89d3625SFelix Fietkau 
530a85b590cSFelix Fietkau struct mt76_dev *
531c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
532c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
533c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
534a85b590cSFelix Fietkau {
535a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
536ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
537a85b590cSFelix Fietkau 	struct mt76_dev *dev;
538e5443256SFelix Fietkau 	int i;
539a85b590cSFelix Fietkau 
540a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
541a85b590cSFelix Fietkau 	if (!hw)
542a85b590cSFelix Fietkau 		return NULL;
543a85b590cSFelix Fietkau 
544a85b590cSFelix Fietkau 	dev = hw->priv;
545a85b590cSFelix Fietkau 	dev->hw = hw;
546c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
547c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
548c0f7b25aSLorenzo Bianconi 
549ac24dd35SFelix Fietkau 	phy = &dev->phy;
550ac24dd35SFelix Fietkau 	phy->dev = dev;
551ac24dd35SFelix Fietkau 	phy->hw = hw;
552ac24dd35SFelix Fietkau 
553a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
554a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
555a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
556c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
557108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
55826e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
559a85b590cSFelix Fietkau 
56009872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
56109872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
56209872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
563781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
56409872957SLorenzo Bianconi 
5658af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5668af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
5678af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
5688af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
5698af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
5708af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
5718af414e8SLorenzo Bianconi #endif
5728af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5738af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
5748af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
5758af414e8SLorenzo Bianconi 
57651252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
57751252cc5SLorenzo Bianconi 	idr_init(&dev->token);
57851252cc5SLorenzo Bianconi 
579bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
580bd1e3e7bSLorenzo Bianconi 
581e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
582e5443256SFelix Fietkau 
583e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
584e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
585e5443256SFelix Fietkau 
586a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
587a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
588a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
589a86f1d01SLorenzo Bianconi 		return NULL;
590a86f1d01SLorenzo Bianconi 	}
591a86f1d01SLorenzo Bianconi 
592a85b590cSFelix Fietkau 	return dev;
593a85b590cSFelix Fietkau }
594a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
595a85b590cSFelix Fietkau 
59617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
59717f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
59817f1de56SFelix Fietkau {
59917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
600c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
60117f1de56SFelix Fietkau 	int ret;
60217f1de56SFelix Fietkau 
60317f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
604d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
605d43de9cfSLorenzo Bianconi 	if (ret)
606d43de9cfSLorenzo Bianconi 		return ret;
60717f1de56SFelix Fietkau 
60848dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
60977af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
61017f1de56SFelix Fietkau 		if (ret)
61117f1de56SFelix Fietkau 			return ret;
61217f1de56SFelix Fietkau 	}
61317f1de56SFelix Fietkau 
61448dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
61577af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
61617f1de56SFelix Fietkau 		if (ret)
61717f1de56SFelix Fietkau 			return ret;
61817f1de56SFelix Fietkau 	}
61917f1de56SFelix Fietkau 
620edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
621edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
622edf9dab8SLorenzo Bianconi 		if (ret)
623edf9dab8SLorenzo Bianconi 			return ret;
624edf9dab8SLorenzo Bianconi 	}
625edf9dab8SLorenzo Bianconi 
626c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
627c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
628c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
629edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
63017f1de56SFelix Fietkau 
631b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
63217f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
63317f1de56SFelix Fietkau 		if (ret)
63417f1de56SFelix Fietkau 			return ret;
635b374e868SArnd Bergmann 	}
63617f1de56SFelix Fietkau 
637781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
638781eef5bSFelix Fietkau 	if (ret)
639781eef5bSFelix Fietkau 		return ret;
640781eef5bSFelix Fietkau 
641781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
642781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
643781eef5bSFelix Fietkau 
644781eef5bSFelix Fietkau 	return 0;
64517f1de56SFelix Fietkau }
64617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
64717f1de56SFelix Fietkau 
64817f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
64917f1de56SFelix Fietkau {
65017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
65117f1de56SFelix Fietkau 
652d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
65336f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
654c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
65517f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
65617f1de56SFelix Fietkau }
65717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
65817f1de56SFelix Fietkau 
659def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
660def34a2fSLorenzo Bianconi {
661781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
662a86f1d01SLorenzo Bianconi 	if (dev->wq) {
663a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
664a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
665a86f1d01SLorenzo Bianconi 	}
666def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
667def34a2fSLorenzo Bianconi }
668def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
669def34a2fSLorenzo Bianconi 
670cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
671cc4b3c13SLorenzo Bianconi {
672cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
6732c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
674cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
675cc4b3c13SLorenzo Bianconi 
676cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
677cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
6782c2bdd23SFelix Fietkau 
6792c2bdd23SFelix Fietkau 	/*
6802c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
6812c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
6822c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
6832c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
6842c2bdd23SFelix Fietkau 	 * address.
6852c2bdd23SFelix Fietkau 	 */
6862c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
6872c2bdd23SFelix Fietkau 		int offset = 0;
6882c2bdd23SFelix Fietkau 
6892c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
6902c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
6912c2bdd23SFelix Fietkau 
6922c2bdd23SFelix Fietkau 			if ((status->flag &
6932c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
6942c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
6952c2bdd23SFelix Fietkau 				offset += 8;
6962c2bdd23SFelix Fietkau 		}
6972c2bdd23SFelix Fietkau 
6982c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
6992c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
7002c2bdd23SFelix Fietkau 			return;
7012c2bdd23SFelix Fietkau 		}
7022c2bdd23SFelix Fietkau 	}
703cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
704cc4b3c13SLorenzo Bianconi }
705cc4b3c13SLorenzo Bianconi 
706cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
707cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
708cc4b3c13SLorenzo Bianconi {
709cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
710cc4b3c13SLorenzo Bianconi 
711cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
712cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
713cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
714cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
715cc4b3c13SLorenzo Bianconi 
716cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
717cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
718cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
719cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
720cc4b3c13SLorenzo Bianconi 	} else {
721cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
722cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
723cc4b3c13SLorenzo Bianconi 	}
724cc4b3c13SLorenzo Bianconi 
725cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
726cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
727cc4b3c13SLorenzo Bianconi }
728cc4b3c13SLorenzo Bianconi 
72917f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
73017f1de56SFelix Fietkau {
731011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
732011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
733011849e0SFelix Fietkau 
734011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
73517f1de56SFelix Fietkau 		dev_kfree_skb(skb);
73617f1de56SFelix Fietkau 		return;
73717f1de56SFelix Fietkau 	}
73817f1de56SFelix Fietkau 
739f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
740c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
741c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
742f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
743c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
744f0efa862SFelix Fietkau 	}
745f0efa862SFelix Fietkau #endif
746cc4b3c13SLorenzo Bianconi 
747cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
74817f1de56SFelix Fietkau }
74917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
75017f1de56SFelix Fietkau 
7515a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
75226e40d4cSFelix Fietkau {
753af005f26SLorenzo Bianconi 	struct mt76_queue *q;
75491990519SLorenzo Bianconi 	int i;
7555a95ca41SFelix Fietkau 
7565a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
75791990519SLorenzo Bianconi 		q = phy->q_tx[i];
758af005f26SLorenzo Bianconi 		if (q && q->queued)
75926e40d4cSFelix Fietkau 			return true;
76026e40d4cSFelix Fietkau 	}
76126e40d4cSFelix Fietkau 
76226e40d4cSFelix Fietkau 	return false;
76326e40d4cSFelix Fietkau }
76439d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
76526e40d4cSFelix Fietkau 
7660fd0eb54SFelix Fietkau static struct mt76_channel_state *
76796747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
7680fd0eb54SFelix Fietkau {
7690fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
7700fd0eb54SFelix Fietkau 	int idx;
7710fd0eb54SFelix Fietkau 
7720fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
77396747a51SFelix Fietkau 		msband = &phy->sband_2g;
774edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
775edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
7760fd0eb54SFelix Fietkau 	else
77796747a51SFelix Fietkau 		msband = &phy->sband_5g;
7780fd0eb54SFelix Fietkau 
7790fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
7800fd0eb54SFelix Fietkau 	return &msband->chan[idx];
7810fd0eb54SFelix Fietkau }
7820fd0eb54SFelix Fietkau 
78304414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
78496747a51SFelix Fietkau {
78596747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
78696747a51SFelix Fietkau 
78796747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
78896747a51SFelix Fietkau 						  phy->survey_time));
78996747a51SFelix Fietkau 	phy->survey_time = time;
79096747a51SFelix Fietkau }
79104414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
79296747a51SFelix Fietkau 
793c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
7945ce09c1aSFelix Fietkau {
795c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
796aec65e48SFelix Fietkau 	ktime_t cur_time;
797aec65e48SFelix Fietkau 
7985ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
799c560b137SRyder Lee 		dev->drv->update_survey(phy);
8005ce09c1aSFelix Fietkau 
801aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
802c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
803aec65e48SFelix Fietkau 
8045ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
805c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
80696747a51SFelix Fietkau 
807237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
8085ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
8095ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
810237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
8115ce09c1aSFelix Fietkau 	}
8125ce09c1aSFelix Fietkau }
8135ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
8145ce09c1aSFelix Fietkau 
81596747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
81617f1de56SFelix Fietkau {
81796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
81896747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
81917f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
82017f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
82126e40d4cSFelix Fietkau 	int timeout = HZ / 5;
82217f1de56SFelix Fietkau 
8235a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
824c560b137SRyder Lee 	mt76_update_survey(phy);
82517f1de56SFelix Fietkau 
8263f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
8273f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
8283f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
8293f306448SFelix Fietkau 
83096747a51SFelix Fietkau 	phy->chandef = *chandef;
83196747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
83217f1de56SFelix Fietkau 
83317f1de56SFelix Fietkau 	if (!offchannel)
83496747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
83517f1de56SFelix Fietkau 
83696747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
83796747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
83817f1de56SFelix Fietkau }
83917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
84017f1de56SFelix Fietkau 
84117f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
84217f1de56SFelix Fietkau 		    struct survey_info *survey)
84317f1de56SFelix Fietkau {
84496747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
84596747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
84617f1de56SFelix Fietkau 	struct mt76_sband *sband;
84717f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
84817f1de56SFelix Fietkau 	struct mt76_channel_state *state;
84917f1de56SFelix Fietkau 	int ret = 0;
85017f1de56SFelix Fietkau 
851237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
85217f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
853c560b137SRyder Lee 		mt76_update_survey(phy);
85417f1de56SFelix Fietkau 
855edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
856edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
857edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
858edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
859edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
860edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
861edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
86296747a51SFelix Fietkau 		sband = &phy->sband_5g;
863edf9dab8SLorenzo Bianconi 	} else {
864edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
86517f1de56SFelix Fietkau 	}
86617f1de56SFelix Fietkau 
867237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
868237312c5SLorenzo Bianconi 		ret = -ENOENT;
869237312c5SLorenzo Bianconi 		goto out;
870237312c5SLorenzo Bianconi 	}
87117f1de56SFelix Fietkau 
87217f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
87396747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
87417f1de56SFelix Fietkau 
87517f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
87617f1de56SFelix Fietkau 	survey->channel = chan;
87717f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
878ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
879e5051965SFelix Fietkau 	if (state->noise)
880e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
881e5051965SFelix Fietkau 
88296747a51SFelix Fietkau 	if (chan == phy->main_chan) {
88317f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
88417f1de56SFelix Fietkau 
8855ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
8865ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
8875ce09c1aSFelix Fietkau 	}
8885ce09c1aSFelix Fietkau 
88917f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
8906bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
891237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
892e5051965SFelix Fietkau 	survey->noise = state->noise;
893237312c5SLorenzo Bianconi 
894237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
895237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
896ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
89717f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
89817f1de56SFelix Fietkau 
899237312c5SLorenzo Bianconi out:
900237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
901237312c5SLorenzo Bianconi 
90217f1de56SFelix Fietkau 	return ret;
90317f1de56SFelix Fietkau }
90417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
90517f1de56SFelix Fietkau 
90630ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
90730ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
90830ce7f44SFelix Fietkau {
90930ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
91030ce7f44SFelix Fietkau 	int i;
91130ce7f44SFelix Fietkau 
91230ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
91330ce7f44SFelix Fietkau 
91430ce7f44SFelix Fietkau 	if (!key)
91530ce7f44SFelix Fietkau 		return;
91630ce7f44SFelix Fietkau 
91701cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
91801cfc1b4SLorenzo Bianconi 		return;
91930ce7f44SFelix Fietkau 
92001cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
921a1b0bbd4SXing Song 
922a1b0bbd4SXing Song 	/* data frame */
92330ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
92430ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
92530ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
92630ce7f44SFelix Fietkau 	}
927a1b0bbd4SXing Song 
928a1b0bbd4SXing Song 	/* robust management frame */
929a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
930a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
931a1b0bbd4SXing Song 
93230ce7f44SFelix Fietkau }
93330ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
93430ce7f44SFelix Fietkau 
9354550fb9eSFelix Fietkau static int
9364550fb9eSFelix Fietkau mt76_rx_signal(struct mt76_rx_status *status)
9374550fb9eSFelix Fietkau {
9384550fb9eSFelix Fietkau 	s8 *chain_signal = status->chain_signal;
9394550fb9eSFelix Fietkau 	int signal = -128;
9404550fb9eSFelix Fietkau 	u8 chains;
9414550fb9eSFelix Fietkau 
9424550fb9eSFelix Fietkau 	for (chains = status->chains; chains; chains >>= 1, chain_signal++) {
9434550fb9eSFelix Fietkau 		int cur, diff;
9444550fb9eSFelix Fietkau 
9456450b133SDeren Wu 		cur = *chain_signal;
9466450b133SDeren Wu 		if (!(chains & BIT(0)) ||
9476450b133SDeren Wu 		    cur > 0)
9484550fb9eSFelix Fietkau 			continue;
9494550fb9eSFelix Fietkau 
9504550fb9eSFelix Fietkau 		if (cur > signal)
9514550fb9eSFelix Fietkau 			swap(cur, signal);
9524550fb9eSFelix Fietkau 
9534550fb9eSFelix Fietkau 		diff = signal - cur;
9544550fb9eSFelix Fietkau 		if (diff == 0)
9554550fb9eSFelix Fietkau 			signal += 3;
9564550fb9eSFelix Fietkau 		else if (diff <= 2)
9574550fb9eSFelix Fietkau 			signal += 2;
9584550fb9eSFelix Fietkau 		else if (diff <= 6)
9594550fb9eSFelix Fietkau 			signal += 1;
9604550fb9eSFelix Fietkau 	}
9614550fb9eSFelix Fietkau 
9624550fb9eSFelix Fietkau 	return signal;
9634550fb9eSFelix Fietkau }
9644550fb9eSFelix Fietkau 
965bfc394ddSFelix Fietkau static void
966bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
967bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
968bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
9694e34249eSFelix Fietkau {
9704e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
971abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
9724e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
9734e34249eSFelix Fietkau 
9744e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
9754e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
9764e34249eSFelix Fietkau 
9774e34249eSFelix Fietkau 	status->flag = mstat.flag;
9784e34249eSFelix Fietkau 	status->freq = mstat.freq;
9794e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
9804e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
9814e34249eSFelix Fietkau 	status->bw = mstat.bw;
982af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
983af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
984af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
9854e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
9864e34249eSFelix Fietkau 	status->nss = mstat.nss;
9874e34249eSFelix Fietkau 	status->band = mstat.band;
9884e34249eSFelix Fietkau 	status->signal = mstat.signal;
9894e34249eSFelix Fietkau 	status->chains = mstat.chains;
990d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
9910fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
9920fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
9934550fb9eSFelix Fietkau 	status->signal = mt76_rx_signal(&mstat);
9944550fb9eSFelix Fietkau 	if (status->signal <= -128)
9954550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
9964e34249eSFelix Fietkau 
997abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
998abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
999abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1000abe3f3daSRyder Lee 
10014e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
100213381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
100313381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
100413381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
100513381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
10069c68a57bSFelix Fietkau 
1007bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1008bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
10094e34249eSFelix Fietkau }
10104e34249eSFelix Fietkau 
101130ce7f44SFelix Fietkau static int
101230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
101330ce7f44SFelix Fietkau {
101430ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
101530ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
101630ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1017a1b0bbd4SXing Song 	int security_idx;
101830ce7f44SFelix Fietkau 	int ret;
101930ce7f44SFelix Fietkau 
102030ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
102130ce7f44SFelix Fietkau 		return 0;
102230ce7f44SFelix Fietkau 
102330ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
102430ce7f44SFelix Fietkau 		return 0;
102530ce7f44SFelix Fietkau 
10267360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
10277360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
10287360cdecSFelix Fietkau 		goto skip_hdr_check;
10297360cdecSFelix Fietkau 
1030a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
103130ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
103230ce7f44SFelix Fietkau 		/*
103330ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
103430ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
103530ce7f44SFelix Fietkau 		 */
103630ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
103730ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
103830ce7f44SFelix Fietkau 			return 0;
103930ce7f44SFelix Fietkau 	}
104030ce7f44SFelix Fietkau 
1041a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1042a1b0bbd4SXing Song 	 *
1043a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1044a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1045a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1046a1b0bbd4SXing Song 	 */
1047a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1048a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1049a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1050a1b0bbd4SXing Song 
10517360cdecSFelix Fietkau skip_hdr_check:
105230ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1053a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
105430ce7f44SFelix Fietkau 		     sizeof(status->iv));
105530ce7f44SFelix Fietkau 	if (ret <= 0)
105630ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
105730ce7f44SFelix Fietkau 
1058a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
105930ce7f44SFelix Fietkau 
106030ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
106130ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
106230ce7f44SFelix Fietkau 
106330ce7f44SFelix Fietkau 	return 0;
106430ce7f44SFelix Fietkau }
106530ce7f44SFelix Fietkau 
1066d71ef286SFelix Fietkau static void
10675ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
10685ce09c1aSFelix Fietkau 		    int len)
10695ce09c1aSFelix Fietkau {
10705ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
107185b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
107285b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
107385b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
107485b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
107585b7a5d0SLorenzo Bianconi 		.band = status->band,
107685b7a5d0SLorenzo Bianconi 		.nss = status->nss,
107785b7a5d0SLorenzo Bianconi 		.bw = status->bw,
107885b7a5d0SLorenzo Bianconi 	};
10795ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
10805ce09c1aSFelix Fietkau 	u32 airtime;
1081e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
10825ce09c1aSFelix Fietkau 
108385b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1084237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
10855ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1086237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
10875ce09c1aSFelix Fietkau 
10885ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
10895ce09c1aSFelix Fietkau 		return;
10905ce09c1aSFelix Fietkau 
10915ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1092e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
10935ce09c1aSFelix Fietkau }
10945ce09c1aSFelix Fietkau 
10955ce09c1aSFelix Fietkau static void
10965ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
10975ce09c1aSFelix Fietkau {
10985ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
10995ce09c1aSFelix Fietkau 	int wcid_idx;
11005ce09c1aSFelix Fietkau 
11015ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
11025ce09c1aSFelix Fietkau 		return;
11035ce09c1aSFelix Fietkau 
11045ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1105bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
11065ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
11075ce09c1aSFelix Fietkau 	else
11085ce09c1aSFelix Fietkau 		wcid = NULL;
11095ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
11105ce09c1aSFelix Fietkau 
11115ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
11125ce09c1aSFelix Fietkau 
11135ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
11145ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
11155ce09c1aSFelix Fietkau }
11165ce09c1aSFelix Fietkau 
11175ce09c1aSFelix Fietkau static void
11185ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
11195ce09c1aSFelix Fietkau {
11205ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
11215ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
11225ce09c1aSFelix Fietkau 
11235ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
11245ce09c1aSFelix Fietkau 		return;
11255ce09c1aSFelix Fietkau 
11265ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1127e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1128e195dad1SFelix Fietkau 
1129e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1130e195dad1SFelix Fietkau 			return;
1131e195dad1SFelix Fietkau 
113298df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
11335ce09c1aSFelix Fietkau 			return;
11345ce09c1aSFelix Fietkau 
11355ce09c1aSFelix Fietkau 		wcid = NULL;
11365ce09c1aSFelix Fietkau 	}
11375ce09c1aSFelix Fietkau 
11385ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
11395ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
11405ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
11415ce09c1aSFelix Fietkau 
11425ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
11435ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
11445ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
11455ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
11465ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
11475ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
11485ce09c1aSFelix Fietkau 		}
11495ce09c1aSFelix Fietkau 
11505ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
11515ce09c1aSFelix Fietkau 		return;
11525ce09c1aSFelix Fietkau 	}
11535ce09c1aSFelix Fietkau 
11545ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
11555ce09c1aSFelix Fietkau }
11565ce09c1aSFelix Fietkau 
11575ce09c1aSFelix Fietkau static void
1158ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1159d71ef286SFelix Fietkau {
1160d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
116177ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1162d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1163bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1164d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1165e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1166d71ef286SFelix Fietkau 	bool ps;
1167d71ef286SFelix Fietkau 
1168bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
1169e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1170e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1171bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
117236d91096SFelix Fietkau 		if (sta)
117336d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
117436d91096SFelix Fietkau 	}
117536d91096SFelix Fietkau 
11765ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
11775ce09c1aSFelix Fietkau 
1178d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1179d71ef286SFelix Fietkau 		return;
1180d71ef286SFelix Fietkau 
1181d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1182d71ef286SFelix Fietkau 
118302e5a769SFelix Fietkau 	if (status->signal <= 0)
118402e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
118502e5a769SFelix Fietkau 
1186ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1187ef13edc0SFelix Fietkau 
1188e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1189e195dad1SFelix Fietkau 		return;
1190e195dad1SFelix Fietkau 
1191d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1192d71ef286SFelix Fietkau 		return;
1193d71ef286SFelix Fietkau 
1194d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1195d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1196d71ef286SFelix Fietkau 		return;
1197d71ef286SFelix Fietkau 	}
1198d71ef286SFelix Fietkau 
1199d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1200d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1201d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1202d71ef286SFelix Fietkau 		return;
1203d71ef286SFelix Fietkau 
1204d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1205d71ef286SFelix Fietkau 
1206d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1207d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1208e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1209d71ef286SFelix Fietkau 
1210d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1211d71ef286SFelix Fietkau 		return;
1212d71ef286SFelix Fietkau 
121311b2a25fSFelix Fietkau 	if (ps)
1214d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1215d71ef286SFelix Fietkau 
1216d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
1217608f7c47SFelix Fietkau 
1218608f7c47SFelix Fietkau 	if (!ps)
1219608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1220608f7c47SFelix Fietkau 
12219f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1222d71ef286SFelix Fietkau }
1223d71ef286SFelix Fietkau 
12249d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
122581e850efSLorenzo Bianconi 		      struct napi_struct *napi)
122617f1de56SFelix Fietkau {
12279c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1228bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
12293298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
12303298b1f8SFelix Fietkau 	LIST_HEAD(list);
12319d9d738bSFelix Fietkau 
1232c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
12339d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1234cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1235cc4b3c13SLorenzo Bianconi 
123630ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
123730ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
123830ce7f44SFelix Fietkau 			continue;
123930ce7f44SFelix Fietkau 		}
124030ce7f44SFelix Fietkau 
1241cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1242bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
12433298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1244cc4b3c13SLorenzo Bianconi 
1245cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1246cc4b3c13SLorenzo Bianconi 		while (nskb) {
1247cc4b3c13SLorenzo Bianconi 			skb = nskb;
1248cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1249cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1250cc4b3c13SLorenzo Bianconi 
1251cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1252cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1253cc4b3c13SLorenzo Bianconi 		}
12549d9d738bSFelix Fietkau 	}
1255c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
12563298b1f8SFelix Fietkau 
12573298b1f8SFelix Fietkau 	if (!napi) {
12583298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
12593298b1f8SFelix Fietkau 		return;
12603298b1f8SFelix Fietkau 	}
12613298b1f8SFelix Fietkau 
12623298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
12633298b1f8SFelix Fietkau 		skb_list_del_init(skb);
12643298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
12653298b1f8SFelix Fietkau 	}
12669d9d738bSFelix Fietkau }
12679d9d738bSFelix Fietkau 
126881e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
126981e850efSLorenzo Bianconi 			   struct napi_struct *napi)
12709d9d738bSFelix Fietkau {
1271aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
127217f1de56SFelix Fietkau 	struct sk_buff *skb;
127317f1de56SFelix Fietkau 
1274aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1275aee5b8cfSFelix Fietkau 
1276d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1277ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
1278aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
1279d71ef286SFelix Fietkau 	}
1280aee5b8cfSFelix Fietkau 
128181e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
12824e34249eSFelix Fietkau }
128381e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1284723b90dcSFelix Fietkau 
1285e28487eaSFelix Fietkau static int
1286e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
1287426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
1288e28487eaSFelix Fietkau {
1289e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1290e28487eaSFelix Fietkau 	int ret;
1291e28487eaSFelix Fietkau 	int i;
1292e28487eaSFelix Fietkau 
1293e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1294e28487eaSFelix Fietkau 
1295e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1296e28487eaSFelix Fietkau 	if (ret)
1297e28487eaSFelix Fietkau 		goto out;
1298e28487eaSFelix Fietkau 
1299e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1300e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1301e28487eaSFelix Fietkau 
1302e28487eaSFelix Fietkau 		if (!sta->txq[i])
1303e28487eaSFelix Fietkau 			continue;
1304e28487eaSFelix Fietkau 
1305e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
130651fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1307e28487eaSFelix Fietkau 	}
1308e28487eaSFelix Fietkau 
1309ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1310426e8e41SFelix Fietkau 	if (ext_phy)
1311426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1312c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
1313e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1314e28487eaSFelix Fietkau 
1315bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_init(wcid);
1316e28487eaSFelix Fietkau out:
1317e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1318e28487eaSFelix Fietkau 
1319e28487eaSFelix Fietkau 	return ret;
1320e28487eaSFelix Fietkau }
1321e28487eaSFelix Fietkau 
132213f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1323723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1324723b90dcSFelix Fietkau {
1325723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
132613f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1327723b90dcSFelix Fietkau 
132858bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
132958bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
133058bab0d4SFelix Fietkau 
1331e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1332e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1333e28487eaSFelix Fietkau 
1334bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_flush(dev, wcid);
1335bd1e3e7bSLorenzo Bianconi 
1336426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1337426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
133813f61dfcSLorenzo Bianconi }
133913f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1340e28487eaSFelix Fietkau 
134113f61dfcSLorenzo Bianconi static void
134213f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
134313f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
134413f61dfcSLorenzo Bianconi {
134513f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
134613f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1347723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1348723b90dcSFelix Fietkau }
1349e28487eaSFelix Fietkau 
1350e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1351e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1352e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1353e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1354e28487eaSFelix Fietkau {
1355426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1356426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1357426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1358e28487eaSFelix Fietkau 
1359e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1360e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1361426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1362e28487eaSFelix Fietkau 
13639c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
13649c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
13659c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
13669c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
13679c193de5SFelix Fietkau 
1368e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1369e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1370e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1371e28487eaSFelix Fietkau 
1372e28487eaSFelix Fietkau 	return 0;
1373e28487eaSFelix Fietkau }
1374e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
13759313faacSFelix Fietkau 
137643ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
137743ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
137843ba1922SFelix Fietkau {
137943ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
138043ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
138143ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
138243ba1922SFelix Fietkau 
138343ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1384*fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
138543ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1386*fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
138743ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
138843ba1922SFelix Fietkau }
138943ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
139043ba1922SFelix Fietkau 
13919313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
13929313faacSFelix Fietkau 		     int *dbm)
13939313faacSFelix Fietkau {
1394beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1395beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
139607cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
13979313faacSFelix Fietkau 
139807cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
13999313faacSFelix Fietkau 
14009313faacSFelix Fietkau 	return 0;
14019313faacSFelix Fietkau }
14029313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1403e7173858SFelix Fietkau 
1404b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1405b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1406b3cb885eSLorenzo Bianconi {
1407b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1408b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1409b3cb885eSLorenzo Bianconi 	int i;
1410b3cb885eSLorenzo Bianconi 
1411b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1412b3cb885eSLorenzo Bianconi 		return -EINVAL;
1413b3cb885eSLorenzo Bianconi 
1414b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1415b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1416b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1417b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1418b3cb885eSLorenzo Bianconi 
1419b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1420b3cb885eSLorenzo Bianconi 			power = 127;
1421b3cb885eSLorenzo Bianconi 
1422b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1423b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1424b3cb885eSLorenzo Bianconi 	}
1425b3cb885eSLorenzo Bianconi 
1426b3cb885eSLorenzo Bianconi 	return 0;
1427b3cb885eSLorenzo Bianconi }
1428b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1429b3cb885eSLorenzo Bianconi 
1430b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1431b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1432b3cb885eSLorenzo Bianconi 		       int power)
1433b3cb885eSLorenzo Bianconi {
1434b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1435b3cb885eSLorenzo Bianconi 	int freq, i;
1436b3cb885eSLorenzo Bianconi 
1437b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1438b3cb885eSLorenzo Bianconi 		return power;
1439b3cb885eSLorenzo Bianconi 
1440b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1441b3cb885eSLorenzo Bianconi 		power = 127;
1442b3cb885eSLorenzo Bianconi 
1443b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1444b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1445b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1446b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1447b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1448b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1449b3cb885eSLorenzo Bianconi 			break;
1450b3cb885eSLorenzo Bianconi 		}
1451b3cb885eSLorenzo Bianconi 	}
1452b3cb885eSLorenzo Bianconi 
1453b3cb885eSLorenzo Bianconi 	return power;
1454b3cb885eSLorenzo Bianconi }
1455b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1456b3cb885eSLorenzo Bianconi 
1457e7173858SFelix Fietkau static void
1458e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1459e7173858SFelix Fietkau {
14608552a434SJohn Crispin 	if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1461e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1462e7173858SFelix Fietkau }
1463e7173858SFelix Fietkau 
1464e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1465e7173858SFelix Fietkau {
1466e7173858SFelix Fietkau 	if (!dev->csa_complete)
1467e7173858SFelix Fietkau 		return;
1468e7173858SFelix Fietkau 
1469e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1470e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1471e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1472e7173858SFelix Fietkau 
1473e7173858SFelix Fietkau 	dev->csa_complete = 0;
1474e7173858SFelix Fietkau }
1475e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1476e7173858SFelix Fietkau 
1477e7173858SFelix Fietkau static void
1478e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1479e7173858SFelix Fietkau {
1480e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1481e7173858SFelix Fietkau 
1482e7173858SFelix Fietkau 	if (!vif->csa_active)
1483e7173858SFelix Fietkau 		return;
1484e7173858SFelix Fietkau 
14858552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1486e7173858SFelix Fietkau }
1487e7173858SFelix Fietkau 
1488e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1489e7173858SFelix Fietkau {
1490e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1491e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1492e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1493e7173858SFelix Fietkau }
1494e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
149587d53103SStanislaw Gruszka 
149687d53103SStanislaw Gruszka int
149787d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
149887d53103SStanislaw Gruszka {
149987d53103SStanislaw Gruszka 	return 0;
150087d53103SStanislaw Gruszka }
150187d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1502eadfd98fSLorenzo Bianconi 
1503eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1504eadfd98fSLorenzo Bianconi {
1505eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1506eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1507eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1508eadfd98fSLorenzo Bianconi 
1509eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1510eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1511eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1512eadfd98fSLorenzo Bianconi 
1513eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1514eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1515eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1516eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1517eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1518eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1519eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1520eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1521eadfd98fSLorenzo Bianconi 
1522eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1523eadfd98fSLorenzo Bianconi }
1524eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1525d2679d65SLorenzo Bianconi 
1526d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1527d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1528d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1529d2679d65SLorenzo Bianconi {
1530d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1531d2679d65SLorenzo Bianconi 
1532d2679d65SLorenzo Bianconi 	if (cck) {
1533edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1534d2679d65SLorenzo Bianconi 			return 0;
1535d2679d65SLorenzo Bianconi 
1536d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
153796747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1538d2679d65SLorenzo Bianconi 		offset = 4;
1539d2679d65SLorenzo Bianconi 	}
1540d2679d65SLorenzo Bianconi 
1541d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1542d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1543d2679d65SLorenzo Bianconi 			return i;
1544d2679d65SLorenzo Bianconi 	}
1545d2679d65SLorenzo Bianconi 
1546d2679d65SLorenzo Bianconi 	return 0;
1547d2679d65SLorenzo Bianconi }
1548d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
15498b8ab5c2SLorenzo Bianconi 
15508b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15518b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
15528b8ab5c2SLorenzo Bianconi {
1553011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
15548b8ab5c2SLorenzo Bianconi 
1555011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
15568b8ab5c2SLorenzo Bianconi }
15578b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
15588b8ab5c2SLorenzo Bianconi 
15598b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
15608b8ab5c2SLorenzo Bianconi {
1561011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
15628b8ab5c2SLorenzo Bianconi 
1563011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
15648b8ab5c2SLorenzo Bianconi }
15658b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1566e49c76d4SLorenzo Bianconi 
1567e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1568e49c76d4SLorenzo Bianconi {
1569beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1570beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1571e49c76d4SLorenzo Bianconi 
1572e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1573beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1574beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1575e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1576e49c76d4SLorenzo Bianconi 
1577e49c76d4SLorenzo Bianconi 	return 0;
1578e49c76d4SLorenzo Bianconi }
1579e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1580b671da33SLorenzo Bianconi 
1581b1cb42adSLorenzo Bianconi struct mt76_queue *
1582b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1583b1cb42adSLorenzo Bianconi 		int ring_base)
1584b671da33SLorenzo Bianconi {
1585b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1586b671da33SLorenzo Bianconi 	int err;
1587b671da33SLorenzo Bianconi 
1588b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1589b671da33SLorenzo Bianconi 	if (!hwq)
1590b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1591b671da33SLorenzo Bianconi 
1592b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1593b671da33SLorenzo Bianconi 	if (err < 0)
1594b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1595b671da33SLorenzo Bianconi 
1596b1cb42adSLorenzo Bianconi 	return hwq;
1597b671da33SLorenzo Bianconi }
1598b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1599e4867225SSean Wang 
160033920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
1601e4867225SSean Wang {
160233920b2bSRyder Lee 	int offset = 0;
1603e4867225SSean Wang 
1604edf9dab8SLorenzo Bianconi 	if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
1605e4867225SSean Wang 		offset = 4;
1606e4867225SSean Wang 
160733920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
160833920b2bSRyder Lee 	if (rateidx < 0)
160933920b2bSRyder Lee 		rateidx = 0;
161033920b2bSRyder Lee 
1611d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1612d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1613d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1614e4867225SSean Wang 
1615d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1616e4867225SSean Wang }
161733920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
161854ae98ffSLorenzo Bianconi 
161954ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
162054ae98ffSLorenzo Bianconi 			 struct mt76_sta_stats *stats)
162154ae98ffSLorenzo Bianconi {
162254ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
162354ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
162454ae98ffSLorenzo Bianconi 
162554ae98ffSLorenzo Bianconi 	wi->sta_count++;
162654ae98ffSLorenzo Bianconi 
162754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
162854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
162954ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
163054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
163154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
163254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
163354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
163454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
163554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
163654ae98ffSLorenzo Bianconi 
163754ae98ffSLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++)
163854ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
163954ae98ffSLorenzo Bianconi 
164054ae98ffSLorenzo Bianconi 	for (i = 0; i < 12; i++)
164154ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
164254ae98ffSLorenzo Bianconi 
164354ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
164454ae98ffSLorenzo Bianconi }
164554ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
16463f306448SFelix Fietkau 
16473f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
16483f306448SFelix Fietkau {
16493f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
16503f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
16513f306448SFelix Fietkau 
16523f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
16533f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
16543f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
16553f306448SFelix Fietkau 
16563f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
16573f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
16583f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
16593f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
16603f306448SFelix Fietkau 
16613f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
16623f306448SFelix Fietkau 	}
16633f306448SFelix Fietkau 
166400a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
16653f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
16663f306448SFelix Fietkau 
16673f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
16683f306448SFelix Fietkau }
16693f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1670