xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 2666bece0905a3e8ccb792602dbc76a63aaafe4b)
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, },
181162d5c14SDeren Wu 	{ .start_freq = 5945, .end_freq = 6165, },
182162d5c14SDeren Wu 	{ .start_freq = 6165, .end_freq = 6405, },
183162d5c14SDeren Wu 	{ .start_freq = 6405, .end_freq = 6525, },
184162d5c14SDeren Wu 	{ .start_freq = 6525, .end_freq = 6705, },
185162d5c14SDeren Wu 	{ .start_freq = 6705, .end_freq = 6865, },
186162d5c14SDeren Wu 	{ .start_freq = 6865, .end_freq = 7125, },
187502604f5SYN Chen };
188502604f5SYN Chen 
18997f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = {
190502604f5SYN Chen 	.type = NL80211_SAR_TYPE_POWER,
191502604f5SYN Chen 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
192502604f5SYN Chen 	.freq_ranges = &mt76_sar_freq_ranges[0],
193502604f5SYN Chen };
194502604f5SYN Chen 
19517f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
19617f1de56SFelix Fietkau {
19717f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
19817f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
19917f1de56SFelix Fietkau 	int led_pin;
20017f1de56SFelix Fietkau 
20117f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
20217f1de56SFelix Fietkau 		return 0;
20317f1de56SFelix Fietkau 
20417f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
20517f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
20617f1de56SFelix Fietkau 
20717f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
20817f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
20917f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
21017f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
21117f1de56SFelix Fietkau 					mt76_tpt_blink,
21217f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
21317f1de56SFelix Fietkau 
21417f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
21517f1de56SFelix Fietkau 	if (np) {
21617f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
21717f1de56SFelix Fietkau 			dev->led_pin = led_pin;
21817f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
2190a14c1d0SLiang He 		of_node_put(np);
22017f1de56SFelix Fietkau 	}
22117f1de56SFelix Fietkau 
22236f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
22336f7e2b2SFelix Fietkau }
22436f7e2b2SFelix Fietkau 
22536f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
22636f7e2b2SFelix Fietkau {
22736f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
22836f7e2b2SFelix Fietkau 		return;
22936f7e2b2SFelix Fietkau 
23036f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
23117f1de56SFelix Fietkau }
23217f1de56SFelix Fietkau 
233bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
234551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
235551e1ef4SLorenzo Bianconi 				 bool vht)
236551e1ef4SLorenzo Bianconi {
237551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
238bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
239551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
240551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
241551e1ef4SLorenzo Bianconi 
242551e1ef4SLorenzo Bianconi 	if (nstream > 1)
243551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
244551e1ef4SLorenzo Bianconi 	else
245551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
246551e1ef4SLorenzo Bianconi 
247551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
248551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
249551e1ef4SLorenzo Bianconi 
250551e1ef4SLorenzo Bianconi 	if (!vht)
251551e1ef4SLorenzo Bianconi 		return;
252551e1ef4SLorenzo Bianconi 
253551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
254551e1ef4SLorenzo Bianconi 	if (nstream > 1)
255551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
256551e1ef4SLorenzo Bianconi 	else
257551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
258abba3453SDeren Wu 	vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
259abba3453SDeren Wu 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
260551e1ef4SLorenzo Bianconi 
261551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
262551e1ef4SLorenzo Bianconi 		if (i < nstream)
263551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
264551e1ef4SLorenzo Bianconi 		else
265551e1ef4SLorenzo Bianconi 			mcs_map |=
266551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
267551e1ef4SLorenzo Bianconi 	}
268551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
269551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
270781b80f4SFelix Fietkau 	if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
271d9fcfc14SDeren Wu 		vht_cap->vht_mcs.tx_highest |=
272d9fcfc14SDeren Wu 				cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
273551e1ef4SLorenzo Bianconi }
274551e1ef4SLorenzo Bianconi 
275bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2765ebdc3e0SLorenzo Bianconi {
27748dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
278bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
27948dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
280bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
281edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz)
282edf9dab8SLorenzo Bianconi 		mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
2835ebdc3e0SLorenzo Bianconi }
2845ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
2855ebdc3e0SLorenzo Bianconi 
28617f1de56SFelix Fietkau static int
28777af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
28817f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
289edf9dab8SLorenzo Bianconi 		struct ieee80211_rate *rates, int n_rates,
290edf9dab8SLorenzo Bianconi 		bool ht, bool vht)
29117f1de56SFelix Fietkau {
29217f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
29317f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
29477af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
29577af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
29617f1de56SFelix Fietkau 	void *chanlist;
29717f1de56SFelix Fietkau 	int size;
29817f1de56SFelix Fietkau 
29917f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
30017f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
30117f1de56SFelix Fietkau 	if (!chanlist)
30217f1de56SFelix Fietkau 		return -ENOMEM;
30317f1de56SFelix Fietkau 
304a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
30517f1de56SFelix Fietkau 				    GFP_KERNEL);
30617f1de56SFelix Fietkau 	if (!msband->chan)
30717f1de56SFelix Fietkau 		return -ENOMEM;
30817f1de56SFelix Fietkau 
30917f1de56SFelix Fietkau 	sband->channels = chanlist;
31017f1de56SFelix Fietkau 	sband->n_channels = n_chan;
31117f1de56SFelix Fietkau 	sband->bitrates = rates;
31217f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
31317f1de56SFelix Fietkau 
314edf9dab8SLorenzo Bianconi 	if (!ht)
315edf9dab8SLorenzo Bianconi 		return 0;
316edf9dab8SLorenzo Bianconi 
31717f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
31817f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
31917f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
32017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
32117f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
32217f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
32317f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
32417f1de56SFelix Fietkau 
32517f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
32617f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
32717f1de56SFelix Fietkau 
32877af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
329551e1ef4SLorenzo Bianconi 
33017f1de56SFelix Fietkau 	if (!vht)
33117f1de56SFelix Fietkau 		return 0;
33217f1de56SFelix Fietkau 
33317f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
33417f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
33517f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
33617f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
33749149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
33849149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
33917f1de56SFelix Fietkau 
34017f1de56SFelix Fietkau 	return 0;
34117f1de56SFelix Fietkau }
34217f1de56SFelix Fietkau 
34317f1de56SFelix Fietkau static int
34477af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
34517f1de56SFelix Fietkau 		   int n_rates)
34617f1de56SFelix Fietkau {
34777af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
34817f1de56SFelix Fietkau 
34977af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
35077af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
351edf9dab8SLorenzo Bianconi 			       n_rates, true, false);
35217f1de56SFelix Fietkau }
35317f1de56SFelix Fietkau 
35417f1de56SFelix Fietkau static int
35577af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
35617f1de56SFelix Fietkau 		   int n_rates, bool vht)
35717f1de56SFelix Fietkau {
35877af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
35917f1de56SFelix Fietkau 
36077af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
36177af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
362edf9dab8SLorenzo Bianconi 			       n_rates, true, vht);
363edf9dab8SLorenzo Bianconi }
364edf9dab8SLorenzo Bianconi 
365edf9dab8SLorenzo Bianconi static int
366edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
367edf9dab8SLorenzo Bianconi 		   int n_rates)
368edf9dab8SLorenzo Bianconi {
369edf9dab8SLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
370edf9dab8SLorenzo Bianconi 
371edf9dab8SLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
372edf9dab8SLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_6ghz), rates,
373edf9dab8SLorenzo Bianconi 			       n_rates, false, false);
37417f1de56SFelix Fietkau }
37517f1de56SFelix Fietkau 
37617f1de56SFelix Fietkau static void
377c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
378c89d3625SFelix Fietkau 		 enum nl80211_band band)
37917f1de56SFelix Fietkau {
380c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
38117f1de56SFelix Fietkau 	bool found = false;
38217f1de56SFelix Fietkau 	int i;
38317f1de56SFelix Fietkau 
38417f1de56SFelix Fietkau 	if (!sband)
38517f1de56SFelix Fietkau 		return;
38617f1de56SFelix Fietkau 
38717f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
38817f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
38917f1de56SFelix Fietkau 			continue;
39017f1de56SFelix Fietkau 
39117f1de56SFelix Fietkau 		found = true;
39217f1de56SFelix Fietkau 		break;
39317f1de56SFelix Fietkau 	}
39417f1de56SFelix Fietkau 
395c89d3625SFelix Fietkau 	if (found) {
396c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
397c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
39817f1de56SFelix Fietkau 		return;
399c89d3625SFelix Fietkau 	}
40017f1de56SFelix Fietkau 
40117f1de56SFelix Fietkau 	sband->n_channels = 0;
402c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
40317f1de56SFelix Fietkau }
40417f1de56SFelix Fietkau 
405d43de9cfSLorenzo Bianconi static int
40698df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
407c89d3625SFelix Fietkau {
40898df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
409c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
410c89d3625SFelix Fietkau 
411c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
41298df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
413c89d3625SFelix Fietkau 
414c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
415dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
416b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
417b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
418c89d3625SFelix Fietkau 
419c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
420c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
421d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
422c89d3625SFelix Fietkau 
4230a57d636SBo Jiao 	wiphy->available_antennas_tx = phy->antenna_mask;
4240a57d636SBo Jiao 	wiphy->available_antennas_rx = phy->antenna_mask;
425c89d3625SFelix Fietkau 
426d43de9cfSLorenzo Bianconi 	wiphy->sar_capa = &mt76_sar_capa;
427d43de9cfSLorenzo Bianconi 	phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
428d43de9cfSLorenzo Bianconi 				sizeof(struct mt76_freq_range_power),
429d43de9cfSLorenzo Bianconi 				GFP_KERNEL);
430d43de9cfSLorenzo Bianconi 	if (!phy->frp)
431d43de9cfSLorenzo Bianconi 		return -ENOMEM;
432d43de9cfSLorenzo Bianconi 
433c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
434b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
435c9619dfaSShayne Chen 
436c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
437c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
438c89d3625SFelix Fietkau 
439c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
440c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
441c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
442c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
443c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
444c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
445ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
4465b0fb852SBen Greear 
4475b0fb852SBen Greear 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
448c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
449c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
4505b0fb852SBen Greear 	}
4515b0fb852SBen Greear 
452c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
453c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
454c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
455d43de9cfSLorenzo Bianconi 
456d43de9cfSLorenzo Bianconi 	return 0;
457c89d3625SFelix Fietkau }
458c89d3625SFelix Fietkau 
459c89d3625SFelix Fietkau struct mt76_phy *
460c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
461dc44c45cSLorenzo Bianconi 	       const struct ieee80211_ops *ops, u8 band_idx)
462c89d3625SFelix Fietkau {
463c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
464db78a791SLorenzo Bianconi 	unsigned int phy_size;
465c89d3625SFelix Fietkau 	struct mt76_phy *phy;
466c89d3625SFelix Fietkau 
467c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
468db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
469c89d3625SFelix Fietkau 	if (!hw)
470c89d3625SFelix Fietkau 		return NULL;
471c89d3625SFelix Fietkau 
472c89d3625SFelix Fietkau 	phy = hw->priv;
473c89d3625SFelix Fietkau 	phy->dev = dev;
474c89d3625SFelix Fietkau 	phy->hw = hw;
475db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
476dc44c45cSLorenzo Bianconi 	phy->band_idx = band_idx;
477c89d3625SFelix Fietkau 
4788af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4798af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4808af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4818af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4828af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4838af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4848af414e8SLorenzo Bianconi #endif
4858af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4868af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4878af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4888af414e8SLorenzo Bianconi 
489c89d3625SFelix Fietkau 	return phy;
490c89d3625SFelix Fietkau }
491c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
492c89d3625SFelix Fietkau 
493db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
494db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
495c89d3625SFelix Fietkau {
496c89d3625SFelix Fietkau 	int ret;
497c89d3625SFelix Fietkau 
498d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, phy->hw);
499d43de9cfSLorenzo Bianconi 	if (ret)
500d43de9cfSLorenzo Bianconi 		return ret;
501db78a791SLorenzo Bianconi 
502db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
503db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
504db78a791SLorenzo Bianconi 		if (ret)
505db78a791SLorenzo Bianconi 			return ret;
506db78a791SLorenzo Bianconi 	}
507db78a791SLorenzo Bianconi 
508db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
509db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
510db78a791SLorenzo Bianconi 		if (ret)
511db78a791SLorenzo Bianconi 			return ret;
512db78a791SLorenzo Bianconi 	}
513db78a791SLorenzo Bianconi 
514edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
515edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
516edf9dab8SLorenzo Bianconi 		if (ret)
517edf9dab8SLorenzo Bianconi 			return ret;
518edf9dab8SLorenzo Bianconi 	}
519edf9dab8SLorenzo Bianconi 
520db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
521db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
522db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
523edf9dab8SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
524db78a791SLorenzo Bianconi 
525c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
526c89d3625SFelix Fietkau 	if (ret)
527c89d3625SFelix Fietkau 		return ret;
528c89d3625SFelix Fietkau 
529dc44c45cSLorenzo Bianconi 	phy->dev->phys[phy->band_idx] = phy;
530db78a791SLorenzo Bianconi 
531c89d3625SFelix Fietkau 	return 0;
532c89d3625SFelix Fietkau }
533c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
534c89d3625SFelix Fietkau 
535db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
536c89d3625SFelix Fietkau {
537c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
538c89d3625SFelix Fietkau 
539c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
540c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
541dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = NULL;
542c89d3625SFelix Fietkau }
543c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
544c89d3625SFelix Fietkau 
545a85b590cSFelix Fietkau struct mt76_dev *
546c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
547c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
548c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
549a85b590cSFelix Fietkau {
550a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
551ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
552a85b590cSFelix Fietkau 	struct mt76_dev *dev;
553e5443256SFelix Fietkau 	int i;
554a85b590cSFelix Fietkau 
555a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
556a85b590cSFelix Fietkau 	if (!hw)
557a85b590cSFelix Fietkau 		return NULL;
558a85b590cSFelix Fietkau 
559a85b590cSFelix Fietkau 	dev = hw->priv;
560a85b590cSFelix Fietkau 	dev->hw = hw;
561c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
562c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
563d1ddc536SFelix Fietkau 	dev->dma_dev = pdev;
564c0f7b25aSLorenzo Bianconi 
565ac24dd35SFelix Fietkau 	phy = &dev->phy;
566ac24dd35SFelix Fietkau 	phy->dev = dev;
567ac24dd35SFelix Fietkau 	phy->hw = hw;
568dc44c45cSLorenzo Bianconi 	phy->band_idx = MT_BAND0;
569dc44c45cSLorenzo Bianconi 	dev->phys[phy->band_idx] = phy;
570ac24dd35SFelix Fietkau 
571a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
572a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
573a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
574c34f1005SLorenzo Bianconi 	spin_lock_init(&dev->status_lock);
575*2666beceSSujuan Chen 	spin_lock_init(&dev->wed_lock);
576108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
57726e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
578a85b590cSFelix Fietkau 
57909872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
58009872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
58109872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
582781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
58309872957SLorenzo Bianconi 
5848af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5858af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
5868af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
5878af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
5888af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
5898af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
5908af414e8SLorenzo Bianconi #endif
5918af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
5928af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
5938af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
5948af414e8SLorenzo Bianconi 
59551252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
59651252cc5SLorenzo Bianconi 	idr_init(&dev->token);
59751252cc5SLorenzo Bianconi 
598*2666beceSSujuan Chen 	spin_lock_init(&dev->rx_token_lock);
599*2666beceSSujuan Chen 	idr_init(&dev->rx_token);
600*2666beceSSujuan Chen 
601bd1e3e7bSLorenzo Bianconi 	INIT_LIST_HEAD(&dev->wcid_list);
602bd1e3e7bSLorenzo Bianconi 
603e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
604*2666beceSSujuan Chen 	INIT_LIST_HEAD(&dev->rxwi_cache);
60561b5156bSFelix Fietkau 	dev->token_size = dev->drv->token_size;
606e5443256SFelix Fietkau 
607e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
608e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
609e5443256SFelix Fietkau 
610a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
611a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
612a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
613a86f1d01SLorenzo Bianconi 		return NULL;
614a86f1d01SLorenzo Bianconi 	}
615a86f1d01SLorenzo Bianconi 
616a85b590cSFelix Fietkau 	return dev;
617a85b590cSFelix Fietkau }
618a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
619a85b590cSFelix Fietkau 
62017f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
62117f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
62217f1de56SFelix Fietkau {
62317f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
624c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
62517f1de56SFelix Fietkau 	int ret;
62617f1de56SFelix Fietkau 
62717f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
628d43de9cfSLorenzo Bianconi 	ret = mt76_phy_init(phy, hw);
629d43de9cfSLorenzo Bianconi 	if (ret)
630d43de9cfSLorenzo Bianconi 		return ret;
63117f1de56SFelix Fietkau 
63248dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
63377af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
63417f1de56SFelix Fietkau 		if (ret)
63517f1de56SFelix Fietkau 			return ret;
63617f1de56SFelix Fietkau 	}
63717f1de56SFelix Fietkau 
63848dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
63977af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
64017f1de56SFelix Fietkau 		if (ret)
64117f1de56SFelix Fietkau 			return ret;
64217f1de56SFelix Fietkau 	}
64317f1de56SFelix Fietkau 
644edf9dab8SLorenzo Bianconi 	if (phy->cap.has_6ghz) {
645edf9dab8SLorenzo Bianconi 		ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
646edf9dab8SLorenzo Bianconi 		if (ret)
647edf9dab8SLorenzo Bianconi 			return ret;
648edf9dab8SLorenzo Bianconi 	}
649edf9dab8SLorenzo Bianconi 
650c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
651c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
652c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
653edf9dab8SLorenzo Bianconi 	mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
65417f1de56SFelix Fietkau 
655b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
65617f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
65717f1de56SFelix Fietkau 		if (ret)
65817f1de56SFelix Fietkau 			return ret;
659b374e868SArnd Bergmann 	}
66017f1de56SFelix Fietkau 
661781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
662781eef5bSFelix Fietkau 	if (ret)
663781eef5bSFelix Fietkau 		return ret;
664781eef5bSFelix Fietkau 
665781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
666781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
667781eef5bSFelix Fietkau 
668781eef5bSFelix Fietkau 	return 0;
66917f1de56SFelix Fietkau }
67017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
67117f1de56SFelix Fietkau 
67217f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
67317f1de56SFelix Fietkau {
67417f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
67517f1de56SFelix Fietkau 
676d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
67736f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
678c02f86eeSLorenzo Bianconi 	mt76_tx_status_check(dev, true);
67917f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
68017f1de56SFelix Fietkau }
68117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
68217f1de56SFelix Fietkau 
683def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
684def34a2fSLorenzo Bianconi {
685781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
686a86f1d01SLorenzo Bianconi 	if (dev->wq) {
687a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
688a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
689a86f1d01SLorenzo Bianconi 	}
690def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
691def34a2fSLorenzo Bianconi }
692def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
693def34a2fSLorenzo Bianconi 
694cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
695cc4b3c13SLorenzo Bianconi {
696cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
6972c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
698cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
699cc4b3c13SLorenzo Bianconi 
700cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
701cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
7022c2bdd23SFelix Fietkau 
7032c2bdd23SFelix Fietkau 	/*
7042c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
7052c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7062c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
7072c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
7082c2bdd23SFelix Fietkau 	 * address.
7092c2bdd23SFelix Fietkau 	 */
7102c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
7112c2bdd23SFelix Fietkau 		int offset = 0;
7122c2bdd23SFelix Fietkau 
7132c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
7142c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
7152c2bdd23SFelix Fietkau 
7162c2bdd23SFelix Fietkau 			if ((status->flag &
7172c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
7182c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
7192c2bdd23SFelix Fietkau 				offset += 8;
7202c2bdd23SFelix Fietkau 		}
7212c2bdd23SFelix Fietkau 
7222c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
7232c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
7242c2bdd23SFelix Fietkau 			return;
7252c2bdd23SFelix Fietkau 		}
7262c2bdd23SFelix Fietkau 	}
727cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
728cc4b3c13SLorenzo Bianconi }
729cc4b3c13SLorenzo Bianconi 
730cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
731cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
732cc4b3c13SLorenzo Bianconi {
733cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
734cc4b3c13SLorenzo Bianconi 
735cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
736cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
737cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
738cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
739cc4b3c13SLorenzo Bianconi 
740cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
741cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
742cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
743cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
744cc4b3c13SLorenzo Bianconi 	} else {
745cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
746cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
747cc4b3c13SLorenzo Bianconi 	}
748cc4b3c13SLorenzo Bianconi 
749cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
750cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
751cc4b3c13SLorenzo Bianconi }
752cc4b3c13SLorenzo Bianconi 
75317f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
75417f1de56SFelix Fietkau {
755011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
756128c9b7dSLorenzo Bianconi 	struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
757011849e0SFelix Fietkau 
758011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
75917f1de56SFelix Fietkau 		dev_kfree_skb(skb);
76017f1de56SFelix Fietkau 		return;
76117f1de56SFelix Fietkau 	}
76217f1de56SFelix Fietkau 
763f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
764c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
765c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
766f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
767c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
768f0efa862SFelix Fietkau 	}
769f0efa862SFelix Fietkau #endif
770cc4b3c13SLorenzo Bianconi 
771cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
77217f1de56SFelix Fietkau }
77317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
77417f1de56SFelix Fietkau 
7755a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
77626e40d4cSFelix Fietkau {
777af005f26SLorenzo Bianconi 	struct mt76_queue *q;
77891990519SLorenzo Bianconi 	int i;
7795a95ca41SFelix Fietkau 
7805a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
78191990519SLorenzo Bianconi 		q = phy->q_tx[i];
782af005f26SLorenzo Bianconi 		if (q && q->queued)
78326e40d4cSFelix Fietkau 			return true;
78426e40d4cSFelix Fietkau 	}
78526e40d4cSFelix Fietkau 
78626e40d4cSFelix Fietkau 	return false;
78726e40d4cSFelix Fietkau }
78839d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
78926e40d4cSFelix Fietkau 
7900fd0eb54SFelix Fietkau static struct mt76_channel_state *
79196747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
7920fd0eb54SFelix Fietkau {
7930fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
7940fd0eb54SFelix Fietkau 	int idx;
7950fd0eb54SFelix Fietkau 
7960fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
79796747a51SFelix Fietkau 		msband = &phy->sband_2g;
798edf9dab8SLorenzo Bianconi 	else if (c->band == NL80211_BAND_6GHZ)
799edf9dab8SLorenzo Bianconi 		msband = &phy->sband_6g;
8000fd0eb54SFelix Fietkau 	else
80196747a51SFelix Fietkau 		msband = &phy->sband_5g;
8020fd0eb54SFelix Fietkau 
8030fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
8040fd0eb54SFelix Fietkau 	return &msband->chan[idx];
8050fd0eb54SFelix Fietkau }
8060fd0eb54SFelix Fietkau 
80704414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
80896747a51SFelix Fietkau {
80996747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
81096747a51SFelix Fietkau 
81196747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
81296747a51SFelix Fietkau 						  phy->survey_time));
81396747a51SFelix Fietkau 	phy->survey_time = time;
81496747a51SFelix Fietkau }
81504414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
81696747a51SFelix Fietkau 
817c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
8185ce09c1aSFelix Fietkau {
819c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
820aec65e48SFelix Fietkau 	ktime_t cur_time;
821aec65e48SFelix Fietkau 
8225ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
823c560b137SRyder Lee 		dev->drv->update_survey(phy);
8245ce09c1aSFelix Fietkau 
825aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
826c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
827aec65e48SFelix Fietkau 
8285ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
829c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
83096747a51SFelix Fietkau 
831237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
8325ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
8335ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
834237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
8355ce09c1aSFelix Fietkau 	}
8365ce09c1aSFelix Fietkau }
8375ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
8385ce09c1aSFelix Fietkau 
83996747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
84017f1de56SFelix Fietkau {
84196747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
84296747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
84317f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
84417f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
84526e40d4cSFelix Fietkau 	int timeout = HZ / 5;
84617f1de56SFelix Fietkau 
8475a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
848c560b137SRyder Lee 	mt76_update_survey(phy);
84917f1de56SFelix Fietkau 
8503f306448SFelix Fietkau 	if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
8513f306448SFelix Fietkau 	    phy->chandef.width != chandef->width)
8523f306448SFelix Fietkau 		phy->dfs_state = MT_DFS_STATE_UNKNOWN;
8533f306448SFelix Fietkau 
85496747a51SFelix Fietkau 	phy->chandef = *chandef;
85596747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
85617f1de56SFelix Fietkau 
85717f1de56SFelix Fietkau 	if (!offchannel)
85896747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
85917f1de56SFelix Fietkau 
86096747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
86196747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
86217f1de56SFelix Fietkau }
86317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
86417f1de56SFelix Fietkau 
86517f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
86617f1de56SFelix Fietkau 		    struct survey_info *survey)
86717f1de56SFelix Fietkau {
86896747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
86996747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
87017f1de56SFelix Fietkau 	struct mt76_sband *sband;
87117f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
87217f1de56SFelix Fietkau 	struct mt76_channel_state *state;
87317f1de56SFelix Fietkau 	int ret = 0;
87417f1de56SFelix Fietkau 
875237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
87617f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
877c560b137SRyder Lee 		mt76_update_survey(phy);
87817f1de56SFelix Fietkau 
879edf9dab8SLorenzo Bianconi 	if (idx >= phy->sband_2g.sband.n_channels +
880edf9dab8SLorenzo Bianconi 		   phy->sband_5g.sband.n_channels) {
881edf9dab8SLorenzo Bianconi 		idx -= (phy->sband_2g.sband.n_channels +
882edf9dab8SLorenzo Bianconi 			phy->sband_5g.sband.n_channels);
883edf9dab8SLorenzo Bianconi 		sband = &phy->sband_6g;
884edf9dab8SLorenzo Bianconi 	} else if (idx >= phy->sband_2g.sband.n_channels) {
885edf9dab8SLorenzo Bianconi 		idx -= phy->sband_2g.sband.n_channels;
88696747a51SFelix Fietkau 		sband = &phy->sband_5g;
887edf9dab8SLorenzo Bianconi 	} else {
888edf9dab8SLorenzo Bianconi 		sband = &phy->sband_2g;
88917f1de56SFelix Fietkau 	}
89017f1de56SFelix Fietkau 
891237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
892237312c5SLorenzo Bianconi 		ret = -ENOENT;
893237312c5SLorenzo Bianconi 		goto out;
894237312c5SLorenzo Bianconi 	}
89517f1de56SFelix Fietkau 
89617f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
89796747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
89817f1de56SFelix Fietkau 
89917f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
90017f1de56SFelix Fietkau 	survey->channel = chan;
90117f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
902ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
903e5051965SFelix Fietkau 	if (state->noise)
904e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
905e5051965SFelix Fietkau 
90696747a51SFelix Fietkau 	if (chan == phy->main_chan) {
90717f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
90817f1de56SFelix Fietkau 
9095ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
9105ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
9115ce09c1aSFelix Fietkau 	}
9125ce09c1aSFelix Fietkau 
91317f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
9146bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
915237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
916e5051965SFelix Fietkau 	survey->noise = state->noise;
917237312c5SLorenzo Bianconi 
918237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
919237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
920ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
92117f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
92217f1de56SFelix Fietkau 
923237312c5SLorenzo Bianconi out:
924237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
925237312c5SLorenzo Bianconi 
92617f1de56SFelix Fietkau 	return ret;
92717f1de56SFelix Fietkau }
92817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
92917f1de56SFelix Fietkau 
93030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
93130ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
93230ce7f44SFelix Fietkau {
93330ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
93430ce7f44SFelix Fietkau 	int i;
93530ce7f44SFelix Fietkau 
93630ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
93730ce7f44SFelix Fietkau 
93830ce7f44SFelix Fietkau 	if (!key)
93930ce7f44SFelix Fietkau 		return;
94030ce7f44SFelix Fietkau 
94101cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
94201cfc1b4SLorenzo Bianconi 		return;
94330ce7f44SFelix Fietkau 
94401cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
945a1b0bbd4SXing Song 
946a1b0bbd4SXing Song 	/* data frame */
94730ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
94830ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
94930ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
95030ce7f44SFelix Fietkau 	}
951a1b0bbd4SXing Song 
952a1b0bbd4SXing Song 	/* robust management frame */
953a1b0bbd4SXing Song 	ieee80211_get_key_rx_seq(key, -1, &seq);
954a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
955a1b0bbd4SXing Song 
95630ce7f44SFelix Fietkau }
95730ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
95830ce7f44SFelix Fietkau 
959a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
9604550fb9eSFelix Fietkau {
9614550fb9eSFelix Fietkau 	int signal = -128;
9624550fb9eSFelix Fietkau 	u8 chains;
9634550fb9eSFelix Fietkau 
964a71b648eSRyder Lee 	for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
9654550fb9eSFelix Fietkau 		int cur, diff;
9664550fb9eSFelix Fietkau 
9676450b133SDeren Wu 		cur = *chain_signal;
9686450b133SDeren Wu 		if (!(chains & BIT(0)) ||
9696450b133SDeren Wu 		    cur > 0)
9704550fb9eSFelix Fietkau 			continue;
9714550fb9eSFelix Fietkau 
9724550fb9eSFelix Fietkau 		if (cur > signal)
9734550fb9eSFelix Fietkau 			swap(cur, signal);
9744550fb9eSFelix Fietkau 
9754550fb9eSFelix Fietkau 		diff = signal - cur;
9764550fb9eSFelix Fietkau 		if (diff == 0)
9774550fb9eSFelix Fietkau 			signal += 3;
9784550fb9eSFelix Fietkau 		else if (diff <= 2)
9794550fb9eSFelix Fietkau 			signal += 2;
9804550fb9eSFelix Fietkau 		else if (diff <= 6)
9814550fb9eSFelix Fietkau 			signal += 1;
9824550fb9eSFelix Fietkau 	}
9834550fb9eSFelix Fietkau 
9844550fb9eSFelix Fietkau 	return signal;
9854550fb9eSFelix Fietkau }
986a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
9874550fb9eSFelix Fietkau 
988bfc394ddSFelix Fietkau static void
989bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
990bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
991bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
9924e34249eSFelix Fietkau {
9934e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
994abe3f3daSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
9954e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
9964e34249eSFelix Fietkau 
9974e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
9984e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
9994e34249eSFelix Fietkau 
10004e34249eSFelix Fietkau 	status->flag = mstat.flag;
10014e34249eSFelix Fietkau 	status->freq = mstat.freq;
10024e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
10034e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
10044e34249eSFelix Fietkau 	status->bw = mstat.bw;
1005af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
1006af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
1007af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
10084e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
10094e34249eSFelix Fietkau 	status->nss = mstat.nss;
10104e34249eSFelix Fietkau 	status->band = mstat.band;
10114e34249eSFelix Fietkau 	status->signal = mstat.signal;
10124e34249eSFelix Fietkau 	status->chains = mstat.chains;
1013d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
10140fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
10150fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
1016a71b648eSRyder Lee 	status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
10174550fb9eSFelix Fietkau 	if (status->signal <= -128)
10184550fb9eSFelix Fietkau 		status->flag |= RX_FLAG_NO_SIGNAL_VAL;
10194e34249eSFelix Fietkau 
1020abe3f3daSRyder Lee 	if (ieee80211_is_beacon(hdr->frame_control) ||
1021abe3f3daSRyder Lee 	    ieee80211_is_probe_resp(hdr->frame_control))
1022abe3f3daSRyder Lee 		status->boottime_ns = ktime_get_boottime_ns();
1023abe3f3daSRyder Lee 
10244e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
102513381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
102613381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
102713381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
102813381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
10299c68a57bSFelix Fietkau 
1030bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
1031128c9b7dSLorenzo Bianconi 	*hw = mt76_phy_hw(dev, mstat.phy_idx);
10324e34249eSFelix Fietkau }
10334e34249eSFelix Fietkau 
10343c1032e1SFelix Fietkau static void
103530ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
103630ce7f44SFelix Fietkau {
103730ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
103830ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
103930ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
1040a1b0bbd4SXing Song 	int security_idx;
104130ce7f44SFelix Fietkau 	int ret;
104230ce7f44SFelix Fietkau 
104330ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
10443c1032e1SFelix Fietkau 		return;
104530ce7f44SFelix Fietkau 
10461858e4fcSMeiChia Chiu 	if (status->flag & RX_FLAG_ONLY_MONITOR)
10473c1032e1SFelix Fietkau 		return;
10481858e4fcSMeiChia Chiu 
104930ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
10503c1032e1SFelix Fietkau 		return;
105130ce7f44SFelix Fietkau 
10527360cdecSFelix Fietkau 	security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
10537360cdecSFelix Fietkau 	if (status->flag & RX_FLAG_8023)
10547360cdecSFelix Fietkau 		goto skip_hdr_check;
10557360cdecSFelix Fietkau 
1056a1b0bbd4SXing Song 	hdr = mt76_skb_get_hdr(skb);
105730ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
105830ce7f44SFelix Fietkau 		/*
105930ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
106030ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
106130ce7f44SFelix Fietkau 		 */
106230ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
106330ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
10643c1032e1SFelix Fietkau 			return;
106530ce7f44SFelix Fietkau 	}
106630ce7f44SFelix Fietkau 
1067a1b0bbd4SXing Song 	/* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1068a1b0bbd4SXing Song 	 *
1069a1b0bbd4SXing Song 	 * the recipient shall maintain a single replay counter for received
1070a1b0bbd4SXing Song 	 * individually addressed robust Management frames that are received
1071a1b0bbd4SXing Song 	 * with the To DS subfield equal to 0, [...]
1072a1b0bbd4SXing Song 	 */
1073a1b0bbd4SXing Song 	if (ieee80211_is_mgmt(hdr->frame_control) &&
1074a1b0bbd4SXing Song 	    !ieee80211_has_tods(hdr->frame_control))
1075a1b0bbd4SXing Song 		security_idx = IEEE80211_NUM_TIDS;
1076a1b0bbd4SXing Song 
10777360cdecSFelix Fietkau skip_hdr_check:
107830ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1079a1b0bbd4SXing Song 	ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
108030ce7f44SFelix Fietkau 		     sizeof(status->iv));
10813c1032e1SFelix Fietkau 	if (ret <= 0) {
10823c1032e1SFelix Fietkau 		status->flag |= RX_FLAG_ONLY_MONITOR;
10833c1032e1SFelix Fietkau 		return;
10843c1032e1SFelix Fietkau 	}
108530ce7f44SFelix Fietkau 
1086a1b0bbd4SXing Song 	memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
108730ce7f44SFelix Fietkau 
108830ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
108930ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
109030ce7f44SFelix Fietkau }
109130ce7f44SFelix Fietkau 
1092d71ef286SFelix Fietkau static void
10935ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
10945ce09c1aSFelix Fietkau 		    int len)
10955ce09c1aSFelix Fietkau {
10965ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
109785b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
109885b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
109985b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
110085b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
110185b7a5d0SLorenzo Bianconi 		.band = status->band,
110285b7a5d0SLorenzo Bianconi 		.nss = status->nss,
110385b7a5d0SLorenzo Bianconi 		.bw = status->bw,
110485b7a5d0SLorenzo Bianconi 	};
11055ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
11065ce09c1aSFelix Fietkau 	u32 airtime;
1107e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11085ce09c1aSFelix Fietkau 
110985b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1110237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
11115ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
1112237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
11135ce09c1aSFelix Fietkau 
11145ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
11155ce09c1aSFelix Fietkau 		return;
11165ce09c1aSFelix Fietkau 
11175ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1118e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
11195ce09c1aSFelix Fietkau }
11205ce09c1aSFelix Fietkau 
11215ce09c1aSFelix Fietkau static void
11225ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
11235ce09c1aSFelix Fietkau {
11245ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
11255ce09c1aSFelix Fietkau 	int wcid_idx;
11265ce09c1aSFelix Fietkau 
11275ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
11285ce09c1aSFelix Fietkau 		return;
11295ce09c1aSFelix Fietkau 
11305ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
1131bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
11325ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
11335ce09c1aSFelix Fietkau 	else
11345ce09c1aSFelix Fietkau 		wcid = NULL;
11355ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
11365ce09c1aSFelix Fietkau 
11375ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
11385ce09c1aSFelix Fietkau 
11395ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
11405ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
11415ce09c1aSFelix Fietkau }
11425ce09c1aSFelix Fietkau 
11435ce09c1aSFelix Fietkau static void
11445ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
11455ce09c1aSFelix Fietkau {
11465ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
11475ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
11485ce09c1aSFelix Fietkau 
11495ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
11505ce09c1aSFelix Fietkau 		return;
11515ce09c1aSFelix Fietkau 
11525ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
1153e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1154e195dad1SFelix Fietkau 
1155e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
1156e195dad1SFelix Fietkau 			return;
1157e195dad1SFelix Fietkau 
115898df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
11595ce09c1aSFelix Fietkau 			return;
11605ce09c1aSFelix Fietkau 
11615ce09c1aSFelix Fietkau 		wcid = NULL;
11625ce09c1aSFelix Fietkau 	}
11635ce09c1aSFelix Fietkau 
11645ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
11655ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
11665ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
11675ce09c1aSFelix Fietkau 
11685ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
11695ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
11705ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
11715ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
11725ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
11735ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
11745ce09c1aSFelix Fietkau 		}
11755ce09c1aSFelix Fietkau 
11765ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
11775ce09c1aSFelix Fietkau 		return;
11785ce09c1aSFelix Fietkau 	}
11795ce09c1aSFelix Fietkau 
11805ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
11815ce09c1aSFelix Fietkau }
11825ce09c1aSFelix Fietkau 
11835ce09c1aSFelix Fietkau static void
1184ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1185d71ef286SFelix Fietkau {
1186d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
118777ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1188d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
1189bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
1190d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
1191e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1192d71ef286SFelix Fietkau 	bool ps;
1193d71ef286SFelix Fietkau 
1194128c9b7dSLorenzo Bianconi 	hw = mt76_phy_hw(dev, status->phy_idx);
1195e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1196e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
1197bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
119836d91096SFelix Fietkau 		if (sta)
119936d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
120036d91096SFelix Fietkau 	}
120136d91096SFelix Fietkau 
12025ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
12035ce09c1aSFelix Fietkau 
1204d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
1205d71ef286SFelix Fietkau 		return;
1206d71ef286SFelix Fietkau 
1207d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1208d71ef286SFelix Fietkau 
120902e5a769SFelix Fietkau 	if (status->signal <= 0)
121002e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
121102e5a769SFelix Fietkau 
1212ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1213ef13edc0SFelix Fietkau 
1214e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1215e195dad1SFelix Fietkau 		return;
1216e195dad1SFelix Fietkau 
1217d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1218d71ef286SFelix Fietkau 		return;
1219d71ef286SFelix Fietkau 
1220d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1221d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1222d71ef286SFelix Fietkau 		return;
1223d71ef286SFelix Fietkau 	}
1224d71ef286SFelix Fietkau 
1225d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1226d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1227d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1228d71ef286SFelix Fietkau 		return;
1229d71ef286SFelix Fietkau 
1230d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1231d71ef286SFelix Fietkau 
1232d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1233d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1234e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1235d71ef286SFelix Fietkau 
1236d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1237d71ef286SFelix Fietkau 		return;
1238d71ef286SFelix Fietkau 
123911b2a25fSFelix Fietkau 	if (ps)
1240d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1241d71ef286SFelix Fietkau 
1242d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
1243608f7c47SFelix Fietkau 
1244608f7c47SFelix Fietkau 	if (!ps)
1245608f7c47SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1246608f7c47SFelix Fietkau 
12479f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1248d71ef286SFelix Fietkau }
1249d71ef286SFelix Fietkau 
12509d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
125181e850efSLorenzo Bianconi 		      struct napi_struct *napi)
125217f1de56SFelix Fietkau {
12539c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1254bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
12553298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
12563298b1f8SFelix Fietkau 	LIST_HEAD(list);
12579d9d738bSFelix Fietkau 
1258c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
12599d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1260cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1261cc4b3c13SLorenzo Bianconi 
12623c1032e1SFelix Fietkau 		mt76_check_ccmp_pn(skb);
1263cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1264bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
12653298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1266cc4b3c13SLorenzo Bianconi 
1267cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1268cc4b3c13SLorenzo Bianconi 		while (nskb) {
1269cc4b3c13SLorenzo Bianconi 			skb = nskb;
1270cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1271cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1272cc4b3c13SLorenzo Bianconi 
1273cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1274cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1275cc4b3c13SLorenzo Bianconi 		}
12769d9d738bSFelix Fietkau 	}
1277c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
12783298b1f8SFelix Fietkau 
12793298b1f8SFelix Fietkau 	if (!napi) {
12803298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
12813298b1f8SFelix Fietkau 		return;
12823298b1f8SFelix Fietkau 	}
12833298b1f8SFelix Fietkau 
12843298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
12853298b1f8SFelix Fietkau 		skb_list_del_init(skb);
12863298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
12873298b1f8SFelix Fietkau 	}
12889d9d738bSFelix Fietkau }
12899d9d738bSFelix Fietkau 
129081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
129181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
12929d9d738bSFelix Fietkau {
1293aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
129417f1de56SFelix Fietkau 	struct sk_buff *skb;
129517f1de56SFelix Fietkau 
1296aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1297aee5b8cfSFelix Fietkau 
1298d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1299ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
1300aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
1301d71ef286SFelix Fietkau 	}
1302aee5b8cfSFelix Fietkau 
130381e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
13044e34249eSFelix Fietkau }
130581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1306723b90dcSFelix Fietkau 
1307e28487eaSFelix Fietkau static int
1308a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1309a1a99d7bSLorenzo Bianconi 	     struct ieee80211_sta *sta)
1310e28487eaSFelix Fietkau {
1311e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1312a1a99d7bSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
1313e28487eaSFelix Fietkau 	int ret;
1314e28487eaSFelix Fietkau 	int i;
1315e28487eaSFelix Fietkau 
1316e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1317e28487eaSFelix Fietkau 
1318e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1319e28487eaSFelix Fietkau 	if (ret)
1320e28487eaSFelix Fietkau 		goto out;
1321e28487eaSFelix Fietkau 
1322e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1323e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1324e28487eaSFelix Fietkau 
1325e28487eaSFelix Fietkau 		if (!sta->txq[i])
1326e28487eaSFelix Fietkau 			continue;
1327e28487eaSFelix Fietkau 
1328e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
132951fb1278SFelix Fietkau 		mtxq->wcid = wcid->idx;
1330e28487eaSFelix Fietkau 	}
1331e28487eaSFelix Fietkau 
1332ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1333a1a99d7bSLorenzo Bianconi 	if (phy->band_idx == MT_BAND1)
1334426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1335a1a99d7bSLorenzo Bianconi 	wcid->phy_idx = phy->band_idx;
1336e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1337e28487eaSFelix Fietkau 
1338bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_init(wcid);
1339e28487eaSFelix Fietkau out:
1340e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1341e28487eaSFelix Fietkau 
1342e28487eaSFelix Fietkau 	return ret;
1343e28487eaSFelix Fietkau }
1344e28487eaSFelix Fietkau 
134513f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1346723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1347723b90dcSFelix Fietkau {
1348723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
134913f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1350723b90dcSFelix Fietkau 
135158bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
135258bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
135358bab0d4SFelix Fietkau 
1354e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1355e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1356e28487eaSFelix Fietkau 
1357bd1e3e7bSLorenzo Bianconi 	mt76_packet_id_flush(dev, wcid);
1358bd1e3e7bSLorenzo Bianconi 
1359426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1360426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
136113f61dfcSLorenzo Bianconi }
136213f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1363e28487eaSFelix Fietkau 
136413f61dfcSLorenzo Bianconi static void
136513f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
136613f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
136713f61dfcSLorenzo Bianconi {
136813f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
136913f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1370723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1371723b90dcSFelix Fietkau }
1372e28487eaSFelix Fietkau 
1373e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1374e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1375e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1376e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1377e28487eaSFelix Fietkau {
1378426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1379426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1380e28487eaSFelix Fietkau 
1381e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1382e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1383a1a99d7bSLorenzo Bianconi 		return mt76_sta_add(phy, vif, sta);
1384e28487eaSFelix Fietkau 
13859c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
13869c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
13879c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
13889c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
13899c193de5SFelix Fietkau 
1390e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1391e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1392e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1393e28487eaSFelix Fietkau 
1394e28487eaSFelix Fietkau 	return 0;
1395e28487eaSFelix Fietkau }
1396e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
13979313faacSFelix Fietkau 
139843ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
139943ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
140043ba1922SFelix Fietkau {
140143ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
140243ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
140343ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
140443ba1922SFelix Fietkau 
140543ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
1406fcfe1b5eSFelix Fietkau 	spin_lock_bh(&dev->status_lock);
140743ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1408fcfe1b5eSFelix Fietkau 	spin_unlock_bh(&dev->status_lock);
140943ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
141043ba1922SFelix Fietkau }
141143ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
141243ba1922SFelix Fietkau 
14139313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
14149313faacSFelix Fietkau 		     int *dbm)
14159313faacSFelix Fietkau {
1416beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1417beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
141807cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
14199313faacSFelix Fietkau 
142007cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
14219313faacSFelix Fietkau 
14229313faacSFelix Fietkau 	return 0;
14239313faacSFelix Fietkau }
14249313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1425e7173858SFelix Fietkau 
1426b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1427b3cb885eSLorenzo Bianconi 			const struct cfg80211_sar_specs *sar)
1428b3cb885eSLorenzo Bianconi {
1429b3cb885eSLorenzo Bianconi 	struct mt76_phy *phy = hw->priv;
1430b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1431b3cb885eSLorenzo Bianconi 	int i;
1432b3cb885eSLorenzo Bianconi 
1433b3cb885eSLorenzo Bianconi 	if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1434b3cb885eSLorenzo Bianconi 		return -EINVAL;
1435b3cb885eSLorenzo Bianconi 
1436b3cb885eSLorenzo Bianconi 	for (i = 0; i < sar->num_sub_specs; i++) {
1437b3cb885eSLorenzo Bianconi 		u32 index = sar->sub_specs[i].freq_range_index;
1438b3cb885eSLorenzo Bianconi 		/* SAR specifies power limitaton in 0.25dbm */
1439b3cb885eSLorenzo Bianconi 		s32 power = sar->sub_specs[i].power >> 1;
1440b3cb885eSLorenzo Bianconi 
1441b3cb885eSLorenzo Bianconi 		if (power > 127 || power < -127)
1442b3cb885eSLorenzo Bianconi 			power = 127;
1443b3cb885eSLorenzo Bianconi 
1444b3cb885eSLorenzo Bianconi 		phy->frp[index].range = &capa->freq_ranges[index];
1445b3cb885eSLorenzo Bianconi 		phy->frp[index].power = power;
1446b3cb885eSLorenzo Bianconi 	}
1447b3cb885eSLorenzo Bianconi 
1448b3cb885eSLorenzo Bianconi 	return 0;
1449b3cb885eSLorenzo Bianconi }
1450b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1451b3cb885eSLorenzo Bianconi 
1452b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1453b3cb885eSLorenzo Bianconi 		       struct ieee80211_channel *chan,
1454b3cb885eSLorenzo Bianconi 		       int power)
1455b3cb885eSLorenzo Bianconi {
1456b3cb885eSLorenzo Bianconi 	const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1457b3cb885eSLorenzo Bianconi 	int freq, i;
1458b3cb885eSLorenzo Bianconi 
1459b3cb885eSLorenzo Bianconi 	if (!capa || !phy->frp)
1460b3cb885eSLorenzo Bianconi 		return power;
1461b3cb885eSLorenzo Bianconi 
1462b3cb885eSLorenzo Bianconi 	if (power > 127 || power < -127)
1463b3cb885eSLorenzo Bianconi 		power = 127;
1464b3cb885eSLorenzo Bianconi 
1465b3cb885eSLorenzo Bianconi 	freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1466b3cb885eSLorenzo Bianconi 	for (i = 0 ; i < capa->num_freq_ranges; i++) {
1467b3cb885eSLorenzo Bianconi 		if (phy->frp[i].range &&
1468b3cb885eSLorenzo Bianconi 		    freq >= phy->frp[i].range->start_freq &&
1469b3cb885eSLorenzo Bianconi 		    freq < phy->frp[i].range->end_freq) {
1470b3cb885eSLorenzo Bianconi 			power = min_t(int, phy->frp[i].power, power);
1471b3cb885eSLorenzo Bianconi 			break;
1472b3cb885eSLorenzo Bianconi 		}
1473b3cb885eSLorenzo Bianconi 	}
1474b3cb885eSLorenzo Bianconi 
1475b3cb885eSLorenzo Bianconi 	return power;
1476b3cb885eSLorenzo Bianconi }
1477b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1478b3cb885eSLorenzo Bianconi 
1479e7173858SFelix Fietkau static void
1480e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1481e7173858SFelix Fietkau {
1482d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1483e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1484e7173858SFelix Fietkau }
1485e7173858SFelix Fietkau 
1486e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1487e7173858SFelix Fietkau {
1488e7173858SFelix Fietkau 	if (!dev->csa_complete)
1489e7173858SFelix Fietkau 		return;
1490e7173858SFelix Fietkau 
1491e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1492e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1493e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1494e7173858SFelix Fietkau 
1495e7173858SFelix Fietkau 	dev->csa_complete = 0;
1496e7173858SFelix Fietkau }
1497e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1498e7173858SFelix Fietkau 
1499e7173858SFelix Fietkau static void
1500e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1501e7173858SFelix Fietkau {
1502e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1503e7173858SFelix Fietkau 
1504d0a9123eSJohannes Berg 	if (!vif->bss_conf.csa_active)
1505e7173858SFelix Fietkau 		return;
1506e7173858SFelix Fietkau 
15078552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1508e7173858SFelix Fietkau }
1509e7173858SFelix Fietkau 
1510e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1511e7173858SFelix Fietkau {
1512e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1513e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1514e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1515e7173858SFelix Fietkau }
1516e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
151787d53103SStanislaw Gruszka 
151887d53103SStanislaw Gruszka int
151987d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
152087d53103SStanislaw Gruszka {
152187d53103SStanislaw Gruszka 	return 0;
152287d53103SStanislaw Gruszka }
152387d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1524eadfd98fSLorenzo Bianconi 
1525eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1526eadfd98fSLorenzo Bianconi {
1527eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1528eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1529eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1530eadfd98fSLorenzo Bianconi 
1531eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1532eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1533eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1534eadfd98fSLorenzo Bianconi 
1535eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1536eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1537eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1538eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1539eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1540eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1541eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1542eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1543eadfd98fSLorenzo Bianconi 
1544eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1545eadfd98fSLorenzo Bianconi }
1546eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1547d2679d65SLorenzo Bianconi 
1548d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1549d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1550d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1551d2679d65SLorenzo Bianconi {
1552d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1553d2679d65SLorenzo Bianconi 
1554d2679d65SLorenzo Bianconi 	if (cck) {
1555edf9dab8SLorenzo Bianconi 		if (sband != &dev->phy.sband_2g.sband)
1556d2679d65SLorenzo Bianconi 			return 0;
1557d2679d65SLorenzo Bianconi 
1558d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
155996747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1560d2679d65SLorenzo Bianconi 		offset = 4;
1561d2679d65SLorenzo Bianconi 	}
1562d2679d65SLorenzo Bianconi 
1563d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1564d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1565d2679d65SLorenzo Bianconi 			return i;
1566d2679d65SLorenzo Bianconi 	}
1567d2679d65SLorenzo Bianconi 
1568d2679d65SLorenzo Bianconi 	return 0;
1569d2679d65SLorenzo Bianconi }
1570d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
15718b8ab5c2SLorenzo Bianconi 
15728b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15738b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
15748b8ab5c2SLorenzo Bianconi {
1575011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
15768b8ab5c2SLorenzo Bianconi 
1577011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
15788b8ab5c2SLorenzo Bianconi }
15798b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
15808b8ab5c2SLorenzo Bianconi 
15818b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
15828b8ab5c2SLorenzo Bianconi {
1583011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
15848b8ab5c2SLorenzo Bianconi 
1585011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
15868b8ab5c2SLorenzo Bianconi }
15878b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1588e49c76d4SLorenzo Bianconi 
1589e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1590e49c76d4SLorenzo Bianconi {
1591beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1592beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1593e49c76d4SLorenzo Bianconi 
1594e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1595beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1596beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1597e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1598e49c76d4SLorenzo Bianconi 
1599e49c76d4SLorenzo Bianconi 	return 0;
1600e49c76d4SLorenzo Bianconi }
1601e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1602b671da33SLorenzo Bianconi 
1603b1cb42adSLorenzo Bianconi struct mt76_queue *
1604b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1605f68d6762SFelix Fietkau 		int ring_base, u32 flags)
1606b671da33SLorenzo Bianconi {
1607b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1608b671da33SLorenzo Bianconi 	int err;
1609b671da33SLorenzo Bianconi 
1610b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1611b671da33SLorenzo Bianconi 	if (!hwq)
1612b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1613b671da33SLorenzo Bianconi 
1614f68d6762SFelix Fietkau 	hwq->flags = flags;
1615f68d6762SFelix Fietkau 
1616b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1617b671da33SLorenzo Bianconi 	if (err < 0)
1618b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1619b671da33SLorenzo Bianconi 
1620b1cb42adSLorenzo Bianconi 	return hwq;
1621b671da33SLorenzo Bianconi }
1622b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1623e4867225SSean Wang 
162433920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
1625e4867225SSean Wang {
162633920b2bSRyder Lee 	int offset = 0;
1627e4867225SSean Wang 
1628edf9dab8SLorenzo Bianconi 	if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
1629e4867225SSean Wang 		offset = 4;
1630e4867225SSean Wang 
163133920b2bSRyder Lee 	/* pick the lowest rate for hidden nodes */
163233920b2bSRyder Lee 	if (rateidx < 0)
163333920b2bSRyder Lee 		rateidx = 0;
163433920b2bSRyder Lee 
1635d4f3d1c4SLorenzo Bianconi 	rateidx += offset;
1636d4f3d1c4SLorenzo Bianconi 	if (rateidx >= ARRAY_SIZE(mt76_rates))
1637d4f3d1c4SLorenzo Bianconi 		rateidx = offset;
1638e4867225SSean Wang 
1639d4f3d1c4SLorenzo Bianconi 	return mt76_rates[rateidx].hw_value;
1640e4867225SSean Wang }
164133920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
164254ae98ffSLorenzo Bianconi 
164354ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
164454ae98ffSLorenzo Bianconi 			 struct mt76_sta_stats *stats)
164554ae98ffSLorenzo Bianconi {
164654ae98ffSLorenzo Bianconi 	int i, ei = wi->initial_stat_idx;
164754ae98ffSLorenzo Bianconi 	u64 *data = wi->data;
164854ae98ffSLorenzo Bianconi 
164954ae98ffSLorenzo Bianconi 	wi->sta_count++;
165054ae98ffSLorenzo Bianconi 
165154ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
165254ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
165354ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
165454ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
165554ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
165654ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
165754ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
165854ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
165954ae98ffSLorenzo Bianconi 	data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
166054ae98ffSLorenzo Bianconi 
166154ae98ffSLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++)
166254ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_bw[i];
166354ae98ffSLorenzo Bianconi 
166454ae98ffSLorenzo Bianconi 	for (i = 0; i < 12; i++)
166554ae98ffSLorenzo Bianconi 		data[ei++] += stats->tx_mcs[i];
166654ae98ffSLorenzo Bianconi 
166754ae98ffSLorenzo Bianconi 	wi->worker_stat_count = ei - wi->initial_stat_idx;
166854ae98ffSLorenzo Bianconi }
166954ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
16703f306448SFelix Fietkau 
16713f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
16723f306448SFelix Fietkau {
16733f306448SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
16743f306448SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
16753f306448SFelix Fietkau 
16763f306448SFelix Fietkau 	if (dev->region == NL80211_DFS_UNSET ||
16773f306448SFelix Fietkau 	    test_bit(MT76_SCANNING, &phy->state))
16783f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
16793f306448SFelix Fietkau 
16803f306448SFelix Fietkau 	if (!hw->conf.radar_enabled) {
16813f306448SFelix Fietkau 		if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
16823f306448SFelix Fietkau 		    (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
16833f306448SFelix Fietkau 			return MT_DFS_STATE_ACTIVE;
16843f306448SFelix Fietkau 
16853f306448SFelix Fietkau 		return MT_DFS_STATE_DISABLED;
16863f306448SFelix Fietkau 	}
16873f306448SFelix Fietkau 
168800a883e6SFelix Fietkau 	if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
16893f306448SFelix Fietkau 		return MT_DFS_STATE_CAC;
16903f306448SFelix Fietkau 
16913f306448SFelix Fietkau 	return MT_DFS_STATE_ACTIVE;
16923f306448SFelix Fietkau }
16933f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1694