xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 77ae1d5e13eb51651899fbfb6d7a34bc5ee7d4af)
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;
124beaaeb6bSFelix Fietkau 	int i, nstream = hweight8(dev->phy.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)
15996747a51SFelix Fietkau 		mt76_init_stream_cap(dev, &dev->phy.sband_2g.sband, false);
1605ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_5ghz)
16196747a51SFelix Fietkau 		mt76_init_stream_cap(dev, &dev->phy.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 
19117f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
19217f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
19317f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
19417f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
19517f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
19617f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
19717f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
19817f1de56SFelix Fietkau 
19917f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
20017f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20117f1de56SFelix Fietkau 
202551e1ef4SLorenzo Bianconi 	mt76_init_stream_cap(dev, sband, vht);
203551e1ef4SLorenzo Bianconi 
20417f1de56SFelix Fietkau 	if (!vht)
20517f1de56SFelix Fietkau 		return 0;
20617f1de56SFelix Fietkau 
20717f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
20817f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
20917f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
21017f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
21149149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
212f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
213f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
21449149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
21517f1de56SFelix Fietkau 
21617f1de56SFelix Fietkau 	return 0;
21717f1de56SFelix Fietkau }
21817f1de56SFelix Fietkau 
21917f1de56SFelix Fietkau static int
22017f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22117f1de56SFelix Fietkau 		   int n_rates)
22217f1de56SFelix Fietkau {
22396747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband;
22417f1de56SFelix Fietkau 
22596747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_2g,
22617f1de56SFelix Fietkau 			       mt76_channels_2ghz,
22717f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
22817f1de56SFelix Fietkau 			       rates, n_rates, false);
22917f1de56SFelix Fietkau }
23017f1de56SFelix Fietkau 
23117f1de56SFelix Fietkau static int
23217f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
23317f1de56SFelix Fietkau 		   int n_rates, bool vht)
23417f1de56SFelix Fietkau {
23596747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband;
23617f1de56SFelix Fietkau 
23796747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_5g,
23817f1de56SFelix Fietkau 			       mt76_channels_5ghz,
23917f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
24017f1de56SFelix Fietkau 			       rates, n_rates, vht);
24117f1de56SFelix Fietkau }
24217f1de56SFelix Fietkau 
24317f1de56SFelix Fietkau static void
244c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
245c89d3625SFelix Fietkau 		 enum nl80211_band band)
24617f1de56SFelix Fietkau {
247c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
24817f1de56SFelix Fietkau 	bool found = false;
24917f1de56SFelix Fietkau 	int i;
25017f1de56SFelix Fietkau 
25117f1de56SFelix Fietkau 	if (!sband)
25217f1de56SFelix Fietkau 		return;
25317f1de56SFelix Fietkau 
25417f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
25517f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
25617f1de56SFelix Fietkau 			continue;
25717f1de56SFelix Fietkau 
25817f1de56SFelix Fietkau 		found = true;
25917f1de56SFelix Fietkau 		break;
26017f1de56SFelix Fietkau 	}
26117f1de56SFelix Fietkau 
262c89d3625SFelix Fietkau 	if (found) {
263c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
264c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
26517f1de56SFelix Fietkau 		return;
266c89d3625SFelix Fietkau 	}
26717f1de56SFelix Fietkau 
26817f1de56SFelix Fietkau 	sband->n_channels = 0;
269c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
27017f1de56SFelix Fietkau }
27117f1de56SFelix Fietkau 
272c89d3625SFelix Fietkau static void
273c89d3625SFelix Fietkau mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
274c89d3625SFelix Fietkau {
275c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
276c89d3625SFelix Fietkau 
277c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
278c89d3625SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
279c89d3625SFelix Fietkau 
280c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
281dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
282dd89a013SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS;
283c89d3625SFelix Fietkau 
284c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
285c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
286d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
287c89d3625SFelix Fietkau 
288c89d3625SFelix Fietkau 	wiphy->available_antennas_tx = dev->phy.antenna_mask;
289c89d3625SFelix Fietkau 	wiphy->available_antennas_rx = dev->phy.antenna_mask;
290c89d3625SFelix Fietkau 
291c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
292c9619dfaSShayne Chen 
293c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
294c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
295c89d3625SFelix Fietkau 
296c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
297c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
298c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
299c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
300c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
301c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
302c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
303c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
304c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
305c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
306c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
307c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
308c89d3625SFelix Fietkau 
309c89d3625SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
310c89d3625SFelix Fietkau 	wiphy->interface_modes =
311c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
312c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
313c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
314c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
315c89d3625SFelix Fietkau #endif
316c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
317c89d3625SFelix Fietkau }
318c89d3625SFelix Fietkau 
319c89d3625SFelix Fietkau struct mt76_phy *
320c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
321c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
322c89d3625SFelix Fietkau {
323c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
324c89d3625SFelix Fietkau 	struct mt76_phy *phy;
325c89d3625SFelix Fietkau 	unsigned int phy_size, chan_size;
326c89d3625SFelix Fietkau 	unsigned int size_2g, size_5g;
327c89d3625SFelix Fietkau 	void *priv;
328c89d3625SFelix Fietkau 
329c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
330c89d3625SFelix Fietkau 	chan_size = sizeof(dev->phy.sband_2g.chan[0]);
331c89d3625SFelix Fietkau 	size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
332c89d3625SFelix Fietkau 	size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
333c89d3625SFelix Fietkau 
334c89d3625SFelix Fietkau 	size += phy_size + size_2g + size_5g;
335c89d3625SFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
336c89d3625SFelix Fietkau 	if (!hw)
337c89d3625SFelix Fietkau 		return NULL;
338c89d3625SFelix Fietkau 
339c89d3625SFelix Fietkau 	phy = hw->priv;
340c89d3625SFelix Fietkau 	phy->dev = dev;
341c89d3625SFelix Fietkau 	phy->hw = hw;
342c89d3625SFelix Fietkau 
343c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
344c89d3625SFelix Fietkau 
345c89d3625SFelix Fietkau 	priv = hw->priv + phy_size;
346c89d3625SFelix Fietkau 
347c89d3625SFelix Fietkau 	phy->sband_2g = dev->phy.sband_2g;
348c89d3625SFelix Fietkau 	phy->sband_2g.chan = priv;
349c89d3625SFelix Fietkau 	priv += size_2g;
350c89d3625SFelix Fietkau 
351c89d3625SFelix Fietkau 	phy->sband_5g = dev->phy.sband_5g;
352c89d3625SFelix Fietkau 	phy->sband_5g.chan = priv;
353c89d3625SFelix Fietkau 	priv += size_5g;
354c89d3625SFelix Fietkau 
355c89d3625SFelix Fietkau 	phy->priv = priv;
356c89d3625SFelix Fietkau 
357c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
358c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
359c89d3625SFelix Fietkau 
360c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
361c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
362c89d3625SFelix Fietkau 
363c89d3625SFelix Fietkau 	return phy;
364c89d3625SFelix Fietkau }
365c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
366c89d3625SFelix Fietkau 
367c89d3625SFelix Fietkau int
368c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy)
369c89d3625SFelix Fietkau {
370c89d3625SFelix Fietkau 	int ret;
371c89d3625SFelix Fietkau 
372c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
373c89d3625SFelix Fietkau 	if (ret)
374c89d3625SFelix Fietkau 		return ret;
375c89d3625SFelix Fietkau 
376c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
377c89d3625SFelix Fietkau 	return 0;
378c89d3625SFelix Fietkau }
379c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
380c89d3625SFelix Fietkau 
381c89d3625SFelix Fietkau void
382c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy)
383c89d3625SFelix Fietkau {
384c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
385c89d3625SFelix Fietkau 
386c89d3625SFelix Fietkau 	dev->phy2 = NULL;
387c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
388c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
389c89d3625SFelix Fietkau }
390c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
391c89d3625SFelix Fietkau 
392a85b590cSFelix Fietkau struct mt76_dev *
393c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
394c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
395c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
396a85b590cSFelix Fietkau {
397a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
398ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
399a85b590cSFelix Fietkau 	struct mt76_dev *dev;
400e5443256SFelix Fietkau 	int i;
401a85b590cSFelix Fietkau 
402a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
403a85b590cSFelix Fietkau 	if (!hw)
404a85b590cSFelix Fietkau 		return NULL;
405a85b590cSFelix Fietkau 
406a85b590cSFelix Fietkau 	dev = hw->priv;
407a85b590cSFelix Fietkau 	dev->hw = hw;
408c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
409c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
410c0f7b25aSLorenzo Bianconi 
411ac24dd35SFelix Fietkau 	phy = &dev->phy;
412ac24dd35SFelix Fietkau 	phy->dev = dev;
413ac24dd35SFelix Fietkau 	phy->hw = hw;
414ac24dd35SFelix Fietkau 
415a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
416a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
417a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
418108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
41926e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
42088046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
421a85b590cSFelix Fietkau 
42209872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
42309872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
42409872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
42509872957SLorenzo Bianconi 
426e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
427e5443256SFelix Fietkau 
428e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
429e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
430e5443256SFelix Fietkau 
431c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
432c325c9c7SLorenzo Bianconi 
433a85b590cSFelix Fietkau 	return dev;
434a85b590cSFelix Fietkau }
435a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
436a85b590cSFelix Fietkau 
43717f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
43817f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
43917f1de56SFelix Fietkau {
44017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
441c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
44217f1de56SFelix Fietkau 	int ret;
44317f1de56SFelix Fietkau 
44417f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
445c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
44617f1de56SFelix Fietkau 
44717f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
44817f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
44917f1de56SFelix Fietkau 		if (ret)
45017f1de56SFelix Fietkau 			return ret;
45117f1de56SFelix Fietkau 	}
45217f1de56SFelix Fietkau 
45317f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
45417f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
45517f1de56SFelix Fietkau 		if (ret)
45617f1de56SFelix Fietkau 			return ret;
45717f1de56SFelix Fietkau 	}
45817f1de56SFelix Fietkau 
459c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
460c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
461c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
46217f1de56SFelix Fietkau 
463b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
46417f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
46517f1de56SFelix Fietkau 		if (ret)
46617f1de56SFelix Fietkau 			return ret;
467b374e868SArnd Bergmann 	}
46817f1de56SFelix Fietkau 
46917f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
47017f1de56SFelix Fietkau }
47117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
47217f1de56SFelix Fietkau 
47317f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
47417f1de56SFelix Fietkau {
47517f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
47617f1de56SFelix Fietkau 
477d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
47836f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
47979d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
48017f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
48117f1de56SFelix Fietkau }
48217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
48317f1de56SFelix Fietkau 
484def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
485def34a2fSLorenzo Bianconi {
486def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
487def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
488def34a2fSLorenzo Bianconi }
489def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
490def34a2fSLorenzo Bianconi 
49117f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
49217f1de56SFelix Fietkau {
493011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
494011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
495011849e0SFelix Fietkau 
496011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
49717f1de56SFelix Fietkau 		dev_kfree_skb(skb);
49817f1de56SFelix Fietkau 		return;
49917f1de56SFelix Fietkau 	}
50017f1de56SFelix Fietkau 
50117f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
50217f1de56SFelix Fietkau }
50317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
50417f1de56SFelix Fietkau 
5055a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
50626e40d4cSFelix Fietkau {
5075a95ca41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
508af005f26SLorenzo Bianconi 	struct mt76_queue *q;
5095a95ca41SFelix Fietkau 	int i, offset;
51026e40d4cSFelix Fietkau 
5115a95ca41SFelix Fietkau 	offset = __MT_TXQ_MAX * (phy != &dev->phy);
5125a95ca41SFelix Fietkau 
5135a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
5145a95ca41SFelix Fietkau 		q = dev->q_tx[offset + i].q;
515af005f26SLorenzo Bianconi 		if (q && q->queued)
51626e40d4cSFelix Fietkau 			return true;
51726e40d4cSFelix Fietkau 	}
51826e40d4cSFelix Fietkau 
51926e40d4cSFelix Fietkau 	return false;
52026e40d4cSFelix Fietkau }
52139d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
52226e40d4cSFelix Fietkau 
5230fd0eb54SFelix Fietkau static struct mt76_channel_state *
52496747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
5250fd0eb54SFelix Fietkau {
5260fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
5270fd0eb54SFelix Fietkau 	int idx;
5280fd0eb54SFelix Fietkau 
5290fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
53096747a51SFelix Fietkau 		msband = &phy->sband_2g;
5310fd0eb54SFelix Fietkau 	else
53296747a51SFelix Fietkau 		msband = &phy->sband_5g;
5330fd0eb54SFelix Fietkau 
5340fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
5350fd0eb54SFelix Fietkau 	return &msband->chan[idx];
5360fd0eb54SFelix Fietkau }
5370fd0eb54SFelix Fietkau 
53896747a51SFelix Fietkau static void
53996747a51SFelix Fietkau mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
54096747a51SFelix Fietkau {
54196747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
54296747a51SFelix Fietkau 
54396747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
54496747a51SFelix Fietkau 						  phy->survey_time));
54596747a51SFelix Fietkau 	phy->survey_time = time;
54696747a51SFelix Fietkau }
54796747a51SFelix Fietkau 
5485ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
5495ce09c1aSFelix Fietkau {
550aec65e48SFelix Fietkau 	ktime_t cur_time;
551aec65e48SFelix Fietkau 
5525ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
5535ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
5545ce09c1aSFelix Fietkau 
555aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
55696747a51SFelix Fietkau 	mt76_update_survey_active_time(&dev->phy, cur_time);
55796747a51SFelix Fietkau 	if (dev->phy2)
55896747a51SFelix Fietkau 		mt76_update_survey_active_time(dev->phy2, cur_time);
559aec65e48SFelix Fietkau 
5605ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
56196747a51SFelix Fietkau 		struct mt76_channel_state *state = dev->phy.chan_state;
56296747a51SFelix Fietkau 
563237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
5645ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
5655ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
566237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
5675ce09c1aSFelix Fietkau 	}
5685ce09c1aSFelix Fietkau }
5695ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
5705ce09c1aSFelix Fietkau 
57196747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
57217f1de56SFelix Fietkau {
57396747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
57496747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
57517f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
57617f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
57726e40d4cSFelix Fietkau 	int timeout = HZ / 5;
57817f1de56SFelix Fietkau 
5795a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
5805ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
58117f1de56SFelix Fietkau 
58296747a51SFelix Fietkau 	phy->chandef = *chandef;
58396747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
58417f1de56SFelix Fietkau 
58517f1de56SFelix Fietkau 	if (!offchannel)
58696747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
58717f1de56SFelix Fietkau 
58896747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
58996747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
59017f1de56SFelix Fietkau }
59117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
59217f1de56SFelix Fietkau 
59317f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
59417f1de56SFelix Fietkau 		    struct survey_info *survey)
59517f1de56SFelix Fietkau {
59696747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
59796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
59817f1de56SFelix Fietkau 	struct mt76_sband *sband;
59917f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
60017f1de56SFelix Fietkau 	struct mt76_channel_state *state;
60117f1de56SFelix Fietkau 	int ret = 0;
60217f1de56SFelix Fietkau 
603237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
60417f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
6055ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
60617f1de56SFelix Fietkau 
60796747a51SFelix Fietkau 	sband = &phy->sband_2g;
60817f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
60917f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
61096747a51SFelix Fietkau 		sband = &phy->sband_5g;
61117f1de56SFelix Fietkau 	}
61217f1de56SFelix Fietkau 
613237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
614237312c5SLorenzo Bianconi 		ret = -ENOENT;
615237312c5SLorenzo Bianconi 		goto out;
616237312c5SLorenzo Bianconi 	}
61717f1de56SFelix Fietkau 
61817f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
61996747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
62017f1de56SFelix Fietkau 
62117f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
62217f1de56SFelix Fietkau 	survey->channel = chan;
62317f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
624ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
625e5051965SFelix Fietkau 	if (state->noise)
626e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
627e5051965SFelix Fietkau 
62896747a51SFelix Fietkau 	if (chan == phy->main_chan) {
62917f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
63017f1de56SFelix Fietkau 
6315ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
6325ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
6335ce09c1aSFelix Fietkau 	}
6345ce09c1aSFelix Fietkau 
63517f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
6366bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
637237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
638e5051965SFelix Fietkau 	survey->noise = state->noise;
639237312c5SLorenzo Bianconi 
640237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
641237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
642ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
64317f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
64417f1de56SFelix Fietkau 
645237312c5SLorenzo Bianconi out:
646237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
647237312c5SLorenzo Bianconi 
64817f1de56SFelix Fietkau 	return ret;
64917f1de56SFelix Fietkau }
65017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
65117f1de56SFelix Fietkau 
65230ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
65330ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
65430ce7f44SFelix Fietkau {
65530ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
65630ce7f44SFelix Fietkau 	int i;
65730ce7f44SFelix Fietkau 
65830ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
65930ce7f44SFelix Fietkau 
66030ce7f44SFelix Fietkau 	if (!key)
66130ce7f44SFelix Fietkau 		return;
66230ce7f44SFelix Fietkau 
66301cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
66401cfc1b4SLorenzo Bianconi 		return;
66530ce7f44SFelix Fietkau 
66601cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
66730ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
66830ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
66930ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
67030ce7f44SFelix Fietkau 	}
67130ce7f44SFelix Fietkau }
67230ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
67330ce7f44SFelix Fietkau 
674bfc394ddSFelix Fietkau static void
675bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
676bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
677bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
6784e34249eSFelix Fietkau {
6794e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
6804e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
6814e34249eSFelix Fietkau 
6824e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
6834e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
6844e34249eSFelix Fietkau 
6854e34249eSFelix Fietkau 	status->flag = mstat.flag;
6864e34249eSFelix Fietkau 	status->freq = mstat.freq;
6874e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
6884e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
6894e34249eSFelix Fietkau 	status->bw = mstat.bw;
690af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
691af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
692af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
6934e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
6944e34249eSFelix Fietkau 	status->nss = mstat.nss;
6954e34249eSFelix Fietkau 	status->band = mstat.band;
6964e34249eSFelix Fietkau 	status->signal = mstat.signal;
6974e34249eSFelix Fietkau 	status->chains = mstat.chains;
698d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
6994e34249eSFelix Fietkau 
7004e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
70113381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
70213381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
70313381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
70413381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
7059c68a57bSFelix Fietkau 
706bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
707bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
7084e34249eSFelix Fietkau }
7094e34249eSFelix Fietkau 
71030ce7f44SFelix Fietkau static int
71130ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
71230ce7f44SFelix Fietkau {
71330ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
71430ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
71530ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
71630ce7f44SFelix Fietkau 	int ret;
71730ce7f44SFelix Fietkau 
71830ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
71930ce7f44SFelix Fietkau 		return 0;
72030ce7f44SFelix Fietkau 
72130ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
72230ce7f44SFelix Fietkau 		return 0;
72330ce7f44SFelix Fietkau 
72430ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
72530ce7f44SFelix Fietkau 		/*
72630ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
72730ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
72830ce7f44SFelix Fietkau 		 */
729*77ae1d5eSRyder Lee 		hdr = mt76_skb_get_hdr(skb);
73030ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
73130ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
73230ce7f44SFelix Fietkau 			return 0;
73330ce7f44SFelix Fietkau 	}
73430ce7f44SFelix Fietkau 
73530ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
73630ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
73730ce7f44SFelix Fietkau 		     sizeof(status->iv));
73830ce7f44SFelix Fietkau 	if (ret <= 0)
73930ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
74030ce7f44SFelix Fietkau 
74130ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
74230ce7f44SFelix Fietkau 
74330ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
74430ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
74530ce7f44SFelix Fietkau 
74630ce7f44SFelix Fietkau 	return 0;
74730ce7f44SFelix Fietkau }
74830ce7f44SFelix Fietkau 
749d71ef286SFelix Fietkau static void
7505ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
7515ce09c1aSFelix Fietkau 		    int len)
7525ce09c1aSFelix Fietkau {
7535ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
75485b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
75585b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
75685b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
75785b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
75885b7a5d0SLorenzo Bianconi 		.band = status->band,
75985b7a5d0SLorenzo Bianconi 		.nss = status->nss,
76085b7a5d0SLorenzo Bianconi 		.bw = status->bw,
76185b7a5d0SLorenzo Bianconi 	};
7625ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
7635ce09c1aSFelix Fietkau 	u32 airtime;
7645ce09c1aSFelix Fietkau 
76585b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
766237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
7675ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
768237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
7695ce09c1aSFelix Fietkau 
7705ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
7715ce09c1aSFelix Fietkau 		return;
7725ce09c1aSFelix Fietkau 
7735ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
7745ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
7755ce09c1aSFelix Fietkau }
7765ce09c1aSFelix Fietkau 
7775ce09c1aSFelix Fietkau static void
7785ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
7795ce09c1aSFelix Fietkau {
7805ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
7815ce09c1aSFelix Fietkau 	int wcid_idx;
7825ce09c1aSFelix Fietkau 
7835ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
7845ce09c1aSFelix Fietkau 		return;
7855ce09c1aSFelix Fietkau 
7865ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
787bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
7885ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
7895ce09c1aSFelix Fietkau 	else
7905ce09c1aSFelix Fietkau 		wcid = NULL;
7915ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
7925ce09c1aSFelix Fietkau 
7935ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
7945ce09c1aSFelix Fietkau 
7955ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
7965ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
7975ce09c1aSFelix Fietkau }
7985ce09c1aSFelix Fietkau 
7995ce09c1aSFelix Fietkau static void
8005ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
8015ce09c1aSFelix Fietkau {
802*77ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
8035ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8045ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
8055ce09c1aSFelix Fietkau 
8065ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
8075ce09c1aSFelix Fietkau 		return;
8085ce09c1aSFelix Fietkau 
8095ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
8105ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
8115ce09c1aSFelix Fietkau 			return;
8125ce09c1aSFelix Fietkau 
8135ce09c1aSFelix Fietkau 		wcid = NULL;
8145ce09c1aSFelix Fietkau 	}
8155ce09c1aSFelix Fietkau 
8165ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
8175ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
8185ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
8195ce09c1aSFelix Fietkau 
8205ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
8215ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
8225ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
8235ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
8245ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
8255ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
8265ce09c1aSFelix Fietkau 		}
8275ce09c1aSFelix Fietkau 
8285ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
8295ce09c1aSFelix Fietkau 		return;
8305ce09c1aSFelix Fietkau 	}
8315ce09c1aSFelix Fietkau 
8325ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
8335ce09c1aSFelix Fietkau }
8345ce09c1aSFelix Fietkau 
8355ce09c1aSFelix Fietkau static void
836ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
837d71ef286SFelix Fietkau {
838d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
839*77ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
840d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
841bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
842d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
843d71ef286SFelix Fietkau 	bool ps;
84490fdc171SFelix Fietkau 	int i;
845d71ef286SFelix Fietkau 
846bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
84736d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
848bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
84936d91096SFelix Fietkau 		if (sta)
85036d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
85136d91096SFelix Fietkau 	}
85236d91096SFelix Fietkau 
8535ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
8545ce09c1aSFelix Fietkau 
855d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
856d71ef286SFelix Fietkau 		return;
857d71ef286SFelix Fietkau 
858d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
859d71ef286SFelix Fietkau 
86002e5a769SFelix Fietkau 	if (status->signal <= 0)
86102e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
86202e5a769SFelix Fietkau 
863ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
864ef13edc0SFelix Fietkau 
865d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
866d71ef286SFelix Fietkau 		return;
867d71ef286SFelix Fietkau 
868d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
869d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
870d71ef286SFelix Fietkau 		return;
871d71ef286SFelix Fietkau 	}
872d71ef286SFelix Fietkau 
873d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
874d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
875d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
876d71ef286SFelix Fietkau 		return;
877d71ef286SFelix Fietkau 
878d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
879d71ef286SFelix Fietkau 
880d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
881d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
882d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
883d71ef286SFelix Fietkau 
884d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
885d71ef286SFelix Fietkau 		return;
886d71ef286SFelix Fietkau 
88711b2a25fSFelix Fietkau 	if (ps)
888d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
88911b2a25fSFelix Fietkau 	else
890d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
891d71ef286SFelix Fietkau 
892d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
8939f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
89490fdc171SFelix Fietkau 
89590fdc171SFelix Fietkau 	if (ps)
89690fdc171SFelix Fietkau 		return;
89790fdc171SFelix Fietkau 
89890fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
89990fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
90090fdc171SFelix Fietkau 
90190fdc171SFelix Fietkau 		if (!sta->txq[i])
90290fdc171SFelix Fietkau 			continue;
90390fdc171SFelix Fietkau 
90490fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
90590fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
906bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
90790fdc171SFelix Fietkau 	}
908d71ef286SFelix Fietkau }
909d71ef286SFelix Fietkau 
9109d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
91181e850efSLorenzo Bianconi 		      struct napi_struct *napi)
91217f1de56SFelix Fietkau {
9139c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
914bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
9159d9d738bSFelix Fietkau 	struct sk_buff *skb;
9169d9d738bSFelix Fietkau 
917c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
9189d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
91930ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
92030ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
92130ce7f44SFelix Fietkau 			continue;
92230ce7f44SFelix Fietkau 		}
92330ce7f44SFelix Fietkau 
924bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
925bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
9269d9d738bSFelix Fietkau 	}
927c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
9289d9d738bSFelix Fietkau }
9299d9d738bSFelix Fietkau 
93081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
93181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
9329d9d738bSFelix Fietkau {
933aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
93417f1de56SFelix Fietkau 	struct sk_buff *skb;
93517f1de56SFelix Fietkau 
936aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
937aee5b8cfSFelix Fietkau 
938d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
939ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
940aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
941d71ef286SFelix Fietkau 	}
942aee5b8cfSFelix Fietkau 
94381e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
9444e34249eSFelix Fietkau }
94581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
946723b90dcSFelix Fietkau 
947e28487eaSFelix Fietkau static int
948e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
949426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
950e28487eaSFelix Fietkau {
951e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
952e28487eaSFelix Fietkau 	int ret;
953e28487eaSFelix Fietkau 	int i;
954e28487eaSFelix Fietkau 
955e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
956e28487eaSFelix Fietkau 
957e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
958e28487eaSFelix Fietkau 	if (ret)
959e28487eaSFelix Fietkau 		goto out;
960e28487eaSFelix Fietkau 
961e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
962e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
963e28487eaSFelix Fietkau 
964e28487eaSFelix Fietkau 		if (!sta->txq[i])
965e28487eaSFelix Fietkau 			continue;
966e28487eaSFelix Fietkau 
967e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
968e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
969e28487eaSFelix Fietkau 
970e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
971e28487eaSFelix Fietkau 	}
972e28487eaSFelix Fietkau 
973ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
974426e8e41SFelix Fietkau 	if (ext_phy)
975426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
976c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
977e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
978e28487eaSFelix Fietkau 
979e28487eaSFelix Fietkau out:
980e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
981e28487eaSFelix Fietkau 
982e28487eaSFelix Fietkau 	return ret;
983e28487eaSFelix Fietkau }
984e28487eaSFelix Fietkau 
98513f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
986723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
987723b90dcSFelix Fietkau {
988723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
98913f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
990723b90dcSFelix Fietkau 
99158bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
99258bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
99358bab0d4SFelix Fietkau 
994e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
995e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
996e28487eaSFelix Fietkau 
997723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
998723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
999723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
1000426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1001426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
100213f61dfcSLorenzo Bianconi }
100313f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1004e28487eaSFelix Fietkau 
100513f61dfcSLorenzo Bianconi static void
100613f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
100713f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
100813f61dfcSLorenzo Bianconi {
100913f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
101013f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1011723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1012723b90dcSFelix Fietkau }
1013e28487eaSFelix Fietkau 
1014e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1015e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1016e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1017e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1018e28487eaSFelix Fietkau {
1019426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1020426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1021426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1022e28487eaSFelix Fietkau 
1023e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1024e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1025426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1026e28487eaSFelix Fietkau 
10279c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
10289c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
10299c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
10309c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
10319c193de5SFelix Fietkau 
1032e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1033e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1034e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1035e28487eaSFelix Fietkau 
1036e28487eaSFelix Fietkau 	return 0;
1037e28487eaSFelix Fietkau }
1038e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
10399313faacSFelix Fietkau 
104043ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
104143ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
104243ba1922SFelix Fietkau {
104343ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
104443ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
104543ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
104643ba1922SFelix Fietkau 
104743ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
104843ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
104943ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
105043ba1922SFelix Fietkau }
105143ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
105243ba1922SFelix Fietkau 
10539313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10549313faacSFelix Fietkau 		     int *dbm)
10559313faacSFelix Fietkau {
1056beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1057beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
105807cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
10599313faacSFelix Fietkau 
106007cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
10619313faacSFelix Fietkau 
10629313faacSFelix Fietkau 	return 0;
10639313faacSFelix Fietkau }
10649313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1065e7173858SFelix Fietkau 
1066e7173858SFelix Fietkau static void
1067e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1068e7173858SFelix Fietkau {
1069e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
1070e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1071e7173858SFelix Fietkau }
1072e7173858SFelix Fietkau 
1073e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1074e7173858SFelix Fietkau {
1075e7173858SFelix Fietkau 	if (!dev->csa_complete)
1076e7173858SFelix Fietkau 		return;
1077e7173858SFelix Fietkau 
1078e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1079e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1080e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1081e7173858SFelix Fietkau 
1082e7173858SFelix Fietkau 	dev->csa_complete = 0;
1083e7173858SFelix Fietkau }
1084e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1085e7173858SFelix Fietkau 
1086e7173858SFelix Fietkau static void
1087e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1088e7173858SFelix Fietkau {
1089e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1090e7173858SFelix Fietkau 
1091e7173858SFelix Fietkau 	if (!vif->csa_active)
1092e7173858SFelix Fietkau 		return;
1093e7173858SFelix Fietkau 
1094e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
1095e7173858SFelix Fietkau }
1096e7173858SFelix Fietkau 
1097e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1098e7173858SFelix Fietkau {
1099e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1100e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1101e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1102e7173858SFelix Fietkau }
1103e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
110487d53103SStanislaw Gruszka 
110587d53103SStanislaw Gruszka int
110687d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
110787d53103SStanislaw Gruszka {
110887d53103SStanislaw Gruszka 	return 0;
110987d53103SStanislaw Gruszka }
111087d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1111eadfd98fSLorenzo Bianconi 
1112eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1113eadfd98fSLorenzo Bianconi {
1114eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1115eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1116eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1117eadfd98fSLorenzo Bianconi 
1118eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1119eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1120eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1121eadfd98fSLorenzo Bianconi 
1122eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1123eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1124eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1125eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1126eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1127eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1128eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1129eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1130eadfd98fSLorenzo Bianconi 
1131eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1132eadfd98fSLorenzo Bianconi }
1133eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1134d2679d65SLorenzo Bianconi 
1135d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1136d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1137d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1138d2679d65SLorenzo Bianconi {
1139d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1140d2679d65SLorenzo Bianconi 
1141d2679d65SLorenzo Bianconi 	if (cck) {
114296747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1143d2679d65SLorenzo Bianconi 			return 0;
1144d2679d65SLorenzo Bianconi 
1145d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
114696747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1147d2679d65SLorenzo Bianconi 		offset = 4;
1148d2679d65SLorenzo Bianconi 	}
1149d2679d65SLorenzo Bianconi 
1150d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1151d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1152d2679d65SLorenzo Bianconi 			return i;
1153d2679d65SLorenzo Bianconi 	}
1154d2679d65SLorenzo Bianconi 
1155d2679d65SLorenzo Bianconi 	return 0;
1156d2679d65SLorenzo Bianconi }
1157d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
11588b8ab5c2SLorenzo Bianconi 
11598b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
11608b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
11618b8ab5c2SLorenzo Bianconi {
1162011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11638b8ab5c2SLorenzo Bianconi 
1164011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
11658b8ab5c2SLorenzo Bianconi }
11668b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
11678b8ab5c2SLorenzo Bianconi 
11688b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
11698b8ab5c2SLorenzo Bianconi {
1170011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11718b8ab5c2SLorenzo Bianconi 
1172011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
11738b8ab5c2SLorenzo Bianconi }
11748b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1175e49c76d4SLorenzo Bianconi 
1176e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1177e49c76d4SLorenzo Bianconi {
1178beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1179beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1180e49c76d4SLorenzo Bianconi 
1181e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1182beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1183beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1184e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1185e49c76d4SLorenzo Bianconi 
1186e49c76d4SLorenzo Bianconi 	return 0;
1187e49c76d4SLorenzo Bianconi }
1188e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1189