xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision bfc394dd65ef474142027123b96fd1f01ec46f85)
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;
277ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
278a85b590cSFelix Fietkau 	struct mt76_dev *dev;
279e5443256SFelix Fietkau 	int i;
280a85b590cSFelix Fietkau 
281a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
282a85b590cSFelix Fietkau 	if (!hw)
283a85b590cSFelix Fietkau 		return NULL;
284a85b590cSFelix Fietkau 
285a85b590cSFelix Fietkau 	dev = hw->priv;
286a85b590cSFelix Fietkau 	dev->hw = hw;
287c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
288c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
289c0f7b25aSLorenzo Bianconi 
290ac24dd35SFelix Fietkau 	phy = &dev->phy;
291ac24dd35SFelix Fietkau 	phy->dev = dev;
292ac24dd35SFelix Fietkau 	phy->hw = hw;
293ac24dd35SFelix Fietkau 
294a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
295a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
296a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
297108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
29826e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
29988046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
300a85b590cSFelix Fietkau 
301e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
302e5443256SFelix Fietkau 
303e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
304e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
305e5443256SFelix Fietkau 
306c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
307c325c9c7SLorenzo Bianconi 
308a85b590cSFelix Fietkau 	return dev;
309a85b590cSFelix Fietkau }
310a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
311a85b590cSFelix Fietkau 
31217f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
31317f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
31417f1de56SFelix Fietkau {
31517f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
31617f1de56SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
31717f1de56SFelix Fietkau 	int ret;
31817f1de56SFelix Fietkau 
31917f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
32017f1de56SFelix Fietkau 
32117f1de56SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
32217f1de56SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
32317f1de56SFelix Fietkau 
32417f1de56SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
32517f1de56SFelix Fietkau 
326b37b30afSKristian Evensen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
32755857ab8SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
328b37b30afSKristian Evensen 
32924114a5fSLorenzo Bianconi 	wiphy->available_antennas_tx = dev->antenna_mask;
33024114a5fSLorenzo Bianconi 	wiphy->available_antennas_rx = dev->antenna_mask;
33124114a5fSLorenzo Bianconi 
33217f1de56SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
33317f1de56SFelix Fietkau 	hw->max_tx_fragments = 16;
33417f1de56SFelix Fietkau 
33517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
33617f1de56SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
33717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
33817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
33917f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
34017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
34117f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
34217f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
34317f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
34417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
34517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
346d71ef286SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
34788046b2cSFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
348f545540dSFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
34919d0affaSLorenzo Bianconi 	ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
35017f1de56SFelix Fietkau 
35117f1de56SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
3520eb8c104SLorenzo Bianconi 	wiphy->interface_modes =
3530eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_STATION) |
3540eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_AP) |
3550eb8c104SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
3560eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_MESH_POINT) |
3570eb8c104SLorenzo Bianconi #endif
3580eb8c104SLorenzo Bianconi 		BIT(NL80211_IFTYPE_ADHOC);
35917f1de56SFelix Fietkau 
36017f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
36117f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
36217f1de56SFelix Fietkau 		if (ret)
36317f1de56SFelix Fietkau 			return ret;
36417f1de56SFelix Fietkau 	}
36517f1de56SFelix Fietkau 
36617f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
36717f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
36817f1de56SFelix Fietkau 		if (ret)
36917f1de56SFelix Fietkau 			return ret;
37017f1de56SFelix Fietkau 	}
37117f1de56SFelix Fietkau 
37217f1de56SFelix Fietkau 	wiphy_read_of_freq_limits(dev->hw->wiphy);
37317f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_2GHZ);
37417f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_5GHZ);
37517f1de56SFelix Fietkau 
376b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
37717f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
37817f1de56SFelix Fietkau 		if (ret)
37917f1de56SFelix Fietkau 			return ret;
380b374e868SArnd Bergmann 	}
38117f1de56SFelix Fietkau 
38217f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
38317f1de56SFelix Fietkau }
38417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
38517f1de56SFelix Fietkau 
38617f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
38717f1de56SFelix Fietkau {
38817f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
38917f1de56SFelix Fietkau 
390d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
39136f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
39279d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
39317f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
39417f1de56SFelix Fietkau }
39517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
39617f1de56SFelix Fietkau 
397def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
398def34a2fSLorenzo Bianconi {
399def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
400def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
401def34a2fSLorenzo Bianconi }
402def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
403def34a2fSLorenzo Bianconi 
40417f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
40517f1de56SFelix Fietkau {
40617f1de56SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state)) {
40717f1de56SFelix Fietkau 		dev_kfree_skb(skb);
40817f1de56SFelix Fietkau 		return;
40917f1de56SFelix Fietkau 	}
41017f1de56SFelix Fietkau 
41117f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
41217f1de56SFelix Fietkau }
41317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
41417f1de56SFelix Fietkau 
41539d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev)
41626e40d4cSFelix Fietkau {
417af005f26SLorenzo Bianconi 	struct mt76_queue *q;
41826e40d4cSFelix Fietkau 	int i;
41926e40d4cSFelix Fietkau 
42026e40d4cSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
421af005f26SLorenzo Bianconi 		q = dev->q_tx[i].q;
422af005f26SLorenzo Bianconi 		if (q && q->queued)
42326e40d4cSFelix Fietkau 			return true;
42426e40d4cSFelix Fietkau 	}
42526e40d4cSFelix Fietkau 
42626e40d4cSFelix Fietkau 	return false;
42726e40d4cSFelix Fietkau }
42839d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
42926e40d4cSFelix Fietkau 
4300fd0eb54SFelix Fietkau static struct mt76_channel_state *
4310fd0eb54SFelix Fietkau mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
4320fd0eb54SFelix Fietkau {
4330fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
4340fd0eb54SFelix Fietkau 	int idx;
4350fd0eb54SFelix Fietkau 
4360fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
4370fd0eb54SFelix Fietkau 		msband = &dev->sband_2g;
4380fd0eb54SFelix Fietkau 	else
4390fd0eb54SFelix Fietkau 		msband = &dev->sband_5g;
4400fd0eb54SFelix Fietkau 
4410fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
4420fd0eb54SFelix Fietkau 	return &msband->chan[idx];
4430fd0eb54SFelix Fietkau }
4440fd0eb54SFelix Fietkau 
4455ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
4465ce09c1aSFelix Fietkau {
447aec65e48SFelix Fietkau 	struct mt76_channel_state *state = dev->chan_state;
448aec65e48SFelix Fietkau 	ktime_t cur_time;
449aec65e48SFelix Fietkau 
450aec65e48SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state))
451aec65e48SFelix Fietkau 		return;
452aec65e48SFelix Fietkau 
4535ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
4545ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
4555ce09c1aSFelix Fietkau 
456aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
457aec65e48SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(cur_time,
458aec65e48SFelix Fietkau 						  dev->survey_time));
459aec65e48SFelix Fietkau 	dev->survey_time = cur_time;
460aec65e48SFelix Fietkau 
4615ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
462237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
4635ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
4645ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
465237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
4665ce09c1aSFelix Fietkau 	}
4675ce09c1aSFelix Fietkau }
4685ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
4695ce09c1aSFelix Fietkau 
47017f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev)
47117f1de56SFelix Fietkau {
47217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
47317f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
47417f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
47526e40d4cSFelix Fietkau 	int timeout = HZ / 5;
47617f1de56SFelix Fietkau 
47726e40d4cSFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
4785ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
47917f1de56SFelix Fietkau 
48017f1de56SFelix Fietkau 	dev->chandef = *chandef;
4810fd0eb54SFelix Fietkau 	dev->chan_state = mt76_channel_state(dev, chandef->chan);
48217f1de56SFelix Fietkau 
48317f1de56SFelix Fietkau 	if (!offchannel)
48417f1de56SFelix Fietkau 		dev->main_chan = chandef->chan;
48517f1de56SFelix Fietkau 
4860fd0eb54SFelix Fietkau 	if (chandef->chan != dev->main_chan)
4870fd0eb54SFelix Fietkau 		memset(dev->chan_state, 0, sizeof(*dev->chan_state));
48817f1de56SFelix Fietkau }
48917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
49017f1de56SFelix Fietkau 
49117f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
49217f1de56SFelix Fietkau 		    struct survey_info *survey)
49317f1de56SFelix Fietkau {
49417f1de56SFelix Fietkau 	struct mt76_dev *dev = hw->priv;
49517f1de56SFelix Fietkau 	struct mt76_sband *sband;
49617f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
49717f1de56SFelix Fietkau 	struct mt76_channel_state *state;
49817f1de56SFelix Fietkau 	int ret = 0;
49917f1de56SFelix Fietkau 
500237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
50117f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
5025ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
50317f1de56SFelix Fietkau 
50417f1de56SFelix Fietkau 	sband = &dev->sband_2g;
50517f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
50617f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
50717f1de56SFelix Fietkau 		sband = &dev->sband_5g;
50817f1de56SFelix Fietkau 	}
50917f1de56SFelix Fietkau 
510237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
511237312c5SLorenzo Bianconi 		ret = -ENOENT;
512237312c5SLorenzo Bianconi 		goto out;
513237312c5SLorenzo Bianconi 	}
51417f1de56SFelix Fietkau 
51517f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
51617f1de56SFelix Fietkau 	state = mt76_channel_state(dev, chan);
51717f1de56SFelix Fietkau 
51817f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
51917f1de56SFelix Fietkau 	survey->channel = chan;
52017f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
521ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
5225ce09c1aSFelix Fietkau 	if (chan == dev->main_chan) {
52317f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
52417f1de56SFelix Fietkau 
5255ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
5265ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
5275ce09c1aSFelix Fietkau 	}
5285ce09c1aSFelix Fietkau 
52917f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
5306bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
531237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
532237312c5SLorenzo Bianconi 
533237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
534237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
535ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
53617f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
53717f1de56SFelix Fietkau 
538237312c5SLorenzo Bianconi out:
539237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
540237312c5SLorenzo Bianconi 
54117f1de56SFelix Fietkau 	return ret;
54217f1de56SFelix Fietkau }
54317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
54417f1de56SFelix Fietkau 
54530ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
54630ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
54730ce7f44SFelix Fietkau {
54830ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
54930ce7f44SFelix Fietkau 	int i;
55030ce7f44SFelix Fietkau 
55130ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
55230ce7f44SFelix Fietkau 
55330ce7f44SFelix Fietkau 	if (!key)
55430ce7f44SFelix Fietkau 		return;
55530ce7f44SFelix Fietkau 
55601cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
55701cfc1b4SLorenzo Bianconi 		return;
55830ce7f44SFelix Fietkau 
55901cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
56030ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
56130ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
56230ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
56330ce7f44SFelix Fietkau 	}
56430ce7f44SFelix Fietkau }
56530ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
56630ce7f44SFelix Fietkau 
567*bfc394ddSFelix Fietkau static void
568*bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
569*bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
570*bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
5714e34249eSFelix Fietkau {
572*bfc394ddSFelix Fietkau 
5734e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5744e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
5754e34249eSFelix Fietkau 
5764e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
5774e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
5784e34249eSFelix Fietkau 
5794e34249eSFelix Fietkau 	status->flag = mstat.flag;
5804e34249eSFelix Fietkau 	status->freq = mstat.freq;
5814e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
5824e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
5834e34249eSFelix Fietkau 	status->bw = mstat.bw;
5844e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
5854e34249eSFelix Fietkau 	status->nss = mstat.nss;
5864e34249eSFelix Fietkau 	status->band = mstat.band;
5874e34249eSFelix Fietkau 	status->signal = mstat.signal;
5884e34249eSFelix Fietkau 	status->chains = mstat.chains;
589d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
5904e34249eSFelix Fietkau 
5914e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
59213381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
59313381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
59413381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
59513381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
5969c68a57bSFelix Fietkau 
597*bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
598*bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
5994e34249eSFelix Fietkau }
6004e34249eSFelix Fietkau 
60130ce7f44SFelix Fietkau static int
60230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
60330ce7f44SFelix Fietkau {
60430ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
60530ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
60630ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
60730ce7f44SFelix Fietkau 	int ret;
60830ce7f44SFelix Fietkau 
60930ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
61030ce7f44SFelix Fietkau 		return 0;
61130ce7f44SFelix Fietkau 
61230ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
61330ce7f44SFelix Fietkau 		return 0;
61430ce7f44SFelix Fietkau 
61530ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
61630ce7f44SFelix Fietkau 		/*
61730ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
61830ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
61930ce7f44SFelix Fietkau 		 */
62030ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *)skb->data;
62130ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
62230ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
62330ce7f44SFelix Fietkau 			return 0;
62430ce7f44SFelix Fietkau 	}
62530ce7f44SFelix Fietkau 
62630ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
62730ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
62830ce7f44SFelix Fietkau 		     sizeof(status->iv));
62930ce7f44SFelix Fietkau 	if (ret <= 0)
63030ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
63130ce7f44SFelix Fietkau 
63230ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
63330ce7f44SFelix Fietkau 
63430ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
63530ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
63630ce7f44SFelix Fietkau 
63730ce7f44SFelix Fietkau 	return 0;
63830ce7f44SFelix Fietkau }
63930ce7f44SFelix Fietkau 
640d71ef286SFelix Fietkau static void
6415ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
6425ce09c1aSFelix Fietkau 		    int len)
6435ce09c1aSFelix Fietkau {
6445ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
6455ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
6465ce09c1aSFelix Fietkau 	u32 airtime;
6475ce09c1aSFelix Fietkau 
6485ce09c1aSFelix Fietkau 	airtime = mt76_calc_rx_airtime(dev, status, len);
649237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
6505ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
651237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
6525ce09c1aSFelix Fietkau 
6535ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
6545ce09c1aSFelix Fietkau 		return;
6555ce09c1aSFelix Fietkau 
6565ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
6575ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
6585ce09c1aSFelix Fietkau }
6595ce09c1aSFelix Fietkau 
6605ce09c1aSFelix Fietkau static void
6615ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
6625ce09c1aSFelix Fietkau {
6635ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
6645ce09c1aSFelix Fietkau 	int wcid_idx;
6655ce09c1aSFelix Fietkau 
6665ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
6675ce09c1aSFelix Fietkau 		return;
6685ce09c1aSFelix Fietkau 
6695ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
670bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
6715ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
6725ce09c1aSFelix Fietkau 	else
6735ce09c1aSFelix Fietkau 		wcid = NULL;
6745ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
6755ce09c1aSFelix Fietkau 
6765ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
6775ce09c1aSFelix Fietkau 
6785ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
6795ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
6805ce09c1aSFelix Fietkau }
6815ce09c1aSFelix Fietkau 
6825ce09c1aSFelix Fietkau static void
6835ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
6845ce09c1aSFelix Fietkau {
6855ce09c1aSFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
6865ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
6875ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
6885ce09c1aSFelix Fietkau 
6895ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
6905ce09c1aSFelix Fietkau 		return;
6915ce09c1aSFelix Fietkau 
6925ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
6935ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
6945ce09c1aSFelix Fietkau 			return;
6955ce09c1aSFelix Fietkau 
6965ce09c1aSFelix Fietkau 		wcid = NULL;
6975ce09c1aSFelix Fietkau 	}
6985ce09c1aSFelix Fietkau 
6995ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
7005ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
7015ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
7025ce09c1aSFelix Fietkau 
7035ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
7045ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
7055ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
7065ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
7075ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
7085ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
7095ce09c1aSFelix Fietkau 		}
7105ce09c1aSFelix Fietkau 
7115ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
7125ce09c1aSFelix Fietkau 		return;
7135ce09c1aSFelix Fietkau 	}
7145ce09c1aSFelix Fietkau 
7155ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
7165ce09c1aSFelix Fietkau }
7175ce09c1aSFelix Fietkau 
7185ce09c1aSFelix Fietkau static void
719ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
720d71ef286SFelix Fietkau {
721d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
722d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
723d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
724*bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
725d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
726d71ef286SFelix Fietkau 	bool ps;
72790fdc171SFelix Fietkau 	int i;
728d71ef286SFelix Fietkau 
729*bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
73036d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
731*bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
73236d91096SFelix Fietkau 		if (sta)
73336d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
73436d91096SFelix Fietkau 	}
73536d91096SFelix Fietkau 
7365ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
7375ce09c1aSFelix Fietkau 
738d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
739d71ef286SFelix Fietkau 		return;
740d71ef286SFelix Fietkau 
741d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
742d71ef286SFelix Fietkau 
74302e5a769SFelix Fietkau 	if (status->signal <= 0)
74402e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
74502e5a769SFelix Fietkau 
746ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
747ef13edc0SFelix Fietkau 
748d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
749d71ef286SFelix Fietkau 		return;
750d71ef286SFelix Fietkau 
751d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
752d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
753d71ef286SFelix Fietkau 		return;
754d71ef286SFelix Fietkau 	}
755d71ef286SFelix Fietkau 
756d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
757d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
758d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
759d71ef286SFelix Fietkau 		return;
760d71ef286SFelix Fietkau 
761d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
762d71ef286SFelix Fietkau 
763d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
764d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
765d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
766d71ef286SFelix Fietkau 
767d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
768d71ef286SFelix Fietkau 		return;
769d71ef286SFelix Fietkau 
77011b2a25fSFelix Fietkau 	if (ps)
771d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
77211b2a25fSFelix Fietkau 	else
773d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
774d71ef286SFelix Fietkau 
775d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
7769f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
77790fdc171SFelix Fietkau 
77890fdc171SFelix Fietkau 	if (ps)
77990fdc171SFelix Fietkau 		return;
78090fdc171SFelix Fietkau 
78190fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
78290fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
78390fdc171SFelix Fietkau 
78490fdc171SFelix Fietkau 		if (!sta->txq[i])
78590fdc171SFelix Fietkau 			continue;
78690fdc171SFelix Fietkau 
78790fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
78890fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
789*bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
79090fdc171SFelix Fietkau 	}
791d71ef286SFelix Fietkau }
792d71ef286SFelix Fietkau 
7939d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
79481e850efSLorenzo Bianconi 		      struct napi_struct *napi)
79517f1de56SFelix Fietkau {
7969c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
797*bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
7989d9d738bSFelix Fietkau 	struct sk_buff *skb;
7999d9d738bSFelix Fietkau 
800c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
8019d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
80230ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
80330ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
80430ce7f44SFelix Fietkau 			continue;
80530ce7f44SFelix Fietkau 		}
80630ce7f44SFelix Fietkau 
807*bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
808*bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
8099d9d738bSFelix Fietkau 	}
810c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
8119d9d738bSFelix Fietkau }
8129d9d738bSFelix Fietkau 
81381e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
81481e850efSLorenzo Bianconi 			   struct napi_struct *napi)
8159d9d738bSFelix Fietkau {
816aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
81717f1de56SFelix Fietkau 	struct sk_buff *skb;
81817f1de56SFelix Fietkau 
819aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
820aee5b8cfSFelix Fietkau 
821d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
822ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
823aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
824d71ef286SFelix Fietkau 	}
825aee5b8cfSFelix Fietkau 
82681e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
8274e34249eSFelix Fietkau }
82881e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
829723b90dcSFelix Fietkau 
830e28487eaSFelix Fietkau static int
831e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
832e28487eaSFelix Fietkau 	     struct ieee80211_sta *sta)
833e28487eaSFelix Fietkau {
834e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
835e28487eaSFelix Fietkau 	int ret;
836e28487eaSFelix Fietkau 	int i;
837e28487eaSFelix Fietkau 
838e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
839e28487eaSFelix Fietkau 
840e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
841e28487eaSFelix Fietkau 	if (ret)
842e28487eaSFelix Fietkau 		goto out;
843e28487eaSFelix Fietkau 
844e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
845e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
846e28487eaSFelix Fietkau 
847e28487eaSFelix Fietkau 		if (!sta->txq[i])
848e28487eaSFelix Fietkau 			continue;
849e28487eaSFelix Fietkau 
850e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
851e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
852e28487eaSFelix Fietkau 
853e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
854e28487eaSFelix Fietkau 	}
855e28487eaSFelix Fietkau 
856ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
857e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
858e28487eaSFelix Fietkau 
859e28487eaSFelix Fietkau out:
860e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
861e28487eaSFelix Fietkau 
862e28487eaSFelix Fietkau 	return ret;
863e28487eaSFelix Fietkau }
864e28487eaSFelix Fietkau 
86513f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
866723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
867723b90dcSFelix Fietkau {
868723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
86913f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
870723b90dcSFelix Fietkau 
871723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
872723b90dcSFelix Fietkau 	synchronize_rcu();
873723b90dcSFelix Fietkau 
87458bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
87558bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
87658bab0d4SFelix Fietkau 
877e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
878e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
879e28487eaSFelix Fietkau 
880723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
881723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
882723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
883723b90dcSFelix Fietkau 	mt76_wcid_free(dev->wcid_mask, idx);
88413f61dfcSLorenzo Bianconi }
88513f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
886e28487eaSFelix Fietkau 
88713f61dfcSLorenzo Bianconi static void
88813f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
88913f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
89013f61dfcSLorenzo Bianconi {
89113f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
89213f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
893723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
894723b90dcSFelix Fietkau }
895e28487eaSFelix Fietkau 
896e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
897e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
898e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
899e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
900e28487eaSFelix Fietkau {
901e28487eaSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
902e28487eaSFelix Fietkau 
903e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
904e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
905e28487eaSFelix Fietkau 		return mt76_sta_add(dev, vif, sta);
906e28487eaSFelix Fietkau 
9079c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
9089c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
9099c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
9109c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
9119c193de5SFelix Fietkau 
912e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
913e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
914e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
915e28487eaSFelix Fietkau 
916e28487eaSFelix Fietkau 	return 0;
917e28487eaSFelix Fietkau }
918e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
9199313faacSFelix Fietkau 
9209313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
9219313faacSFelix Fietkau 		     int *dbm)
9229313faacSFelix Fietkau {
9239313faacSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
924d0ff23c1SBen Hutchings 	int n_chains = hweight8(dev->antenna_mask);
9259313faacSFelix Fietkau 
926cee646d6SFelix Fietkau 	*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
9279313faacSFelix Fietkau 
9289313faacSFelix Fietkau 	/* convert from per-chain power to combined
929c19b0ca5SLorenzo Bianconi 	 * output power
9309313faacSFelix Fietkau 	 */
931c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
932c19b0ca5SLorenzo Bianconi 	case 4:
933c19b0ca5SLorenzo Bianconi 		*dbm += 6;
934c19b0ca5SLorenzo Bianconi 		break;
935c19b0ca5SLorenzo Bianconi 	case 3:
936c19b0ca5SLorenzo Bianconi 		*dbm += 4;
937c19b0ca5SLorenzo Bianconi 		break;
938c19b0ca5SLorenzo Bianconi 	case 2:
9399313faacSFelix Fietkau 		*dbm += 3;
940c19b0ca5SLorenzo Bianconi 		break;
941c19b0ca5SLorenzo Bianconi 	default:
942c19b0ca5SLorenzo Bianconi 		break;
943c19b0ca5SLorenzo Bianconi 	}
9449313faacSFelix Fietkau 
9459313faacSFelix Fietkau 	return 0;
9469313faacSFelix Fietkau }
9479313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
948e7173858SFelix Fietkau 
949e7173858SFelix Fietkau static void
950e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
951e7173858SFelix Fietkau {
952e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
953e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
954e7173858SFelix Fietkau }
955e7173858SFelix Fietkau 
956e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
957e7173858SFelix Fietkau {
958e7173858SFelix Fietkau 	if (!dev->csa_complete)
959e7173858SFelix Fietkau 		return;
960e7173858SFelix Fietkau 
961e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
962e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
963e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
964e7173858SFelix Fietkau 
965e7173858SFelix Fietkau 	dev->csa_complete = 0;
966e7173858SFelix Fietkau }
967e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
968e7173858SFelix Fietkau 
969e7173858SFelix Fietkau static void
970e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
971e7173858SFelix Fietkau {
972e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
973e7173858SFelix Fietkau 
974e7173858SFelix Fietkau 	if (!vif->csa_active)
975e7173858SFelix Fietkau 		return;
976e7173858SFelix Fietkau 
977e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
978e7173858SFelix Fietkau }
979e7173858SFelix Fietkau 
980e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
981e7173858SFelix Fietkau {
982e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
983e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
984e7173858SFelix Fietkau 		__mt76_csa_check, dev);
985e7173858SFelix Fietkau }
986e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
98787d53103SStanislaw Gruszka 
98887d53103SStanislaw Gruszka int
98987d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
99087d53103SStanislaw Gruszka {
99187d53103SStanislaw Gruszka 	return 0;
99287d53103SStanislaw Gruszka }
99387d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
994eadfd98fSLorenzo Bianconi 
995eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
996eadfd98fSLorenzo Bianconi {
997eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
998eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
999eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1000eadfd98fSLorenzo Bianconi 
1001eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1002eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1003eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1004eadfd98fSLorenzo Bianconi 
1005eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1006eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1007eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1008eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1009eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1010eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1011eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1012eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1013eadfd98fSLorenzo Bianconi 
1014eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1015eadfd98fSLorenzo Bianconi }
1016eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1017d2679d65SLorenzo Bianconi 
1018d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1019d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1020d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1021d2679d65SLorenzo Bianconi {
1022d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1023d2679d65SLorenzo Bianconi 
1024d2679d65SLorenzo Bianconi 	if (cck) {
1025d2679d65SLorenzo Bianconi 		if (sband == &dev->sband_5g.sband)
1026d2679d65SLorenzo Bianconi 			return 0;
1027d2679d65SLorenzo Bianconi 
1028d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
1029d2679d65SLorenzo Bianconi 	} else if (sband == &dev->sband_2g.sband) {
1030d2679d65SLorenzo Bianconi 		offset = 4;
1031d2679d65SLorenzo Bianconi 	}
1032d2679d65SLorenzo Bianconi 
1033d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1034d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1035d2679d65SLorenzo Bianconi 			return i;
1036d2679d65SLorenzo Bianconi 	}
1037d2679d65SLorenzo Bianconi 
1038d2679d65SLorenzo Bianconi 	return 0;
1039d2679d65SLorenzo Bianconi }
1040d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
10418b8ab5c2SLorenzo Bianconi 
10428b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10438b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
10448b8ab5c2SLorenzo Bianconi {
10458b8ab5c2SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
10468b8ab5c2SLorenzo Bianconi 
10478b8ab5c2SLorenzo Bianconi 	set_bit(MT76_SCANNING, &dev->state);
10488b8ab5c2SLorenzo Bianconi }
10498b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
10508b8ab5c2SLorenzo Bianconi 
10518b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
10528b8ab5c2SLorenzo Bianconi {
10538b8ab5c2SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
10548b8ab5c2SLorenzo Bianconi 
10558b8ab5c2SLorenzo Bianconi 	clear_bit(MT76_SCANNING, &dev->state);
10568b8ab5c2SLorenzo Bianconi }
10578b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1058e49c76d4SLorenzo Bianconi 
1059e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1060e49c76d4SLorenzo Bianconi {
1061e49c76d4SLorenzo Bianconi 	struct mt76_dev *dev = hw->priv;
1062e49c76d4SLorenzo Bianconi 
1063e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1064e49c76d4SLorenzo Bianconi 	*tx_ant = dev->antenna_mask;
1065e49c76d4SLorenzo Bianconi 	*rx_ant = dev->antenna_mask;
1066e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1067e49c76d4SLorenzo Bianconi 
1068e49c76d4SLorenzo Bianconi 	return 0;
1069e49c76d4SLorenzo Bianconi }
1070e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1071