xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 502604f545978d2d4b12f8029785d5f1e4b32e56)
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 
2317f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
2417f1de56SFelix Fietkau 	CHAN2G(1, 2412),
2517f1de56SFelix Fietkau 	CHAN2G(2, 2417),
2617f1de56SFelix Fietkau 	CHAN2G(3, 2422),
2717f1de56SFelix Fietkau 	CHAN2G(4, 2427),
2817f1de56SFelix Fietkau 	CHAN2G(5, 2432),
2917f1de56SFelix Fietkau 	CHAN2G(6, 2437),
3017f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3117f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3217f1de56SFelix Fietkau 	CHAN2G(9, 2452),
3317f1de56SFelix Fietkau 	CHAN2G(10, 2457),
3417f1de56SFelix Fietkau 	CHAN2G(11, 2462),
3517f1de56SFelix Fietkau 	CHAN2G(12, 2467),
3617f1de56SFelix Fietkau 	CHAN2G(13, 2472),
3717f1de56SFelix Fietkau 	CHAN2G(14, 2484),
3817f1de56SFelix Fietkau };
3917f1de56SFelix Fietkau 
4017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4117f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4217f1de56SFelix Fietkau 	CHAN5G(40, 5200),
4317f1de56SFelix Fietkau 	CHAN5G(44, 5220),
4417f1de56SFelix Fietkau 	CHAN5G(48, 5240),
4517f1de56SFelix Fietkau 
4617f1de56SFelix Fietkau 	CHAN5G(52, 5260),
4717f1de56SFelix Fietkau 	CHAN5G(56, 5280),
4817f1de56SFelix Fietkau 	CHAN5G(60, 5300),
4917f1de56SFelix Fietkau 	CHAN5G(64, 5320),
5017f1de56SFelix Fietkau 
5117f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5217f1de56SFelix Fietkau 	CHAN5G(104, 5520),
5317f1de56SFelix Fietkau 	CHAN5G(108, 5540),
5417f1de56SFelix Fietkau 	CHAN5G(112, 5560),
5517f1de56SFelix Fietkau 	CHAN5G(116, 5580),
5617f1de56SFelix Fietkau 	CHAN5G(120, 5600),
5717f1de56SFelix Fietkau 	CHAN5G(124, 5620),
5817f1de56SFelix Fietkau 	CHAN5G(128, 5640),
5917f1de56SFelix Fietkau 	CHAN5G(132, 5660),
6017f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6117f1de56SFelix Fietkau 	CHAN5G(140, 5700),
629da82fb7SMarkus Theil 	CHAN5G(144, 5720),
6317f1de56SFelix Fietkau 
6417f1de56SFelix Fietkau 	CHAN5G(149, 5745),
6517f1de56SFelix Fietkau 	CHAN5G(153, 5765),
6617f1de56SFelix Fietkau 	CHAN5G(157, 5785),
6717f1de56SFelix Fietkau 	CHAN5G(161, 5805),
6817f1de56SFelix Fietkau 	CHAN5G(165, 5825),
699da82fb7SMarkus Theil 	CHAN5G(169, 5845),
709da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7117f1de56SFelix Fietkau };
7217f1de56SFelix Fietkau 
7317f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
7417f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
7517f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
7617f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
7717f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
7817f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
7917f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
8017f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
8117f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
8217f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
8317f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
8417f1de56SFelix Fietkau };
8517f1de56SFelix Fietkau 
8654b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = {
8754b8fdebSLorenzo Bianconi 	CCK_RATE(0, 10),
8854b8fdebSLorenzo Bianconi 	CCK_RATE(1, 20),
8954b8fdebSLorenzo Bianconi 	CCK_RATE(2, 55),
9054b8fdebSLorenzo Bianconi 	CCK_RATE(3, 110),
9154b8fdebSLorenzo Bianconi 	OFDM_RATE(11, 60),
9254b8fdebSLorenzo Bianconi 	OFDM_RATE(15, 90),
9354b8fdebSLorenzo Bianconi 	OFDM_RATE(10, 120),
9454b8fdebSLorenzo Bianconi 	OFDM_RATE(14, 180),
9554b8fdebSLorenzo Bianconi 	OFDM_RATE(9,  240),
9654b8fdebSLorenzo Bianconi 	OFDM_RATE(13, 360),
9754b8fdebSLorenzo Bianconi 	OFDM_RATE(8,  480),
9854b8fdebSLorenzo Bianconi 	OFDM_RATE(12, 540),
9954b8fdebSLorenzo Bianconi };
10054b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates);
10154b8fdebSLorenzo Bianconi 
102*502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
103*502604f5SYN Chen 	{ .start_freq = 2402, .end_freq = 2494, },
104*502604f5SYN Chen 	{ .start_freq = 5150, .end_freq = 5350, },
105*502604f5SYN Chen 	{ .start_freq = 5350, .end_freq = 5470, },
106*502604f5SYN Chen 	{ .start_freq = 5470, .end_freq = 5725, },
107*502604f5SYN Chen 	{ .start_freq = 5725, .end_freq = 5950, },
108*502604f5SYN Chen };
109*502604f5SYN Chen 
110*502604f5SYN Chen const struct cfg80211_sar_capa mt76_sar_capa = {
111*502604f5SYN Chen 	.type = NL80211_SAR_TYPE_POWER,
112*502604f5SYN Chen 	.num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
113*502604f5SYN Chen 	.freq_ranges = &mt76_sar_freq_ranges[0],
114*502604f5SYN Chen };
115*502604f5SYN Chen EXPORT_SYMBOL_GPL(mt76_sar_capa);
116*502604f5SYN Chen 
11717f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
11817f1de56SFelix Fietkau {
11917f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
12017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
12117f1de56SFelix Fietkau 	int led_pin;
12217f1de56SFelix Fietkau 
12317f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
12417f1de56SFelix Fietkau 		return 0;
12517f1de56SFelix Fietkau 
12617f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
12717f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
12817f1de56SFelix Fietkau 
12917f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
13017f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
13117f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
13217f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
13317f1de56SFelix Fietkau 					mt76_tpt_blink,
13417f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
13517f1de56SFelix Fietkau 
13617f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
13717f1de56SFelix Fietkau 	if (np) {
13817f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
13917f1de56SFelix Fietkau 			dev->led_pin = led_pin;
14017f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
14117f1de56SFelix Fietkau 	}
14217f1de56SFelix Fietkau 
14336f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
14436f7e2b2SFelix Fietkau }
14536f7e2b2SFelix Fietkau 
14636f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
14736f7e2b2SFelix Fietkau {
14836f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
14936f7e2b2SFelix Fietkau 		return;
15036f7e2b2SFelix Fietkau 
15136f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
15217f1de56SFelix Fietkau }
15317f1de56SFelix Fietkau 
154bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
155551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
156551e1ef4SLorenzo Bianconi 				 bool vht)
157551e1ef4SLorenzo Bianconi {
158551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
159bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
160551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
161551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
162551e1ef4SLorenzo Bianconi 
163551e1ef4SLorenzo Bianconi 	if (nstream > 1)
164551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
165551e1ef4SLorenzo Bianconi 	else
166551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
167551e1ef4SLorenzo Bianconi 
168551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
169551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
170551e1ef4SLorenzo Bianconi 
171551e1ef4SLorenzo Bianconi 	if (!vht)
172551e1ef4SLorenzo Bianconi 		return;
173551e1ef4SLorenzo Bianconi 
174551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
175551e1ef4SLorenzo Bianconi 	if (nstream > 1)
176551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
177551e1ef4SLorenzo Bianconi 	else
178551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
179551e1ef4SLorenzo Bianconi 
180551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
181551e1ef4SLorenzo Bianconi 		if (i < nstream)
182551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
183551e1ef4SLorenzo Bianconi 		else
184551e1ef4SLorenzo Bianconi 			mcs_map |=
185551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
186551e1ef4SLorenzo Bianconi 	}
187551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
188551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
189551e1ef4SLorenzo Bianconi }
190551e1ef4SLorenzo Bianconi 
191bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
1925ebdc3e0SLorenzo Bianconi {
19348dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz)
194bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
19548dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz)
196bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
1975ebdc3e0SLorenzo Bianconi }
1985ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1995ebdc3e0SLorenzo Bianconi 
20017f1de56SFelix Fietkau static int
20177af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
20217f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
20317f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
20417f1de56SFelix Fietkau {
20517f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
20617f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
20777af762eSLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap;
20877af762eSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
20917f1de56SFelix Fietkau 	void *chanlist;
21017f1de56SFelix Fietkau 	int size;
21117f1de56SFelix Fietkau 
21217f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
21317f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
21417f1de56SFelix Fietkau 	if (!chanlist)
21517f1de56SFelix Fietkau 		return -ENOMEM;
21617f1de56SFelix Fietkau 
217a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
21817f1de56SFelix Fietkau 				    GFP_KERNEL);
21917f1de56SFelix Fietkau 	if (!msband->chan)
22017f1de56SFelix Fietkau 		return -ENOMEM;
22117f1de56SFelix Fietkau 
22217f1de56SFelix Fietkau 	sband->channels = chanlist;
22317f1de56SFelix Fietkau 	sband->n_channels = n_chan;
22417f1de56SFelix Fietkau 	sband->bitrates = rates;
22517f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
22617f1de56SFelix Fietkau 
22717f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
22817f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
22917f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
23017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
23117f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
23217f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
23317f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
23417f1de56SFelix Fietkau 
23517f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
23617f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
23717f1de56SFelix Fietkau 
23877af762eSLorenzo Bianconi 	mt76_init_stream_cap(phy, sband, vht);
239551e1ef4SLorenzo Bianconi 
24017f1de56SFelix Fietkau 	if (!vht)
24117f1de56SFelix Fietkau 		return 0;
24217f1de56SFelix Fietkau 
24317f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
24417f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
24517f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
24617f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
24749149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
248f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
249f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
25049149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
25117f1de56SFelix Fietkau 
25217f1de56SFelix Fietkau 	return 0;
25317f1de56SFelix Fietkau }
25417f1de56SFelix Fietkau 
25517f1de56SFelix Fietkau static int
25677af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
25717f1de56SFelix Fietkau 		   int n_rates)
25817f1de56SFelix Fietkau {
25977af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
26017f1de56SFelix Fietkau 
26177af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
26277af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_2ghz), rates,
26377af762eSLorenzo Bianconi 			       n_rates, false);
26417f1de56SFelix Fietkau }
26517f1de56SFelix Fietkau 
26617f1de56SFelix Fietkau static int
26777af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
26817f1de56SFelix Fietkau 		   int n_rates, bool vht)
26917f1de56SFelix Fietkau {
27077af762eSLorenzo Bianconi 	phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
27117f1de56SFelix Fietkau 
27277af762eSLorenzo Bianconi 	return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
27377af762eSLorenzo Bianconi 			       ARRAY_SIZE(mt76_channels_5ghz), rates,
27477af762eSLorenzo Bianconi 			       n_rates, vht);
27517f1de56SFelix Fietkau }
27617f1de56SFelix Fietkau 
27717f1de56SFelix Fietkau static void
278c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
279c89d3625SFelix Fietkau 		 enum nl80211_band band)
28017f1de56SFelix Fietkau {
281c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
28217f1de56SFelix Fietkau 	bool found = false;
28317f1de56SFelix Fietkau 	int i;
28417f1de56SFelix Fietkau 
28517f1de56SFelix Fietkau 	if (!sband)
28617f1de56SFelix Fietkau 		return;
28717f1de56SFelix Fietkau 
28817f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
28917f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
29017f1de56SFelix Fietkau 			continue;
29117f1de56SFelix Fietkau 
29217f1de56SFelix Fietkau 		found = true;
29317f1de56SFelix Fietkau 		break;
29417f1de56SFelix Fietkau 	}
29517f1de56SFelix Fietkau 
296c89d3625SFelix Fietkau 	if (found) {
297c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
298c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
29917f1de56SFelix Fietkau 		return;
300c89d3625SFelix Fietkau 	}
30117f1de56SFelix Fietkau 
30217f1de56SFelix Fietkau 	sband->n_channels = 0;
303c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
30417f1de56SFelix Fietkau }
30517f1de56SFelix Fietkau 
306c89d3625SFelix Fietkau static void
30798df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
308c89d3625SFelix Fietkau {
30998df2baeSLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
310c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
311c89d3625SFelix Fietkau 
312c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
31398df2baeSLorenzo Bianconi 	SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
314c89d3625SFelix Fietkau 
315c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
316dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
317b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
318b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
319c89d3625SFelix Fietkau 
320c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
321c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
322d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
323c89d3625SFelix Fietkau 
324c89d3625SFelix Fietkau 	wiphy->available_antennas_tx = dev->phy.antenna_mask;
325c89d3625SFelix Fietkau 	wiphy->available_antennas_rx = dev->phy.antenna_mask;
326c89d3625SFelix Fietkau 
327c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
328b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
329c9619dfaSShayne Chen 
330c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
331c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
332c89d3625SFelix Fietkau 
333c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
334c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
335c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
336c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
337c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
338c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
339ed89b893SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
340b443e55fSRyder Lee 
341b443e55fSRyder Lee 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
342c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
343c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
344b443e55fSRyder Lee 	}
345d39b52e3SSean Wang 
346c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
347c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
348c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
349c89d3625SFelix Fietkau }
350c89d3625SFelix Fietkau 
351c89d3625SFelix Fietkau struct mt76_phy *
352c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
353c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
354c89d3625SFelix Fietkau {
355c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
356db78a791SLorenzo Bianconi 	unsigned int phy_size;
357c89d3625SFelix Fietkau 	struct mt76_phy *phy;
358c89d3625SFelix Fietkau 
359c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
360db78a791SLorenzo Bianconi 	hw = ieee80211_alloc_hw(size + phy_size, ops);
361c89d3625SFelix Fietkau 	if (!hw)
362c89d3625SFelix Fietkau 		return NULL;
363c89d3625SFelix Fietkau 
364c89d3625SFelix Fietkau 	phy = hw->priv;
365c89d3625SFelix Fietkau 	phy->dev = dev;
366c89d3625SFelix Fietkau 	phy->hw = hw;
367db78a791SLorenzo Bianconi 	phy->priv = hw->priv + phy_size;
368c89d3625SFelix Fietkau 
3698af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
3708af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
3718af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
3728af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
3738af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
3748af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
3758af414e8SLorenzo Bianconi #endif
3768af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
3778af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
3788af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
3798af414e8SLorenzo Bianconi 
380c89d3625SFelix Fietkau 	return phy;
381c89d3625SFelix Fietkau }
382c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
383c89d3625SFelix Fietkau 
384db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
385db78a791SLorenzo Bianconi 		      struct ieee80211_rate *rates, int n_rates)
386c89d3625SFelix Fietkau {
387c89d3625SFelix Fietkau 	int ret;
388c89d3625SFelix Fietkau 
38998df2baeSLorenzo Bianconi 	mt76_phy_init(phy, phy->hw);
390db78a791SLorenzo Bianconi 
391db78a791SLorenzo Bianconi 	if (phy->cap.has_2ghz) {
392db78a791SLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
393db78a791SLorenzo Bianconi 		if (ret)
394db78a791SLorenzo Bianconi 			return ret;
395db78a791SLorenzo Bianconi 	}
396db78a791SLorenzo Bianconi 
397db78a791SLorenzo Bianconi 	if (phy->cap.has_5ghz) {
398db78a791SLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
399db78a791SLorenzo Bianconi 		if (ret)
400db78a791SLorenzo Bianconi 			return ret;
401db78a791SLorenzo Bianconi 	}
402db78a791SLorenzo Bianconi 
403db78a791SLorenzo Bianconi 	wiphy_read_of_freq_limits(phy->hw->wiphy);
404db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
405db78a791SLorenzo Bianconi 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
406db78a791SLorenzo Bianconi 
407c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
408c89d3625SFelix Fietkau 	if (ret)
409c89d3625SFelix Fietkau 		return ret;
410c89d3625SFelix Fietkau 
411c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
412db78a791SLorenzo Bianconi 
413c89d3625SFelix Fietkau 	return 0;
414c89d3625SFelix Fietkau }
415c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
416c89d3625SFelix Fietkau 
417db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
418c89d3625SFelix Fietkau {
419c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
420c89d3625SFelix Fietkau 
421c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
422c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
42394b6df08SFelix Fietkau 	dev->phy2 = NULL;
424c89d3625SFelix Fietkau }
425c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
426c89d3625SFelix Fietkau 
427a85b590cSFelix Fietkau struct mt76_dev *
428c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
429c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
430c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
431a85b590cSFelix Fietkau {
432a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
433ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
434a85b590cSFelix Fietkau 	struct mt76_dev *dev;
435e5443256SFelix Fietkau 	int i;
436a85b590cSFelix Fietkau 
437a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
438a85b590cSFelix Fietkau 	if (!hw)
439a85b590cSFelix Fietkau 		return NULL;
440a85b590cSFelix Fietkau 
441a85b590cSFelix Fietkau 	dev = hw->priv;
442a85b590cSFelix Fietkau 	dev->hw = hw;
443c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
444c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
445c0f7b25aSLorenzo Bianconi 
446ac24dd35SFelix Fietkau 	phy = &dev->phy;
447ac24dd35SFelix Fietkau 	phy->dev = dev;
448ac24dd35SFelix Fietkau 	phy->hw = hw;
449ac24dd35SFelix Fietkau 
450a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
451a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
452a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
453108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
45426e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
45588046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
456a85b590cSFelix Fietkau 
45709872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
45809872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
45909872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
460781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
46109872957SLorenzo Bianconi 
4628af414e8SLorenzo Bianconi 	hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4638af414e8SLorenzo Bianconi 	hw->wiphy->interface_modes =
4648af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
4658af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
4668af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4678af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
4688af414e8SLorenzo Bianconi #endif
4698af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
4708af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
4718af414e8SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
4728af414e8SLorenzo Bianconi 
47351252cc5SLorenzo Bianconi 	spin_lock_init(&dev->token_lock);
47451252cc5SLorenzo Bianconi 	idr_init(&dev->token);
47551252cc5SLorenzo Bianconi 
476e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
477e5443256SFelix Fietkau 
478e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
479e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
480e5443256SFelix Fietkau 
481a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
482a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
483a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
484a86f1d01SLorenzo Bianconi 		return NULL;
485a86f1d01SLorenzo Bianconi 	}
486a86f1d01SLorenzo Bianconi 
487a85b590cSFelix Fietkau 	return dev;
488a85b590cSFelix Fietkau }
489a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
490a85b590cSFelix Fietkau 
49117f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
49217f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
49317f1de56SFelix Fietkau {
49417f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
495c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
49617f1de56SFelix Fietkau 	int ret;
49717f1de56SFelix Fietkau 
49817f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
49998df2baeSLorenzo Bianconi 	mt76_phy_init(phy, hw);
50017f1de56SFelix Fietkau 
50148dbce5cSLorenzo Bianconi 	if (phy->cap.has_2ghz) {
50277af762eSLorenzo Bianconi 		ret = mt76_init_sband_2g(phy, rates, n_rates);
50317f1de56SFelix Fietkau 		if (ret)
50417f1de56SFelix Fietkau 			return ret;
50517f1de56SFelix Fietkau 	}
50617f1de56SFelix Fietkau 
50748dbce5cSLorenzo Bianconi 	if (phy->cap.has_5ghz) {
50877af762eSLorenzo Bianconi 		ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
50917f1de56SFelix Fietkau 		if (ret)
51017f1de56SFelix Fietkau 			return ret;
51117f1de56SFelix Fietkau 	}
51217f1de56SFelix Fietkau 
513c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
514c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
515c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
51617f1de56SFelix Fietkau 
517b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
51817f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
51917f1de56SFelix Fietkau 		if (ret)
52017f1de56SFelix Fietkau 			return ret;
521b374e868SArnd Bergmann 	}
52217f1de56SFelix Fietkau 
523781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
524781eef5bSFelix Fietkau 	if (ret)
525781eef5bSFelix Fietkau 		return ret;
526781eef5bSFelix Fietkau 
527781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
528781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
529781eef5bSFelix Fietkau 
530781eef5bSFelix Fietkau 	return 0;
53117f1de56SFelix Fietkau }
53217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
53317f1de56SFelix Fietkau 
53417f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
53517f1de56SFelix Fietkau {
53617f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
53717f1de56SFelix Fietkau 
538d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
53936f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
54079d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
54117f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
54217f1de56SFelix Fietkau }
54317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
54417f1de56SFelix Fietkau 
545def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
546def34a2fSLorenzo Bianconi {
547781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
548a86f1d01SLorenzo Bianconi 	if (dev->wq) {
549a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
550a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
551a86f1d01SLorenzo Bianconi 	}
552def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
553def34a2fSLorenzo Bianconi }
554def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
555def34a2fSLorenzo Bianconi 
556cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
557cc4b3c13SLorenzo Bianconi {
558cc4b3c13SLorenzo Bianconi 	struct sk_buff *skb = phy->rx_amsdu[q].head;
5592c2bdd23SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
560cc4b3c13SLorenzo Bianconi 	struct mt76_dev *dev = phy->dev;
561cc4b3c13SLorenzo Bianconi 
562cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].head = NULL;
563cc4b3c13SLorenzo Bianconi 	phy->rx_amsdu[q].tail = NULL;
5642c2bdd23SFelix Fietkau 
5652c2bdd23SFelix Fietkau 	/*
5662c2bdd23SFelix Fietkau 	 * Validate if the amsdu has a proper first subframe.
5672c2bdd23SFelix Fietkau 	 * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
5682c2bdd23SFelix Fietkau 	 * flag of the QoS header gets flipped. In such cases, the first
5692c2bdd23SFelix Fietkau 	 * subframe has a LLC/SNAP header in the location of the destination
5702c2bdd23SFelix Fietkau 	 * address.
5712c2bdd23SFelix Fietkau 	 */
5722c2bdd23SFelix Fietkau 	if (skb_shinfo(skb)->frag_list) {
5732c2bdd23SFelix Fietkau 		int offset = 0;
5742c2bdd23SFelix Fietkau 
5752c2bdd23SFelix Fietkau 		if (!(status->flag & RX_FLAG_8023)) {
5762c2bdd23SFelix Fietkau 			offset = ieee80211_get_hdrlen_from_skb(skb);
5772c2bdd23SFelix Fietkau 
5782c2bdd23SFelix Fietkau 			if ((status->flag &
5792c2bdd23SFelix Fietkau 			     (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
5802c2bdd23SFelix Fietkau 			    RX_FLAG_DECRYPTED)
5812c2bdd23SFelix Fietkau 				offset += 8;
5822c2bdd23SFelix Fietkau 		}
5832c2bdd23SFelix Fietkau 
5842c2bdd23SFelix Fietkau 		if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
5852c2bdd23SFelix Fietkau 			dev_kfree_skb(skb);
5862c2bdd23SFelix Fietkau 			return;
5872c2bdd23SFelix Fietkau 		}
5882c2bdd23SFelix Fietkau 	}
589cc4b3c13SLorenzo Bianconi 	__skb_queue_tail(&dev->rx_skb[q], skb);
590cc4b3c13SLorenzo Bianconi }
591cc4b3c13SLorenzo Bianconi 
592cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
593cc4b3c13SLorenzo Bianconi 				  struct sk_buff *skb)
594cc4b3c13SLorenzo Bianconi {
595cc4b3c13SLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
596cc4b3c13SLorenzo Bianconi 
597cc4b3c13SLorenzo Bianconi 	if (phy->rx_amsdu[q].head &&
598cc4b3c13SLorenzo Bianconi 	    (!status->amsdu || status->first_amsdu ||
599cc4b3c13SLorenzo Bianconi 	     status->seqno != phy->rx_amsdu[q].seqno))
600cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
601cc4b3c13SLorenzo Bianconi 
602cc4b3c13SLorenzo Bianconi 	if (!phy->rx_amsdu[q].head) {
603cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
604cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].seqno = status->seqno;
605cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].head = skb;
606cc4b3c13SLorenzo Bianconi 	} else {
607cc4b3c13SLorenzo Bianconi 		*phy->rx_amsdu[q].tail = skb;
608cc4b3c13SLorenzo Bianconi 		phy->rx_amsdu[q].tail = &skb->next;
609cc4b3c13SLorenzo Bianconi 	}
610cc4b3c13SLorenzo Bianconi 
611cc4b3c13SLorenzo Bianconi 	if (!status->amsdu || status->last_amsdu)
612cc4b3c13SLorenzo Bianconi 		mt76_rx_release_amsdu(phy, q);
613cc4b3c13SLorenzo Bianconi }
614cc4b3c13SLorenzo Bianconi 
61517f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
61617f1de56SFelix Fietkau {
617011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
618011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
619011849e0SFelix Fietkau 
620011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
62117f1de56SFelix Fietkau 		dev_kfree_skb(skb);
62217f1de56SFelix Fietkau 		return;
62317f1de56SFelix Fietkau 	}
62417f1de56SFelix Fietkau 
625f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
626c918c74dSShayne Chen 	if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
627c918c74dSShayne Chen 		phy->test.rx_stats.packets[q]++;
628f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
629c918c74dSShayne Chen 			phy->test.rx_stats.fcs_error[q]++;
630f0efa862SFelix Fietkau 	}
631f0efa862SFelix Fietkau #endif
632cc4b3c13SLorenzo Bianconi 
633cc4b3c13SLorenzo Bianconi 	mt76_rx_release_burst(phy, q, skb);
63417f1de56SFelix Fietkau }
63517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
63617f1de56SFelix Fietkau 
6375a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
63826e40d4cSFelix Fietkau {
639af005f26SLorenzo Bianconi 	struct mt76_queue *q;
64091990519SLorenzo Bianconi 	int i;
6415a95ca41SFelix Fietkau 
6425a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
64391990519SLorenzo Bianconi 		q = phy->q_tx[i];
644af005f26SLorenzo Bianconi 		if (q && q->queued)
64526e40d4cSFelix Fietkau 			return true;
64626e40d4cSFelix Fietkau 	}
64726e40d4cSFelix Fietkau 
64826e40d4cSFelix Fietkau 	return false;
64926e40d4cSFelix Fietkau }
65039d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
65126e40d4cSFelix Fietkau 
6520fd0eb54SFelix Fietkau static struct mt76_channel_state *
65396747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
6540fd0eb54SFelix Fietkau {
6550fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
6560fd0eb54SFelix Fietkau 	int idx;
6570fd0eb54SFelix Fietkau 
6580fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
65996747a51SFelix Fietkau 		msband = &phy->sband_2g;
6600fd0eb54SFelix Fietkau 	else
66196747a51SFelix Fietkau 		msband = &phy->sband_5g;
6620fd0eb54SFelix Fietkau 
6630fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
6640fd0eb54SFelix Fietkau 	return &msband->chan[idx];
6650fd0eb54SFelix Fietkau }
6660fd0eb54SFelix Fietkau 
66704414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
66896747a51SFelix Fietkau {
66996747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
67096747a51SFelix Fietkau 
67196747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
67296747a51SFelix Fietkau 						  phy->survey_time));
67396747a51SFelix Fietkau 	phy->survey_time = time;
67496747a51SFelix Fietkau }
67504414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
67696747a51SFelix Fietkau 
677c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
6785ce09c1aSFelix Fietkau {
679c560b137SRyder Lee 	struct mt76_dev *dev = phy->dev;
680aec65e48SFelix Fietkau 	ktime_t cur_time;
681aec65e48SFelix Fietkau 
6825ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
683c560b137SRyder Lee 		dev->drv->update_survey(phy);
6845ce09c1aSFelix Fietkau 
685aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
686c560b137SRyder Lee 	mt76_update_survey_active_time(phy, cur_time);
687aec65e48SFelix Fietkau 
6885ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
689c560b137SRyder Lee 		struct mt76_channel_state *state = phy->chan_state;
69096747a51SFelix Fietkau 
691237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
6925ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
6935ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
694237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
6955ce09c1aSFelix Fietkau 	}
6965ce09c1aSFelix Fietkau }
6975ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
6985ce09c1aSFelix Fietkau 
69996747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
70017f1de56SFelix Fietkau {
70196747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
70296747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
70317f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
70417f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
70526e40d4cSFelix Fietkau 	int timeout = HZ / 5;
70617f1de56SFelix Fietkau 
7075a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
708c560b137SRyder Lee 	mt76_update_survey(phy);
70917f1de56SFelix Fietkau 
71096747a51SFelix Fietkau 	phy->chandef = *chandef;
71196747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
71217f1de56SFelix Fietkau 
71317f1de56SFelix Fietkau 	if (!offchannel)
71496747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
71517f1de56SFelix Fietkau 
71696747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
71796747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
71817f1de56SFelix Fietkau }
71917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
72017f1de56SFelix Fietkau 
72117f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
72217f1de56SFelix Fietkau 		    struct survey_info *survey)
72317f1de56SFelix Fietkau {
72496747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
72596747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
72617f1de56SFelix Fietkau 	struct mt76_sband *sband;
72717f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
72817f1de56SFelix Fietkau 	struct mt76_channel_state *state;
72917f1de56SFelix Fietkau 	int ret = 0;
73017f1de56SFelix Fietkau 
731237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
73217f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
733c560b137SRyder Lee 		mt76_update_survey(phy);
73417f1de56SFelix Fietkau 
73596747a51SFelix Fietkau 	sband = &phy->sband_2g;
73617f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
73717f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
73896747a51SFelix Fietkau 		sband = &phy->sband_5g;
73917f1de56SFelix Fietkau 	}
74017f1de56SFelix Fietkau 
741237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
742237312c5SLorenzo Bianconi 		ret = -ENOENT;
743237312c5SLorenzo Bianconi 		goto out;
744237312c5SLorenzo Bianconi 	}
74517f1de56SFelix Fietkau 
74617f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
74796747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
74817f1de56SFelix Fietkau 
74917f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
75017f1de56SFelix Fietkau 	survey->channel = chan;
75117f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
752ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
753e5051965SFelix Fietkau 	if (state->noise)
754e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
755e5051965SFelix Fietkau 
75696747a51SFelix Fietkau 	if (chan == phy->main_chan) {
75717f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
75817f1de56SFelix Fietkau 
7595ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
7605ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
7615ce09c1aSFelix Fietkau 	}
7625ce09c1aSFelix Fietkau 
76317f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
7646bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
765237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
766e5051965SFelix Fietkau 	survey->noise = state->noise;
767237312c5SLorenzo Bianconi 
768237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
769237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
770ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
77117f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
77217f1de56SFelix Fietkau 
773237312c5SLorenzo Bianconi out:
774237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
775237312c5SLorenzo Bianconi 
77617f1de56SFelix Fietkau 	return ret;
77717f1de56SFelix Fietkau }
77817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
77917f1de56SFelix Fietkau 
78030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
78130ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
78230ce7f44SFelix Fietkau {
78330ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
78430ce7f44SFelix Fietkau 	int i;
78530ce7f44SFelix Fietkau 
78630ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
78730ce7f44SFelix Fietkau 
78830ce7f44SFelix Fietkau 	if (!key)
78930ce7f44SFelix Fietkau 		return;
79030ce7f44SFelix Fietkau 
79101cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
79201cfc1b4SLorenzo Bianconi 		return;
79330ce7f44SFelix Fietkau 
79401cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
79530ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
79630ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
79730ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
79830ce7f44SFelix Fietkau 	}
79930ce7f44SFelix Fietkau }
80030ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
80130ce7f44SFelix Fietkau 
802bfc394ddSFelix Fietkau static void
803bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
804bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
805bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
8064e34249eSFelix Fietkau {
8074e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
8084e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
8094e34249eSFelix Fietkau 
8104e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
8114e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
8124e34249eSFelix Fietkau 
8134e34249eSFelix Fietkau 	status->flag = mstat.flag;
8144e34249eSFelix Fietkau 	status->freq = mstat.freq;
8154e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
8164e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
8174e34249eSFelix Fietkau 	status->bw = mstat.bw;
818af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
819af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
820af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
8214e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
8224e34249eSFelix Fietkau 	status->nss = mstat.nss;
8234e34249eSFelix Fietkau 	status->band = mstat.band;
8244e34249eSFelix Fietkau 	status->signal = mstat.signal;
8254e34249eSFelix Fietkau 	status->chains = mstat.chains;
826d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
8270fda6d7bSRyder Lee 	status->device_timestamp = mstat.timestamp;
8280fda6d7bSRyder Lee 	status->mactime = mstat.timestamp;
8294e34249eSFelix Fietkau 
8304e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
83113381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
83213381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
83313381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
83413381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
8359c68a57bSFelix Fietkau 
836bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
837bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
8384e34249eSFelix Fietkau }
8394e34249eSFelix Fietkau 
84030ce7f44SFelix Fietkau static int
84130ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
84230ce7f44SFelix Fietkau {
84330ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
84430ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
84530ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
846e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
84730ce7f44SFelix Fietkau 	int ret;
84830ce7f44SFelix Fietkau 
84930ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
85030ce7f44SFelix Fietkau 		return 0;
85130ce7f44SFelix Fietkau 
85230ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
85330ce7f44SFelix Fietkau 		return 0;
85430ce7f44SFelix Fietkau 
85530ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
85630ce7f44SFelix Fietkau 		/*
85730ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
85830ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
85930ce7f44SFelix Fietkau 		 */
86077ae1d5eSRyder Lee 		hdr = mt76_skb_get_hdr(skb);
86130ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
86230ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
86330ce7f44SFelix Fietkau 			return 0;
86430ce7f44SFelix Fietkau 	}
86530ce7f44SFelix Fietkau 
86630ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
867e195dad1SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[tidno],
86830ce7f44SFelix Fietkau 		     sizeof(status->iv));
86930ce7f44SFelix Fietkau 	if (ret <= 0)
87030ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
87130ce7f44SFelix Fietkau 
872e195dad1SFelix Fietkau 	memcpy(wcid->rx_key_pn[tidno], status->iv, sizeof(status->iv));
87330ce7f44SFelix Fietkau 
87430ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
87530ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
87630ce7f44SFelix Fietkau 
87730ce7f44SFelix Fietkau 	return 0;
87830ce7f44SFelix Fietkau }
87930ce7f44SFelix Fietkau 
880d71ef286SFelix Fietkau static void
8815ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
8825ce09c1aSFelix Fietkau 		    int len)
8835ce09c1aSFelix Fietkau {
8845ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
88585b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
88685b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
88785b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
88885b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
88985b7a5d0SLorenzo Bianconi 		.band = status->band,
89085b7a5d0SLorenzo Bianconi 		.nss = status->nss,
89185b7a5d0SLorenzo Bianconi 		.bw = status->bw,
89285b7a5d0SLorenzo Bianconi 	};
8935ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
8945ce09c1aSFelix Fietkau 	u32 airtime;
895e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
8965ce09c1aSFelix Fietkau 
89785b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
898237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
8995ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
900237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
9015ce09c1aSFelix Fietkau 
9025ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
9035ce09c1aSFelix Fietkau 		return;
9045ce09c1aSFelix Fietkau 
9055ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
906e195dad1SFelix Fietkau 	ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
9075ce09c1aSFelix Fietkau }
9085ce09c1aSFelix Fietkau 
9095ce09c1aSFelix Fietkau static void
9105ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
9115ce09c1aSFelix Fietkau {
9125ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
9135ce09c1aSFelix Fietkau 	int wcid_idx;
9145ce09c1aSFelix Fietkau 
9155ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
9165ce09c1aSFelix Fietkau 		return;
9175ce09c1aSFelix Fietkau 
9185ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
919bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
9205ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
9215ce09c1aSFelix Fietkau 	else
9225ce09c1aSFelix Fietkau 		wcid = NULL;
9235ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
9245ce09c1aSFelix Fietkau 
9255ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
9265ce09c1aSFelix Fietkau 
9275ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
9285ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
9295ce09c1aSFelix Fietkau }
9305ce09c1aSFelix Fietkau 
9315ce09c1aSFelix Fietkau static void
9325ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
9335ce09c1aSFelix Fietkau {
9345ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
9355ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
9365ce09c1aSFelix Fietkau 
9375ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
9385ce09c1aSFelix Fietkau 		return;
9395ce09c1aSFelix Fietkau 
9405ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
941e195dad1SFelix Fietkau 		struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
942e195dad1SFelix Fietkau 
943e195dad1SFelix Fietkau 		if (status->flag & RX_FLAG_8023)
944e195dad1SFelix Fietkau 			return;
945e195dad1SFelix Fietkau 
94698df2baeSLorenzo Bianconi 		if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
9475ce09c1aSFelix Fietkau 			return;
9485ce09c1aSFelix Fietkau 
9495ce09c1aSFelix Fietkau 		wcid = NULL;
9505ce09c1aSFelix Fietkau 	}
9515ce09c1aSFelix Fietkau 
9525ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
9535ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
9545ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
9555ce09c1aSFelix Fietkau 
9565ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
9575ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
9585ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
9595ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
9605ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
9615ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
9625ce09c1aSFelix Fietkau 		}
9635ce09c1aSFelix Fietkau 
9645ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
9655ce09c1aSFelix Fietkau 		return;
9665ce09c1aSFelix Fietkau 	}
9675ce09c1aSFelix Fietkau 
9685ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
9695ce09c1aSFelix Fietkau }
9705ce09c1aSFelix Fietkau 
9715ce09c1aSFelix Fietkau static void
972ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
973d71ef286SFelix Fietkau {
974d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
97577ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
976d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
977bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
978d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
979e195dad1SFelix Fietkau 	u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
980d71ef286SFelix Fietkau 	bool ps;
981d71ef286SFelix Fietkau 
982bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
983e195dad1SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
984e195dad1SFelix Fietkau 	    !(status->flag & RX_FLAG_8023)) {
985bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
98636d91096SFelix Fietkau 		if (sta)
98736d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
98836d91096SFelix Fietkau 	}
98936d91096SFelix Fietkau 
9905ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
9915ce09c1aSFelix Fietkau 
992d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
993d71ef286SFelix Fietkau 		return;
994d71ef286SFelix Fietkau 
995d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
996d71ef286SFelix Fietkau 
99702e5a769SFelix Fietkau 	if (status->signal <= 0)
99802e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
99902e5a769SFelix Fietkau 
1000ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
1001ef13edc0SFelix Fietkau 
1002e195dad1SFelix Fietkau 	if (status->flag & RX_FLAG_8023)
1003e195dad1SFelix Fietkau 		return;
1004e195dad1SFelix Fietkau 
1005d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1006d71ef286SFelix Fietkau 		return;
1007d71ef286SFelix Fietkau 
1008d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
1009d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
1010d71ef286SFelix Fietkau 		return;
1011d71ef286SFelix Fietkau 	}
1012d71ef286SFelix Fietkau 
1013d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
1014d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
1015d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
1016d71ef286SFelix Fietkau 		return;
1017d71ef286SFelix Fietkau 
1018d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
1019d71ef286SFelix Fietkau 
1020d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1021d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
1022e195dad1SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, tidno);
1023d71ef286SFelix Fietkau 
1024d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1025d71ef286SFelix Fietkau 		return;
1026d71ef286SFelix Fietkau 
102711b2a25fSFelix Fietkau 	if (ps)
1028d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
102911b2a25fSFelix Fietkau 	else
1030d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1031d71ef286SFelix Fietkau 
1032d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
10339f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
1034d71ef286SFelix Fietkau }
1035d71ef286SFelix Fietkau 
10369d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
103781e850efSLorenzo Bianconi 		      struct napi_struct *napi)
103817f1de56SFelix Fietkau {
10399c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
1040bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
10413298b1f8SFelix Fietkau 	struct sk_buff *skb, *tmp;
10423298b1f8SFelix Fietkau 	LIST_HEAD(list);
10439d9d738bSFelix Fietkau 
1044c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
10459d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
1046cc4b3c13SLorenzo Bianconi 		struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1047cc4b3c13SLorenzo Bianconi 
104830ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
104930ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
105030ce7f44SFelix Fietkau 			continue;
105130ce7f44SFelix Fietkau 		}
105230ce7f44SFelix Fietkau 
1053cc4b3c13SLorenzo Bianconi 		skb_shinfo(skb)->frag_list = NULL;
1054bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
10553298b1f8SFelix Fietkau 		ieee80211_rx_list(hw, sta, skb, &list);
1056cc4b3c13SLorenzo Bianconi 
1057cc4b3c13SLorenzo Bianconi 		/* subsequent amsdu frames */
1058cc4b3c13SLorenzo Bianconi 		while (nskb) {
1059cc4b3c13SLorenzo Bianconi 			skb = nskb;
1060cc4b3c13SLorenzo Bianconi 			nskb = nskb->next;
1061cc4b3c13SLorenzo Bianconi 			skb->next = NULL;
1062cc4b3c13SLorenzo Bianconi 
1063cc4b3c13SLorenzo Bianconi 			mt76_rx_convert(dev, skb, &hw, &sta);
1064cc4b3c13SLorenzo Bianconi 			ieee80211_rx_list(hw, sta, skb, &list);
1065cc4b3c13SLorenzo Bianconi 		}
10669d9d738bSFelix Fietkau 	}
1067c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
10683298b1f8SFelix Fietkau 
10693298b1f8SFelix Fietkau 	if (!napi) {
10703298b1f8SFelix Fietkau 		netif_receive_skb_list(&list);
10713298b1f8SFelix Fietkau 		return;
10723298b1f8SFelix Fietkau 	}
10733298b1f8SFelix Fietkau 
10743298b1f8SFelix Fietkau 	list_for_each_entry_safe(skb, tmp, &list, list) {
10753298b1f8SFelix Fietkau 		skb_list_del_init(skb);
10763298b1f8SFelix Fietkau 		napi_gro_receive(napi, skb);
10773298b1f8SFelix Fietkau 	}
10789d9d738bSFelix Fietkau }
10799d9d738bSFelix Fietkau 
108081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
108181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
10829d9d738bSFelix Fietkau {
1083aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
108417f1de56SFelix Fietkau 	struct sk_buff *skb;
108517f1de56SFelix Fietkau 
1086aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
1087aee5b8cfSFelix Fietkau 
1088d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1089ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
1090aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
1091d71ef286SFelix Fietkau 	}
1092aee5b8cfSFelix Fietkau 
109381e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
10944e34249eSFelix Fietkau }
109581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1096723b90dcSFelix Fietkau 
1097e28487eaSFelix Fietkau static int
1098e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
1099426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
1100e28487eaSFelix Fietkau {
1101e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1102e28487eaSFelix Fietkau 	int ret;
1103e28487eaSFelix Fietkau 	int i;
1104e28487eaSFelix Fietkau 
1105e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
1106e28487eaSFelix Fietkau 
1107e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
1108e28487eaSFelix Fietkau 	if (ret)
1109e28487eaSFelix Fietkau 		goto out;
1110e28487eaSFelix Fietkau 
1111e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1112e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1113e28487eaSFelix Fietkau 
1114e28487eaSFelix Fietkau 		if (!sta->txq[i])
1115e28487eaSFelix Fietkau 			continue;
1116e28487eaSFelix Fietkau 
1117e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
1118e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
1119e28487eaSFelix Fietkau 	}
1120e28487eaSFelix Fietkau 
1121ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1122426e8e41SFelix Fietkau 	if (ext_phy)
1123426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1124c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
1125e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1126e28487eaSFelix Fietkau 
1127e28487eaSFelix Fietkau out:
1128e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1129e28487eaSFelix Fietkau 
1130e28487eaSFelix Fietkau 	return ret;
1131e28487eaSFelix Fietkau }
1132e28487eaSFelix Fietkau 
113313f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1134723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1135723b90dcSFelix Fietkau {
1136723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
113713f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1138723b90dcSFelix Fietkau 
113958bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
114058bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
114158bab0d4SFelix Fietkau 
1142e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1143e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1144e28487eaSFelix Fietkau 
1145723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
1146426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1147426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
114813f61dfcSLorenzo Bianconi }
114913f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1150e28487eaSFelix Fietkau 
115113f61dfcSLorenzo Bianconi static void
115213f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
115313f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
115413f61dfcSLorenzo Bianconi {
115513f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
115613f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1157723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1158723b90dcSFelix Fietkau }
1159e28487eaSFelix Fietkau 
1160e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1161e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1162e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1163e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1164e28487eaSFelix Fietkau {
1165426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1166426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1167426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1168e28487eaSFelix Fietkau 
1169e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1170e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1171426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1172e28487eaSFelix Fietkau 
11739c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
11749c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
11759c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
11769c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
11779c193de5SFelix Fietkau 
1178e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1179e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1180e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1181e28487eaSFelix Fietkau 
1182e28487eaSFelix Fietkau 	return 0;
1183e28487eaSFelix Fietkau }
1184e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
11859313faacSFelix Fietkau 
118643ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
118743ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
118843ba1922SFelix Fietkau {
118943ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
119043ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
119143ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
119243ba1922SFelix Fietkau 
119343ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
119443ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
119543ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
119643ba1922SFelix Fietkau }
119743ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
119843ba1922SFelix Fietkau 
11999313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
12009313faacSFelix Fietkau 		     int *dbm)
12019313faacSFelix Fietkau {
1202beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1203beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
120407cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
12059313faacSFelix Fietkau 
120607cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
12079313faacSFelix Fietkau 
12089313faacSFelix Fietkau 	return 0;
12099313faacSFelix Fietkau }
12109313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1211e7173858SFelix Fietkau 
1212e7173858SFelix Fietkau static void
1213e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1214e7173858SFelix Fietkau {
12158552a434SJohn Crispin 	if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1216e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1217e7173858SFelix Fietkau }
1218e7173858SFelix Fietkau 
1219e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1220e7173858SFelix Fietkau {
1221e7173858SFelix Fietkau 	if (!dev->csa_complete)
1222e7173858SFelix Fietkau 		return;
1223e7173858SFelix Fietkau 
1224e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1225e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1226e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1227e7173858SFelix Fietkau 
1228e7173858SFelix Fietkau 	dev->csa_complete = 0;
1229e7173858SFelix Fietkau }
1230e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1231e7173858SFelix Fietkau 
1232e7173858SFelix Fietkau static void
1233e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1234e7173858SFelix Fietkau {
1235e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1236e7173858SFelix Fietkau 
1237e7173858SFelix Fietkau 	if (!vif->csa_active)
1238e7173858SFelix Fietkau 		return;
1239e7173858SFelix Fietkau 
12408552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1241e7173858SFelix Fietkau }
1242e7173858SFelix Fietkau 
1243e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1244e7173858SFelix Fietkau {
1245e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1246e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1247e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1248e7173858SFelix Fietkau }
1249e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
125087d53103SStanislaw Gruszka 
125187d53103SStanislaw Gruszka int
125287d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
125387d53103SStanislaw Gruszka {
125487d53103SStanislaw Gruszka 	return 0;
125587d53103SStanislaw Gruszka }
125687d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1257eadfd98fSLorenzo Bianconi 
1258eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1259eadfd98fSLorenzo Bianconi {
1260eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1261eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1262eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1263eadfd98fSLorenzo Bianconi 
1264eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1265eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1266eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1267eadfd98fSLorenzo Bianconi 
1268eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1269eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1270eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1271eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1272eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1273eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1274eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1275eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1276eadfd98fSLorenzo Bianconi 
1277eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1278eadfd98fSLorenzo Bianconi }
1279eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1280d2679d65SLorenzo Bianconi 
1281d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1282d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1283d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1284d2679d65SLorenzo Bianconi {
1285d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1286d2679d65SLorenzo Bianconi 
1287d2679d65SLorenzo Bianconi 	if (cck) {
128896747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1289d2679d65SLorenzo Bianconi 			return 0;
1290d2679d65SLorenzo Bianconi 
1291d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
129296747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1293d2679d65SLorenzo Bianconi 		offset = 4;
1294d2679d65SLorenzo Bianconi 	}
1295d2679d65SLorenzo Bianconi 
1296d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1297d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1298d2679d65SLorenzo Bianconi 			return i;
1299d2679d65SLorenzo Bianconi 	}
1300d2679d65SLorenzo Bianconi 
1301d2679d65SLorenzo Bianconi 	return 0;
1302d2679d65SLorenzo Bianconi }
1303d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
13048b8ab5c2SLorenzo Bianconi 
13058b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
13068b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
13078b8ab5c2SLorenzo Bianconi {
1308011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
13098b8ab5c2SLorenzo Bianconi 
1310011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
13118b8ab5c2SLorenzo Bianconi }
13128b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
13138b8ab5c2SLorenzo Bianconi 
13148b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
13158b8ab5c2SLorenzo Bianconi {
1316011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
13178b8ab5c2SLorenzo Bianconi 
1318011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
13198b8ab5c2SLorenzo Bianconi }
13208b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1321e49c76d4SLorenzo Bianconi 
1322e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1323e49c76d4SLorenzo Bianconi {
1324beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1325beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1326e49c76d4SLorenzo Bianconi 
1327e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1328beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1329beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1330e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1331e49c76d4SLorenzo Bianconi 
1332e49c76d4SLorenzo Bianconi 	return 0;
1333e49c76d4SLorenzo Bianconi }
1334e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1335b671da33SLorenzo Bianconi 
1336b1cb42adSLorenzo Bianconi struct mt76_queue *
1337b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1338b1cb42adSLorenzo Bianconi 		int ring_base)
1339b671da33SLorenzo Bianconi {
1340b671da33SLorenzo Bianconi 	struct mt76_queue *hwq;
1341b671da33SLorenzo Bianconi 	int err;
1342b671da33SLorenzo Bianconi 
1343b671da33SLorenzo Bianconi 	hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1344b671da33SLorenzo Bianconi 	if (!hwq)
1345b1cb42adSLorenzo Bianconi 		return ERR_PTR(-ENOMEM);
1346b671da33SLorenzo Bianconi 
1347b671da33SLorenzo Bianconi 	err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1348b671da33SLorenzo Bianconi 	if (err < 0)
1349b1cb42adSLorenzo Bianconi 		return ERR_PTR(err);
1350b671da33SLorenzo Bianconi 
1351b1cb42adSLorenzo Bianconi 	return hwq;
1352b671da33SLorenzo Bianconi }
1353b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1354