xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision c19b0ca503a855f41358f98ac533d2a4e867fe34)
117f1de56SFelix Fietkau /*
217f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
317f1de56SFelix Fietkau  *
417f1de56SFelix Fietkau  * Permission to use, copy, modify, and/or distribute this software for any
517f1de56SFelix Fietkau  * purpose with or without fee is hereby granted, provided that the above
617f1de56SFelix Fietkau  * copyright notice and this permission notice appear in all copies.
717f1de56SFelix Fietkau  *
817f1de56SFelix Fietkau  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
917f1de56SFelix Fietkau  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1017f1de56SFelix Fietkau  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1117f1de56SFelix Fietkau  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1217f1de56SFelix Fietkau  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1317f1de56SFelix Fietkau  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1417f1de56SFelix Fietkau  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1517f1de56SFelix Fietkau  */
1617f1de56SFelix Fietkau #include <linux/of.h>
1717f1de56SFelix Fietkau #include "mt76.h"
1817f1de56SFelix Fietkau 
1917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
2017f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
2117f1de56SFelix Fietkau 	.center_freq = (_freq),			\
2217f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2317f1de56SFelix Fietkau 	.max_power = 30,			\
2417f1de56SFelix Fietkau }
2517f1de56SFelix Fietkau 
2617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
2717f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
2817f1de56SFelix Fietkau 	.center_freq = (_freq),			\
2917f1de56SFelix Fietkau 	.hw_value = (_idx),			\
3017f1de56SFelix Fietkau 	.max_power = 30,			\
3117f1de56SFelix Fietkau }
3217f1de56SFelix Fietkau 
3317f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3417f1de56SFelix Fietkau 	CHAN2G(1, 2412),
3517f1de56SFelix Fietkau 	CHAN2G(2, 2417),
3617f1de56SFelix Fietkau 	CHAN2G(3, 2422),
3717f1de56SFelix Fietkau 	CHAN2G(4, 2427),
3817f1de56SFelix Fietkau 	CHAN2G(5, 2432),
3917f1de56SFelix Fietkau 	CHAN2G(6, 2437),
4017f1de56SFelix Fietkau 	CHAN2G(7, 2442),
4117f1de56SFelix Fietkau 	CHAN2G(8, 2447),
4217f1de56SFelix Fietkau 	CHAN2G(9, 2452),
4317f1de56SFelix Fietkau 	CHAN2G(10, 2457),
4417f1de56SFelix Fietkau 	CHAN2G(11, 2462),
4517f1de56SFelix Fietkau 	CHAN2G(12, 2467),
4617f1de56SFelix Fietkau 	CHAN2G(13, 2472),
4717f1de56SFelix Fietkau 	CHAN2G(14, 2484),
4817f1de56SFelix Fietkau };
4917f1de56SFelix Fietkau 
5017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
5117f1de56SFelix Fietkau 	CHAN5G(36, 5180),
5217f1de56SFelix Fietkau 	CHAN5G(40, 5200),
5317f1de56SFelix Fietkau 	CHAN5G(44, 5220),
5417f1de56SFelix Fietkau 	CHAN5G(48, 5240),
5517f1de56SFelix Fietkau 
5617f1de56SFelix Fietkau 	CHAN5G(52, 5260),
5717f1de56SFelix Fietkau 	CHAN5G(56, 5280),
5817f1de56SFelix Fietkau 	CHAN5G(60, 5300),
5917f1de56SFelix Fietkau 	CHAN5G(64, 5320),
6017f1de56SFelix Fietkau 
6117f1de56SFelix Fietkau 	CHAN5G(100, 5500),
6217f1de56SFelix Fietkau 	CHAN5G(104, 5520),
6317f1de56SFelix Fietkau 	CHAN5G(108, 5540),
6417f1de56SFelix Fietkau 	CHAN5G(112, 5560),
6517f1de56SFelix Fietkau 	CHAN5G(116, 5580),
6617f1de56SFelix Fietkau 	CHAN5G(120, 5600),
6717f1de56SFelix Fietkau 	CHAN5G(124, 5620),
6817f1de56SFelix Fietkau 	CHAN5G(128, 5640),
6917f1de56SFelix Fietkau 	CHAN5G(132, 5660),
7017f1de56SFelix Fietkau 	CHAN5G(136, 5680),
7117f1de56SFelix Fietkau 	CHAN5G(140, 5700),
7217f1de56SFelix Fietkau 
7317f1de56SFelix Fietkau 	CHAN5G(149, 5745),
7417f1de56SFelix Fietkau 	CHAN5G(153, 5765),
7517f1de56SFelix Fietkau 	CHAN5G(157, 5785),
7617f1de56SFelix Fietkau 	CHAN5G(161, 5805),
7717f1de56SFelix Fietkau 	CHAN5G(165, 5825),
7817f1de56SFelix Fietkau };
7917f1de56SFelix Fietkau 
8017f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
8117f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
8217f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
8317f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
8417f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
8517f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
8617f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
8717f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
8817f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
8917f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
9017f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
9117f1de56SFelix Fietkau };
9217f1de56SFelix Fietkau 
9317f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
9417f1de56SFelix Fietkau {
9517f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
9617f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
9717f1de56SFelix Fietkau 	int led_pin;
9817f1de56SFelix Fietkau 
9917f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
10017f1de56SFelix Fietkau 		return 0;
10117f1de56SFelix Fietkau 
10217f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
10317f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
10417f1de56SFelix Fietkau 
10517f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
10617f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
10717f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
10817f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
10917f1de56SFelix Fietkau 					mt76_tpt_blink,
11017f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
11117f1de56SFelix Fietkau 
11217f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
11317f1de56SFelix Fietkau 	if (np) {
11417f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
11517f1de56SFelix Fietkau 			dev->led_pin = led_pin;
11617f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
11717f1de56SFelix Fietkau 	}
11817f1de56SFelix Fietkau 
11917f1de56SFelix Fietkau 	return devm_led_classdev_register(dev->dev, &dev->led_cdev);
12017f1de56SFelix Fietkau }
12117f1de56SFelix Fietkau 
122551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev,
123551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
124551e1ef4SLorenzo Bianconi 				 bool vht)
125551e1ef4SLorenzo Bianconi {
126551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
127d0ff23c1SBen Hutchings 	int i, nstream = hweight8(dev->antenna_mask);
128551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
129551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
130551e1ef4SLorenzo Bianconi 
131551e1ef4SLorenzo Bianconi 	if (nstream > 1)
132551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
133551e1ef4SLorenzo Bianconi 	else
134551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
135551e1ef4SLorenzo Bianconi 
136551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
137551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
138551e1ef4SLorenzo Bianconi 
139551e1ef4SLorenzo Bianconi 	if (!vht)
140551e1ef4SLorenzo Bianconi 		return;
141551e1ef4SLorenzo Bianconi 
142551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
143551e1ef4SLorenzo Bianconi 	if (nstream > 1)
144551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
145551e1ef4SLorenzo Bianconi 	else
146551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
147551e1ef4SLorenzo Bianconi 
148551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
149551e1ef4SLorenzo Bianconi 		if (i < nstream)
150551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
151551e1ef4SLorenzo Bianconi 		else
152551e1ef4SLorenzo Bianconi 			mcs_map |=
153551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
154551e1ef4SLorenzo Bianconi 	}
155551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
156551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
157551e1ef4SLorenzo Bianconi }
158551e1ef4SLorenzo Bianconi 
1595ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
1605ebdc3e0SLorenzo Bianconi {
1615ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_2ghz)
1625ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_2g.sband, false);
1635ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_5ghz)
1645ebdc3e0SLorenzo Bianconi 		mt76_init_stream_cap(dev, &dev->sband_5g.sband, vht);
1655ebdc3e0SLorenzo Bianconi }
1665ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1675ebdc3e0SLorenzo Bianconi 
16817f1de56SFelix Fietkau static int
16917f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
17017f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
17117f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
17217f1de56SFelix Fietkau {
17317f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
17417f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
17517f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
17617f1de56SFelix Fietkau 	void *chanlist;
17717f1de56SFelix Fietkau 	int size;
17817f1de56SFelix Fietkau 
17917f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
18017f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
18117f1de56SFelix Fietkau 	if (!chanlist)
18217f1de56SFelix Fietkau 		return -ENOMEM;
18317f1de56SFelix Fietkau 
184a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
18517f1de56SFelix Fietkau 				    GFP_KERNEL);
18617f1de56SFelix Fietkau 	if (!msband->chan)
18717f1de56SFelix Fietkau 		return -ENOMEM;
18817f1de56SFelix Fietkau 
18917f1de56SFelix Fietkau 	sband->channels = chanlist;
19017f1de56SFelix Fietkau 	sband->n_channels = n_chan;
19117f1de56SFelix Fietkau 	sband->bitrates = rates;
19217f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
19317f1de56SFelix Fietkau 	dev->chandef.chan = &sband->channels[0];
19417f1de56SFelix Fietkau 
19517f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
19617f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
19717f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
19817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
19917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
20017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
20117f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
20217f1de56SFelix Fietkau 
20317f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
20417f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20517f1de56SFelix Fietkau 	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
20617f1de56SFelix Fietkau 
207551e1ef4SLorenzo Bianconi 	mt76_init_stream_cap(dev, sband, vht);
208551e1ef4SLorenzo Bianconi 
20917f1de56SFelix Fietkau 	if (!vht)
21017f1de56SFelix Fietkau 		return 0;
21117f1de56SFelix Fietkau 
21217f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
21317f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
21417f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
21517f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
21649149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
217f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
218f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
21949149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
22017f1de56SFelix Fietkau 
22117f1de56SFelix Fietkau 	return 0;
22217f1de56SFelix Fietkau }
22317f1de56SFelix Fietkau 
22417f1de56SFelix Fietkau static int
22517f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22617f1de56SFelix Fietkau 		   int n_rates)
22717f1de56SFelix Fietkau {
22817f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband;
22917f1de56SFelix Fietkau 
23017f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_2g,
23117f1de56SFelix Fietkau 			       mt76_channels_2ghz,
23217f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
23317f1de56SFelix Fietkau 			       rates, n_rates, false);
23417f1de56SFelix Fietkau }
23517f1de56SFelix Fietkau 
23617f1de56SFelix Fietkau static int
23717f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
23817f1de56SFelix Fietkau 		   int n_rates, bool vht)
23917f1de56SFelix Fietkau {
24017f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband;
24117f1de56SFelix Fietkau 
24217f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_5g,
24317f1de56SFelix Fietkau 			       mt76_channels_5ghz,
24417f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
24517f1de56SFelix Fietkau 			       rates, n_rates, vht);
24617f1de56SFelix Fietkau }
24717f1de56SFelix Fietkau 
24817f1de56SFelix Fietkau static void
24917f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band)
25017f1de56SFelix Fietkau {
25117f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band];
25217f1de56SFelix Fietkau 	bool found = false;
25317f1de56SFelix Fietkau 	int i;
25417f1de56SFelix Fietkau 
25517f1de56SFelix Fietkau 	if (!sband)
25617f1de56SFelix Fietkau 		return;
25717f1de56SFelix Fietkau 
25817f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
25917f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
26017f1de56SFelix Fietkau 			continue;
26117f1de56SFelix Fietkau 
26217f1de56SFelix Fietkau 		found = true;
26317f1de56SFelix Fietkau 		break;
26417f1de56SFelix Fietkau 	}
26517f1de56SFelix Fietkau 
26617f1de56SFelix Fietkau 	if (found)
26717f1de56SFelix Fietkau 		return;
26817f1de56SFelix Fietkau 
26917f1de56SFelix Fietkau 	sband->n_channels = 0;
27017f1de56SFelix Fietkau 	dev->hw->wiphy->bands[band] = NULL;
27117f1de56SFelix Fietkau }
27217f1de56SFelix Fietkau 
273a85b590cSFelix Fietkau struct mt76_dev *
274c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
275c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
276c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
277a85b590cSFelix Fietkau {
278a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
279a85b590cSFelix Fietkau 	struct mt76_dev *dev;
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 
290a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
291a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
292a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
293108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
29426e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
29588046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
296a85b590cSFelix Fietkau 
297a85b590cSFelix Fietkau 	return dev;
298a85b590cSFelix Fietkau }
299a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
300a85b590cSFelix Fietkau 
30117f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
30217f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
30317f1de56SFelix Fietkau {
30417f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
30517f1de56SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
30617f1de56SFelix Fietkau 	int ret;
30717f1de56SFelix Fietkau 
30817f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
30917f1de56SFelix Fietkau 
31017f1de56SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
31117f1de56SFelix Fietkau 
31217f1de56SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
31317f1de56SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
31417f1de56SFelix Fietkau 
31517f1de56SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
31617f1de56SFelix Fietkau 
317b37b30afSKristian Evensen 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
318b37b30afSKristian Evensen 
31924114a5fSLorenzo Bianconi 	wiphy->available_antennas_tx = dev->antenna_mask;
32024114a5fSLorenzo Bianconi 	wiphy->available_antennas_rx = dev->antenna_mask;
32124114a5fSLorenzo Bianconi 
32217f1de56SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
32317f1de56SFelix Fietkau 	hw->max_tx_fragments = 16;
32417f1de56SFelix Fietkau 
32517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
32617f1de56SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
32717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
32817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
32917f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
33017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
33117f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
33217f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
33317f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
33417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
33517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
336d71ef286SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
33788046b2cSFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
338f545540dSFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
33917f1de56SFelix Fietkau 
34017f1de56SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
34117f1de56SFelix Fietkau 
34217f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
34317f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
34417f1de56SFelix Fietkau 		if (ret)
34517f1de56SFelix Fietkau 			return ret;
34617f1de56SFelix Fietkau 	}
34717f1de56SFelix Fietkau 
34817f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
34917f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
35017f1de56SFelix Fietkau 		if (ret)
35117f1de56SFelix Fietkau 			return ret;
35217f1de56SFelix Fietkau 	}
35317f1de56SFelix Fietkau 
35417f1de56SFelix Fietkau 	wiphy_read_of_freq_limits(dev->hw->wiphy);
35517f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_2GHZ);
35617f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_5GHZ);
35717f1de56SFelix Fietkau 
358b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
35917f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
36017f1de56SFelix Fietkau 		if (ret)
36117f1de56SFelix Fietkau 			return ret;
362b374e868SArnd Bergmann 	}
36317f1de56SFelix Fietkau 
36417f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
36517f1de56SFelix Fietkau }
36617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
36717f1de56SFelix Fietkau 
36817f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
36917f1de56SFelix Fietkau {
37017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
37117f1de56SFelix Fietkau 
37279d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
37317f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
37417f1de56SFelix Fietkau }
37517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
37617f1de56SFelix Fietkau 
377def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
378def34a2fSLorenzo Bianconi {
379def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
380def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
381def34a2fSLorenzo Bianconi }
382def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
383def34a2fSLorenzo Bianconi 
38417f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
38517f1de56SFelix Fietkau {
38617f1de56SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state)) {
38717f1de56SFelix Fietkau 		dev_kfree_skb(skb);
38817f1de56SFelix Fietkau 		return;
38917f1de56SFelix Fietkau 	}
39017f1de56SFelix Fietkau 
39117f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
39217f1de56SFelix Fietkau }
39317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
39417f1de56SFelix Fietkau 
39539d501d9SStanislaw Gruszka bool mt76_has_tx_pending(struct mt76_dev *dev)
39626e40d4cSFelix Fietkau {
397af005f26SLorenzo Bianconi 	struct mt76_queue *q;
39826e40d4cSFelix Fietkau 	int i;
39926e40d4cSFelix Fietkau 
40026e40d4cSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
401af005f26SLorenzo Bianconi 		q = dev->q_tx[i].q;
402af005f26SLorenzo Bianconi 		if (q && q->queued)
40326e40d4cSFelix Fietkau 			return true;
40426e40d4cSFelix Fietkau 	}
40526e40d4cSFelix Fietkau 
40626e40d4cSFelix Fietkau 	return false;
40726e40d4cSFelix Fietkau }
40839d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
40926e40d4cSFelix Fietkau 
41017f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev)
41117f1de56SFelix Fietkau {
41217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
41317f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
41417f1de56SFelix Fietkau 	struct mt76_channel_state *state;
41517f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
41626e40d4cSFelix Fietkau 	int timeout = HZ / 5;
41717f1de56SFelix Fietkau 
41889bc67e3SFelix Fietkau 	if (offchannel)
41989bc67e3SFelix Fietkau 		set_bit(MT76_OFFCHANNEL, &dev->state);
42089bc67e3SFelix Fietkau 	else
42189bc67e3SFelix Fietkau 		clear_bit(MT76_OFFCHANNEL, &dev->state);
42289bc67e3SFelix Fietkau 
42326e40d4cSFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
42426e40d4cSFelix Fietkau 
42517f1de56SFelix Fietkau 	if (dev->drv->update_survey)
42617f1de56SFelix Fietkau 		dev->drv->update_survey(dev);
42717f1de56SFelix Fietkau 
42817f1de56SFelix Fietkau 	dev->chandef = *chandef;
42917f1de56SFelix Fietkau 
43017f1de56SFelix Fietkau 	if (!offchannel)
43117f1de56SFelix Fietkau 		dev->main_chan = chandef->chan;
43217f1de56SFelix Fietkau 
43317f1de56SFelix Fietkau 	if (chandef->chan != dev->main_chan) {
43417f1de56SFelix Fietkau 		state = mt76_channel_state(dev, chandef->chan);
43517f1de56SFelix Fietkau 		memset(state, 0, sizeof(*state));
43617f1de56SFelix Fietkau 	}
43717f1de56SFelix Fietkau }
43817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
43917f1de56SFelix Fietkau 
44017f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
44117f1de56SFelix Fietkau 		    struct survey_info *survey)
44217f1de56SFelix Fietkau {
44317f1de56SFelix Fietkau 	struct mt76_dev *dev = hw->priv;
44417f1de56SFelix Fietkau 	struct mt76_sband *sband;
44517f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
44617f1de56SFelix Fietkau 	struct mt76_channel_state *state;
44717f1de56SFelix Fietkau 	int ret = 0;
44817f1de56SFelix Fietkau 
44917f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
45017f1de56SFelix Fietkau 		dev->drv->update_survey(dev);
45117f1de56SFelix Fietkau 
45217f1de56SFelix Fietkau 	sband = &dev->sband_2g;
45317f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
45417f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
45517f1de56SFelix Fietkau 		sband = &dev->sband_5g;
45617f1de56SFelix Fietkau 	}
45717f1de56SFelix Fietkau 
45817f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels)
45917f1de56SFelix Fietkau 		return -ENOENT;
46017f1de56SFelix Fietkau 
46117f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
46217f1de56SFelix Fietkau 	state = mt76_channel_state(dev, chan);
46317f1de56SFelix Fietkau 
46417f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
46517f1de56SFelix Fietkau 	survey->channel = chan;
46617f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
46717f1de56SFelix Fietkau 	if (chan == dev->main_chan)
46817f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
46917f1de56SFelix Fietkau 
47017f1de56SFelix Fietkau 	spin_lock_bh(&dev->cc_lock);
47117f1de56SFelix Fietkau 	survey->time = div_u64(state->cc_active, 1000);
47217f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
47317f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
47417f1de56SFelix Fietkau 
47517f1de56SFelix Fietkau 	return ret;
47617f1de56SFelix Fietkau }
47717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
47817f1de56SFelix Fietkau 
47930ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
48030ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
48130ce7f44SFelix Fietkau {
48230ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
48330ce7f44SFelix Fietkau 	int i;
48430ce7f44SFelix Fietkau 
48530ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
48630ce7f44SFelix Fietkau 
48730ce7f44SFelix Fietkau 	if (!key)
48830ce7f44SFelix Fietkau 		return;
48930ce7f44SFelix Fietkau 
49030ce7f44SFelix Fietkau 	if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
49130ce7f44SFelix Fietkau 		wcid->rx_check_pn = true;
49230ce7f44SFelix Fietkau 
49330ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
49430ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
49530ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
49630ce7f44SFelix Fietkau 	}
49730ce7f44SFelix Fietkau }
49830ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
49930ce7f44SFelix Fietkau 
50082e1dd0fSStanislaw Gruszka struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
5014e34249eSFelix Fietkau {
5024e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
5034e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
5044e34249eSFelix Fietkau 
5054e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *) skb->cb);
5064e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
5074e34249eSFelix Fietkau 
5084e34249eSFelix Fietkau 	status->flag = mstat.flag;
5094e34249eSFelix Fietkau 	status->freq = mstat.freq;
5104e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
5114e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
5124e34249eSFelix Fietkau 	status->bw = mstat.bw;
5134e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
5144e34249eSFelix Fietkau 	status->nss = mstat.nss;
5154e34249eSFelix Fietkau 	status->band = mstat.band;
5164e34249eSFelix Fietkau 	status->signal = mstat.signal;
5174e34249eSFelix Fietkau 	status->chains = mstat.chains;
5184e34249eSFelix Fietkau 
5194e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
5204e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal));
5214e34249eSFelix Fietkau 	memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal));
5229c68a57bSFelix Fietkau 
5239c68a57bSFelix Fietkau 	return wcid_to_sta(mstat.wcid);
5244e34249eSFelix Fietkau }
52582e1dd0fSStanislaw Gruszka EXPORT_SYMBOL(mt76_rx_convert);
5264e34249eSFelix Fietkau 
52730ce7f44SFelix Fietkau static int
52830ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
52930ce7f44SFelix Fietkau {
53030ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
53130ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
53230ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
53330ce7f44SFelix Fietkau 	int ret;
53430ce7f44SFelix Fietkau 
53530ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
53630ce7f44SFelix Fietkau 		return 0;
53730ce7f44SFelix Fietkau 
53830ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
53930ce7f44SFelix Fietkau 		return 0;
54030ce7f44SFelix Fietkau 
54130ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
54230ce7f44SFelix Fietkau 		/*
54330ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
54430ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
54530ce7f44SFelix Fietkau 		 */
54630ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *) skb->data;
54730ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
54830ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
54930ce7f44SFelix Fietkau 			return 0;
55030ce7f44SFelix Fietkau 	}
55130ce7f44SFelix Fietkau 
55230ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
55330ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
55430ce7f44SFelix Fietkau 		     sizeof(status->iv));
55530ce7f44SFelix Fietkau 	if (ret <= 0)
55630ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
55730ce7f44SFelix Fietkau 
55830ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
55930ce7f44SFelix Fietkau 
56030ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
56130ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
56230ce7f44SFelix Fietkau 
56330ce7f44SFelix Fietkau 	return 0;
56430ce7f44SFelix Fietkau }
56530ce7f44SFelix Fietkau 
566d71ef286SFelix Fietkau static void
567ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
568d71ef286SFelix Fietkau {
569d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
570d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
571d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
572d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
573d71ef286SFelix Fietkau 	bool ps;
57490fdc171SFelix Fietkau 	int i;
575d71ef286SFelix Fietkau 
57636d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
57736d91096SFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL);
57836d91096SFelix Fietkau 		if (sta)
57936d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv;
58036d91096SFelix Fietkau 	}
58136d91096SFelix Fietkau 
582d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
583d71ef286SFelix Fietkau 		return;
584d71ef286SFelix Fietkau 
585d71ef286SFelix Fietkau 	sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv);
586d71ef286SFelix Fietkau 
58702e5a769SFelix Fietkau 	if (status->signal <= 0)
58802e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
58902e5a769SFelix Fietkau 
590ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
591ef13edc0SFelix Fietkau 
592d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
593d71ef286SFelix Fietkau 		return;
594d71ef286SFelix Fietkau 
595d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
596d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
597d71ef286SFelix Fietkau 		return;
598d71ef286SFelix Fietkau 	}
599d71ef286SFelix Fietkau 
600d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
601d71ef286SFelix Fietkau 		!(ieee80211_is_mgmt(hdr->frame_control) ||
602d71ef286SFelix Fietkau 		  ieee80211_is_data(hdr->frame_control)))
603d71ef286SFelix Fietkau 		return;
604d71ef286SFelix Fietkau 
605d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
606d71ef286SFelix Fietkau 
607d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
608d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
609d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
610d71ef286SFelix Fietkau 
611d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
612d71ef286SFelix Fietkau 		return;
613d71ef286SFelix Fietkau 
61411b2a25fSFelix Fietkau 	if (ps)
615d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
61611b2a25fSFelix Fietkau 	else
617d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
618d71ef286SFelix Fietkau 
619d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
6209f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
62190fdc171SFelix Fietkau 
62290fdc171SFelix Fietkau 	if (ps)
62390fdc171SFelix Fietkau 		return;
62490fdc171SFelix Fietkau 
62590fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
62690fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
62790fdc171SFelix Fietkau 
62890fdc171SFelix Fietkau 		if (!sta->txq[i])
62990fdc171SFelix Fietkau 			continue;
63090fdc171SFelix Fietkau 
63190fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv;
63290fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
63390fdc171SFelix Fietkau 			ieee80211_schedule_txq(dev->hw, sta->txq[i]);
63490fdc171SFelix Fietkau 	}
635d71ef286SFelix Fietkau }
636d71ef286SFelix Fietkau 
6379d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
63881e850efSLorenzo Bianconi 		      struct napi_struct *napi)
63917f1de56SFelix Fietkau {
6409c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
6419d9d738bSFelix Fietkau 	struct sk_buff *skb;
6429d9d738bSFelix Fietkau 
643c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
6449d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
64530ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
64630ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
64730ce7f44SFelix Fietkau 			continue;
64830ce7f44SFelix Fietkau 		}
64930ce7f44SFelix Fietkau 
6509d9d738bSFelix Fietkau 		sta = mt76_rx_convert(skb);
6519d9d738bSFelix Fietkau 		ieee80211_rx_napi(dev->hw, sta, skb, napi);
6529d9d738bSFelix Fietkau 	}
653c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
6549d9d738bSFelix Fietkau }
6559d9d738bSFelix Fietkau 
65681e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
65781e850efSLorenzo Bianconi 			   struct napi_struct *napi)
6589d9d738bSFelix Fietkau {
659aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
66017f1de56SFelix Fietkau 	struct sk_buff *skb;
66117f1de56SFelix Fietkau 
662aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
663aee5b8cfSFelix Fietkau 
664d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
665ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
666aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
667d71ef286SFelix Fietkau 	}
668aee5b8cfSFelix Fietkau 
66981e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
6704e34249eSFelix Fietkau }
67181e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
672723b90dcSFelix Fietkau 
673e28487eaSFelix Fietkau static int
674e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
675e28487eaSFelix Fietkau 	     struct ieee80211_sta *sta)
676e28487eaSFelix Fietkau {
677e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
678e28487eaSFelix Fietkau 	int ret;
679e28487eaSFelix Fietkau 	int i;
680e28487eaSFelix Fietkau 
681e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
682e28487eaSFelix Fietkau 
683e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
684e28487eaSFelix Fietkau 	if (ret)
685e28487eaSFelix Fietkau 		goto out;
686e28487eaSFelix Fietkau 
687e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
688e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
689e28487eaSFelix Fietkau 
690e28487eaSFelix Fietkau 		if (!sta->txq[i])
691e28487eaSFelix Fietkau 			continue;
692e28487eaSFelix Fietkau 
693e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
694e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
695e28487eaSFelix Fietkau 
696e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
697e28487eaSFelix Fietkau 	}
698e28487eaSFelix Fietkau 
699ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
700e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
701e28487eaSFelix Fietkau 
702e28487eaSFelix Fietkau out:
703e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
704e28487eaSFelix Fietkau 
705e28487eaSFelix Fietkau 	return ret;
706e28487eaSFelix Fietkau }
707e28487eaSFelix Fietkau 
70813f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
709723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
710723b90dcSFelix Fietkau {
711723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
71213f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
713723b90dcSFelix Fietkau 
714723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
715723b90dcSFelix Fietkau 	synchronize_rcu();
716723b90dcSFelix Fietkau 
717e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
718e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
719e28487eaSFelix Fietkau 
720723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
721723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
722723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
723723b90dcSFelix Fietkau 	mt76_wcid_free(dev->wcid_mask, idx);
72413f61dfcSLorenzo Bianconi }
72513f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
726e28487eaSFelix Fietkau 
72713f61dfcSLorenzo Bianconi static void
72813f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
72913f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
73013f61dfcSLorenzo Bianconi {
73113f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
73213f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
733723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
734723b90dcSFelix Fietkau }
735e28487eaSFelix Fietkau 
736e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
737e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
738e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
739e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
740e28487eaSFelix Fietkau {
741e28487eaSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
742e28487eaSFelix Fietkau 
743e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
744e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
745e28487eaSFelix Fietkau 		return mt76_sta_add(dev, vif, sta);
746e28487eaSFelix Fietkau 
7479c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
7489c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
7499c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
7509c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
7519c193de5SFelix Fietkau 
752e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
753e28487eaSFelix Fietkau 		 new_state == IEEE80211_STA_NOTEXIST)
754e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
755e28487eaSFelix Fietkau 
756e28487eaSFelix Fietkau 	return 0;
757e28487eaSFelix Fietkau }
758e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
7599313faacSFelix Fietkau 
7609313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
7619313faacSFelix Fietkau 		     int *dbm)
7629313faacSFelix Fietkau {
7639313faacSFelix Fietkau 	struct mt76_dev *dev = hw->priv;
764d0ff23c1SBen Hutchings 	int n_chains = hweight8(dev->antenna_mask);
7659313faacSFelix Fietkau 
766cee646d6SFelix Fietkau 	*dbm = DIV_ROUND_UP(dev->txpower_cur, 2);
7679313faacSFelix Fietkau 
7689313faacSFelix Fietkau 	/* convert from per-chain power to combined
769*c19b0ca5SLorenzo Bianconi 	 * output power
7709313faacSFelix Fietkau 	 */
771*c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
772*c19b0ca5SLorenzo Bianconi 	case 4:
773*c19b0ca5SLorenzo Bianconi 		*dbm += 6;
774*c19b0ca5SLorenzo Bianconi 		break;
775*c19b0ca5SLorenzo Bianconi 	case 3:
776*c19b0ca5SLorenzo Bianconi 		*dbm += 4;
777*c19b0ca5SLorenzo Bianconi 		break;
778*c19b0ca5SLorenzo Bianconi 	case 2:
7799313faacSFelix Fietkau 		*dbm += 3;
780*c19b0ca5SLorenzo Bianconi 		break;
781*c19b0ca5SLorenzo Bianconi 	default:
782*c19b0ca5SLorenzo Bianconi 		break;
783*c19b0ca5SLorenzo Bianconi 	}
7849313faacSFelix Fietkau 
7859313faacSFelix Fietkau 	return 0;
7869313faacSFelix Fietkau }
7879313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
788e7173858SFelix Fietkau 
789e7173858SFelix Fietkau static void
790e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
791e7173858SFelix Fietkau {
792e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
793e7173858SFelix Fietkau 	    ieee80211_csa_finish(vif);
794e7173858SFelix Fietkau }
795e7173858SFelix Fietkau 
796e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
797e7173858SFelix Fietkau {
798e7173858SFelix Fietkau 	if (!dev->csa_complete)
799e7173858SFelix Fietkau 		return;
800e7173858SFelix Fietkau 
801e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
802e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
803e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
804e7173858SFelix Fietkau 
805e7173858SFelix Fietkau 	dev->csa_complete = 0;
806e7173858SFelix Fietkau }
807e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
808e7173858SFelix Fietkau 
809e7173858SFelix Fietkau static void
810e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
811e7173858SFelix Fietkau {
812e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
813e7173858SFelix Fietkau 
814e7173858SFelix Fietkau 	if (!vif->csa_active)
815e7173858SFelix Fietkau 		return;
816e7173858SFelix Fietkau 
817e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
818e7173858SFelix Fietkau }
819e7173858SFelix Fietkau 
820e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
821e7173858SFelix Fietkau {
822e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
823e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
824e7173858SFelix Fietkau 		__mt76_csa_check, dev);
825e7173858SFelix Fietkau }
826e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
82787d53103SStanislaw Gruszka 
82887d53103SStanislaw Gruszka int
82987d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
83087d53103SStanislaw Gruszka {
83187d53103SStanislaw Gruszka 	return 0;
83287d53103SStanislaw Gruszka }
83387d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
834eadfd98fSLorenzo Bianconi 
835eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
836eadfd98fSLorenzo Bianconi {
837eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
838eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
839eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
840eadfd98fSLorenzo Bianconi 
841eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
842eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
843eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
844eadfd98fSLorenzo Bianconi 
845eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
846eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
847eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
848eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
849eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
850eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
851eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
852eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
853eadfd98fSLorenzo Bianconi 
854eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
855eadfd98fSLorenzo Bianconi }
856eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
857