xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 0e3d677750fbee9e5e5dbace091870e7386e553d)
1*0e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
517f1de56SFelix Fietkau #include <linux/of.h>
617f1de56SFelix Fietkau #include "mt76.h"
717f1de56SFelix Fietkau 
817f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
917f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1017f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1117f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1217f1de56SFelix Fietkau 	.max_power = 30,			\
1317f1de56SFelix Fietkau }
1417f1de56SFelix Fietkau 
1517f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1617f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1717f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1817f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1917f1de56SFelix Fietkau 	.max_power = 30,			\
2017f1de56SFelix Fietkau }
2117f1de56SFelix Fietkau 
2217f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
2317f1de56SFelix Fietkau 	CHAN2G(1, 2412),
2417f1de56SFelix Fietkau 	CHAN2G(2, 2417),
2517f1de56SFelix Fietkau 	CHAN2G(3, 2422),
2617f1de56SFelix Fietkau 	CHAN2G(4, 2427),
2717f1de56SFelix Fietkau 	CHAN2G(5, 2432),
2817f1de56SFelix Fietkau 	CHAN2G(6, 2437),
2917f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3017f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3117f1de56SFelix Fietkau 	CHAN2G(9, 2452),
3217f1de56SFelix Fietkau 	CHAN2G(10, 2457),
3317f1de56SFelix Fietkau 	CHAN2G(11, 2462),
3417f1de56SFelix Fietkau 	CHAN2G(12, 2467),
3517f1de56SFelix Fietkau 	CHAN2G(13, 2472),
3617f1de56SFelix Fietkau 	CHAN2G(14, 2484),
3717f1de56SFelix Fietkau };
3817f1de56SFelix Fietkau 
3917f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4017f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4117f1de56SFelix Fietkau 	CHAN5G(40, 5200),
4217f1de56SFelix Fietkau 	CHAN5G(44, 5220),
4317f1de56SFelix Fietkau 	CHAN5G(48, 5240),
4417f1de56SFelix Fietkau 
4517f1de56SFelix Fietkau 	CHAN5G(52, 5260),
4617f1de56SFelix Fietkau 	CHAN5G(56, 5280),
4717f1de56SFelix Fietkau 	CHAN5G(60, 5300),
4817f1de56SFelix Fietkau 	CHAN5G(64, 5320),
4917f1de56SFelix Fietkau 
5017f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5117f1de56SFelix Fietkau 	CHAN5G(104, 5520),
5217f1de56SFelix Fietkau 	CHAN5G(108, 5540),
5317f1de56SFelix Fietkau 	CHAN5G(112, 5560),
5417f1de56SFelix Fietkau 	CHAN5G(116, 5580),
5517f1de56SFelix Fietkau 	CHAN5G(120, 5600),
5617f1de56SFelix Fietkau 	CHAN5G(124, 5620),
5717f1de56SFelix Fietkau 	CHAN5G(128, 5640),
5817f1de56SFelix Fietkau 	CHAN5G(132, 5660),
5917f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6017f1de56SFelix Fietkau 	CHAN5G(140, 5700),
6117f1de56SFelix Fietkau 
6217f1de56SFelix Fietkau 	CHAN5G(149, 5745),
6317f1de56SFelix Fietkau 	CHAN5G(153, 5765),
6417f1de56SFelix Fietkau 	CHAN5G(157, 5785),
6517f1de56SFelix Fietkau 	CHAN5G(161, 5805),
6617f1de56SFelix Fietkau 	CHAN5G(165, 5825),
6717f1de56SFelix Fietkau };
6817f1de56SFelix Fietkau 
6917f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
7017f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
7117f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
7217f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
7317f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
7417f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
7517f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
7617f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
7717f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
7817f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
7917f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
8017f1de56SFelix Fietkau };
8117f1de56SFelix Fietkau 
8217f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
8317f1de56SFelix Fietkau {
8417f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
8517f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
8617f1de56SFelix Fietkau 	int led_pin;
8717f1de56SFelix Fietkau 
8817f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
8917f1de56SFelix Fietkau 		return 0;
9017f1de56SFelix Fietkau 
9117f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
9217f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
9317f1de56SFelix Fietkau 
9417f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
9517f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
9617f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
9717f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
9817f1de56SFelix Fietkau 					mt76_tpt_blink,
9917f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
10017f1de56SFelix Fietkau 
10117f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
10217f1de56SFelix Fietkau 	if (np) {
10317f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
10417f1de56SFelix Fietkau 			dev->led_pin = led_pin;
10517f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
10617f1de56SFelix Fietkau 	}
10717f1de56SFelix Fietkau 
10817f1de56SFelix Fietkau 	return devm_led_classdev_register(dev->dev, &dev->led_cdev);
10917f1de56SFelix Fietkau }
11017f1de56SFelix Fietkau 
111551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev,
112551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
113551e1ef4SLorenzo Bianconi 				 bool vht)
114551e1ef4SLorenzo Bianconi {
115551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
116d0ff23c1SBen Hutchings 	int i, nstream = hweight8(dev->antenna_mask);
117551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
118551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
119551e1ef4SLorenzo Bianconi 
120551e1ef4SLorenzo Bianconi 	if (nstream > 1)
121551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
122551e1ef4SLorenzo Bianconi 	else
123551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
124551e1ef4SLorenzo Bianconi 
125551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
126551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
127551e1ef4SLorenzo Bianconi 
128551e1ef4SLorenzo Bianconi 	if (!vht)
129551e1ef4SLorenzo Bianconi 		return;
130551e1ef4SLorenzo Bianconi 
131551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
132551e1ef4SLorenzo Bianconi 	if (nstream > 1)
133551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
134551e1ef4SLorenzo Bianconi 	else
135551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
136551e1ef4SLorenzo Bianconi 
137551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
138551e1ef4SLorenzo Bianconi 		if (i < nstream)
139551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
140551e1ef4SLorenzo Bianconi 		else
141551e1ef4SLorenzo Bianconi 			mcs_map |=
142551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
143551e1ef4SLorenzo Bianconi 	}
144551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
145551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
146551e1ef4SLorenzo Bianconi }
147551e1ef4SLorenzo Bianconi 
1485ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
1495ebdc3e0SLorenzo Bianconi {
1505ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_2ghz)
1515ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_2g.sband, false);
1525ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_5ghz)
1535ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht);
1545ebdc3e0SLorenzo Bianconi }
1555ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1565ebdc3e0SLorenzo Bianconi 
15717f1de56SFelix Fietkau static int
15817f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
15917f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
16017f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
16117f1de56SFelix Fietkau {
16217f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
16317f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
16417f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
16517f1de56SFelix Fietkau 	void *chanlist;
16617f1de56SFelix Fietkau 	int size;
16717f1de56SFelix Fietkau 
16817f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
16917f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
17017f1de56SFelix Fietkau 	if (!chanlist)
17117f1de56SFelix Fietkau 		return -ENOMEM;
17217f1de56SFelix Fietkau 
173a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
17417f1de56SFelix Fietkau 				    GFP_KERNEL);
17517f1de56SFelix Fietkau 	if (!msband->chan)
17617f1de56SFelix Fietkau 		return -ENOMEM;
17717f1de56SFelix Fietkau 
17817f1de56SFelix Fietkau 	sband->channels = chanlist;
17917f1de56SFelix Fietkau 	sband->n_channels = n_chan;
18017f1de56SFelix Fietkau 	sband->bitrates = rates;
18117f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
18217f1de56SFelix Fietkau 	dev->chandef.chan = &sband->channels[0];
18317f1de56SFelix Fietkau 
18417f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
18517f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
18617f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
18717f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
18817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
18917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
19017f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
19117f1de56SFelix Fietkau 
19217f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
19317f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
19417f1de56SFelix Fietkau 	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
19517f1de56SFelix Fietkau 
196551e1ef4SLorenzo Bianconi 	mt76_init_stream_cap(dev, sband, vht);
197551e1ef4SLorenzo Bianconi 
19817f1de56SFelix Fietkau 	if (!vht)
19917f1de56SFelix Fietkau 		return 0;
20017f1de56SFelix Fietkau 
20117f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
20217f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
20317f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
20417f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
20549149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
206f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
207f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
20849149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
20917f1de56SFelix Fietkau 
21017f1de56SFelix Fietkau 	return 0;
21117f1de56SFelix Fietkau }
21217f1de56SFelix Fietkau 
21317f1de56SFelix Fietkau static int
21417f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
21517f1de56SFelix Fietkau 		   int n_rates)
21617f1de56SFelix Fietkau {
21717f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband;
21817f1de56SFelix Fietkau 
21917f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_2g,
22017f1de56SFelix Fietkau 			       mt76_channels_2ghz,
22117f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
22217f1de56SFelix Fietkau 			       rates, n_rates, false);
22317f1de56SFelix Fietkau }
22417f1de56SFelix Fietkau 
22517f1de56SFelix Fietkau static int
22617f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22717f1de56SFelix Fietkau 		   int n_rates, bool vht)
22817f1de56SFelix Fietkau {
22917f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband;
23017f1de56SFelix Fietkau 
23117f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_5g,
23217f1de56SFelix Fietkau 			       mt76_channels_5ghz,
23317f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
23417f1de56SFelix Fietkau 			       rates, n_rates, vht);
23517f1de56SFelix Fietkau }
23617f1de56SFelix Fietkau 
23717f1de56SFelix Fietkau static void
23817f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band)
23917f1de56SFelix Fietkau {
24017f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band];
24117f1de56SFelix Fietkau 	bool found = false;
24217f1de56SFelix Fietkau 	int i;
24317f1de56SFelix Fietkau 
24417f1de56SFelix Fietkau 	if (!sband)
24517f1de56SFelix Fietkau 		return;
24617f1de56SFelix Fietkau 
24717f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
24817f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
24917f1de56SFelix Fietkau 			continue;
25017f1de56SFelix Fietkau 
25117f1de56SFelix Fietkau 		found = true;
25217f1de56SFelix Fietkau 		break;
25317f1de56SFelix Fietkau 	}
25417f1de56SFelix Fietkau 
25517f1de56SFelix Fietkau 	if (found)
25617f1de56SFelix Fietkau 		return;
25717f1de56SFelix Fietkau 
25817f1de56SFelix Fietkau 	sband->n_channels = 0;
25917f1de56SFelix Fietkau 	dev->hw->wiphy->bands[band] = NULL;
26017f1de56SFelix Fietkau }
26117f1de56SFelix Fietkau 
262a85b590cSFelix Fietkau struct mt76_dev *
263c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
264c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
265c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
266a85b590cSFelix Fietkau {
267a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
268a85b590cSFelix Fietkau 	struct mt76_dev *dev;
269a85b590cSFelix Fietkau 
270a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
271a85b590cSFelix Fietkau 	if (!hw)
272a85b590cSFelix Fietkau 		return NULL;
273a85b590cSFelix Fietkau 
274a85b590cSFelix Fietkau 	dev = hw->priv;
275a85b590cSFelix Fietkau 	dev->hw = hw;
276c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
277c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
278c0f7b25aSLorenzo Bianconi 
279a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
280a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
281a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
282108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
28326e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
28488046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
285a85b590cSFelix Fietkau 
286a85b590cSFelix Fietkau 	return dev;
287a85b590cSFelix Fietkau }
288a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
289a85b590cSFelix Fietkau 
29017f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
29117f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
29217f1de56SFelix Fietkau {
29317f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
29417f1de56SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
29517f1de56SFelix Fietkau 	int ret;
29617f1de56SFelix Fietkau 
29717f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
29817f1de56SFelix Fietkau 
29917f1de56SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
30017f1de56SFelix Fietkau 
30117f1de56SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
30217f1de56SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
30317f1de56SFelix Fietkau 
30417f1de56SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
30517f1de56SFelix Fietkau 
306b37b30afSKristian Evensen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
307b37b30afSKristian Evensen 
30824114a5fSLorenzo Bianconi 	wiphy->available_antennas_tx = dev->antenna_mask;
30924114a5fSLorenzo Bianconi 	wiphy->available_antennas_rx = dev->antenna_mask;
31024114a5fSLorenzo Bianconi 
31117f1de56SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
31217f1de56SFelix Fietkau 	hw->max_tx_fragments = 16;
31317f1de56SFelix Fietkau 
31417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
31517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
31617f1de56SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
31717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
31817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
31917f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
32017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
32117f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
32217f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
32317f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
32417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
325d71ef286SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
32688046b2cSFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
327f545540dSFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
32817f1de56SFelix Fietkau 
32917f1de56SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
33017f1de56SFelix Fietkau 
33117f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
33217f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
33317f1de56SFelix Fietkau 		if (ret)
33417f1de56SFelix Fietkau 			return ret;
33517f1de56SFelix Fietkau 	}
33617f1de56SFelix Fietkau 
33717f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
33817f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
33917f1de56SFelix Fietkau 		if (ret)
34017f1de56SFelix Fietkau 			return ret;
34117f1de56SFelix Fietkau 	}
34217f1de56SFelix Fietkau 
34317f1de56SFelix Fietkau 	wiphy_read_of_freq_limits(dev->hw->wiphy);
34417f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_2GHZ);
34517f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_5GHZ);
34617f1de56SFelix Fietkau 
347b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
34817f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
34917f1de56SFelix Fietkau 		if (ret)
35017f1de56SFelix Fietkau 			return ret;
351b374e868SArnd Bergmann 	}
35217f1de56SFelix Fietkau 
35317f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
35417f1de56SFelix Fietkau }
35517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
35617f1de56SFelix Fietkau 
35717f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
35817f1de56SFelix Fietkau {
35917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
36017f1de56SFelix Fietkau 
36179d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
36217f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
36317f1de56SFelix Fietkau }
36417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
36517f1de56SFelix Fietkau 
366def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
367def34a2fSLorenzo Bianconi {
368def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
369def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
370def34a2fSLorenzo Bianconi }
371def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
372def34a2fSLorenzo Bianconi 
37317f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
37417f1de56SFelix Fietkau {
37517f1de56SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state)) {
37617f1de56SFelix Fietkau 		dev_kfree_skb(skb);
37717f1de56SFelix Fietkau 		return;
37817f1de56SFelix Fietkau 	}
37917f1de56SFelix Fietkau 
38017f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
38117f1de56SFelix Fietkau }
38217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
38317f1de56SFelix Fietkau 
38439d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev)
38526e40d4cSFelix Fietkau {
386af005f26SLorenzo Bianconi 	struct mt76_queue *q;
38726e40d4cSFelix Fietkau 	int i;
38826e40d4cSFelix Fietkau 
38926e40d4cSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
390af005f26SLorenzo Bianconi 		q = dev->q_tx[i].q;
391af005f26SLorenzo Bianconi 		if (q && q->queued)
39226e40d4cSFelix Fietkau 			return true;
39326e40d4cSFelix Fietkau 	}
39426e40d4cSFelix Fietkau 
39526e40d4cSFelix Fietkau 	return false;
39626e40d4cSFelix Fietkau }
39739d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
39826e40d4cSFelix Fietkau 
39917f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev)
40017f1de56SFelix Fietkau {
40117f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
40217f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
40317f1de56SFelix Fietkau 	struct mt76_channel_state *state;
40417f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
40526e40d4cSFelix Fietkau 	int timeout = HZ / 5;
40617f1de56SFelix Fietkau 
40789bc67e3SFelix Fietkau 	if (offchannel)
40889bc67e3SFelix Fietkau 		set_bit(MT76_OFFCHANNEL, &dev->state);
40989bc67e3SFelix Fietkau 	else
41089bc67e3SFelix Fietkau 		clear_bit(MT76_OFFCHANNEL, &dev->state);
41189bc67e3SFelix Fietkau 
41226e40d4cSFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
41326e40d4cSFelix Fietkau 
41417f1de56SFelix Fietkau 	if (dev->drv->update_survey)
41517f1de56SFelix Fietkau 		dev->drv->update_survey(dev);
41617f1de56SFelix Fietkau 
41717f1de56SFelix Fietkau 	dev->chandef = *chandef;
41817f1de56SFelix Fietkau 
41917f1de56SFelix Fietkau 	if (!offchannel)
42017f1de56SFelix Fietkau 		dev->main_chan = chandef->chan;
42117f1de56SFelix Fietkau 
42217f1de56SFelix Fietkau 	if (chandef->chan != dev->main_chan) {
42317f1de56SFelix Fietkau 		state = mt76_channel_state(dev, chandef->chan);
42417f1de56SFelix Fietkau 		memset(state, 0, sizeof(*state));
42517f1de56SFelix Fietkau 	}
42617f1de56SFelix Fietkau }
42717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
42817f1de56SFelix Fietkau 
42917f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
43017f1de56SFelix Fietkau 		    struct survey_info *survey)
43117f1de56SFelix Fietkau {
43217f1de56SFelix Fietkau 	struct mt76_dev *dev = hw->priv;
43317f1de56SFelix Fietkau 	struct mt76_sband *sband;
43417f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
43517f1de56SFelix Fietkau 	struct mt76_channel_state *state;
43617f1de56SFelix Fietkau 	int ret = 0;
43717f1de56SFelix Fietkau 
43817f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
43917f1de56SFelix Fietkau 		dev->drv->update_survey(dev);
44017f1de56SFelix Fietkau 
44117f1de56SFelix Fietkau 	sband = &dev->sband_2g;
44217f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
44317f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
44417f1de56SFelix Fietkau 		sband = &dev->sband_5g;
44517f1de56SFelix Fietkau 	}
44617f1de56SFelix Fietkau 
44717f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels)
44817f1de56SFelix Fietkau 		return -ENOENT;
44917f1de56SFelix Fietkau 
45017f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
45117f1de56SFelix Fietkau 	state = mt76_channel_state(dev, chan);
45217f1de56SFelix Fietkau 
45317f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
45417f1de56SFelix Fietkau 	survey->channel = chan;
45517f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
45617f1de56SFelix Fietkau 	if (chan == dev->main_chan)
45717f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
45817f1de56SFelix Fietkau 
45917f1de56SFelix Fietkau 	spin_lock_bh(&dev->cc_lock);
46017f1de56SFelix Fietkau 	survey->time = div_u64(state->cc_active, 1000);
46117f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
46217f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
46317f1de56SFelix Fietkau 
46417f1de56SFelix Fietkau 	return ret;
46517f1de56SFelix Fietkau }
46617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
46717f1de56SFelix Fietkau 
46830ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
46930ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
47030ce7f44SFelix Fietkau {
47130ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
47230ce7f44SFelix Fietkau 	int i;
47330ce7f44SFelix Fietkau 
47430ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
47530ce7f44SFelix Fietkau 
47630ce7f44SFelix Fietkau 	if (!key)
47730ce7f44SFelix Fietkau 		return;
47830ce7f44SFelix Fietkau 
47930ce7f44SFelix Fietkau 	if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
48030ce7f44SFelix Fietkau 		wcid->rx_check_pn = true;
48130ce7f44SFelix Fietkau 
48230ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
48330ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
48430ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
48530ce7f44SFelix Fietkau 	}
48630ce7f44SFelix Fietkau }
48730ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
48830ce7f44SFelix Fietkau 
48982e1dd0fSStanislaw Gruszka struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
4904e34249eSFelix Fietkau {
4914e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4924e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
4934e34249eSFelix Fietkau 
4944e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *) skb->cb);
4954e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
4964e34249eSFelix Fietkau 
4974e34249eSFelix Fietkau 	status->flag = mstat.flag;
4984e34249eSFelix Fietkau 	status->freq = mstat.freq;
4994e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
5004e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
5014e34249eSFelix Fietkau 	status->bw = mstat.bw;
5024e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
5034e34249eSFelix Fietkau 	status->nss = mstat.nss;
5044e34249eSFelix Fietkau 	status->band = mstat.band;
5054e34249eSFelix Fietkau 	status->signal = mstat.signal;
5064e34249eSFelix Fietkau 	status->chains = mstat.chains;
5074e34249eSFelix Fietkau 
5084e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
5094e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal));
5104e34249eSFelix Fietkau 	memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal));
5119c68a57bSFelix Fietkau 
5129c68a57bSFelix Fietkau 	return wcid_to_sta(mstat.wcid);
5134e34249eSFelix Fietkau }
51482e1dd0fSStanislaw Gruszka EXPORT_SYMBOL(mt76_rx_convert);
5154e34249eSFelix Fietkau 
51630ce7f44SFelix Fietkau static int
51730ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
51830ce7f44SFelix Fietkau {
51930ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
52030ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
52130ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
52230ce7f44SFelix Fietkau 	int ret;
52330ce7f44SFelix Fietkau 
52430ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
52530ce7f44SFelix Fietkau 		return 0;
52630ce7f44SFelix Fietkau 
52730ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
52830ce7f44SFelix Fietkau 		return 0;
52930ce7f44SFelix Fietkau 
53030ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
53130ce7f44SFelix Fietkau 		/*
53230ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
53330ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
53430ce7f44SFelix Fietkau 		 */
53530ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *) skb->data;
53630ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
53730ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
53830ce7f44SFelix Fietkau 			return 0;
53930ce7f44SFelix Fietkau 	}
54030ce7f44SFelix Fietkau 
54130ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
54230ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
54330ce7f44SFelix Fietkau 		     sizeof(status->iv));
54430ce7f44SFelix Fietkau 	if (ret <= 0)
54530ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
54630ce7f44SFelix Fietkau 
54730ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
54830ce7f44SFelix Fietkau 
54930ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
55030ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
55130ce7f44SFelix Fietkau 
55230ce7f44SFelix Fietkau 	return 0;
55330ce7f44SFelix Fietkau }
55430ce7f44SFelix Fietkau 
555d71ef286SFelix Fietkau static void
556ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
557d71ef286SFelix Fietkau {
558d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
559d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
560d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
561d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
562d71ef286SFelix Fietkau 	bool ps;
56390fdc171SFelix Fietkau 	int i;
564d71ef286SFelix Fietkau 
56536d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
56636d91096SFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
56736d91096SFelix Fietkau 		if (sta)
56836d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv;
56936d91096SFelix Fietkau 	}
57036d91096SFelix Fietkau 
571d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
572d71ef286SFelix Fietkau 		return;
573d71ef286SFelix Fietkau 
574d71ef286SFelix Fietkau 	sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv);
575d71ef286SFelix Fietkau 
57602e5a769SFelix Fietkau 	if (status->signal <= 0)
57702e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
57802e5a769SFelix Fietkau 
579ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
580ef13edc0SFelix Fietkau 
581d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
582d71ef286SFelix Fietkau 		return;
583d71ef286SFelix Fietkau 
584d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
585d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
586d71ef286SFelix Fietkau 		return;
587d71ef286SFelix Fietkau 	}
588d71ef286SFelix Fietkau 
589d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
590d71ef286SFelix Fietkau 		!(ieee80211_is_mgmt(hdr->frame_control) ||
591d71ef286SFelix Fietkau 		  ieee80211_is_data(hdr->frame_control)))
592d71ef286SFelix Fietkau 		return;
593d71ef286SFelix Fietkau 
594d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
595d71ef286SFelix Fietkau 
596d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
597d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
598d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
599d71ef286SFelix Fietkau 
600d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
601d71ef286SFelix Fietkau 		return;
602d71ef286SFelix Fietkau 
60311b2a25fSFelix Fietkau 	if (ps)
604d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
60511b2a25fSFelix Fietkau 	else
606d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
607d71ef286SFelix Fietkau 
608d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
6099f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
61090fdc171SFelix Fietkau 
61190fdc171SFelix Fietkau 	if (ps)
61290fdc171SFelix Fietkau 		return;
61390fdc171SFelix Fietkau 
61490fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
61590fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
61690fdc171SFelix Fietkau 
61790fdc171SFelix Fietkau 		if (!sta->txq[i])
61890fdc171SFelix Fietkau 			continue;
61990fdc171SFelix Fietkau 
62090fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv;
62190fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
62290fdc171SFelix Fietkau 			ieee80211_schedule_txq(dev->hw, sta->txq[i]);
62390fdc171SFelix Fietkau 	}
624d71ef286SFelix Fietkau }
625d71ef286SFelix Fietkau 
6269d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
62781e850efSLorenzo Bianconi 		      struct napi_struct *napi)
62817f1de56SFelix Fietkau {
6299c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
6309d9d738bSFelix Fietkau 	struct sk_buff *skb;
6319d9d738bSFelix Fietkau 
632c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
6339d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
63430ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
63530ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
63630ce7f44SFelix Fietkau 			continue;
63730ce7f44SFelix Fietkau 		}
63830ce7f44SFelix Fietkau 
6399d9d738bSFelix Fietkau 		sta = mt76_rx_convert(skb);
6409d9d738bSFelix Fietkau 		ieee80211_rx_napi(dev->hw, sta, skb, napi);
6419d9d738bSFelix Fietkau 	}
642c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
6439d9d738bSFelix Fietkau }
6449d9d738bSFelix Fietkau 
64581e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
64681e850efSLorenzo Bianconi 			   struct napi_struct *napi)
6479d9d738bSFelix Fietkau {
648aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
64917f1de56SFelix Fietkau 	struct sk_buff *skb;
65017f1de56SFelix Fietkau 
651aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
652aee5b8cfSFelix Fietkau 
653d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
654ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
655aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
656d71ef286SFelix Fietkau 	}
657aee5b8cfSFelix Fietkau 
65881e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
6594e34249eSFelix Fietkau }
66081e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
661723b90dcSFelix Fietkau 
662e28487eaSFelix Fietkau static int
663e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
664e28487eaSFelix Fietkau 	     struct ieee80211_sta *sta)
665e28487eaSFelix Fietkau {
666e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
667e28487eaSFelix Fietkau 	int ret;
668e28487eaSFelix Fietkau 	int i;
669e28487eaSFelix Fietkau 
670e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
671e28487eaSFelix Fietkau 
672e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
673e28487eaSFelix Fietkau 	if (ret)
674e28487eaSFelix Fietkau 		goto out;
675e28487eaSFelix Fietkau 
676e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
677e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
678e28487eaSFelix Fietkau 
679e28487eaSFelix Fietkau 		if (!sta->txq[i])
680e28487eaSFelix Fietkau 			continue;
681e28487eaSFelix Fietkau 
682e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
683e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
684e28487eaSFelix Fietkau 
685e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
686e28487eaSFelix Fietkau 	}
687e28487eaSFelix Fietkau 
688ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
689e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
690e28487eaSFelix Fietkau 
691e28487eaSFelix Fietkau out:
692e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
693e28487eaSFelix Fietkau 
694e28487eaSFelix Fietkau 	return ret;
695e28487eaSFelix Fietkau }
696e28487eaSFelix Fietkau 
69713f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
698723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
699723b90dcSFelix Fietkau {
700723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
70113f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
702723b90dcSFelix Fietkau 
703723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
704723b90dcSFelix Fietkau 	synchronize_rcu();
705723b90dcSFelix Fietkau 
706e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
707e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
708e28487eaSFelix Fietkau 
709723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
710723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
711723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
712723b90dcSFelix Fietkau 	mt76_wcid_free(dev->wcid_mask, idx);
71313f61dfcSLorenzo Bianconi }
71413f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
715e28487eaSFelix Fietkau 
71613f61dfcSLorenzo Bianconi static void
71713f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
71813f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
71913f61dfcSLorenzo Bianconi {
72013f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
72113f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
722723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
723723b90dcSFelix Fietkau }
724e28487eaSFelix Fietkau 
725e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
726e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
727e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
728e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
729e28487eaSFelix Fietkau {
730e28487eaSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
731e28487eaSFelix Fietkau 
732e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
733e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
734e28487eaSFelix Fietkau 		return mt76_sta_add(dev, vif, sta);
735e28487eaSFelix Fietkau 
7369c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
7379c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
7389c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
7399c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
7409c193de5SFelix Fietkau 
741e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
742e28487eaSFelix Fietkau 		 new_state == IEEE80211_STA_NOTEXIST)
743e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
744e28487eaSFelix Fietkau 
745e28487eaSFelix Fietkau 	return 0;
746e28487eaSFelix Fietkau }
747e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
7489313faacSFelix Fietkau 
7499313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
7509313faacSFelix Fietkau 		     int *dbm)
7519313faacSFelix Fietkau {
7529313faacSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
753d0ff23c1SBen Hutchings 	int n_chains = hweight8(dev->antenna_mask);
7549313faacSFelix Fietkau 
755cee646d6SFelix Fietkau 	*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
7569313faacSFelix Fietkau 
7579313faacSFelix Fietkau 	/* convert from per-chain power to combined
758c19b0ca5SLorenzo Bianconi 	 * output power
7599313faacSFelix Fietkau 	 */
760c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
761c19b0ca5SLorenzo Bianconi 	case 4:
762c19b0ca5SLorenzo Bianconi 		*dbm += 6;
763c19b0ca5SLorenzo Bianconi 		break;
764c19b0ca5SLorenzo Bianconi 	case 3:
765c19b0ca5SLorenzo Bianconi 		*dbm += 4;
766c19b0ca5SLorenzo Bianconi 		break;
767c19b0ca5SLorenzo Bianconi 	case 2:
7689313faacSFelix Fietkau 		*dbm += 3;
769c19b0ca5SLorenzo Bianconi 		break;
770c19b0ca5SLorenzo Bianconi 	default:
771c19b0ca5SLorenzo Bianconi 		break;
772c19b0ca5SLorenzo Bianconi 	}
7739313faacSFelix Fietkau 
7749313faacSFelix Fietkau 	return 0;
7759313faacSFelix Fietkau }
7769313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
777e7173858SFelix Fietkau 
778e7173858SFelix Fietkau static void
779e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
780e7173858SFelix Fietkau {
781e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
782e7173858SFelix Fietkau 	    ieee80211_csa_finish(vif);
783e7173858SFelix Fietkau }
784e7173858SFelix Fietkau 
785e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
786e7173858SFelix Fietkau {
787e7173858SFelix Fietkau 	if (!dev->csa_complete)
788e7173858SFelix Fietkau 		return;
789e7173858SFelix Fietkau 
790e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
791e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
792e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
793e7173858SFelix Fietkau 
794e7173858SFelix Fietkau 	dev->csa_complete = 0;
795e7173858SFelix Fietkau }
796e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
797e7173858SFelix Fietkau 
798e7173858SFelix Fietkau static void
799e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
800e7173858SFelix Fietkau {
801e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
802e7173858SFelix Fietkau 
803e7173858SFelix Fietkau 	if (!vif->csa_active)
804e7173858SFelix Fietkau 		return;
805e7173858SFelix Fietkau 
806e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
807e7173858SFelix Fietkau }
808e7173858SFelix Fietkau 
809e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
810e7173858SFelix Fietkau {
811e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
812e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
813e7173858SFelix Fietkau 		__mt76_csa_check, dev);
814e7173858SFelix Fietkau }
815e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
81687d53103SStanislaw Gruszka 
81787d53103SStanislaw Gruszka int
81887d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
81987d53103SStanislaw Gruszka {
82087d53103SStanislaw Gruszka 	return 0;
82187d53103SStanislaw Gruszka }
82287d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
823eadfd98fSLorenzo Bianconi 
824eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
825eadfd98fSLorenzo Bianconi {
826eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
827eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
828eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
829eadfd98fSLorenzo Bianconi 
830eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
831eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
832eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
833eadfd98fSLorenzo Bianconi 
834eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
835eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
836eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
837eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
838eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
839eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
840eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
841eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
842eadfd98fSLorenzo Bianconi 
843eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
844eadfd98fSLorenzo Bianconi }
845eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
846d2679d65SLorenzo Bianconi 
847d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
848d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
849d2679d65SLorenzo Bianconi 		  int idx, bool cck)
850d2679d65SLorenzo Bianconi {
851d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
852d2679d65SLorenzo Bianconi 
853d2679d65SLorenzo Bianconi 	if (cck) {
854d2679d65SLorenzo Bianconi 		if (sband == &dev->sband_5g.sband)
855d2679d65SLorenzo Bianconi 			return 0;
856d2679d65SLorenzo Bianconi 
857d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
858d2679d65SLorenzo Bianconi 	} else if (sband == &dev->sband_2g.sband) {
859d2679d65SLorenzo Bianconi 		offset = 4;
860d2679d65SLorenzo Bianconi 	}
861d2679d65SLorenzo Bianconi 
862d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
863d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
864d2679d65SLorenzo Bianconi 			return i;
865d2679d65SLorenzo Bianconi 	}
866d2679d65SLorenzo Bianconi 
867d2679d65SLorenzo Bianconi 	return 0;
868d2679d65SLorenzo Bianconi }
869d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
870