xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision b3cb885e56d5f64880109da9516ef2df1e9db7b9)
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 
183502604f5SYN Chen 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 EXPORT_SYMBOL_GPL(mt76_sar_capa);
189502604f5SYN Chen 
19017f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
19117f1de56SFelix Fietkau {
19217f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
19317f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
19417f1de56SFelix Fietkau 	int led_pin;
19517f1de56SFelix Fietkau 
19617f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
19717f1de56SFelix Fietkau 		return 0;
19817f1de56SFelix Fietkau 
19917f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
20017f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
20117f1de56SFelix Fietkau 
20217f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
20317f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
20417f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
20517f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
20617f1de56SFelix Fietkau 					mt76_tpt_blink,
20717f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
20817f1de56SFelix Fietkau 
20917f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
21017f1de56SFelix Fietkau 	if (np) {
21117f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
21217f1de56SFelix Fietkau 			dev->led_pin = led_pin;
21317f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
21417f1de56SFelix Fietkau 	}
21517f1de56SFelix Fietkau 
21636f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
21736f7e2b2SFelix Fietkau }
21836f7e2b2SFelix Fietkau 
21936f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
22036f7e2b2SFelix Fietkau {
22136f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
22236f7e2b2SFelix Fietkau 		return;
22336f7e2b2SFelix Fietkau 
22436f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
22517f1de56SFelix Fietkau }
22617f1de56SFelix Fietkau 
227bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
228551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
229551e1ef4SLorenzo Bianconi 				 bool vht)
230551e1ef4SLorenzo Bianconi {
231551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
232bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
233551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
234551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
235551e1ef4SLorenzo Bianconi 
236551e1ef4SLorenzo Bianconi 	if (nstream > 1)
237551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
238551e1ef4SLorenzo Bianconi 	else
239551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
240551e1ef4SLorenzo Bianconi 
241551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
242551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
243551e1ef4SLorenzo Bianconi 
244551e1ef4SLorenzo Bianconi 	if (!vht)
245551e1ef4SLorenzo Bianconi 		return;
246551e1ef4SLorenzo Bianconi 
247551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
248551e1ef4SLorenzo Bianconi 	if (nstream > 1)
249551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
250551e1ef4SLorenzo Bianconi 	else
251551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
252551e1ef4SLorenzo Bianconi 
253551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
254551e1ef4SLorenzo Bianconi 		if (i < nstream)
255551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
256551e1ef4SLorenzo Bianconi 		else
257551e1ef4SLorenzo Bianconi 			mcs_map |=
258551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
259551e1ef4SLorenzo Bianconi 	}
260551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
261551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
262551e1ef4SLorenzo Bianconi }
263551e1ef4SLorenzo Bianconi 
264bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2655ebdc3e0SLorenzo Bianconi {
26648dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
267bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
26848dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
269bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
270edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz)
271edf9dab8SLorenzo Bianconi 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
2725ebdc3e0SLorenzo Bianconi }
2735ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
2745ebdc3e0SLorenzo Bianconi 
27517f1de56SFelix Fietkau static int
27677af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
27717f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
278edf9dab8SLorenzo Bianconi 		struct ieee80211_rate *rates, int n_rates,
279edf9dab8SLorenzo Bianconi 		bool ht, bool vht)
28017f1de56SFelix Fietkau {
28117f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
28217f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
28377af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
28477af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
28517f1de56SFelix Fietkau 	void *chanlist;
28617f1de56SFelix Fietkau 	int size;
28717f1de56SFelix Fietkau 
28817f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
28917f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
29017f1de56SFelix Fietkau 	if (!chanlist)
29117f1de56SFelix Fietkau 		return -ENOMEM;
29217f1de56SFelix Fietkau 
293a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
29417f1de56SFelix Fietkau 				    GFP_KERNEL);
29517f1de56SFelix Fietkau 	if (!msband->chan)
29617f1de56SFelix Fietkau 		return -ENOMEM;
29717f1de56SFelix Fietkau 
29817f1de56SFelix Fietkau 	sband->channels = chanlist;
29917f1de56SFelix Fietkau 	sband->n_channels = n_chan;
30017f1de56SFelix Fietkau 	sband->bitrates = rates;
30117f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
30217f1de56SFelix Fietkau 
303edf9dab8SLorenzo Bianconi 	if (!ht)
304edf9dab8SLorenzo Bianconi 		return 0;
305edf9dab8SLorenzo Bianconi 
30617f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
30717f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
30817f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
30917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
31017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
31117f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
31217f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
31317f1de56SFelix Fietkau 
31417f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
31517f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
31617f1de56SFelix Fietkau 
31777af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
318551e1ef4SLorenzo Bianconi 
31917f1de56SFelix Fietkau 	if (!vht)
32017f1de56SFelix Fietkau 		return 0;
32117f1de56SFelix Fietkau 
32217f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
32317f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
32417f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
32517f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
32649149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
327f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
328f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
32949149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
33017f1de56SFelix Fietkau 
33117f1de56SFelix Fietkau 	return 0;
33217f1de56SFelix Fietkau }
33317f1de56SFelix Fietkau 
33417f1de56SFelix Fietkau static int
33577af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
33617f1de56SFelix Fietkau 		   int n_rates)
33717f1de56SFelix Fietkau {
33877af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
33917f1de56SFelix Fietkau 
34077af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
34177af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
342edf9dab8SLorenzo Bianconi 			       n_rates, true, false);
34317f1de56SFelix Fietkau }
34417f1de56SFelix Fietkau 
34517f1de56SFelix Fietkau static int
34677af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
34717f1de56SFelix Fietkau 		   int n_rates, bool vht)
34817f1de56SFelix Fietkau {
34977af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
35017f1de56SFelix Fietkau 
35177af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
35277af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
353edf9dab8SLorenzo Bianconi 			       n_rates, true, vht);
354edf9dab8SLorenzo Bianconi }
355edf9dab8SLorenzo Bianconi 
356edf9dab8SLorenzo Bianconi static int
357edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
358edf9dab8SLorenzo Bianconi 		   int n_rates)
359edf9dab8SLorenzo Bianconi {
360edf9dab8SLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
361edf9dab8SLorenzo Bianconi 
362edf9dab8SLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
363edf9dab8SLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
364edf9dab8SLorenzo Bianconi 			       n_rates, false, false);
36517f1de56SFelix Fietkau }
36617f1de56SFelix Fietkau 
36717f1de56SFelix Fietkau static void
368c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
369c89d3625SFelix Fietkau 		 enum nl80211_band band)
37017f1de56SFelix Fietkau {
371c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
37217f1de56SFelix Fietkau 	bool found = false;
37317f1de56SFelix Fietkau 	int i;
37417f1de56SFelix Fietkau 
37517f1de56SFelix Fietkau 	if (!sband)
37617f1de56SFelix Fietkau 		return;
37717f1de56SFelix Fietkau 
37817f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
37917f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
38017f1de56SFelix Fietkau 			continue;
38117f1de56SFelix Fietkau 
38217f1de56SFelix Fietkau 		found = true;
38317f1de56SFelix Fietkau 		break;
38417f1de56SFelix Fietkau 	}
38517f1de56SFelix Fietkau 
386c89d3625SFelix Fietkau 	if (found) {
387c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
388c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
38917f1de56SFelix Fietkau 		return;
390c89d3625SFelix Fietkau 	}
39117f1de56SFelix Fietkau 
39217f1de56SFelix Fietkau 	sband->n_channels = 0;
393c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
39417f1de56SFelix Fietkau }
39517f1de56SFelix Fietkau 
396c89d3625SFelix Fietkau static void
39798df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
398c89d3625SFelix Fietkau {
39998df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
400c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
401c89d3625SFelix Fietkau 
402c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
40398df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
404c89d3625SFelix Fietkau 
405c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
406dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
407b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
408b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
409c89d3625SFelix Fietkau 
410c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
411c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
412d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
413c89d3625SFelix Fietkau 
4140a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4150a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
416c89d3625SFelix Fietkau 
417c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
418b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
419c9619dfaSShayne Chen 
420c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
421c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
422c89d3625SFelix Fietkau 
423c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
424c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
425c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
426c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
427c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
428c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
429ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
430c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
431c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
432c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
433c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
434c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
435c89d3625SFelix Fietkau }
436c89d3625SFelix Fietkau 
437c89d3625SFelix Fietkau struct mt76_phy *
438c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
439c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
440c89d3625SFelix Fietkau {
441c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
442db78a791SLorenzo Bianconi 	unsigned int phy_size;
443c89d3625SFelix Fietkau 	struct mt76_phy *phy;
444c89d3625SFelix Fietkau 
445c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
446db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
447c89d3625SFelix Fietkau 	if (!hw)
448c89d3625SFelix Fietkau 		return NULL;
449c89d3625SFelix Fietkau 
450c89d3625SFelix Fietkau 	phy = hw->priv;
451c89d3625SFelix Fietkau 	phy->dev = dev;
452c89d3625SFelix Fietkau 	phy->hw = hw;
453db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
454c89d3625SFelix Fietkau 
4558af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4568af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4578af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4588af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4598af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4608af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4618af414e8SLorenzo Bianconi #endif
4628af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4638af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4648af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4658af414e8SLorenzo Bianconi 
466c89d3625SFelix Fietkau 	return phy;
467c89d3625SFelix Fietkau }
468c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
469c89d3625SFelix Fietkau 
470db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
471db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
472c89d3625SFelix Fietkau {
473c89d3625SFelix Fietkau 	int ret;
474c89d3625SFelix Fietkau 
47598df2baeSLorenzo Bianconi 	mt76_phy_init(phy, phy->hw);
476db78a791SLorenzo Bianconi 
477db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
478db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
479db78a791SLorenzo Bianconi 		if (ret)
480db78a791SLorenzo Bianconi 			return ret;
481db78a791SLorenzo Bianconi 	}
482db78a791SLorenzo Bianconi 
483db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
484db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
485db78a791SLorenzo Bianconi 		if (ret)
486db78a791SLorenzo Bianconi 			return ret;
487db78a791SLorenzo Bianconi 	}
488db78a791SLorenzo Bianconi 
489edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
490edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
491edf9dab8SLorenzo Bianconi 		if (ret)
492edf9dab8SLorenzo Bianconi 			return ret;
493edf9dab8SLorenzo Bianconi 	}
494edf9dab8SLorenzo Bianconi 
495db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
496db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
497db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
498edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
499db78a791SLorenzo Bianconi 
500c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
501c89d3625SFelix Fietkau 	if (ret)
502c89d3625SFelix Fietkau 		return ret;
503c89d3625SFelix Fietkau 
504c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
505db78a791SLorenzo Bianconi 
506c89d3625SFelix Fietkau 	return 0;
507c89d3625SFelix Fietkau }
508c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
509c89d3625SFelix Fietkau 
510db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
511c89d3625SFelix Fietkau {
512c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
513c89d3625SFelix Fietkau 
514c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
515c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
51694b6df08SFelix Fietkau 	dev->phy2 = NULL;
517c89d3625SFelix Fietkau }
518c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
519c89d3625SFelix Fietkau 
520a85b590cSFelix Fietkau struct mt76_dev *
521c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
522c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
523c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
524a85b590cSFelix Fietkau {
525a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
526ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
527a85b590cSFelix Fietkau 	struct mt76_dev *dev;
528e5443256SFelix Fietkau 	int i;
529a85b590cSFelix Fietkau 
530a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
531a85b590cSFelix Fietkau 	if (!hw)
532a85b590cSFelix Fietkau 		return NULL;
533a85b590cSFelix Fietkau 
534a85b590cSFelix Fietkau 	dev = hw->priv;
535a85b590cSFelix Fietkau 	dev->hw = hw;
536c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
537c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
538c0f7b25aSLorenzo Bianconi 
539ac24dd35SFelix Fietkau 	phy = &dev->phy;
540ac24dd35SFelix Fietkau 	phy->dev = dev;
541ac24dd35SFelix Fietkau 	phy->hw = hw;
542ac24dd35SFelix Fietkau 
543a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
544a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
545a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
546c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
547108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
54826e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
549a85b590cSFelix Fietkau 
55009872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
55109872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
55209872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
553781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
55409872957SLorenzo Bianconi 
5558af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5568af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
5578af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
5588af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
5598af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
5608af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
5618af414e8SLorenzo Bianconi #endif
5628af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5638af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
5648af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
5658af414e8SLorenzo Bianconi 
56651252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
56751252cc5SLorenzo Bianconi 	idr_init(&dev->token);
56851252cc5SLorenzo Bianconi 
569bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
570bd1e3e7bSLorenzo Bianconi 
571e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
572e5443256SFelix Fietkau 
573e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
574e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
575e5443256SFelix Fietkau 
576a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
577a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
578a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
579a86f1d01SLorenzo Bianconi 		return NULL;
580a86f1d01SLorenzo Bianconi 	}
581a86f1d01SLorenzo Bianconi 
582a85b590cSFelix Fietkau 	return dev;
583a85b590cSFelix Fietkau }
584a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
585a85b590cSFelix Fietkau 
58617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
58717f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
58817f1de56SFelix Fietkau {
58917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
590c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
59117f1de56SFelix Fietkau 	int ret;
59217f1de56SFelix Fietkau 
59317f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
59498df2baeSLorenzo Bianconi 	mt76_phy_init(phy, hw);
59517f1de56SFelix Fietkau 
59648dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
59777af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
59817f1de56SFelix Fietkau 		if (ret)
59917f1de56SFelix Fietkau 			return ret;
60017f1de56SFelix Fietkau 	}
60117f1de56SFelix Fietkau 
60248dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
60377af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
60417f1de56SFelix Fietkau 		if (ret)
60517f1de56SFelix Fietkau 			return ret;
60617f1de56SFelix Fietkau 	}
60717f1de56SFelix Fietkau 
608edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
609edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
610edf9dab8SLorenzo Bianconi 		if (ret)
611edf9dab8SLorenzo Bianconi 			return ret;
612edf9dab8SLorenzo Bianconi 	}
613edf9dab8SLorenzo Bianconi 
614c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
615c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
616c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
617edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
61817f1de56SFelix Fietkau 
619b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
62017f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
62117f1de56SFelix Fietkau 		if (ret)
62217f1de56SFelix Fietkau 			return ret;
623b374e868SArnd Bergmann 	}
62417f1de56SFelix Fietkau 
625781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
626781eef5bSFelix Fietkau 	if (ret)
627781eef5bSFelix Fietkau 		return ret;
628781eef5bSFelix Fietkau 
629781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
630781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
631781eef5bSFelix Fietkau 
632781eef5bSFelix Fietkau 	return 0;
63317f1de56SFelix Fietkau }
63417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
63517f1de56SFelix Fietkau 
63617f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
63717f1de56SFelix Fietkau {
63817f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
63917f1de56SFelix Fietkau 
640d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
64136f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
642c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
64317f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
64417f1de56SFelix Fietkau }
64517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
64617f1de56SFelix Fietkau 
647def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
648def34a2fSLorenzo Bianconi {
649781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
650a86f1d01SLorenzo Bianconi 	if (dev->wq) {
651a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
652a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
653a86f1d01SLorenzo Bianconi 	}
654def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
655def34a2fSLorenzo Bianconi }
656def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
657def34a2fSLorenzo Bianconi 
658cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
659cc4b3c13SLorenzo Bianconi {
660cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
6612c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
662cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
663cc4b3c13SLorenzo Bianconi 
664cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
665cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
6662c2bdd23SFelix Fietkau 
6672c2bdd23SFelix Fietkau 	/*
6682c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
6692c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
6702c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
6712c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
6722c2bdd23SFelix Fietkau 	 * address.
6732c2bdd23SFelix Fietkau 	 */
6742c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
6752c2bdd23SFelix Fietkau 		int offset = 0;
6762c2bdd23SFelix Fietkau 
6772c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
6782c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
6792c2bdd23SFelix Fietkau 
6802c2bdd23SFelix Fietkau 			if ((status->flag &
6812c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
6822c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
6832c2bdd23SFelix Fietkau 				offset += 8;
6842c2bdd23SFelix Fietkau 		}
6852c2bdd23SFelix Fietkau 
6862c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
6872c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
6882c2bdd23SFelix Fietkau 			return;
6892c2bdd23SFelix Fietkau 		}
6902c2bdd23SFelix Fietkau 	}
691cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
692cc4b3c13SLorenzo Bianconi }
693cc4b3c13SLorenzo Bianconi 
694cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
695cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
696cc4b3c13SLorenzo Bianconi {
697cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
698cc4b3c13SLorenzo Bianconi 
699cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
700cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
701cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
702cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
703cc4b3c13SLorenzo Bianconi 
704cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
705cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
706cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
707cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
708cc4b3c13SLorenzo Bianconi 	} else {
709cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
710cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
711cc4b3c13SLorenzo Bianconi 	}
712cc4b3c13SLorenzo Bianconi 
713cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
714cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
715cc4b3c13SLorenzo Bianconi }
716cc4b3c13SLorenzo Bianconi 
71717f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
71817f1de56SFelix Fietkau {
719011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
720011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
721011849e0SFelix Fietkau 
722011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
72317f1de56SFelix Fietkau 		dev_kfree_skb(skb);
72417f1de56SFelix Fietkau 		return;
72517f1de56SFelix Fietkau 	}
72617f1de56SFelix Fietkau 
727f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
728c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
729c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
730f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
731c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
732f0efa862SFelix Fietkau 	}
733f0efa862SFelix Fietkau #endif
734cc4b3c13SLorenzo Bianconi 
735cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
73617f1de56SFelix Fietkau }
73717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
73817f1de56SFelix Fietkau 
7395a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
74026e40d4cSFelix Fietkau {
741af005f26SLorenzo Bianconi 	struct mt76_queue *q;
74291990519SLorenzo Bianconi 	int i;
7435a95ca41SFelix Fietkau 
7445a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
74591990519SLorenzo Bianconi 		q = phy->q_tx[i];
746af005f26SLorenzo Bianconi 		if (q && q->queued)
74726e40d4cSFelix Fietkau 			return true;
74826e40d4cSFelix Fietkau 	}
74926e40d4cSFelix Fietkau 
75026e40d4cSFelix Fietkau 	return false;
75126e40d4cSFelix Fietkau }
75239d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
75326e40d4cSFelix Fietkau 
7540fd0eb54SFelix Fietkau static struct mt76_channel_state *
75596747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
7560fd0eb54SFelix Fietkau {
7570fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
7580fd0eb54SFelix Fietkau 	int idx;
7590fd0eb54SFelix Fietkau 
7600fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
76196747a51SFelix Fietkau 		msband = &phy->sband_2g;
762edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
763edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
7640fd0eb54SFelix Fietkau 	else
76596747a51SFelix Fietkau 		msband = &phy->sband_5g;
7660fd0eb54SFelix Fietkau 
7670fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
7680fd0eb54SFelix Fietkau 	return &msband->chan[idx];
7690fd0eb54SFelix Fietkau }
7700fd0eb54SFelix Fietkau 
77104414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
77296747a51SFelix Fietkau {
77396747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
77496747a51SFelix Fietkau 
77596747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
77696747a51SFelix Fietkau 						  phy->survey_time));
77796747a51SFelix Fietkau 	phy->survey_time = time;
77896747a51SFelix Fietkau }
77904414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
78096747a51SFelix Fietkau 
781c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
7825ce09c1aSFelix Fietkau {
783c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
784aec65e48SFelix Fietkau 	ktime_t cur_time;
785aec65e48SFelix Fietkau 
7865ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
787c560b137SRyder Lee 		dev->drv->update_survey(phy);
7885ce09c1aSFelix Fietkau 
789aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
790c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
791aec65e48SFelix Fietkau 
7925ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
793c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
79496747a51SFelix Fietkau 
795237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
7965ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
7975ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
798237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
7995ce09c1aSFelix Fietkau 	}
8005ce09c1aSFelix Fietkau }
8015ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
8025ce09c1aSFelix Fietkau 
80396747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
80417f1de56SFelix Fietkau {
80596747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
80696747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
80717f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
80817f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
80926e40d4cSFelix Fietkau 	int timeout = HZ / 5;
81017f1de56SFelix Fietkau 
8115a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
812c560b137SRyder Lee 	mt76_update_survey(phy);
81317f1de56SFelix Fietkau 
81496747a51SFelix Fietkau 	phy->chandef = *chandef;
81596747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
81617f1de56SFelix Fietkau 
81717f1de56SFelix Fietkau 	if (!offchannel)
81896747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
81917f1de56SFelix Fietkau 
82096747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
82196747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
82217f1de56SFelix Fietkau }
82317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
82417f1de56SFelix Fietkau 
82517f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
82617f1de56SFelix Fietkau 		    struct survey_info *survey)
82717f1de56SFelix Fietkau {
82896747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
82996747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
83017f1de56SFelix Fietkau 	struct mt76_sband *sband;
83117f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
83217f1de56SFelix Fietkau 	struct mt76_channel_state *state;
83317f1de56SFelix Fietkau 	int ret = 0;
83417f1de56SFelix Fietkau 
835237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
83617f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
837c560b137SRyder Lee 		mt76_update_survey(phy);
83817f1de56SFelix Fietkau 
839edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
840edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
841edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
842edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
843edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
844edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
845edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
84696747a51SFelix Fietkau 		sband = &phy->sband_5g;
847edf9dab8SLorenzo Bianconi 	} else {
848edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
84917f1de56SFelix Fietkau 	}
85017f1de56SFelix Fietkau 
851237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
852237312c5SLorenzo Bianconi 		ret = -ENOENT;
853237312c5SLorenzo Bianconi 		goto out;
854237312c5SLorenzo Bianconi 	}
85517f1de56SFelix Fietkau 
85617f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
85796747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
85817f1de56SFelix Fietkau 
85917f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
86017f1de56SFelix Fietkau 	survey->channel = chan;
86117f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
862ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
863e5051965SFelix Fietkau 	if (state->noise)
864e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
865e5051965SFelix Fietkau 
86696747a51SFelix Fietkau 	if (chan == phy->main_chan) {
86717f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
86817f1de56SFelix Fietkau 
8695ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
8705ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
8715ce09c1aSFelix Fietkau 	}
8725ce09c1aSFelix Fietkau 
87317f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
8746bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
875237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
876e5051965SFelix Fietkau 	survey->noise = state->noise;
877237312c5SLorenzo Bianconi 
878237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
879237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
880ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
88117f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
88217f1de56SFelix Fietkau 
883237312c5SLorenzo Bianconi out:
884237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
885237312c5SLorenzo Bianconi 
88617f1de56SFelix Fietkau 	return ret;
88717f1de56SFelix Fietkau }
88817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
88917f1de56SFelix Fietkau 
89030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
89130ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
89230ce7f44SFelix Fietkau {
89330ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
89430ce7f44SFelix Fietkau 	int i;
89530ce7f44SFelix Fietkau 
89630ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
89730ce7f44SFelix Fietkau 
89830ce7f44SFelix Fietkau 	if (!key)
89930ce7f44SFelix Fietkau 		return;
90030ce7f44SFelix Fietkau 
90101cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
90201cfc1b4SLorenzo Bianconi 		return;
90330ce7f44SFelix Fietkau 
90401cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
905a1b0bbd4SXing Song 
906a1b0bbd4SXing Song 	/* data frame */
90730ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
90830ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
90930ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
91030ce7f44SFelix Fietkau 	}
911a1b0bbd4SXing Song 
912a1b0bbd4SXing Song 	/* robust management frame */
913a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
914a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
915a1b0bbd4SXing Song 
91630ce7f44SFelix Fietkau }
91730ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
91830ce7f44SFelix Fietkau 
919bfc394ddSFelix Fietkau static void
920bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
921bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
922bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
9234e34249eSFelix Fietkau {
9244e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
925abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
9264e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
9274e34249eSFelix Fietkau 
9284e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
9294e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
9304e34249eSFelix Fietkau 
9314e34249eSFelix Fietkau 	status->flag = mstat.flag;
9324e34249eSFelix Fietkau 	status->freq = mstat.freq;
9334e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
9344e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
9354e34249eSFelix Fietkau 	status->bw = mstat.bw;
936af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
937af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
938af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
9394e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
9404e34249eSFelix Fietkau 	status->nss = mstat.nss;
9414e34249eSFelix Fietkau 	status->band = mstat.band;
9424e34249eSFelix Fietkau 	status->signal = mstat.signal;
9434e34249eSFelix Fietkau 	status->chains = mstat.chains;
944d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
9450fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
9460fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
9474e34249eSFelix Fietkau 
948abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
949abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
950abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
951abe3f3daSRyder Lee 
9524e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
95313381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
95413381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
95513381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
95613381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
9579c68a57bSFelix Fietkau 
958bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
959bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
9604e34249eSFelix Fietkau }
9614e34249eSFelix Fietkau 
96230ce7f44SFelix Fietkau static int
96330ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
96430ce7f44SFelix Fietkau {
96530ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
96630ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
96730ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
968a1b0bbd4SXing Song 	int security_idx;
96930ce7f44SFelix Fietkau 	int ret;
97030ce7f44SFelix Fietkau 
97130ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
97230ce7f44SFelix Fietkau 		return 0;
97330ce7f44SFelix Fietkau 
97430ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
97530ce7f44SFelix Fietkau 		return 0;
97630ce7f44SFelix Fietkau 
9777360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
9787360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
9797360cdecSFelix Fietkau 		goto skip_hdr_check;
9807360cdecSFelix Fietkau 
981a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
98230ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
98330ce7f44SFelix Fietkau 		/*
98430ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
98530ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
98630ce7f44SFelix Fietkau 		 */
98730ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
98830ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
98930ce7f44SFelix Fietkau 			return 0;
99030ce7f44SFelix Fietkau 	}
99130ce7f44SFelix Fietkau 
992a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
993a1b0bbd4SXing Song 	 *
994a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
995a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
996a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
997a1b0bbd4SXing Song 	 */
998a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
999a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1000a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1001a1b0bbd4SXing Song 
10027360cdecSFelix Fietkau skip_hdr_check:
100330ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1004a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
100530ce7f44SFelix Fietkau 		     sizeof(status->iv));
100630ce7f44SFelix Fietkau 	if (ret <= 0)
100730ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
100830ce7f44SFelix Fietkau 
1009a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
101030ce7f44SFelix Fietkau 
101130ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
101230ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
101330ce7f44SFelix Fietkau 
101430ce7f44SFelix Fietkau 	return 0;
101530ce7f44SFelix Fietkau }
101630ce7f44SFelix Fietkau 
1017d71ef286SFelix Fietkau static void
10185ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
10195ce09c1aSFelix Fietkau 		    int len)
10205ce09c1aSFelix Fietkau {
10215ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
102285b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
102385b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
102485b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
102585b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
102685b7a5d0SLorenzo Bianconi 		.band = status->band,
102785b7a5d0SLorenzo Bianconi 		.nss = status->nss,
102885b7a5d0SLorenzo Bianconi 		.bw = status->bw,
102985b7a5d0SLorenzo Bianconi 	};
10305ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
10315ce09c1aSFelix Fietkau 	u32 airtime;
1032e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
10335ce09c1aSFelix Fietkau 
103485b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1035237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
10365ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1037237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
10385ce09c1aSFelix Fietkau 
10395ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
10405ce09c1aSFelix Fietkau 		return;
10415ce09c1aSFelix Fietkau 
10425ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1043e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
10445ce09c1aSFelix Fietkau }
10455ce09c1aSFelix Fietkau 
10465ce09c1aSFelix Fietkau static void
10475ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
10485ce09c1aSFelix Fietkau {
10495ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
10505ce09c1aSFelix Fietkau 	int wcid_idx;
10515ce09c1aSFelix Fietkau 
10525ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
10535ce09c1aSFelix Fietkau 		return;
10545ce09c1aSFelix Fietkau 
10555ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1056bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
10575ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
10585ce09c1aSFelix Fietkau 	else
10595ce09c1aSFelix Fietkau 		wcid = NULL;
10605ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
10615ce09c1aSFelix Fietkau 
10625ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
10635ce09c1aSFelix Fietkau 
10645ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
10655ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
10665ce09c1aSFelix Fietkau }
10675ce09c1aSFelix Fietkau 
10685ce09c1aSFelix Fietkau static void
10695ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
10705ce09c1aSFelix Fietkau {
10715ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
10725ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
10735ce09c1aSFelix Fietkau 
10745ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
10755ce09c1aSFelix Fietkau 		return;
10765ce09c1aSFelix Fietkau 
10775ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1078e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1079e195dad1SFelix Fietkau 
1080e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1081e195dad1SFelix Fietkau 			return;
1082e195dad1SFelix Fietkau 
108398df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
10845ce09c1aSFelix Fietkau 			return;
10855ce09c1aSFelix Fietkau 
10865ce09c1aSFelix Fietkau 		wcid = NULL;
10875ce09c1aSFelix Fietkau 	}
10885ce09c1aSFelix Fietkau 
10895ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
10905ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
10915ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
10925ce09c1aSFelix Fietkau 
10935ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
10945ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
10955ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
10965ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
10975ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
10985ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
10995ce09c1aSFelix Fietkau 		}
11005ce09c1aSFelix Fietkau 
11015ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
11025ce09c1aSFelix Fietkau 		return;
11035ce09c1aSFelix Fietkau 	}
11045ce09c1aSFelix Fietkau 
11055ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
11065ce09c1aSFelix Fietkau }
11075ce09c1aSFelix Fietkau 
11085ce09c1aSFelix Fietkau static void
1109ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1110d71ef286SFelix Fietkau {
1111d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
111277ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1113d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1114bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1115d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1116e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1117d71ef286SFelix Fietkau 	bool ps;
1118d71ef286SFelix Fietkau 
1119bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
1120e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1121e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1122bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
112336d91096SFelix Fietkau 		if (sta)
112436d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
112536d91096SFelix Fietkau 	}
112636d91096SFelix Fietkau 
11275ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
11285ce09c1aSFelix Fietkau 
1129d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1130d71ef286SFelix Fietkau 		return;
1131d71ef286SFelix Fietkau 
1132d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1133d71ef286SFelix Fietkau 
113402e5a769SFelix Fietkau 	if (status->signal <= 0)
113502e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
113602e5a769SFelix Fietkau 
1137ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1138ef13edc0SFelix Fietkau 
1139e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1140e195dad1SFelix Fietkau 		return;
1141e195dad1SFelix Fietkau 
1142d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1143d71ef286SFelix Fietkau 		return;
1144d71ef286SFelix Fietkau 
1145d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1146d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1147d71ef286SFelix Fietkau 		return;
1148d71ef286SFelix Fietkau 	}
1149d71ef286SFelix Fietkau 
1150d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1151d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1152d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1153d71ef286SFelix Fietkau 		return;
1154d71ef286SFelix Fietkau 
1155d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1156d71ef286SFelix Fietkau 
1157d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1158d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1159e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1160d71ef286SFelix Fietkau 
1161d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1162d71ef286SFelix Fietkau 		return;
1163d71ef286SFelix Fietkau 
116411b2a25fSFelix Fietkau 	if (ps)
1165d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
116611b2a25fSFelix Fietkau 	else
1167d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1168d71ef286SFelix Fietkau 
1169d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
11709f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1171d71ef286SFelix Fietkau }
1172d71ef286SFelix Fietkau 
11739d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
117481e850efSLorenzo Bianconi 		      struct napi_struct *napi)
117517f1de56SFelix Fietkau {
11769c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1177bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
11783298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
11793298b1f8SFelix Fietkau 	LIST_HEAD(list);
11809d9d738bSFelix Fietkau 
1181c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
11829d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1183cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1184cc4b3c13SLorenzo Bianconi 
118530ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
118630ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
118730ce7f44SFelix Fietkau 			continue;
118830ce7f44SFelix Fietkau 		}
118930ce7f44SFelix Fietkau 
1190cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1191bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
11923298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1193cc4b3c13SLorenzo Bianconi 
1194cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1195cc4b3c13SLorenzo Bianconi 		while (nskb) {
1196cc4b3c13SLorenzo Bianconi 			skb = nskb;
1197cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1198cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1199cc4b3c13SLorenzo Bianconi 
1200cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1201cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1202cc4b3c13SLorenzo Bianconi 		}
12039d9d738bSFelix Fietkau 	}
1204c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
12053298b1f8SFelix Fietkau 
12063298b1f8SFelix Fietkau 	if (!napi) {
12073298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
12083298b1f8SFelix Fietkau 		return;
12093298b1f8SFelix Fietkau 	}
12103298b1f8SFelix Fietkau 
12113298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
12123298b1f8SFelix Fietkau 		skb_list_del_init(skb);
12133298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
12143298b1f8SFelix Fietkau 	}
12159d9d738bSFelix Fietkau }
12169d9d738bSFelix Fietkau 
121781e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
121881e850efSLorenzo Bianconi 			   struct napi_struct *napi)
12199d9d738bSFelix Fietkau {
1220aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
122117f1de56SFelix Fietkau 	struct sk_buff *skb;
122217f1de56SFelix Fietkau 
1223aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1224aee5b8cfSFelix Fietkau 
1225d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1226ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
1227aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
1228d71ef286SFelix Fietkau 	}
1229aee5b8cfSFelix Fietkau 
123081e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
12314e34249eSFelix Fietkau }
123281e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1233723b90dcSFelix Fietkau 
1234e28487eaSFelix Fietkau static int
1235e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
1236426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
1237e28487eaSFelix Fietkau {
1238e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1239e28487eaSFelix Fietkau 	int ret;
1240e28487eaSFelix Fietkau 	int i;
1241e28487eaSFelix Fietkau 
1242e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1243e28487eaSFelix Fietkau 
1244e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1245e28487eaSFelix Fietkau 	if (ret)
1246e28487eaSFelix Fietkau 		goto out;
1247e28487eaSFelix Fietkau 
1248e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1249e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1250e28487eaSFelix Fietkau 
1251e28487eaSFelix Fietkau 		if (!sta->txq[i])
1252e28487eaSFelix Fietkau 			continue;
1253e28487eaSFelix Fietkau 
1254e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
1255e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
1256e28487eaSFelix Fietkau 	}
1257e28487eaSFelix Fietkau 
1258ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1259426e8e41SFelix Fietkau 	if (ext_phy)
1260426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1261c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
1262e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1263e28487eaSFelix Fietkau 
1264bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_init(wcid);
1265e28487eaSFelix Fietkau out:
1266e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1267e28487eaSFelix Fietkau 
1268e28487eaSFelix Fietkau 	return ret;
1269e28487eaSFelix Fietkau }
1270e28487eaSFelix Fietkau 
127113f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1272723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1273723b90dcSFelix Fietkau {
1274723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
127513f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1276723b90dcSFelix Fietkau 
127758bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
127858bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
127958bab0d4SFelix Fietkau 
1280e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1281e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1282e28487eaSFelix Fietkau 
1283bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_flush(dev, wcid);
1284bd1e3e7bSLorenzo Bianconi 
1285426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1286426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
128713f61dfcSLorenzo Bianconi }
128813f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1289e28487eaSFelix Fietkau 
129013f61dfcSLorenzo Bianconi static void
129113f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
129213f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
129313f61dfcSLorenzo Bianconi {
129413f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
129513f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1296723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1297723b90dcSFelix Fietkau }
1298e28487eaSFelix Fietkau 
1299e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1300e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1301e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1302e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1303e28487eaSFelix Fietkau {
1304426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1305426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1306426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1307e28487eaSFelix Fietkau 
1308e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1309e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1310426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1311e28487eaSFelix Fietkau 
13129c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
13139c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
13149c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
13159c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
13169c193de5SFelix Fietkau 
1317e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1318e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1319e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1320e28487eaSFelix Fietkau 
1321e28487eaSFelix Fietkau 	return 0;
1322e28487eaSFelix Fietkau }
1323e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
13249313faacSFelix Fietkau 
132543ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
132643ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
132743ba1922SFelix Fietkau {
132843ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
132943ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
133043ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
133143ba1922SFelix Fietkau 
133243ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
133343ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
133443ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
133543ba1922SFelix Fietkau }
133643ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
133743ba1922SFelix Fietkau 
13389313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
13399313faacSFelix Fietkau 		     int *dbm)
13409313faacSFelix Fietkau {
1341beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1342beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
134307cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
13449313faacSFelix Fietkau 
134507cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
13469313faacSFelix Fietkau 
13479313faacSFelix Fietkau 	return 0;
13489313faacSFelix Fietkau }
13499313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1350e7173858SFelix Fietkau 
1351*b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1352*b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1353*b3cb885eSLorenzo Bianconi {
1354*b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1355*b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1356*b3cb885eSLorenzo Bianconi 	int i;
1357*b3cb885eSLorenzo Bianconi 
1358*b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1359*b3cb885eSLorenzo Bianconi 		return -EINVAL;
1360*b3cb885eSLorenzo Bianconi 
1361*b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1362*b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1363*b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1364*b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1365*b3cb885eSLorenzo Bianconi 
1366*b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1367*b3cb885eSLorenzo Bianconi 			power = 127;
1368*b3cb885eSLorenzo Bianconi 
1369*b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1370*b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1371*b3cb885eSLorenzo Bianconi 	}
1372*b3cb885eSLorenzo Bianconi 
1373*b3cb885eSLorenzo Bianconi 	return 0;
1374*b3cb885eSLorenzo Bianconi }
1375*b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1376*b3cb885eSLorenzo Bianconi 
1377*b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1378*b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1379*b3cb885eSLorenzo Bianconi 		       int power)
1380*b3cb885eSLorenzo Bianconi {
1381*b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1382*b3cb885eSLorenzo Bianconi 	int freq, i;
1383*b3cb885eSLorenzo Bianconi 
1384*b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1385*b3cb885eSLorenzo Bianconi 		return power;
1386*b3cb885eSLorenzo Bianconi 
1387*b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1388*b3cb885eSLorenzo Bianconi 		power = 127;
1389*b3cb885eSLorenzo Bianconi 
1390*b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1391*b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1392*b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1393*b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1394*b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1395*b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1396*b3cb885eSLorenzo Bianconi 			break;
1397*b3cb885eSLorenzo Bianconi 		}
1398*b3cb885eSLorenzo Bianconi 	}
1399*b3cb885eSLorenzo Bianconi 
1400*b3cb885eSLorenzo Bianconi 	return power;
1401*b3cb885eSLorenzo Bianconi }
1402*b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1403*b3cb885eSLorenzo Bianconi 
1404e7173858SFelix Fietkau static void
1405e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1406e7173858SFelix Fietkau {
14078552a434SJohn Crispin 	if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1408e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1409e7173858SFelix Fietkau }
1410e7173858SFelix Fietkau 
1411e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1412e7173858SFelix Fietkau {
1413e7173858SFelix Fietkau 	if (!dev->csa_complete)
1414e7173858SFelix Fietkau 		return;
1415e7173858SFelix Fietkau 
1416e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1417e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1418e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1419e7173858SFelix Fietkau 
1420e7173858SFelix Fietkau 	dev->csa_complete = 0;
1421e7173858SFelix Fietkau }
1422e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1423e7173858SFelix Fietkau 
1424e7173858SFelix Fietkau static void
1425e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1426e7173858SFelix Fietkau {
1427e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1428e7173858SFelix Fietkau 
1429e7173858SFelix Fietkau 	if (!vif->csa_active)
1430e7173858SFelix Fietkau 		return;
1431e7173858SFelix Fietkau 
14328552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1433e7173858SFelix Fietkau }
1434e7173858SFelix Fietkau 
1435e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1436e7173858SFelix Fietkau {
1437e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1438e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1439e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1440e7173858SFelix Fietkau }
1441e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
144287d53103SStanislaw Gruszka 
144387d53103SStanislaw Gruszka int
144487d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
144587d53103SStanislaw Gruszka {
144687d53103SStanislaw Gruszka 	return 0;
144787d53103SStanislaw Gruszka }
144887d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1449eadfd98fSLorenzo Bianconi 
1450eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1451eadfd98fSLorenzo Bianconi {
1452eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1453eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1454eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1455eadfd98fSLorenzo Bianconi 
1456eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1457eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1458eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1459eadfd98fSLorenzo Bianconi 
1460eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1461eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1462eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1463eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1464eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1465eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1466eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1467eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1468eadfd98fSLorenzo Bianconi 
1469eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1470eadfd98fSLorenzo Bianconi }
1471eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1472d2679d65SLorenzo Bianconi 
1473d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1474d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1475d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1476d2679d65SLorenzo Bianconi {
1477d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1478d2679d65SLorenzo Bianconi 
1479d2679d65SLorenzo Bianconi 	if (cck) {
1480edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1481d2679d65SLorenzo Bianconi 			return 0;
1482d2679d65SLorenzo Bianconi 
1483d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
148496747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1485d2679d65SLorenzo Bianconi 		offset = 4;
1486d2679d65SLorenzo Bianconi 	}
1487d2679d65SLorenzo Bianconi 
1488d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1489d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1490d2679d65SLorenzo Bianconi 			return i;
1491d2679d65SLorenzo Bianconi 	}
1492d2679d65SLorenzo Bianconi 
1493d2679d65SLorenzo Bianconi 	return 0;
1494d2679d65SLorenzo Bianconi }
1495d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
14968b8ab5c2SLorenzo Bianconi 
14978b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
14988b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
14998b8ab5c2SLorenzo Bianconi {
1500011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
15018b8ab5c2SLorenzo Bianconi 
1502011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
15038b8ab5c2SLorenzo Bianconi }
15048b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
15058b8ab5c2SLorenzo Bianconi 
15068b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
15078b8ab5c2SLorenzo Bianconi {
1508011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
15098b8ab5c2SLorenzo Bianconi 
1510011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
15118b8ab5c2SLorenzo Bianconi }
15128b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1513e49c76d4SLorenzo Bianconi 
1514e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1515e49c76d4SLorenzo Bianconi {
1516beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1517beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1518e49c76d4SLorenzo Bianconi 
1519e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1520beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1521beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1522e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1523e49c76d4SLorenzo Bianconi 
1524e49c76d4SLorenzo Bianconi 	return 0;
1525e49c76d4SLorenzo Bianconi }
1526e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1527b671da33SLorenzo Bianconi 
1528b1cb42adSLorenzo Bianconi struct mt76_queue *
1529b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1530b1cb42adSLorenzo Bianconi 		int ring_base)
1531b671da33SLorenzo Bianconi {
1532b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1533b671da33SLorenzo Bianconi 	int err;
1534b671da33SLorenzo Bianconi 
1535b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1536b671da33SLorenzo Bianconi 	if (!hwq)
1537b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1538b671da33SLorenzo Bianconi 
1539b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1540b671da33SLorenzo Bianconi 	if (err < 0)
1541b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1542b671da33SLorenzo Bianconi 
1543b1cb42adSLorenzo Bianconi 	return hwq;
1544b671da33SLorenzo Bianconi }
1545b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1546e4867225SSean Wang 
154733920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
1548e4867225SSean Wang {
154933920b2bSRyder Lee 	int offset = 0;
1550e4867225SSean Wang 
1551edf9dab8SLorenzo Bianconi 	if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
1552e4867225SSean Wang 		offset = 4;
1553e4867225SSean Wang 
155433920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
155533920b2bSRyder Lee 	if (rateidx < 0)
155633920b2bSRyder Lee 		rateidx = 0;
155733920b2bSRyder Lee 
1558d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1559d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1560d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1561e4867225SSean Wang 
1562d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1563e4867225SSean Wang }
156433920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
156554ae98ffSLorenzo Bianconi 
156654ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
156754ae98ffSLorenzo Bianconi 			 struct mt76_sta_stats *stats)
156854ae98ffSLorenzo Bianconi {
156954ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
157054ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
157154ae98ffSLorenzo Bianconi 
157254ae98ffSLorenzo Bianconi 	wi->sta_count++;
157354ae98ffSLorenzo Bianconi 
157454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
157554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
157654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
157754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
157854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
157954ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
158054ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
158154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
158254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
158354ae98ffSLorenzo Bianconi 
158454ae98ffSLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++)
158554ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
158654ae98ffSLorenzo Bianconi 
158754ae98ffSLorenzo Bianconi 	for (i = 0; i < 12; i++)
158854ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
158954ae98ffSLorenzo Bianconi 
159054ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
159154ae98ffSLorenzo Bianconi }
159254ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
1593