xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 6bfa6e38266d234c845c37e976084e6b524743b1)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
517f1de56SFelix Fietkau #include <linux/of.h>
617f1de56SFelix Fietkau #include "mt76.h"
717f1de56SFelix Fietkau 
817f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
917f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1017f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1117f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1217f1de56SFelix Fietkau 	.max_power = 30,			\
1317f1de56SFelix Fietkau }
1417f1de56SFelix Fietkau 
1517f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1617f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1717f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1817f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1917f1de56SFelix Fietkau 	.max_power = 30,			\
2017f1de56SFelix Fietkau }
2117f1de56SFelix Fietkau 
2217f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
2317f1de56SFelix Fietkau 	CHAN2G(1, 2412),
2417f1de56SFelix Fietkau 	CHAN2G(2, 2417),
2517f1de56SFelix Fietkau 	CHAN2G(3, 2422),
2617f1de56SFelix Fietkau 	CHAN2G(4, 2427),
2717f1de56SFelix Fietkau 	CHAN2G(5, 2432),
2817f1de56SFelix Fietkau 	CHAN2G(6, 2437),
2917f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3017f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3117f1de56SFelix Fietkau 	CHAN2G(9, 2452),
3217f1de56SFelix Fietkau 	CHAN2G(10, 2457),
3317f1de56SFelix Fietkau 	CHAN2G(11, 2462),
3417f1de56SFelix Fietkau 	CHAN2G(12, 2467),
3517f1de56SFelix Fietkau 	CHAN2G(13, 2472),
3617f1de56SFelix Fietkau 	CHAN2G(14, 2484),
3717f1de56SFelix Fietkau };
3817f1de56SFelix Fietkau 
3917f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4017f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4117f1de56SFelix Fietkau 	CHAN5G(40, 5200),
4217f1de56SFelix Fietkau 	CHAN5G(44, 5220),
4317f1de56SFelix Fietkau 	CHAN5G(48, 5240),
4417f1de56SFelix Fietkau 
4517f1de56SFelix Fietkau 	CHAN5G(52, 5260),
4617f1de56SFelix Fietkau 	CHAN5G(56, 5280),
4717f1de56SFelix Fietkau 	CHAN5G(60, 5300),
4817f1de56SFelix Fietkau 	CHAN5G(64, 5320),
4917f1de56SFelix Fietkau 
5017f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5117f1de56SFelix Fietkau 	CHAN5G(104, 5520),
5217f1de56SFelix Fietkau 	CHAN5G(108, 5540),
5317f1de56SFelix Fietkau 	CHAN5G(112, 5560),
5417f1de56SFelix Fietkau 	CHAN5G(116, 5580),
5517f1de56SFelix Fietkau 	CHAN5G(120, 5600),
5617f1de56SFelix Fietkau 	CHAN5G(124, 5620),
5717f1de56SFelix Fietkau 	CHAN5G(128, 5640),
5817f1de56SFelix Fietkau 	CHAN5G(132, 5660),
5917f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6017f1de56SFelix Fietkau 	CHAN5G(140, 5700),
6117f1de56SFelix Fietkau 
6217f1de56SFelix Fietkau 	CHAN5G(149, 5745),
6317f1de56SFelix Fietkau 	CHAN5G(153, 5765),
6417f1de56SFelix Fietkau 	CHAN5G(157, 5785),
6517f1de56SFelix Fietkau 	CHAN5G(161, 5805),
6617f1de56SFelix Fietkau 	CHAN5G(165, 5825),
6717f1de56SFelix Fietkau };
6817f1de56SFelix Fietkau 
6917f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
7017f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
7117f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
7217f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
7317f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
7417f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
7517f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
7617f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
7717f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
7817f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
7917f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
8017f1de56SFelix Fietkau };
8117f1de56SFelix Fietkau 
8217f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
8317f1de56SFelix Fietkau {
8417f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
8517f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
8617f1de56SFelix Fietkau 	int led_pin;
8717f1de56SFelix Fietkau 
8817f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
8917f1de56SFelix Fietkau 		return 0;
9017f1de56SFelix Fietkau 
9117f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
9217f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
9317f1de56SFelix Fietkau 
9417f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
9517f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
9617f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
9717f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
9817f1de56SFelix Fietkau 					mt76_tpt_blink,
9917f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
10017f1de56SFelix Fietkau 
10117f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
10217f1de56SFelix Fietkau 	if (np) {
10317f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
10417f1de56SFelix Fietkau 			dev->led_pin = led_pin;
10517f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
10617f1de56SFelix Fietkau 	}
10717f1de56SFelix Fietkau 
10817f1de56SFelix Fietkau 	return devm_led_classdev_register(dev->dev, &dev->led_cdev);
10917f1de56SFelix Fietkau }
11017f1de56SFelix Fietkau 
111551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev,
112551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
113551e1ef4SLorenzo Bianconi 				 bool vht)
114551e1ef4SLorenzo Bianconi {
115551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
116d0ff23c1SBen Hutchings 	int i, nstream = hweight8(dev->antenna_mask);
117551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
118551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
119551e1ef4SLorenzo Bianconi 
120551e1ef4SLorenzo Bianconi 	if (nstream > 1)
121551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
122551e1ef4SLorenzo Bianconi 	else
123551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
124551e1ef4SLorenzo Bianconi 
125551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
126551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
127551e1ef4SLorenzo Bianconi 
128551e1ef4SLorenzo Bianconi 	if (!vht)
129551e1ef4SLorenzo Bianconi 		return;
130551e1ef4SLorenzo Bianconi 
131551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
132551e1ef4SLorenzo Bianconi 	if (nstream > 1)
133551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
134551e1ef4SLorenzo Bianconi 	else
135551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
136551e1ef4SLorenzo Bianconi 
137551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
138551e1ef4SLorenzo Bianconi 		if (i < nstream)
139551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
140551e1ef4SLorenzo Bianconi 		else
141551e1ef4SLorenzo Bianconi 			mcs_map |=
142551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
143551e1ef4SLorenzo Bianconi 	}
144551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
145551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
146551e1ef4SLorenzo Bianconi }
147551e1ef4SLorenzo Bianconi 
1485ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
1495ebdc3e0SLorenzo Bianconi {
1505ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_2ghz)
1515ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_2g.sband, false);
1525ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_5ghz)
1535ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht);
1545ebdc3e0SLorenzo Bianconi }
1555ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1565ebdc3e0SLorenzo Bianconi 
15717f1de56SFelix Fietkau static int
15817f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
15917f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
16017f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
16117f1de56SFelix Fietkau {
16217f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
16317f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
16417f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
16517f1de56SFelix Fietkau 	void *chanlist;
16617f1de56SFelix Fietkau 	int size;
16717f1de56SFelix Fietkau 
16817f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
16917f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
17017f1de56SFelix Fietkau 	if (!chanlist)
17117f1de56SFelix Fietkau 		return -ENOMEM;
17217f1de56SFelix Fietkau 
173a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
17417f1de56SFelix Fietkau 				    GFP_KERNEL);
17517f1de56SFelix Fietkau 	if (!msband->chan)
17617f1de56SFelix Fietkau 		return -ENOMEM;
17717f1de56SFelix Fietkau 
17817f1de56SFelix Fietkau 	sband->channels = chanlist;
17917f1de56SFelix Fietkau 	sband->n_channels = n_chan;
18017f1de56SFelix Fietkau 	sband->bitrates = rates;
18117f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
18217f1de56SFelix Fietkau 	dev->chandef.chan = &sband->channels[0];
1830fd0eb54SFelix Fietkau 	dev->chan_state = &msband->chan[0];
18417f1de56SFelix Fietkau 
18517f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
18617f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
18717f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
18817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
18917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
19017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
19117f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
19217f1de56SFelix Fietkau 
19317f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
19417f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
19517f1de56SFelix Fietkau 	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
19617f1de56SFelix Fietkau 
197551e1ef4SLorenzo Bianconi 	mt76_init_stream_cap(dev, sband, vht);
198551e1ef4SLorenzo Bianconi 
19917f1de56SFelix Fietkau 	if (!vht)
20017f1de56SFelix Fietkau 		return 0;
20117f1de56SFelix Fietkau 
20217f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
20317f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
20417f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
20517f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
20649149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
207f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
208f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
20949149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
21017f1de56SFelix Fietkau 
21117f1de56SFelix Fietkau 	return 0;
21217f1de56SFelix Fietkau }
21317f1de56SFelix Fietkau 
21417f1de56SFelix Fietkau static int
21517f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
21617f1de56SFelix Fietkau 		   int n_rates)
21717f1de56SFelix Fietkau {
21817f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband;
21917f1de56SFelix Fietkau 
22017f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_2g,
22117f1de56SFelix Fietkau 			       mt76_channels_2ghz,
22217f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
22317f1de56SFelix Fietkau 			       rates, n_rates, false);
22417f1de56SFelix Fietkau }
22517f1de56SFelix Fietkau 
22617f1de56SFelix Fietkau static int
22717f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22817f1de56SFelix Fietkau 		   int n_rates, bool vht)
22917f1de56SFelix Fietkau {
23017f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband;
23117f1de56SFelix Fietkau 
23217f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_5g,
23317f1de56SFelix Fietkau 			       mt76_channels_5ghz,
23417f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
23517f1de56SFelix Fietkau 			       rates, n_rates, vht);
23617f1de56SFelix Fietkau }
23717f1de56SFelix Fietkau 
23817f1de56SFelix Fietkau static void
23917f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band)
24017f1de56SFelix Fietkau {
24117f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band];
24217f1de56SFelix Fietkau 	bool found = false;
24317f1de56SFelix Fietkau 	int i;
24417f1de56SFelix Fietkau 
24517f1de56SFelix Fietkau 	if (!sband)
24617f1de56SFelix Fietkau 		return;
24717f1de56SFelix Fietkau 
24817f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
24917f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
25017f1de56SFelix Fietkau 			continue;
25117f1de56SFelix Fietkau 
25217f1de56SFelix Fietkau 		found = true;
25317f1de56SFelix Fietkau 		break;
25417f1de56SFelix Fietkau 	}
25517f1de56SFelix Fietkau 
25617f1de56SFelix Fietkau 	if (found)
25717f1de56SFelix Fietkau 		return;
25817f1de56SFelix Fietkau 
25917f1de56SFelix Fietkau 	sband->n_channels = 0;
26017f1de56SFelix Fietkau 	dev->hw->wiphy->bands[band] = NULL;
26117f1de56SFelix Fietkau }
26217f1de56SFelix Fietkau 
263a85b590cSFelix Fietkau struct mt76_dev *
264c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
265c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
266c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
267a85b590cSFelix Fietkau {
268a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
269a85b590cSFelix Fietkau 	struct mt76_dev *dev;
270a85b590cSFelix Fietkau 
271a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
272a85b590cSFelix Fietkau 	if (!hw)
273a85b590cSFelix Fietkau 		return NULL;
274a85b590cSFelix Fietkau 
275a85b590cSFelix Fietkau 	dev = hw->priv;
276a85b590cSFelix Fietkau 	dev->hw = hw;
277c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
278c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
279c0f7b25aSLorenzo Bianconi 
280a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
281a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
282a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
283108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
28426e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
28588046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
286a85b590cSFelix Fietkau 
287c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
288c325c9c7SLorenzo Bianconi 
289a85b590cSFelix Fietkau 	return dev;
290a85b590cSFelix Fietkau }
291a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
292a85b590cSFelix Fietkau 
29317f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
29417f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
29517f1de56SFelix Fietkau {
29617f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
29717f1de56SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
29817f1de56SFelix Fietkau 	int ret;
29917f1de56SFelix Fietkau 
30017f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
30117f1de56SFelix Fietkau 
30217f1de56SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
30317f1de56SFelix Fietkau 
30417f1de56SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
30517f1de56SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
30617f1de56SFelix Fietkau 
30717f1de56SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
30817f1de56SFelix Fietkau 
309b37b30afSKristian Evensen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
310b37b30afSKristian Evensen 
31124114a5fSLorenzo Bianconi 	wiphy->available_antennas_tx = dev->antenna_mask;
31224114a5fSLorenzo Bianconi 	wiphy->available_antennas_rx = dev->antenna_mask;
31324114a5fSLorenzo Bianconi 
31417f1de56SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
31517f1de56SFelix Fietkau 	hw->max_tx_fragments = 16;
31617f1de56SFelix Fietkau 
31717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
31817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
31917f1de56SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
32017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
32117f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
32217f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
32317f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
32417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
32517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
32617f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
32717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
328d71ef286SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
32988046b2cSFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
330f545540dSFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
33117f1de56SFelix Fietkau 
33217f1de56SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
33317f1de56SFelix Fietkau 
33417f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
33517f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
33617f1de56SFelix Fietkau 		if (ret)
33717f1de56SFelix Fietkau 			return ret;
33817f1de56SFelix Fietkau 	}
33917f1de56SFelix Fietkau 
34017f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
34117f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
34217f1de56SFelix Fietkau 		if (ret)
34317f1de56SFelix Fietkau 			return ret;
34417f1de56SFelix Fietkau 	}
34517f1de56SFelix Fietkau 
34617f1de56SFelix Fietkau 	wiphy_read_of_freq_limits(dev->hw->wiphy);
34717f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_2GHZ);
34817f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_5GHZ);
34917f1de56SFelix Fietkau 
350b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
35117f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
35217f1de56SFelix Fietkau 		if (ret)
35317f1de56SFelix Fietkau 			return ret;
354b374e868SArnd Bergmann 	}
35517f1de56SFelix Fietkau 
35617f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
35717f1de56SFelix Fietkau }
35817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
35917f1de56SFelix Fietkau 
36017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
36117f1de56SFelix Fietkau {
36217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
36317f1de56SFelix Fietkau 
36479d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
36517f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
36617f1de56SFelix Fietkau }
36717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
36817f1de56SFelix Fietkau 
369def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
370def34a2fSLorenzo Bianconi {
371def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
372def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
373def34a2fSLorenzo Bianconi }
374def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
375def34a2fSLorenzo Bianconi 
37617f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
37717f1de56SFelix Fietkau {
37817f1de56SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state)) {
37917f1de56SFelix Fietkau 		dev_kfree_skb(skb);
38017f1de56SFelix Fietkau 		return;
38117f1de56SFelix Fietkau 	}
38217f1de56SFelix Fietkau 
38317f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
38417f1de56SFelix Fietkau }
38517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
38617f1de56SFelix Fietkau 
38739d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev)
38826e40d4cSFelix Fietkau {
389af005f26SLorenzo Bianconi 	struct mt76_queue *q;
39026e40d4cSFelix Fietkau 	int i;
39126e40d4cSFelix Fietkau 
39226e40d4cSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
393af005f26SLorenzo Bianconi 		q = dev->q_tx[i].q;
394af005f26SLorenzo Bianconi 		if (q && q->queued)
39526e40d4cSFelix Fietkau 			return true;
39626e40d4cSFelix Fietkau 	}
39726e40d4cSFelix Fietkau 
39826e40d4cSFelix Fietkau 	return false;
39926e40d4cSFelix Fietkau }
40039d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
40126e40d4cSFelix Fietkau 
4020fd0eb54SFelix Fietkau static struct mt76_channel_state *
4030fd0eb54SFelix Fietkau mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
4040fd0eb54SFelix Fietkau {
4050fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
4060fd0eb54SFelix Fietkau 	int idx;
4070fd0eb54SFelix Fietkau 
4080fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
4090fd0eb54SFelix Fietkau 		msband = &dev->sband_2g;
4100fd0eb54SFelix Fietkau 	else
4110fd0eb54SFelix Fietkau 		msband = &dev->sband_5g;
4120fd0eb54SFelix Fietkau 
4130fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
4140fd0eb54SFelix Fietkau 	return &msband->chan[idx];
4150fd0eb54SFelix Fietkau }
4160fd0eb54SFelix Fietkau 
4175ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
4185ce09c1aSFelix Fietkau {
419aec65e48SFelix Fietkau 	struct mt76_channel_state *state = dev->chan_state;
420aec65e48SFelix Fietkau 	ktime_t cur_time;
421aec65e48SFelix Fietkau 
422aec65e48SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state))
423aec65e48SFelix Fietkau 		return;
424aec65e48SFelix Fietkau 
425aec65e48SFelix Fietkau 	spin_lock_bh(&dev->cc_lock);
4265ce09c1aSFelix Fietkau 
4275ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
4285ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
4295ce09c1aSFelix Fietkau 
430aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
431aec65e48SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(cur_time,
432aec65e48SFelix Fietkau 						  dev->survey_time));
433aec65e48SFelix Fietkau 	dev->survey_time = cur_time;
434aec65e48SFelix Fietkau 
435aec65e48SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
436aec65e48SFelix Fietkau 
4375ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
4385ce09c1aSFelix Fietkau 		spin_lock_bh(&dev->rx_lock);
4395ce09c1aSFelix Fietkau 		spin_lock(&dev->cc_lock);
4405ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
4415ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
4425ce09c1aSFelix Fietkau 		spin_unlock(&dev->cc_lock);
4435ce09c1aSFelix Fietkau 		spin_unlock_bh(&dev->rx_lock);
4445ce09c1aSFelix Fietkau 	}
4455ce09c1aSFelix Fietkau }
4465ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
4475ce09c1aSFelix Fietkau 
44817f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev)
44917f1de56SFelix Fietkau {
45017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
45117f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
45217f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
45326e40d4cSFelix Fietkau 	int timeout = HZ / 5;
45417f1de56SFelix Fietkau 
45526e40d4cSFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
4565ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
45717f1de56SFelix Fietkau 
45817f1de56SFelix Fietkau 	dev->chandef = *chandef;
4590fd0eb54SFelix Fietkau 	dev->chan_state = mt76_channel_state(dev, chandef->chan);
46017f1de56SFelix Fietkau 
46117f1de56SFelix Fietkau 	if (!offchannel)
46217f1de56SFelix Fietkau 		dev->main_chan = chandef->chan;
46317f1de56SFelix Fietkau 
4640fd0eb54SFelix Fietkau 	if (chandef->chan != dev->main_chan)
4650fd0eb54SFelix Fietkau 		memset(dev->chan_state, 0, sizeof(*dev->chan_state));
46617f1de56SFelix Fietkau }
46717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
46817f1de56SFelix Fietkau 
46917f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
47017f1de56SFelix Fietkau 		    struct survey_info *survey)
47117f1de56SFelix Fietkau {
47217f1de56SFelix Fietkau 	struct mt76_dev *dev = hw->priv;
47317f1de56SFelix Fietkau 	struct mt76_sband *sband;
47417f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
47517f1de56SFelix Fietkau 	struct mt76_channel_state *state;
47617f1de56SFelix Fietkau 	int ret = 0;
47717f1de56SFelix Fietkau 
47817f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
4795ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
48017f1de56SFelix Fietkau 
48117f1de56SFelix Fietkau 	sband = &dev->sband_2g;
48217f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
48317f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
48417f1de56SFelix Fietkau 		sband = &dev->sband_5g;
48517f1de56SFelix Fietkau 	}
48617f1de56SFelix Fietkau 
48717f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels)
48817f1de56SFelix Fietkau 		return -ENOENT;
48917f1de56SFelix Fietkau 
49017f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
49117f1de56SFelix Fietkau 	state = mt76_channel_state(dev, chan);
49217f1de56SFelix Fietkau 
49317f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
49417f1de56SFelix Fietkau 	survey->channel = chan;
49517f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
496ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
4975ce09c1aSFelix Fietkau 	if (chan == dev->main_chan) {
49817f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
49917f1de56SFelix Fietkau 
5005ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
5015ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
5025ce09c1aSFelix Fietkau 	}
5035ce09c1aSFelix Fietkau 
50417f1de56SFelix Fietkau 	spin_lock_bh(&dev->cc_lock);
50517f1de56SFelix Fietkau 	survey->time = div_u64(state->cc_active, 1000);
50617f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
5075ce09c1aSFelix Fietkau 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
508*6bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
509ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
51017f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
51117f1de56SFelix Fietkau 
51217f1de56SFelix Fietkau 	return ret;
51317f1de56SFelix Fietkau }
51417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
51517f1de56SFelix Fietkau 
51630ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
51730ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
51830ce7f44SFelix Fietkau {
51930ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
52030ce7f44SFelix Fietkau 	int i;
52130ce7f44SFelix Fietkau 
52230ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
52330ce7f44SFelix Fietkau 
52430ce7f44SFelix Fietkau 	if (!key)
52530ce7f44SFelix Fietkau 		return;
52630ce7f44SFelix Fietkau 
52701cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
52801cfc1b4SLorenzo Bianconi 		return;
52930ce7f44SFelix Fietkau 
53001cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
53130ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
53230ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
53330ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
53430ce7f44SFelix Fietkau 	}
53530ce7f44SFelix Fietkau }
53630ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
53730ce7f44SFelix Fietkau 
538ef836a71SStanislaw Gruszka static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
5394e34249eSFelix Fietkau {
5404e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5414e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
5424e34249eSFelix Fietkau 
5434e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
5444e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
5454e34249eSFelix Fietkau 
5464e34249eSFelix Fietkau 	status->flag = mstat.flag;
5474e34249eSFelix Fietkau 	status->freq = mstat.freq;
5484e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
5494e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
5504e34249eSFelix Fietkau 	status->bw = mstat.bw;
5514e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
5524e34249eSFelix Fietkau 	status->nss = mstat.nss;
5534e34249eSFelix Fietkau 	status->band = mstat.band;
5544e34249eSFelix Fietkau 	status->signal = mstat.signal;
5554e34249eSFelix Fietkau 	status->chains = mstat.chains;
556d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
5574e34249eSFelix Fietkau 
5584e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
55913381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
56013381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
56113381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
56213381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
5639c68a57bSFelix Fietkau 
5649c68a57bSFelix Fietkau 	return wcid_to_sta(mstat.wcid);
5654e34249eSFelix Fietkau }
5664e34249eSFelix Fietkau 
56730ce7f44SFelix Fietkau static int
56830ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
56930ce7f44SFelix Fietkau {
57030ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
57130ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
57230ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
57330ce7f44SFelix Fietkau 	int ret;
57430ce7f44SFelix Fietkau 
57530ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
57630ce7f44SFelix Fietkau 		return 0;
57730ce7f44SFelix Fietkau 
57830ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
57930ce7f44SFelix Fietkau 		return 0;
58030ce7f44SFelix Fietkau 
58130ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
58230ce7f44SFelix Fietkau 		/*
58330ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
58430ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
58530ce7f44SFelix Fietkau 		 */
58630ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *)skb->data;
58730ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
58830ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
58930ce7f44SFelix Fietkau 			return 0;
59030ce7f44SFelix Fietkau 	}
59130ce7f44SFelix Fietkau 
59230ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
59330ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
59430ce7f44SFelix Fietkau 		     sizeof(status->iv));
59530ce7f44SFelix Fietkau 	if (ret <= 0)
59630ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
59730ce7f44SFelix Fietkau 
59830ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
59930ce7f44SFelix Fietkau 
60030ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
60130ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
60230ce7f44SFelix Fietkau 
60330ce7f44SFelix Fietkau 	return 0;
60430ce7f44SFelix Fietkau }
60530ce7f44SFelix Fietkau 
606d71ef286SFelix Fietkau static void
6075ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
6085ce09c1aSFelix Fietkau 		    int len)
6095ce09c1aSFelix Fietkau {
6105ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
6115ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
6125ce09c1aSFelix Fietkau 	u32 airtime;
6135ce09c1aSFelix Fietkau 
6145ce09c1aSFelix Fietkau 	airtime = mt76_calc_rx_airtime(dev, status, len);
6155ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
6165ce09c1aSFelix Fietkau 
6175ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
6185ce09c1aSFelix Fietkau 		return;
6195ce09c1aSFelix Fietkau 
6205ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
6215ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
6225ce09c1aSFelix Fietkau }
6235ce09c1aSFelix Fietkau 
6245ce09c1aSFelix Fietkau static void
6255ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
6265ce09c1aSFelix Fietkau {
6275ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
6285ce09c1aSFelix Fietkau 	int wcid_idx;
6295ce09c1aSFelix Fietkau 
6305ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
6315ce09c1aSFelix Fietkau 		return;
6325ce09c1aSFelix Fietkau 
6335ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
6345ce09c1aSFelix Fietkau 	if (dev->rx_ampdu_status.wcid_idx != 0xff)
6355ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
6365ce09c1aSFelix Fietkau 	else
6375ce09c1aSFelix Fietkau 		wcid = NULL;
6385ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
6395ce09c1aSFelix Fietkau 
6405ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
6415ce09c1aSFelix Fietkau 
6425ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
6435ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
6445ce09c1aSFelix Fietkau }
6455ce09c1aSFelix Fietkau 
6465ce09c1aSFelix Fietkau static void
6475ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
6485ce09c1aSFelix Fietkau {
6495ce09c1aSFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
6505ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
6515ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
6525ce09c1aSFelix Fietkau 
6535ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
6545ce09c1aSFelix Fietkau 		return;
6555ce09c1aSFelix Fietkau 
6565ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
6575ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
6585ce09c1aSFelix Fietkau 			return;
6595ce09c1aSFelix Fietkau 
6605ce09c1aSFelix Fietkau 		wcid = NULL;
6615ce09c1aSFelix Fietkau 	}
6625ce09c1aSFelix Fietkau 
6635ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
6645ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
6655ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
6665ce09c1aSFelix Fietkau 
6675ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
6685ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
6695ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
6705ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
6715ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
6725ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
6735ce09c1aSFelix Fietkau 		}
6745ce09c1aSFelix Fietkau 
6755ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
6765ce09c1aSFelix Fietkau 		return;
6775ce09c1aSFelix Fietkau 	}
6785ce09c1aSFelix Fietkau 
6795ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
6805ce09c1aSFelix Fietkau }
6815ce09c1aSFelix Fietkau 
6825ce09c1aSFelix Fietkau static void
683ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
684d71ef286SFelix Fietkau {
685d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
686d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
687d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
688d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
689d71ef286SFelix Fietkau 	bool ps;
69090fdc171SFelix Fietkau 	int i;
691d71ef286SFelix Fietkau 
69236d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
69336d91096SFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
69436d91096SFelix Fietkau 		if (sta)
69536d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
69636d91096SFelix Fietkau 	}
69736d91096SFelix Fietkau 
6985ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
6995ce09c1aSFelix Fietkau 
700d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
701d71ef286SFelix Fietkau 		return;
702d71ef286SFelix Fietkau 
703d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
704d71ef286SFelix Fietkau 
70502e5a769SFelix Fietkau 	if (status->signal <= 0)
70602e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
70702e5a769SFelix Fietkau 
708ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
709ef13edc0SFelix Fietkau 
710d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
711d71ef286SFelix Fietkau 		return;
712d71ef286SFelix Fietkau 
713d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
714d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
715d71ef286SFelix Fietkau 		return;
716d71ef286SFelix Fietkau 	}
717d71ef286SFelix Fietkau 
718d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
719d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
720d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
721d71ef286SFelix Fietkau 		return;
722d71ef286SFelix Fietkau 
723d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
724d71ef286SFelix Fietkau 
725d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
726d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
727d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
728d71ef286SFelix Fietkau 
729d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
730d71ef286SFelix Fietkau 		return;
731d71ef286SFelix Fietkau 
73211b2a25fSFelix Fietkau 	if (ps)
733d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
73411b2a25fSFelix Fietkau 	else
735d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
736d71ef286SFelix Fietkau 
737d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
7389f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
73990fdc171SFelix Fietkau 
74090fdc171SFelix Fietkau 	if (ps)
74190fdc171SFelix Fietkau 		return;
74290fdc171SFelix Fietkau 
74390fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
74490fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
74590fdc171SFelix Fietkau 
74690fdc171SFelix Fietkau 		if (!sta->txq[i])
74790fdc171SFelix Fietkau 			continue;
74890fdc171SFelix Fietkau 
74990fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
75090fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
75190fdc171SFelix Fietkau 			ieee80211_schedule_txq(dev->hw, sta->txq[i]);
75290fdc171SFelix Fietkau 	}
753d71ef286SFelix Fietkau }
754d71ef286SFelix Fietkau 
7559d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
75681e850efSLorenzo Bianconi 		      struct napi_struct *napi)
75717f1de56SFelix Fietkau {
7589c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
7599d9d738bSFelix Fietkau 	struct sk_buff *skb;
7609d9d738bSFelix Fietkau 
761c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
7629d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
76330ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
76430ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
76530ce7f44SFelix Fietkau 			continue;
76630ce7f44SFelix Fietkau 		}
76730ce7f44SFelix Fietkau 
7689d9d738bSFelix Fietkau 		sta = mt76_rx_convert(skb);
7699d9d738bSFelix Fietkau 		ieee80211_rx_napi(dev->hw, sta, skb, napi);
7709d9d738bSFelix Fietkau 	}
771c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
7729d9d738bSFelix Fietkau }
7739d9d738bSFelix Fietkau 
77481e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
77581e850efSLorenzo Bianconi 			   struct napi_struct *napi)
7769d9d738bSFelix Fietkau {
777aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
77817f1de56SFelix Fietkau 	struct sk_buff *skb;
77917f1de56SFelix Fietkau 
780aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
781aee5b8cfSFelix Fietkau 
782d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
783ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
784aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
785d71ef286SFelix Fietkau 	}
786aee5b8cfSFelix Fietkau 
78781e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
7884e34249eSFelix Fietkau }
78981e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
790723b90dcSFelix Fietkau 
791e28487eaSFelix Fietkau static int
792e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
793e28487eaSFelix Fietkau 	     struct ieee80211_sta *sta)
794e28487eaSFelix Fietkau {
795e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
796e28487eaSFelix Fietkau 	int ret;
797e28487eaSFelix Fietkau 	int i;
798e28487eaSFelix Fietkau 
799e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
800e28487eaSFelix Fietkau 
801e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
802e28487eaSFelix Fietkau 	if (ret)
803e28487eaSFelix Fietkau 		goto out;
804e28487eaSFelix Fietkau 
805e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
806e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
807e28487eaSFelix Fietkau 
808e28487eaSFelix Fietkau 		if (!sta->txq[i])
809e28487eaSFelix Fietkau 			continue;
810e28487eaSFelix Fietkau 
811e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
812e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
813e28487eaSFelix Fietkau 
814e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
815e28487eaSFelix Fietkau 	}
816e28487eaSFelix Fietkau 
817ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
818e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
819e28487eaSFelix Fietkau 
820e28487eaSFelix Fietkau out:
821e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
822e28487eaSFelix Fietkau 
823e28487eaSFelix Fietkau 	return ret;
824e28487eaSFelix Fietkau }
825e28487eaSFelix Fietkau 
82613f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
827723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
828723b90dcSFelix Fietkau {
829723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
83013f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
831723b90dcSFelix Fietkau 
832723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
833723b90dcSFelix Fietkau 	synchronize_rcu();
834723b90dcSFelix Fietkau 
83558bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
83658bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
83758bab0d4SFelix Fietkau 
838e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
839e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
840e28487eaSFelix Fietkau 
841723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
842723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
843723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
844723b90dcSFelix Fietkau 	mt76_wcid_free(dev->wcid_mask, idx);
84513f61dfcSLorenzo Bianconi }
84613f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
847e28487eaSFelix Fietkau 
84813f61dfcSLorenzo Bianconi static void
84913f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
85013f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
85113f61dfcSLorenzo Bianconi {
85213f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
85313f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
854723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
855723b90dcSFelix Fietkau }
856e28487eaSFelix Fietkau 
857e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
858e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
859e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
860e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
861e28487eaSFelix Fietkau {
862e28487eaSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
863e28487eaSFelix Fietkau 
864e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
865e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
866e28487eaSFelix Fietkau 		return mt76_sta_add(dev, vif, sta);
867e28487eaSFelix Fietkau 
8689c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
8699c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
8709c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
8719c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
8729c193de5SFelix Fietkau 
873e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
874e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
875e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
876e28487eaSFelix Fietkau 
877e28487eaSFelix Fietkau 	return 0;
878e28487eaSFelix Fietkau }
879e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
8809313faacSFelix Fietkau 
8819313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
8829313faacSFelix Fietkau 		     int *dbm)
8839313faacSFelix Fietkau {
8849313faacSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
885d0ff23c1SBen Hutchings 	int n_chains = hweight8(dev->antenna_mask);
8869313faacSFelix Fietkau 
887cee646d6SFelix Fietkau 	*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
8889313faacSFelix Fietkau 
8899313faacSFelix Fietkau 	/* convert from per-chain power to combined
890c19b0ca5SLorenzo Bianconi 	 * output power
8919313faacSFelix Fietkau 	 */
892c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
893c19b0ca5SLorenzo Bianconi 	case 4:
894c19b0ca5SLorenzo Bianconi 		*dbm += 6;
895c19b0ca5SLorenzo Bianconi 		break;
896c19b0ca5SLorenzo Bianconi 	case 3:
897c19b0ca5SLorenzo Bianconi 		*dbm += 4;
898c19b0ca5SLorenzo Bianconi 		break;
899c19b0ca5SLorenzo Bianconi 	case 2:
9009313faacSFelix Fietkau 		*dbm += 3;
901c19b0ca5SLorenzo Bianconi 		break;
902c19b0ca5SLorenzo Bianconi 	default:
903c19b0ca5SLorenzo Bianconi 		break;
904c19b0ca5SLorenzo Bianconi 	}
9059313faacSFelix Fietkau 
9069313faacSFelix Fietkau 	return 0;
9079313faacSFelix Fietkau }
9089313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
909e7173858SFelix Fietkau 
910e7173858SFelix Fietkau static void
911e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
912e7173858SFelix Fietkau {
913e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
914e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
915e7173858SFelix Fietkau }
916e7173858SFelix Fietkau 
917e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
918e7173858SFelix Fietkau {
919e7173858SFelix Fietkau 	if (!dev->csa_complete)
920e7173858SFelix Fietkau 		return;
921e7173858SFelix Fietkau 
922e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
923e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
924e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
925e7173858SFelix Fietkau 
926e7173858SFelix Fietkau 	dev->csa_complete = 0;
927e7173858SFelix Fietkau }
928e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
929e7173858SFelix Fietkau 
930e7173858SFelix Fietkau static void
931e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
932e7173858SFelix Fietkau {
933e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
934e7173858SFelix Fietkau 
935e7173858SFelix Fietkau 	if (!vif->csa_active)
936e7173858SFelix Fietkau 		return;
937e7173858SFelix Fietkau 
938e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
939e7173858SFelix Fietkau }
940e7173858SFelix Fietkau 
941e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
942e7173858SFelix Fietkau {
943e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
944e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
945e7173858SFelix Fietkau 		__mt76_csa_check, dev);
946e7173858SFelix Fietkau }
947e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
94887d53103SStanislaw Gruszka 
94987d53103SStanislaw Gruszka int
95087d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
95187d53103SStanislaw Gruszka {
95287d53103SStanislaw Gruszka 	return 0;
95387d53103SStanislaw Gruszka }
95487d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
955eadfd98fSLorenzo Bianconi 
956eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
957eadfd98fSLorenzo Bianconi {
958eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
959eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
960eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
961eadfd98fSLorenzo Bianconi 
962eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
963eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
964eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
965eadfd98fSLorenzo Bianconi 
966eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
967eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
968eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
969eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
970eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
971eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
972eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
973eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
974eadfd98fSLorenzo Bianconi 
975eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
976eadfd98fSLorenzo Bianconi }
977eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
978d2679d65SLorenzo Bianconi 
979d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
980d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
981d2679d65SLorenzo Bianconi 		  int idx, bool cck)
982d2679d65SLorenzo Bianconi {
983d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
984d2679d65SLorenzo Bianconi 
985d2679d65SLorenzo Bianconi 	if (cck) {
986d2679d65SLorenzo Bianconi 		if (sband == &dev->sband_5g.sband)
987d2679d65SLorenzo Bianconi 			return 0;
988d2679d65SLorenzo Bianconi 
989d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
990d2679d65SLorenzo Bianconi 	} else if (sband == &dev->sband_2g.sband) {
991d2679d65SLorenzo Bianconi 		offset = 4;
992d2679d65SLorenzo Bianconi 	}
993d2679d65SLorenzo Bianconi 
994d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
995d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
996d2679d65SLorenzo Bianconi 			return i;
997d2679d65SLorenzo Bianconi 	}
998d2679d65SLorenzo Bianconi 
999d2679d65SLorenzo Bianconi 	return 0;
1000d2679d65SLorenzo Bianconi }
1001d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
10028b8ab5c2SLorenzo Bianconi 
10038b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10048b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
10058b8ab5c2SLorenzo Bianconi {
10068b8ab5c2SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
10078b8ab5c2SLorenzo Bianconi 
10088b8ab5c2SLorenzo Bianconi 	set_bit(MT76_SCANNING, &dev->state);
10098b8ab5c2SLorenzo Bianconi }
10108b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
10118b8ab5c2SLorenzo Bianconi 
10128b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
10138b8ab5c2SLorenzo Bianconi {
10148b8ab5c2SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
10158b8ab5c2SLorenzo Bianconi 
10168b8ab5c2SLorenzo Bianconi 	clear_bit(MT76_SCANNING, &dev->state);
10178b8ab5c2SLorenzo Bianconi }
10188b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1019