xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision e54432563b68592867adefa5c3ab4d7e46546e83)
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 
10836f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
10936f7e2b2SFelix Fietkau }
11036f7e2b2SFelix Fietkau 
11136f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
11236f7e2b2SFelix Fietkau {
11336f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
11436f7e2b2SFelix Fietkau 		return;
11536f7e2b2SFelix Fietkau 
11636f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
11717f1de56SFelix Fietkau }
11817f1de56SFelix Fietkau 
119551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev,
120551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
121551e1ef4SLorenzo Bianconi 				 bool vht)
122551e1ef4SLorenzo Bianconi {
123551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
124d0ff23c1SBen Hutchings 	int i, nstream = hweight8(dev->antenna_mask);
125551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
126551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
127551e1ef4SLorenzo Bianconi 
128551e1ef4SLorenzo Bianconi 	if (nstream > 1)
129551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
130551e1ef4SLorenzo Bianconi 	else
131551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
132551e1ef4SLorenzo Bianconi 
133551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
134551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
135551e1ef4SLorenzo Bianconi 
136551e1ef4SLorenzo Bianconi 	if (!vht)
137551e1ef4SLorenzo Bianconi 		return;
138551e1ef4SLorenzo Bianconi 
139551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
140551e1ef4SLorenzo Bianconi 	if (nstream > 1)
141551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
142551e1ef4SLorenzo Bianconi 	else
143551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
144551e1ef4SLorenzo Bianconi 
145551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
146551e1ef4SLorenzo Bianconi 		if (i < nstream)
147551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
148551e1ef4SLorenzo Bianconi 		else
149551e1ef4SLorenzo Bianconi 			mcs_map |=
150551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
151551e1ef4SLorenzo Bianconi 	}
152551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
153551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
154551e1ef4SLorenzo Bianconi }
155551e1ef4SLorenzo Bianconi 
1565ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
1575ebdc3e0SLorenzo Bianconi {
1585ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_2ghz)
1595ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_2g.sband, false);
1605ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_5ghz)
1615ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht);
1625ebdc3e0SLorenzo Bianconi }
1635ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1645ebdc3e0SLorenzo Bianconi 
16517f1de56SFelix Fietkau static int
16617f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
16717f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
16817f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
16917f1de56SFelix Fietkau {
17017f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
17117f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
17217f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
17317f1de56SFelix Fietkau 	void *chanlist;
17417f1de56SFelix Fietkau 	int size;
17517f1de56SFelix Fietkau 
17617f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
17717f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
17817f1de56SFelix Fietkau 	if (!chanlist)
17917f1de56SFelix Fietkau 		return -ENOMEM;
18017f1de56SFelix Fietkau 
181a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
18217f1de56SFelix Fietkau 				    GFP_KERNEL);
18317f1de56SFelix Fietkau 	if (!msband->chan)
18417f1de56SFelix Fietkau 		return -ENOMEM;
18517f1de56SFelix Fietkau 
18617f1de56SFelix Fietkau 	sband->channels = chanlist;
18717f1de56SFelix Fietkau 	sband->n_channels = n_chan;
18817f1de56SFelix Fietkau 	sband->bitrates = rates;
18917f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
19017f1de56SFelix Fietkau 	dev->chandef.chan = &sband->channels[0];
1910fd0eb54SFelix Fietkau 	dev->chan_state = &msband->chan[0];
19217f1de56SFelix Fietkau 
19317f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
19417f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
19517f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
19617f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
19717f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
19817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
19917f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
20017f1de56SFelix Fietkau 
20117f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
20217f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20317f1de56SFelix Fietkau 	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
20417f1de56SFelix Fietkau 
205551e1ef4SLorenzo Bianconi 	mt76_init_stream_cap(dev, sband, vht);
206551e1ef4SLorenzo Bianconi 
20717f1de56SFelix Fietkau 	if (!vht)
20817f1de56SFelix Fietkau 		return 0;
20917f1de56SFelix Fietkau 
21017f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
21117f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
21217f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
21317f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
21449149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
215f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
216f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
21749149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
21817f1de56SFelix Fietkau 
21917f1de56SFelix Fietkau 	return 0;
22017f1de56SFelix Fietkau }
22117f1de56SFelix Fietkau 
22217f1de56SFelix Fietkau static int
22317f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22417f1de56SFelix Fietkau 		   int n_rates)
22517f1de56SFelix Fietkau {
22617f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband;
22717f1de56SFelix Fietkau 
22817f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_2g,
22917f1de56SFelix Fietkau 			       mt76_channels_2ghz,
23017f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
23117f1de56SFelix Fietkau 			       rates, n_rates, false);
23217f1de56SFelix Fietkau }
23317f1de56SFelix Fietkau 
23417f1de56SFelix Fietkau static int
23517f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
23617f1de56SFelix Fietkau 		   int n_rates, bool vht)
23717f1de56SFelix Fietkau {
23817f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband;
23917f1de56SFelix Fietkau 
24017f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_5g,
24117f1de56SFelix Fietkau 			       mt76_channels_5ghz,
24217f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
24317f1de56SFelix Fietkau 			       rates, n_rates, vht);
24417f1de56SFelix Fietkau }
24517f1de56SFelix Fietkau 
24617f1de56SFelix Fietkau static void
24717f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band)
24817f1de56SFelix Fietkau {
24917f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band];
25017f1de56SFelix Fietkau 	bool found = false;
25117f1de56SFelix Fietkau 	int i;
25217f1de56SFelix Fietkau 
25317f1de56SFelix Fietkau 	if (!sband)
25417f1de56SFelix Fietkau 		return;
25517f1de56SFelix Fietkau 
25617f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
25717f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
25817f1de56SFelix Fietkau 			continue;
25917f1de56SFelix Fietkau 
26017f1de56SFelix Fietkau 		found = true;
26117f1de56SFelix Fietkau 		break;
26217f1de56SFelix Fietkau 	}
26317f1de56SFelix Fietkau 
26417f1de56SFelix Fietkau 	if (found)
26517f1de56SFelix Fietkau 		return;
26617f1de56SFelix Fietkau 
26717f1de56SFelix Fietkau 	sband->n_channels = 0;
26817f1de56SFelix Fietkau 	dev->hw->wiphy->bands[band] = NULL;
26917f1de56SFelix Fietkau }
27017f1de56SFelix Fietkau 
271a85b590cSFelix Fietkau struct mt76_dev *
272c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
273c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
274c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
275a85b590cSFelix Fietkau {
276a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
277a85b590cSFelix Fietkau 	struct mt76_dev *dev;
278*e5443256SFelix Fietkau 	int i;
279a85b590cSFelix Fietkau 
280a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
281a85b590cSFelix Fietkau 	if (!hw)
282a85b590cSFelix Fietkau 		return NULL;
283a85b590cSFelix Fietkau 
284a85b590cSFelix Fietkau 	dev = hw->priv;
285a85b590cSFelix Fietkau 	dev->hw = hw;
286c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
287c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
288c0f7b25aSLorenzo Bianconi 
289a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
290a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
291a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
292108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
29326e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
29488046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
295a85b590cSFelix Fietkau 
296*e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
297*e5443256SFelix Fietkau 
298*e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
299*e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
300*e5443256SFelix Fietkau 
301c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
302c325c9c7SLorenzo Bianconi 
303a85b590cSFelix Fietkau 	return dev;
304a85b590cSFelix Fietkau }
305a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
306a85b590cSFelix Fietkau 
30717f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
30817f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
30917f1de56SFelix Fietkau {
31017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
31117f1de56SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
31217f1de56SFelix Fietkau 	int ret;
31317f1de56SFelix Fietkau 
31417f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
31517f1de56SFelix Fietkau 
31617f1de56SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
31717f1de56SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
31817f1de56SFelix Fietkau 
31917f1de56SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
32017f1de56SFelix Fietkau 
321b37b30afSKristian Evensen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
32255857ab8SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
323b37b30afSKristian Evensen 
32424114a5fSLorenzo Bianconi 	wiphy->available_antennas_tx = dev->antenna_mask;
32524114a5fSLorenzo Bianconi 	wiphy->available_antennas_rx = dev->antenna_mask;
32624114a5fSLorenzo Bianconi 
32717f1de56SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
32817f1de56SFelix Fietkau 	hw->max_tx_fragments = 16;
32917f1de56SFelix Fietkau 
33017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
33117f1de56SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
33217f1de56SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
33317f1de56SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
33417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
33517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
33617f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
33717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
33817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
33917f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
34017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
341d71ef286SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
34288046b2cSFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
343f545540dSFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
34419d0affaSLorenzo Bianconi 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
34517f1de56SFelix Fietkau 
34617f1de56SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
3470eb8c104SLorenzo Bianconi 	wiphy->interface_modes =
3480eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
3490eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
3500eb8c104SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
3510eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
3520eb8c104SLorenzo Bianconi #endif
3530eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
35417f1de56SFelix Fietkau 
35517f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
35617f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
35717f1de56SFelix Fietkau 		if (ret)
35817f1de56SFelix Fietkau 			return ret;
35917f1de56SFelix Fietkau 	}
36017f1de56SFelix Fietkau 
36117f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
36217f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
36317f1de56SFelix Fietkau 		if (ret)
36417f1de56SFelix Fietkau 			return ret;
36517f1de56SFelix Fietkau 	}
36617f1de56SFelix Fietkau 
36717f1de56SFelix Fietkau 	wiphy_read_of_freq_limits(dev->hw->wiphy);
36817f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_2GHZ);
36917f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_5GHZ);
37017f1de56SFelix Fietkau 
371b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
37217f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
37317f1de56SFelix Fietkau 		if (ret)
37417f1de56SFelix Fietkau 			return ret;
375b374e868SArnd Bergmann 	}
37617f1de56SFelix Fietkau 
37717f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
37817f1de56SFelix Fietkau }
37917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
38017f1de56SFelix Fietkau 
38117f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
38217f1de56SFelix Fietkau {
38317f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
38417f1de56SFelix Fietkau 
385d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
38636f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
38779d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
38817f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
38917f1de56SFelix Fietkau }
39017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
39117f1de56SFelix Fietkau 
392def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
393def34a2fSLorenzo Bianconi {
394def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
395def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
396def34a2fSLorenzo Bianconi }
397def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
398def34a2fSLorenzo Bianconi 
39917f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
40017f1de56SFelix Fietkau {
40117f1de56SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state)) {
40217f1de56SFelix Fietkau 		dev_kfree_skb(skb);
40317f1de56SFelix Fietkau 		return;
40417f1de56SFelix Fietkau 	}
40517f1de56SFelix Fietkau 
40617f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
40717f1de56SFelix Fietkau }
40817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
40917f1de56SFelix Fietkau 
41039d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev)
41126e40d4cSFelix Fietkau {
412af005f26SLorenzo Bianconi 	struct mt76_queue *q;
41326e40d4cSFelix Fietkau 	int i;
41426e40d4cSFelix Fietkau 
41526e40d4cSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
416af005f26SLorenzo Bianconi 		q = dev->q_tx[i].q;
417af005f26SLorenzo Bianconi 		if (q && q->queued)
41826e40d4cSFelix Fietkau 			return true;
41926e40d4cSFelix Fietkau 	}
42026e40d4cSFelix Fietkau 
42126e40d4cSFelix Fietkau 	return false;
42226e40d4cSFelix Fietkau }
42339d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
42426e40d4cSFelix Fietkau 
4250fd0eb54SFelix Fietkau static struct mt76_channel_state *
4260fd0eb54SFelix Fietkau mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
4270fd0eb54SFelix Fietkau {
4280fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
4290fd0eb54SFelix Fietkau 	int idx;
4300fd0eb54SFelix Fietkau 
4310fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
4320fd0eb54SFelix Fietkau 		msband = &dev->sband_2g;
4330fd0eb54SFelix Fietkau 	else
4340fd0eb54SFelix Fietkau 		msband = &dev->sband_5g;
4350fd0eb54SFelix Fietkau 
4360fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
4370fd0eb54SFelix Fietkau 	return &msband->chan[idx];
4380fd0eb54SFelix Fietkau }
4390fd0eb54SFelix Fietkau 
4405ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
4415ce09c1aSFelix Fietkau {
442aec65e48SFelix Fietkau 	struct mt76_channel_state *state = dev->chan_state;
443aec65e48SFelix Fietkau 	ktime_t cur_time;
444aec65e48SFelix Fietkau 
445aec65e48SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state))
446aec65e48SFelix Fietkau 		return;
447aec65e48SFelix Fietkau 
4485ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
4495ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
4505ce09c1aSFelix Fietkau 
451aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
452aec65e48SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(cur_time,
453aec65e48SFelix Fietkau 						  dev->survey_time));
454aec65e48SFelix Fietkau 	dev->survey_time = cur_time;
455aec65e48SFelix Fietkau 
4565ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
457237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
4585ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
4595ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
460237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
4615ce09c1aSFelix Fietkau 	}
4625ce09c1aSFelix Fietkau }
4635ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
4645ce09c1aSFelix Fietkau 
46517f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev)
46617f1de56SFelix Fietkau {
46717f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
46817f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
46917f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
47026e40d4cSFelix Fietkau 	int timeout = HZ / 5;
47117f1de56SFelix Fietkau 
47226e40d4cSFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
4735ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
47417f1de56SFelix Fietkau 
47517f1de56SFelix Fietkau 	dev->chandef = *chandef;
4760fd0eb54SFelix Fietkau 	dev->chan_state = mt76_channel_state(dev, chandef->chan);
47717f1de56SFelix Fietkau 
47817f1de56SFelix Fietkau 	if (!offchannel)
47917f1de56SFelix Fietkau 		dev->main_chan = chandef->chan;
48017f1de56SFelix Fietkau 
4810fd0eb54SFelix Fietkau 	if (chandef->chan != dev->main_chan)
4820fd0eb54SFelix Fietkau 		memset(dev->chan_state, 0, sizeof(*dev->chan_state));
48317f1de56SFelix Fietkau }
48417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
48517f1de56SFelix Fietkau 
48617f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
48717f1de56SFelix Fietkau 		    struct survey_info *survey)
48817f1de56SFelix Fietkau {
48917f1de56SFelix Fietkau 	struct mt76_dev *dev = hw->priv;
49017f1de56SFelix Fietkau 	struct mt76_sband *sband;
49117f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
49217f1de56SFelix Fietkau 	struct mt76_channel_state *state;
49317f1de56SFelix Fietkau 	int ret = 0;
49417f1de56SFelix Fietkau 
495237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
49617f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
4975ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
49817f1de56SFelix Fietkau 
49917f1de56SFelix Fietkau 	sband = &dev->sband_2g;
50017f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
50117f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
50217f1de56SFelix Fietkau 		sband = &dev->sband_5g;
50317f1de56SFelix Fietkau 	}
50417f1de56SFelix Fietkau 
505237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
506237312c5SLorenzo Bianconi 		ret = -ENOENT;
507237312c5SLorenzo Bianconi 		goto out;
508237312c5SLorenzo Bianconi 	}
50917f1de56SFelix Fietkau 
51017f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
51117f1de56SFelix Fietkau 	state = mt76_channel_state(dev, chan);
51217f1de56SFelix Fietkau 
51317f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
51417f1de56SFelix Fietkau 	survey->channel = chan;
51517f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
516ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
5175ce09c1aSFelix Fietkau 	if (chan == dev->main_chan) {
51817f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
51917f1de56SFelix Fietkau 
5205ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
5215ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
5225ce09c1aSFelix Fietkau 	}
5235ce09c1aSFelix Fietkau 
52417f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
5256bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
526237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
527237312c5SLorenzo Bianconi 
528237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
529237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
530ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
53117f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
53217f1de56SFelix Fietkau 
533237312c5SLorenzo Bianconi out:
534237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
535237312c5SLorenzo Bianconi 
53617f1de56SFelix Fietkau 	return ret;
53717f1de56SFelix Fietkau }
53817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
53917f1de56SFelix Fietkau 
54030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
54130ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
54230ce7f44SFelix Fietkau {
54330ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
54430ce7f44SFelix Fietkau 	int i;
54530ce7f44SFelix Fietkau 
54630ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
54730ce7f44SFelix Fietkau 
54830ce7f44SFelix Fietkau 	if (!key)
54930ce7f44SFelix Fietkau 		return;
55030ce7f44SFelix Fietkau 
55101cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
55201cfc1b4SLorenzo Bianconi 		return;
55330ce7f44SFelix Fietkau 
55401cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
55530ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
55630ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
55730ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
55830ce7f44SFelix Fietkau 	}
55930ce7f44SFelix Fietkau }
56030ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
56130ce7f44SFelix Fietkau 
562ef836a71SStanislaw Gruszka static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
5634e34249eSFelix Fietkau {
5644e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5654e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
5664e34249eSFelix Fietkau 
5674e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
5684e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
5694e34249eSFelix Fietkau 
5704e34249eSFelix Fietkau 	status->flag = mstat.flag;
5714e34249eSFelix Fietkau 	status->freq = mstat.freq;
5724e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
5734e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
5744e34249eSFelix Fietkau 	status->bw = mstat.bw;
5754e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
5764e34249eSFelix Fietkau 	status->nss = mstat.nss;
5774e34249eSFelix Fietkau 	status->band = mstat.band;
5784e34249eSFelix Fietkau 	status->signal = mstat.signal;
5794e34249eSFelix Fietkau 	status->chains = mstat.chains;
580d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
5814e34249eSFelix Fietkau 
5824e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
58313381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
58413381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
58513381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
58613381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
5879c68a57bSFelix Fietkau 
5889c68a57bSFelix Fietkau 	return wcid_to_sta(mstat.wcid);
5894e34249eSFelix Fietkau }
5904e34249eSFelix Fietkau 
59130ce7f44SFelix Fietkau static int
59230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
59330ce7f44SFelix Fietkau {
59430ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
59530ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
59630ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
59730ce7f44SFelix Fietkau 	int ret;
59830ce7f44SFelix Fietkau 
59930ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
60030ce7f44SFelix Fietkau 		return 0;
60130ce7f44SFelix Fietkau 
60230ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
60330ce7f44SFelix Fietkau 		return 0;
60430ce7f44SFelix Fietkau 
60530ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
60630ce7f44SFelix Fietkau 		/*
60730ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
60830ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
60930ce7f44SFelix Fietkau 		 */
61030ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *)skb->data;
61130ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
61230ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
61330ce7f44SFelix Fietkau 			return 0;
61430ce7f44SFelix Fietkau 	}
61530ce7f44SFelix Fietkau 
61630ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
61730ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
61830ce7f44SFelix Fietkau 		     sizeof(status->iv));
61930ce7f44SFelix Fietkau 	if (ret <= 0)
62030ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
62130ce7f44SFelix Fietkau 
62230ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
62330ce7f44SFelix Fietkau 
62430ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
62530ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
62630ce7f44SFelix Fietkau 
62730ce7f44SFelix Fietkau 	return 0;
62830ce7f44SFelix Fietkau }
62930ce7f44SFelix Fietkau 
630d71ef286SFelix Fietkau static void
6315ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
6325ce09c1aSFelix Fietkau 		    int len)
6335ce09c1aSFelix Fietkau {
6345ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
6355ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
6365ce09c1aSFelix Fietkau 	u32 airtime;
6375ce09c1aSFelix Fietkau 
6385ce09c1aSFelix Fietkau 	airtime = mt76_calc_rx_airtime(dev, status, len);
639237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
6405ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
641237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
6425ce09c1aSFelix Fietkau 
6435ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
6445ce09c1aSFelix Fietkau 		return;
6455ce09c1aSFelix Fietkau 
6465ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
6475ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
6485ce09c1aSFelix Fietkau }
6495ce09c1aSFelix Fietkau 
6505ce09c1aSFelix Fietkau static void
6515ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
6525ce09c1aSFelix Fietkau {
6535ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
6545ce09c1aSFelix Fietkau 	int wcid_idx;
6555ce09c1aSFelix Fietkau 
6565ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
6575ce09c1aSFelix Fietkau 		return;
6585ce09c1aSFelix Fietkau 
6595ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
660bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
6615ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
6625ce09c1aSFelix Fietkau 	else
6635ce09c1aSFelix Fietkau 		wcid = NULL;
6645ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
6655ce09c1aSFelix Fietkau 
6665ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
6675ce09c1aSFelix Fietkau 
6685ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
6695ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
6705ce09c1aSFelix Fietkau }
6715ce09c1aSFelix Fietkau 
6725ce09c1aSFelix Fietkau static void
6735ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
6745ce09c1aSFelix Fietkau {
6755ce09c1aSFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
6765ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
6775ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
6785ce09c1aSFelix Fietkau 
6795ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
6805ce09c1aSFelix Fietkau 		return;
6815ce09c1aSFelix Fietkau 
6825ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
6835ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
6845ce09c1aSFelix Fietkau 			return;
6855ce09c1aSFelix Fietkau 
6865ce09c1aSFelix Fietkau 		wcid = NULL;
6875ce09c1aSFelix Fietkau 	}
6885ce09c1aSFelix Fietkau 
6895ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
6905ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
6915ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
6925ce09c1aSFelix Fietkau 
6935ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
6945ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
6955ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
6965ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
6975ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
6985ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
6995ce09c1aSFelix Fietkau 		}
7005ce09c1aSFelix Fietkau 
7015ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
7025ce09c1aSFelix Fietkau 		return;
7035ce09c1aSFelix Fietkau 	}
7045ce09c1aSFelix Fietkau 
7055ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
7065ce09c1aSFelix Fietkau }
7075ce09c1aSFelix Fietkau 
7085ce09c1aSFelix Fietkau static void
709ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
710d71ef286SFelix Fietkau {
711d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
712d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
713d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
714d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
715d71ef286SFelix Fietkau 	bool ps;
71690fdc171SFelix Fietkau 	int i;
717d71ef286SFelix Fietkau 
71836d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
71936d91096SFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
72036d91096SFelix Fietkau 		if (sta)
72136d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
72236d91096SFelix Fietkau 	}
72336d91096SFelix Fietkau 
7245ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
7255ce09c1aSFelix Fietkau 
726d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
727d71ef286SFelix Fietkau 		return;
728d71ef286SFelix Fietkau 
729d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
730d71ef286SFelix Fietkau 
73102e5a769SFelix Fietkau 	if (status->signal <= 0)
73202e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
73302e5a769SFelix Fietkau 
734ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
735ef13edc0SFelix Fietkau 
736d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
737d71ef286SFelix Fietkau 		return;
738d71ef286SFelix Fietkau 
739d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
740d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
741d71ef286SFelix Fietkau 		return;
742d71ef286SFelix Fietkau 	}
743d71ef286SFelix Fietkau 
744d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
745d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
746d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
747d71ef286SFelix Fietkau 		return;
748d71ef286SFelix Fietkau 
749d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
750d71ef286SFelix Fietkau 
751d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
752d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
753d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
754d71ef286SFelix Fietkau 
755d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
756d71ef286SFelix Fietkau 		return;
757d71ef286SFelix Fietkau 
75811b2a25fSFelix Fietkau 	if (ps)
759d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
76011b2a25fSFelix Fietkau 	else
761d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
762d71ef286SFelix Fietkau 
763d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
7649f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
76590fdc171SFelix Fietkau 
76690fdc171SFelix Fietkau 	if (ps)
76790fdc171SFelix Fietkau 		return;
76890fdc171SFelix Fietkau 
76990fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
77090fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
77190fdc171SFelix Fietkau 
77290fdc171SFelix Fietkau 		if (!sta->txq[i])
77390fdc171SFelix Fietkau 			continue;
77490fdc171SFelix Fietkau 
77590fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
77690fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
77790fdc171SFelix Fietkau 			ieee80211_schedule_txq(dev->hw, sta->txq[i]);
77890fdc171SFelix Fietkau 	}
779d71ef286SFelix Fietkau }
780d71ef286SFelix Fietkau 
7819d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
78281e850efSLorenzo Bianconi 		      struct napi_struct *napi)
78317f1de56SFelix Fietkau {
7849c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
7859d9d738bSFelix Fietkau 	struct sk_buff *skb;
7869d9d738bSFelix Fietkau 
787c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
7889d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
78930ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
79030ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
79130ce7f44SFelix Fietkau 			continue;
79230ce7f44SFelix Fietkau 		}
79330ce7f44SFelix Fietkau 
7949d9d738bSFelix Fietkau 		sta = mt76_rx_convert(skb);
7959d9d738bSFelix Fietkau 		ieee80211_rx_napi(dev->hw, sta, skb, napi);
7969d9d738bSFelix Fietkau 	}
797c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
7989d9d738bSFelix Fietkau }
7999d9d738bSFelix Fietkau 
80081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
80181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
8029d9d738bSFelix Fietkau {
803aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
80417f1de56SFelix Fietkau 	struct sk_buff *skb;
80517f1de56SFelix Fietkau 
806aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
807aee5b8cfSFelix Fietkau 
808d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
809ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
810aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
811d71ef286SFelix Fietkau 	}
812aee5b8cfSFelix Fietkau 
81381e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
8144e34249eSFelix Fietkau }
81581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
816723b90dcSFelix Fietkau 
817e28487eaSFelix Fietkau static int
818e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
819e28487eaSFelix Fietkau 	     struct ieee80211_sta *sta)
820e28487eaSFelix Fietkau {
821e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
822e28487eaSFelix Fietkau 	int ret;
823e28487eaSFelix Fietkau 	int i;
824e28487eaSFelix Fietkau 
825e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
826e28487eaSFelix Fietkau 
827e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
828e28487eaSFelix Fietkau 	if (ret)
829e28487eaSFelix Fietkau 		goto out;
830e28487eaSFelix Fietkau 
831e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
832e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
833e28487eaSFelix Fietkau 
834e28487eaSFelix Fietkau 		if (!sta->txq[i])
835e28487eaSFelix Fietkau 			continue;
836e28487eaSFelix Fietkau 
837e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
838e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
839e28487eaSFelix Fietkau 
840e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
841e28487eaSFelix Fietkau 	}
842e28487eaSFelix Fietkau 
843ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
844e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
845e28487eaSFelix Fietkau 
846e28487eaSFelix Fietkau out:
847e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
848e28487eaSFelix Fietkau 
849e28487eaSFelix Fietkau 	return ret;
850e28487eaSFelix Fietkau }
851e28487eaSFelix Fietkau 
85213f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
853723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
854723b90dcSFelix Fietkau {
855723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
85613f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
857723b90dcSFelix Fietkau 
858723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
859723b90dcSFelix Fietkau 	synchronize_rcu();
860723b90dcSFelix Fietkau 
86158bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
86258bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
86358bab0d4SFelix Fietkau 
864e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
865e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
866e28487eaSFelix Fietkau 
867723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
868723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
869723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
870723b90dcSFelix Fietkau 	mt76_wcid_free(dev->wcid_mask, idx);
87113f61dfcSLorenzo Bianconi }
87213f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
873e28487eaSFelix Fietkau 
87413f61dfcSLorenzo Bianconi static void
87513f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
87613f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
87713f61dfcSLorenzo Bianconi {
87813f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
87913f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
880723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
881723b90dcSFelix Fietkau }
882e28487eaSFelix Fietkau 
883e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
884e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
885e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
886e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
887e28487eaSFelix Fietkau {
888e28487eaSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
889e28487eaSFelix Fietkau 
890e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
891e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
892e28487eaSFelix Fietkau 		return mt76_sta_add(dev, vif, sta);
893e28487eaSFelix Fietkau 
8949c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
8959c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
8969c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
8979c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
8989c193de5SFelix Fietkau 
899e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
900e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
901e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
902e28487eaSFelix Fietkau 
903e28487eaSFelix Fietkau 	return 0;
904e28487eaSFelix Fietkau }
905e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
9069313faacSFelix Fietkau 
9079313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
9089313faacSFelix Fietkau 		     int *dbm)
9099313faacSFelix Fietkau {
9109313faacSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
911d0ff23c1SBen Hutchings 	int n_chains = hweight8(dev->antenna_mask);
9129313faacSFelix Fietkau 
913cee646d6SFelix Fietkau 	*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
9149313faacSFelix Fietkau 
9159313faacSFelix Fietkau 	/* convert from per-chain power to combined
916c19b0ca5SLorenzo Bianconi 	 * output power
9179313faacSFelix Fietkau 	 */
918c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
919c19b0ca5SLorenzo Bianconi 	case 4:
920c19b0ca5SLorenzo Bianconi 		*dbm += 6;
921c19b0ca5SLorenzo Bianconi 		break;
922c19b0ca5SLorenzo Bianconi 	case 3:
923c19b0ca5SLorenzo Bianconi 		*dbm += 4;
924c19b0ca5SLorenzo Bianconi 		break;
925c19b0ca5SLorenzo Bianconi 	case 2:
9269313faacSFelix Fietkau 		*dbm += 3;
927c19b0ca5SLorenzo Bianconi 		break;
928c19b0ca5SLorenzo Bianconi 	default:
929c19b0ca5SLorenzo Bianconi 		break;
930c19b0ca5SLorenzo Bianconi 	}
9319313faacSFelix Fietkau 
9329313faacSFelix Fietkau 	return 0;
9339313faacSFelix Fietkau }
9349313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
935e7173858SFelix Fietkau 
936e7173858SFelix Fietkau static void
937e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
938e7173858SFelix Fietkau {
939e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
940e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
941e7173858SFelix Fietkau }
942e7173858SFelix Fietkau 
943e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
944e7173858SFelix Fietkau {
945e7173858SFelix Fietkau 	if (!dev->csa_complete)
946e7173858SFelix Fietkau 		return;
947e7173858SFelix Fietkau 
948e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
949e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
950e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
951e7173858SFelix Fietkau 
952e7173858SFelix Fietkau 	dev->csa_complete = 0;
953e7173858SFelix Fietkau }
954e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
955e7173858SFelix Fietkau 
956e7173858SFelix Fietkau static void
957e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
958e7173858SFelix Fietkau {
959e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
960e7173858SFelix Fietkau 
961e7173858SFelix Fietkau 	if (!vif->csa_active)
962e7173858SFelix Fietkau 		return;
963e7173858SFelix Fietkau 
964e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
965e7173858SFelix Fietkau }
966e7173858SFelix Fietkau 
967e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
968e7173858SFelix Fietkau {
969e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
970e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
971e7173858SFelix Fietkau 		__mt76_csa_check, dev);
972e7173858SFelix Fietkau }
973e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
97487d53103SStanislaw Gruszka 
97587d53103SStanislaw Gruszka int
97687d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
97787d53103SStanislaw Gruszka {
97887d53103SStanislaw Gruszka 	return 0;
97987d53103SStanislaw Gruszka }
98087d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
981eadfd98fSLorenzo Bianconi 
982eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
983eadfd98fSLorenzo Bianconi {
984eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
985eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
986eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
987eadfd98fSLorenzo Bianconi 
988eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
989eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
990eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
991eadfd98fSLorenzo Bianconi 
992eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
993eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
994eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
995eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
996eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
997eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
998eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
999eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1000eadfd98fSLorenzo Bianconi 
1001eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1002eadfd98fSLorenzo Bianconi }
1003eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1004d2679d65SLorenzo Bianconi 
1005d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1006d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1007d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1008d2679d65SLorenzo Bianconi {
1009d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1010d2679d65SLorenzo Bianconi 
1011d2679d65SLorenzo Bianconi 	if (cck) {
1012d2679d65SLorenzo Bianconi 		if (sband == &dev->sband_5g.sband)
1013d2679d65SLorenzo Bianconi 			return 0;
1014d2679d65SLorenzo Bianconi 
1015d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
1016d2679d65SLorenzo Bianconi 	} else if (sband == &dev->sband_2g.sband) {
1017d2679d65SLorenzo Bianconi 		offset = 4;
1018d2679d65SLorenzo Bianconi 	}
1019d2679d65SLorenzo Bianconi 
1020d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1021d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1022d2679d65SLorenzo Bianconi 			return i;
1023d2679d65SLorenzo Bianconi 	}
1024d2679d65SLorenzo Bianconi 
1025d2679d65SLorenzo Bianconi 	return 0;
1026d2679d65SLorenzo Bianconi }
1027d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
10288b8ab5c2SLorenzo Bianconi 
10298b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10308b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
10318b8ab5c2SLorenzo Bianconi {
10328b8ab5c2SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
10338b8ab5c2SLorenzo Bianconi 
10348b8ab5c2SLorenzo Bianconi 	set_bit(MT76_SCANNING, &dev->state);
10358b8ab5c2SLorenzo Bianconi }
10368b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
10378b8ab5c2SLorenzo Bianconi 
10388b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
10398b8ab5c2SLorenzo Bianconi {
10408b8ab5c2SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
10418b8ab5c2SLorenzo Bianconi 
10428b8ab5c2SLorenzo Bianconi 	clear_bit(MT76_SCANNING, &dev->state);
10438b8ab5c2SLorenzo Bianconi }
10448b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1045e49c76d4SLorenzo Bianconi 
1046e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1047e49c76d4SLorenzo Bianconi {
1048e49c76d4SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
1049e49c76d4SLorenzo Bianconi 
1050e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1051e49c76d4SLorenzo Bianconi 	*tx_ant = dev->antenna_mask;
1052e49c76d4SLorenzo Bianconi 	*rx_ant = dev->antenna_mask;
1053e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1054e49c76d4SLorenzo Bianconi 
1055e49c76d4SLorenzo Bianconi 	return 0;
1056e49c76d4SLorenzo Bianconi }
1057e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1058