xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision f0efa8621550e77492719072d056f30569242b6b)
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),
619da82fb7SMarkus Theil 	CHAN5G(144, 5720),
6217f1de56SFelix Fietkau 
6317f1de56SFelix Fietkau 	CHAN5G(149, 5745),
6417f1de56SFelix Fietkau 	CHAN5G(153, 5765),
6517f1de56SFelix Fietkau 	CHAN5G(157, 5785),
6617f1de56SFelix Fietkau 	CHAN5G(161, 5805),
6717f1de56SFelix Fietkau 	CHAN5G(165, 5825),
689da82fb7SMarkus Theil 	CHAN5G(169, 5845),
699da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7017f1de56SFelix Fietkau };
7117f1de56SFelix Fietkau 
7217f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
7317f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
7417f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
7517f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
7617f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
7717f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
7817f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
7917f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
8017f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
8117f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
8217f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
8317f1de56SFelix Fietkau };
8417f1de56SFelix Fietkau 
8517f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
8617f1de56SFelix Fietkau {
8717f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
8817f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
8917f1de56SFelix Fietkau 	int led_pin;
9017f1de56SFelix Fietkau 
9117f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
9217f1de56SFelix Fietkau 		return 0;
9317f1de56SFelix Fietkau 
9417f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
9517f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
9617f1de56SFelix Fietkau 
9717f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
9817f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
9917f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
10017f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
10117f1de56SFelix Fietkau 					mt76_tpt_blink,
10217f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
10317f1de56SFelix Fietkau 
10417f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
10517f1de56SFelix Fietkau 	if (np) {
10617f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
10717f1de56SFelix Fietkau 			dev->led_pin = led_pin;
10817f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
10917f1de56SFelix Fietkau 	}
11017f1de56SFelix Fietkau 
11136f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
11236f7e2b2SFelix Fietkau }
11336f7e2b2SFelix Fietkau 
11436f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
11536f7e2b2SFelix Fietkau {
11636f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
11736f7e2b2SFelix Fietkau 		return;
11836f7e2b2SFelix Fietkau 
11936f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
12017f1de56SFelix Fietkau }
12117f1de56SFelix Fietkau 
122bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
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;
127bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->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 
159bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
1605ebdc3e0SLorenzo Bianconi {
161bb3e3fecSRyder Lee 	if (phy->dev->cap.has_2ghz)
162bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
163bb3e3fecSRyder Lee 	if (phy->dev->cap.has_5ghz)
164bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->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 
19417f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
19517f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
19617f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
19717f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
19817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
19917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
20017f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
20117f1de56SFelix Fietkau 
20217f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
20317f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20417f1de56SFelix Fietkau 
205bb3e3fecSRyder Lee 	mt76_init_stream_cap(&dev->phy, sband, vht);
206551e1ef4SLorenzo Bianconi 
20717f1de56SFelix Fietkau 	if (!vht)
20817f1de56SFelix Fietkau 		return 0;
20917f1de56SFelix Fietkau 
21017f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
21117f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
21217f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
21317f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
21449149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
215f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
216f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
21749149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
21817f1de56SFelix Fietkau 
21917f1de56SFelix Fietkau 	return 0;
22017f1de56SFelix Fietkau }
22117f1de56SFelix Fietkau 
22217f1de56SFelix Fietkau static int
22317f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22417f1de56SFelix Fietkau 		   int n_rates)
22517f1de56SFelix Fietkau {
22696747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband;
22717f1de56SFelix Fietkau 
22896747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_2g,
22917f1de56SFelix Fietkau 			       mt76_channels_2ghz,
23017f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
23117f1de56SFelix Fietkau 			       rates, n_rates, false);
23217f1de56SFelix Fietkau }
23317f1de56SFelix Fietkau 
23417f1de56SFelix Fietkau static int
23517f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
23617f1de56SFelix Fietkau 		   int n_rates, bool vht)
23717f1de56SFelix Fietkau {
23896747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband;
23917f1de56SFelix Fietkau 
24096747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_5g,
24117f1de56SFelix Fietkau 			       mt76_channels_5ghz,
24217f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
24317f1de56SFelix Fietkau 			       rates, n_rates, vht);
24417f1de56SFelix Fietkau }
24517f1de56SFelix Fietkau 
24617f1de56SFelix Fietkau static void
247c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
248c89d3625SFelix Fietkau 		 enum nl80211_band band)
24917f1de56SFelix Fietkau {
250c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
25117f1de56SFelix Fietkau 	bool found = false;
25217f1de56SFelix Fietkau 	int i;
25317f1de56SFelix Fietkau 
25417f1de56SFelix Fietkau 	if (!sband)
25517f1de56SFelix Fietkau 		return;
25617f1de56SFelix Fietkau 
25717f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
25817f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
25917f1de56SFelix Fietkau 			continue;
26017f1de56SFelix Fietkau 
26117f1de56SFelix Fietkau 		found = true;
26217f1de56SFelix Fietkau 		break;
26317f1de56SFelix Fietkau 	}
26417f1de56SFelix Fietkau 
265c89d3625SFelix Fietkau 	if (found) {
266c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
267c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
26817f1de56SFelix Fietkau 		return;
269c89d3625SFelix Fietkau 	}
27017f1de56SFelix Fietkau 
27117f1de56SFelix Fietkau 	sband->n_channels = 0;
272c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
27317f1de56SFelix Fietkau }
27417f1de56SFelix Fietkau 
275c89d3625SFelix Fietkau static void
276c89d3625SFelix Fietkau mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
277c89d3625SFelix Fietkau {
278c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
279c89d3625SFelix Fietkau 
280c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
281c89d3625SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
282c89d3625SFelix Fietkau 
283c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
284dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
285b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
286b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
287c89d3625SFelix Fietkau 
288c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
289c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
290d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
291c89d3625SFelix Fietkau 
292c89d3625SFelix Fietkau 	wiphy->available_antennas_tx = dev->phy.antenna_mask;
293c89d3625SFelix Fietkau 	wiphy->available_antennas_rx = dev->phy.antenna_mask;
294c89d3625SFelix Fietkau 
295c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
296b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
297c9619dfaSShayne Chen 
298c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
299c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
300c89d3625SFelix Fietkau 
301c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
302c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
303c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
304c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
305c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
306c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
307c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
308c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
309c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
310c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
311c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
312c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
313c89d3625SFelix Fietkau 
314c89d3625SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
315c89d3625SFelix Fietkau 	wiphy->interface_modes =
316c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
317c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
318c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
319c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
320c89d3625SFelix Fietkau #endif
32150eb0a88SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
32250eb0a88SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
323c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
324c89d3625SFelix Fietkau }
325c89d3625SFelix Fietkau 
326c89d3625SFelix Fietkau struct mt76_phy *
327c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
328c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
329c89d3625SFelix Fietkau {
330c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
331c89d3625SFelix Fietkau 	struct mt76_phy *phy;
332c89d3625SFelix Fietkau 	unsigned int phy_size, chan_size;
333c89d3625SFelix Fietkau 	unsigned int size_2g, size_5g;
334c89d3625SFelix Fietkau 	void *priv;
335c89d3625SFelix Fietkau 
336c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
337c89d3625SFelix Fietkau 	chan_size = sizeof(dev->phy.sband_2g.chan[0]);
338c89d3625SFelix Fietkau 	size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
339c89d3625SFelix Fietkau 	size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
340c89d3625SFelix Fietkau 
341c89d3625SFelix Fietkau 	size += phy_size + size_2g + size_5g;
342c89d3625SFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
343c89d3625SFelix Fietkau 	if (!hw)
344c89d3625SFelix Fietkau 		return NULL;
345c89d3625SFelix Fietkau 
346c89d3625SFelix Fietkau 	phy = hw->priv;
347c89d3625SFelix Fietkau 	phy->dev = dev;
348c89d3625SFelix Fietkau 	phy->hw = hw;
349c89d3625SFelix Fietkau 
350c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
351c89d3625SFelix Fietkau 
352c89d3625SFelix Fietkau 	priv = hw->priv + phy_size;
353c89d3625SFelix Fietkau 
354c89d3625SFelix Fietkau 	phy->sband_2g = dev->phy.sband_2g;
355c89d3625SFelix Fietkau 	phy->sband_2g.chan = priv;
356c89d3625SFelix Fietkau 	priv += size_2g;
357c89d3625SFelix Fietkau 
358c89d3625SFelix Fietkau 	phy->sband_5g = dev->phy.sband_5g;
359c89d3625SFelix Fietkau 	phy->sband_5g.chan = priv;
360c89d3625SFelix Fietkau 	priv += size_5g;
361c89d3625SFelix Fietkau 
362c89d3625SFelix Fietkau 	phy->priv = priv;
363c89d3625SFelix Fietkau 
364c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
365c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
366c89d3625SFelix Fietkau 
367c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
368c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
369c89d3625SFelix Fietkau 
370c89d3625SFelix Fietkau 	return phy;
371c89d3625SFelix Fietkau }
372c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
373c89d3625SFelix Fietkau 
374c89d3625SFelix Fietkau int
375c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy)
376c89d3625SFelix Fietkau {
377c89d3625SFelix Fietkau 	int ret;
378c89d3625SFelix Fietkau 
379c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
380c89d3625SFelix Fietkau 	if (ret)
381c89d3625SFelix Fietkau 		return ret;
382c89d3625SFelix Fietkau 
383c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
384c89d3625SFelix Fietkau 	return 0;
385c89d3625SFelix Fietkau }
386c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
387c89d3625SFelix Fietkau 
388c89d3625SFelix Fietkau void
389c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy)
390c89d3625SFelix Fietkau {
391c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
392c89d3625SFelix Fietkau 
393c89d3625SFelix Fietkau 	dev->phy2 = NULL;
394c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
395c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
396c89d3625SFelix Fietkau }
397c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
398c89d3625SFelix Fietkau 
399a85b590cSFelix Fietkau struct mt76_dev *
400c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
401c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
402c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
403a85b590cSFelix Fietkau {
404a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
405ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
406a85b590cSFelix Fietkau 	struct mt76_dev *dev;
407e5443256SFelix Fietkau 	int i;
408a85b590cSFelix Fietkau 
409a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
410a85b590cSFelix Fietkau 	if (!hw)
411a85b590cSFelix Fietkau 		return NULL;
412a85b590cSFelix Fietkau 
413a85b590cSFelix Fietkau 	dev = hw->priv;
414a85b590cSFelix Fietkau 	dev->hw = hw;
415c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
416c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
417c0f7b25aSLorenzo Bianconi 
418ac24dd35SFelix Fietkau 	phy = &dev->phy;
419ac24dd35SFelix Fietkau 	phy->dev = dev;
420ac24dd35SFelix Fietkau 	phy->hw = hw;
421ac24dd35SFelix Fietkau 
422a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
423a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
424a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
425108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
42626e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
42788046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
428a85b590cSFelix Fietkau 
42909872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
43009872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
43109872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
43209872957SLorenzo Bianconi 
433e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
434e5443256SFelix Fietkau 
435e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
436e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
437e5443256SFelix Fietkau 
438c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
439c325c9c7SLorenzo Bianconi 
440a85b590cSFelix Fietkau 	return dev;
441a85b590cSFelix Fietkau }
442a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
443a85b590cSFelix Fietkau 
44417f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
44517f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
44617f1de56SFelix Fietkau {
44717f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
448c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
44917f1de56SFelix Fietkau 	int ret;
45017f1de56SFelix Fietkau 
45117f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
452c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
45317f1de56SFelix Fietkau 
45417f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
45517f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
45617f1de56SFelix Fietkau 		if (ret)
45717f1de56SFelix Fietkau 			return ret;
45817f1de56SFelix Fietkau 	}
45917f1de56SFelix Fietkau 
46017f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
46117f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
46217f1de56SFelix Fietkau 		if (ret)
46317f1de56SFelix Fietkau 			return ret;
46417f1de56SFelix Fietkau 	}
46517f1de56SFelix Fietkau 
466c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
467c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
468c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
46917f1de56SFelix Fietkau 
470b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
47117f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
47217f1de56SFelix Fietkau 		if (ret)
47317f1de56SFelix Fietkau 			return ret;
474b374e868SArnd Bergmann 	}
47517f1de56SFelix Fietkau 
47617f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
47717f1de56SFelix Fietkau }
47817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
47917f1de56SFelix Fietkau 
48017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
48117f1de56SFelix Fietkau {
48217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
48317f1de56SFelix Fietkau 
484d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
48536f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
48679d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
48717f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
48817f1de56SFelix Fietkau }
48917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
49017f1de56SFelix Fietkau 
491def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
492def34a2fSLorenzo Bianconi {
493def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
494def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
495def34a2fSLorenzo Bianconi }
496def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
497def34a2fSLorenzo Bianconi 
49817f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
49917f1de56SFelix Fietkau {
500011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
501011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
502011849e0SFelix Fietkau 
503011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
50417f1de56SFelix Fietkau 		dev_kfree_skb(skb);
50517f1de56SFelix Fietkau 		return;
50617f1de56SFelix Fietkau 	}
50717f1de56SFelix Fietkau 
508*f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
509*f0efa862SFelix Fietkau 	if (dev->test.state == MT76_TM_STATE_RX_FRAMES) {
510*f0efa862SFelix Fietkau 		dev->test.rx_stats.packets[q]++;
511*f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
512*f0efa862SFelix Fietkau 			dev->test.rx_stats.fcs_error[q]++;
513*f0efa862SFelix Fietkau 	}
514*f0efa862SFelix Fietkau #endif
51517f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
51617f1de56SFelix Fietkau }
51717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
51817f1de56SFelix Fietkau 
5195a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
52026e40d4cSFelix Fietkau {
5215a95ca41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
522af005f26SLorenzo Bianconi 	struct mt76_queue *q;
5235a95ca41SFelix Fietkau 	int i, offset;
52426e40d4cSFelix Fietkau 
5255a95ca41SFelix Fietkau 	offset = __MT_TXQ_MAX * (phy != &dev->phy);
5265a95ca41SFelix Fietkau 
5275a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
5285a95ca41SFelix Fietkau 		q = dev->q_tx[offset + i].q;
529af005f26SLorenzo Bianconi 		if (q && q->queued)
53026e40d4cSFelix Fietkau 			return true;
53126e40d4cSFelix Fietkau 	}
53226e40d4cSFelix Fietkau 
53326e40d4cSFelix Fietkau 	return false;
53426e40d4cSFelix Fietkau }
53539d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
53626e40d4cSFelix Fietkau 
5370fd0eb54SFelix Fietkau static struct mt76_channel_state *
53896747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
5390fd0eb54SFelix Fietkau {
5400fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
5410fd0eb54SFelix Fietkau 	int idx;
5420fd0eb54SFelix Fietkau 
5430fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
54496747a51SFelix Fietkau 		msband = &phy->sband_2g;
5450fd0eb54SFelix Fietkau 	else
54696747a51SFelix Fietkau 		msband = &phy->sband_5g;
5470fd0eb54SFelix Fietkau 
5480fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
5490fd0eb54SFelix Fietkau 	return &msband->chan[idx];
5500fd0eb54SFelix Fietkau }
5510fd0eb54SFelix Fietkau 
55296747a51SFelix Fietkau static void
55396747a51SFelix Fietkau mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
55496747a51SFelix Fietkau {
55596747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
55696747a51SFelix Fietkau 
55796747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
55896747a51SFelix Fietkau 						  phy->survey_time));
55996747a51SFelix Fietkau 	phy->survey_time = time;
56096747a51SFelix Fietkau }
56196747a51SFelix Fietkau 
5625ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
5635ce09c1aSFelix Fietkau {
564aec65e48SFelix Fietkau 	ktime_t cur_time;
565aec65e48SFelix Fietkau 
5665ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
5675ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
5685ce09c1aSFelix Fietkau 
569aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
57096747a51SFelix Fietkau 	mt76_update_survey_active_time(&dev->phy, cur_time);
57196747a51SFelix Fietkau 	if (dev->phy2)
57296747a51SFelix Fietkau 		mt76_update_survey_active_time(dev->phy2, cur_time);
573aec65e48SFelix Fietkau 
5745ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
57596747a51SFelix Fietkau 		struct mt76_channel_state *state = dev->phy.chan_state;
57696747a51SFelix Fietkau 
577237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
5785ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
5795ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
580237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
5815ce09c1aSFelix Fietkau 	}
5825ce09c1aSFelix Fietkau }
5835ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
5845ce09c1aSFelix Fietkau 
58596747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
58617f1de56SFelix Fietkau {
58796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
58896747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
58917f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
59017f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
59126e40d4cSFelix Fietkau 	int timeout = HZ / 5;
59217f1de56SFelix Fietkau 
5935a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
5945ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
59517f1de56SFelix Fietkau 
59696747a51SFelix Fietkau 	phy->chandef = *chandef;
59796747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
59817f1de56SFelix Fietkau 
59917f1de56SFelix Fietkau 	if (!offchannel)
60096747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
60117f1de56SFelix Fietkau 
60296747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
60396747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
60417f1de56SFelix Fietkau }
60517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
60617f1de56SFelix Fietkau 
60717f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
60817f1de56SFelix Fietkau 		    struct survey_info *survey)
60917f1de56SFelix Fietkau {
61096747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
61196747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
61217f1de56SFelix Fietkau 	struct mt76_sband *sband;
61317f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
61417f1de56SFelix Fietkau 	struct mt76_channel_state *state;
61517f1de56SFelix Fietkau 	int ret = 0;
61617f1de56SFelix Fietkau 
617237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
61817f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
6195ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
62017f1de56SFelix Fietkau 
62196747a51SFelix Fietkau 	sband = &phy->sband_2g;
62217f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
62317f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
62496747a51SFelix Fietkau 		sband = &phy->sband_5g;
62517f1de56SFelix Fietkau 	}
62617f1de56SFelix Fietkau 
627237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
628237312c5SLorenzo Bianconi 		ret = -ENOENT;
629237312c5SLorenzo Bianconi 		goto out;
630237312c5SLorenzo Bianconi 	}
63117f1de56SFelix Fietkau 
63217f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
63396747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
63417f1de56SFelix Fietkau 
63517f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
63617f1de56SFelix Fietkau 	survey->channel = chan;
63717f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
638ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
639e5051965SFelix Fietkau 	if (state->noise)
640e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
641e5051965SFelix Fietkau 
64296747a51SFelix Fietkau 	if (chan == phy->main_chan) {
64317f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
64417f1de56SFelix Fietkau 
6455ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
6465ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
6475ce09c1aSFelix Fietkau 	}
6485ce09c1aSFelix Fietkau 
64917f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
6506bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
651237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
652e5051965SFelix Fietkau 	survey->noise = state->noise;
653237312c5SLorenzo Bianconi 
654237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
655237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
656ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
65717f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
65817f1de56SFelix Fietkau 
659237312c5SLorenzo Bianconi out:
660237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
661237312c5SLorenzo Bianconi 
66217f1de56SFelix Fietkau 	return ret;
66317f1de56SFelix Fietkau }
66417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
66517f1de56SFelix Fietkau 
66630ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
66730ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
66830ce7f44SFelix Fietkau {
66930ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
67030ce7f44SFelix Fietkau 	int i;
67130ce7f44SFelix Fietkau 
67230ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
67330ce7f44SFelix Fietkau 
67430ce7f44SFelix Fietkau 	if (!key)
67530ce7f44SFelix Fietkau 		return;
67630ce7f44SFelix Fietkau 
67701cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
67801cfc1b4SLorenzo Bianconi 		return;
67930ce7f44SFelix Fietkau 
68001cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
68130ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
68230ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
68330ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
68430ce7f44SFelix Fietkau 	}
68530ce7f44SFelix Fietkau }
68630ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
68730ce7f44SFelix Fietkau 
688bfc394ddSFelix Fietkau static void
689bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
690bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
691bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
6924e34249eSFelix Fietkau {
6934e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
6944e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
6954e34249eSFelix Fietkau 
6964e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
6974e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
6984e34249eSFelix Fietkau 
6994e34249eSFelix Fietkau 	status->flag = mstat.flag;
7004e34249eSFelix Fietkau 	status->freq = mstat.freq;
7014e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
7024e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
7034e34249eSFelix Fietkau 	status->bw = mstat.bw;
704af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
705af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
706af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
7074e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
7084e34249eSFelix Fietkau 	status->nss = mstat.nss;
7094e34249eSFelix Fietkau 	status->band = mstat.band;
7104e34249eSFelix Fietkau 	status->signal = mstat.signal;
7114e34249eSFelix Fietkau 	status->chains = mstat.chains;
712d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
7134e34249eSFelix Fietkau 
7144e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
71513381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
71613381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
71713381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
71813381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
7199c68a57bSFelix Fietkau 
720bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
721bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
7224e34249eSFelix Fietkau }
7234e34249eSFelix Fietkau 
72430ce7f44SFelix Fietkau static int
72530ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
72630ce7f44SFelix Fietkau {
72730ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
72830ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
72930ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
73030ce7f44SFelix Fietkau 	int ret;
73130ce7f44SFelix Fietkau 
73230ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
73330ce7f44SFelix Fietkau 		return 0;
73430ce7f44SFelix Fietkau 
73530ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
73630ce7f44SFelix Fietkau 		return 0;
73730ce7f44SFelix Fietkau 
73830ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
73930ce7f44SFelix Fietkau 		/*
74030ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
74130ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
74230ce7f44SFelix Fietkau 		 */
74377ae1d5eSRyder Lee 		hdr = mt76_skb_get_hdr(skb);
74430ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
74530ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
74630ce7f44SFelix Fietkau 			return 0;
74730ce7f44SFelix Fietkau 	}
74830ce7f44SFelix Fietkau 
74930ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
75030ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
75130ce7f44SFelix Fietkau 		     sizeof(status->iv));
75230ce7f44SFelix Fietkau 	if (ret <= 0)
75330ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
75430ce7f44SFelix Fietkau 
75530ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
75630ce7f44SFelix Fietkau 
75730ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
75830ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
75930ce7f44SFelix Fietkau 
76030ce7f44SFelix Fietkau 	return 0;
76130ce7f44SFelix Fietkau }
76230ce7f44SFelix Fietkau 
763d71ef286SFelix Fietkau static void
7645ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
7655ce09c1aSFelix Fietkau 		    int len)
7665ce09c1aSFelix Fietkau {
7675ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
76885b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
76985b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
77085b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
77185b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
77285b7a5d0SLorenzo Bianconi 		.band = status->band,
77385b7a5d0SLorenzo Bianconi 		.nss = status->nss,
77485b7a5d0SLorenzo Bianconi 		.bw = status->bw,
77585b7a5d0SLorenzo Bianconi 	};
7765ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
7775ce09c1aSFelix Fietkau 	u32 airtime;
7785ce09c1aSFelix Fietkau 
77985b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
780237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
7815ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
782237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
7835ce09c1aSFelix Fietkau 
7845ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
7855ce09c1aSFelix Fietkau 		return;
7865ce09c1aSFelix Fietkau 
7875ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
7885ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
7895ce09c1aSFelix Fietkau }
7905ce09c1aSFelix Fietkau 
7915ce09c1aSFelix Fietkau static void
7925ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
7935ce09c1aSFelix Fietkau {
7945ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
7955ce09c1aSFelix Fietkau 	int wcid_idx;
7965ce09c1aSFelix Fietkau 
7975ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
7985ce09c1aSFelix Fietkau 		return;
7995ce09c1aSFelix Fietkau 
8005ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
801bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
8025ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
8035ce09c1aSFelix Fietkau 	else
8045ce09c1aSFelix Fietkau 		wcid = NULL;
8055ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
8065ce09c1aSFelix Fietkau 
8075ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
8085ce09c1aSFelix Fietkau 
8095ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
8105ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
8115ce09c1aSFelix Fietkau }
8125ce09c1aSFelix Fietkau 
8135ce09c1aSFelix Fietkau static void
8145ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
8155ce09c1aSFelix Fietkau {
81677ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
8175ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8185ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
8195ce09c1aSFelix Fietkau 
8205ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
8215ce09c1aSFelix Fietkau 		return;
8225ce09c1aSFelix Fietkau 
8235ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
8245ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
8255ce09c1aSFelix Fietkau 			return;
8265ce09c1aSFelix Fietkau 
8275ce09c1aSFelix Fietkau 		wcid = NULL;
8285ce09c1aSFelix Fietkau 	}
8295ce09c1aSFelix Fietkau 
8305ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
8315ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
8325ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
8335ce09c1aSFelix Fietkau 
8345ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
8355ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
8365ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
8375ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
8385ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
8395ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
8405ce09c1aSFelix Fietkau 		}
8415ce09c1aSFelix Fietkau 
8425ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
8435ce09c1aSFelix Fietkau 		return;
8445ce09c1aSFelix Fietkau 	}
8455ce09c1aSFelix Fietkau 
8465ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
8475ce09c1aSFelix Fietkau }
8485ce09c1aSFelix Fietkau 
8495ce09c1aSFelix Fietkau static void
850ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
851d71ef286SFelix Fietkau {
852d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
85377ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
854d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
855bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
856d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
857d71ef286SFelix Fietkau 	bool ps;
85890fdc171SFelix Fietkau 	int i;
859d71ef286SFelix Fietkau 
860bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
86136d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
862bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
86336d91096SFelix Fietkau 		if (sta)
86436d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
86536d91096SFelix Fietkau 	}
86636d91096SFelix Fietkau 
8675ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
8685ce09c1aSFelix Fietkau 
869d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
870d71ef286SFelix Fietkau 		return;
871d71ef286SFelix Fietkau 
872d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
873d71ef286SFelix Fietkau 
87402e5a769SFelix Fietkau 	if (status->signal <= 0)
87502e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
87602e5a769SFelix Fietkau 
877ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
878ef13edc0SFelix Fietkau 
879d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
880d71ef286SFelix Fietkau 		return;
881d71ef286SFelix Fietkau 
882d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
883d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
884d71ef286SFelix Fietkau 		return;
885d71ef286SFelix Fietkau 	}
886d71ef286SFelix Fietkau 
887d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
888d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
889d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
890d71ef286SFelix Fietkau 		return;
891d71ef286SFelix Fietkau 
892d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
893d71ef286SFelix Fietkau 
894d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
895d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
896d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
897d71ef286SFelix Fietkau 
898d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
899d71ef286SFelix Fietkau 		return;
900d71ef286SFelix Fietkau 
90111b2a25fSFelix Fietkau 	if (ps)
902d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
90311b2a25fSFelix Fietkau 	else
904d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
905d71ef286SFelix Fietkau 
906d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
9079f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
90890fdc171SFelix Fietkau 
90990fdc171SFelix Fietkau 	if (ps)
91090fdc171SFelix Fietkau 		return;
91190fdc171SFelix Fietkau 
91290fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
91390fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
91490fdc171SFelix Fietkau 
91590fdc171SFelix Fietkau 		if (!sta->txq[i])
91690fdc171SFelix Fietkau 			continue;
91790fdc171SFelix Fietkau 
91890fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
91990fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
920bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
92190fdc171SFelix Fietkau 	}
922d71ef286SFelix Fietkau }
923d71ef286SFelix Fietkau 
9249d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
92581e850efSLorenzo Bianconi 		      struct napi_struct *napi)
92617f1de56SFelix Fietkau {
9279c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
928bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
9299d9d738bSFelix Fietkau 	struct sk_buff *skb;
9309d9d738bSFelix Fietkau 
931c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
9329d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
93330ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
93430ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
93530ce7f44SFelix Fietkau 			continue;
93630ce7f44SFelix Fietkau 		}
93730ce7f44SFelix Fietkau 
938bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
939bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
9409d9d738bSFelix Fietkau 	}
941c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
9429d9d738bSFelix Fietkau }
9439d9d738bSFelix Fietkau 
94481e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
94581e850efSLorenzo Bianconi 			   struct napi_struct *napi)
9469d9d738bSFelix Fietkau {
947aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
94817f1de56SFelix Fietkau 	struct sk_buff *skb;
94917f1de56SFelix Fietkau 
950aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
951aee5b8cfSFelix Fietkau 
952d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
953ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
954aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
955d71ef286SFelix Fietkau 	}
956aee5b8cfSFelix Fietkau 
95781e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
9584e34249eSFelix Fietkau }
95981e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
960723b90dcSFelix Fietkau 
961e28487eaSFelix Fietkau static int
962e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
963426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
964e28487eaSFelix Fietkau {
965e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
966e28487eaSFelix Fietkau 	int ret;
967e28487eaSFelix Fietkau 	int i;
968e28487eaSFelix Fietkau 
969e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
970e28487eaSFelix Fietkau 
971e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
972e28487eaSFelix Fietkau 	if (ret)
973e28487eaSFelix Fietkau 		goto out;
974e28487eaSFelix Fietkau 
975e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
976e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
977e28487eaSFelix Fietkau 
978e28487eaSFelix Fietkau 		if (!sta->txq[i])
979e28487eaSFelix Fietkau 			continue;
980e28487eaSFelix Fietkau 
981e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
982e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
983e28487eaSFelix Fietkau 
984e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
985e28487eaSFelix Fietkau 	}
986e28487eaSFelix Fietkau 
987ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
988426e8e41SFelix Fietkau 	if (ext_phy)
989426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
990c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
991e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
992e28487eaSFelix Fietkau 
993e28487eaSFelix Fietkau out:
994e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
995e28487eaSFelix Fietkau 
996e28487eaSFelix Fietkau 	return ret;
997e28487eaSFelix Fietkau }
998e28487eaSFelix Fietkau 
99913f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1000723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1001723b90dcSFelix Fietkau {
1002723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
100313f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1004723b90dcSFelix Fietkau 
100558bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
100658bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
100758bab0d4SFelix Fietkau 
1008e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1009e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1010e28487eaSFelix Fietkau 
1011723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
1012723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
1013723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
1014426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1015426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
101613f61dfcSLorenzo Bianconi }
101713f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1018e28487eaSFelix Fietkau 
101913f61dfcSLorenzo Bianconi static void
102013f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
102113f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
102213f61dfcSLorenzo Bianconi {
102313f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
102413f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1025723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1026723b90dcSFelix Fietkau }
1027e28487eaSFelix Fietkau 
1028e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1029e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1030e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1031e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1032e28487eaSFelix Fietkau {
1033426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1034426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1035426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1036e28487eaSFelix Fietkau 
1037e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1038e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1039426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1040e28487eaSFelix Fietkau 
10419c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
10429c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
10439c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
10449c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
10459c193de5SFelix Fietkau 
1046e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1047e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1048e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1049e28487eaSFelix Fietkau 
1050e28487eaSFelix Fietkau 	return 0;
1051e28487eaSFelix Fietkau }
1052e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
10539313faacSFelix Fietkau 
105443ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
105543ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
105643ba1922SFelix Fietkau {
105743ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
105843ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
105943ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
106043ba1922SFelix Fietkau 
106143ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
106243ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
106343ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
106443ba1922SFelix Fietkau }
106543ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
106643ba1922SFelix Fietkau 
10679313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10689313faacSFelix Fietkau 		     int *dbm)
10699313faacSFelix Fietkau {
1070beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1071beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
107207cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
10739313faacSFelix Fietkau 
107407cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
10759313faacSFelix Fietkau 
10769313faacSFelix Fietkau 	return 0;
10779313faacSFelix Fietkau }
10789313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1079e7173858SFelix Fietkau 
1080e7173858SFelix Fietkau static void
1081e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1082e7173858SFelix Fietkau {
1083e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
1084e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1085e7173858SFelix Fietkau }
1086e7173858SFelix Fietkau 
1087e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1088e7173858SFelix Fietkau {
1089e7173858SFelix Fietkau 	if (!dev->csa_complete)
1090e7173858SFelix Fietkau 		return;
1091e7173858SFelix Fietkau 
1092e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1093e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1094e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1095e7173858SFelix Fietkau 
1096e7173858SFelix Fietkau 	dev->csa_complete = 0;
1097e7173858SFelix Fietkau }
1098e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1099e7173858SFelix Fietkau 
1100e7173858SFelix Fietkau static void
1101e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1102e7173858SFelix Fietkau {
1103e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1104e7173858SFelix Fietkau 
1105e7173858SFelix Fietkau 	if (!vif->csa_active)
1106e7173858SFelix Fietkau 		return;
1107e7173858SFelix Fietkau 
1108e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
1109e7173858SFelix Fietkau }
1110e7173858SFelix Fietkau 
1111e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1112e7173858SFelix Fietkau {
1113e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1114e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1115e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1116e7173858SFelix Fietkau }
1117e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
111887d53103SStanislaw Gruszka 
111987d53103SStanislaw Gruszka int
112087d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
112187d53103SStanislaw Gruszka {
112287d53103SStanislaw Gruszka 	return 0;
112387d53103SStanislaw Gruszka }
112487d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1125eadfd98fSLorenzo Bianconi 
1126eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1127eadfd98fSLorenzo Bianconi {
1128eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1129eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1130eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1131eadfd98fSLorenzo Bianconi 
1132eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1133eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1134eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1135eadfd98fSLorenzo Bianconi 
1136eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1137eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1138eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1139eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1140eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1141eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1142eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1143eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1144eadfd98fSLorenzo Bianconi 
1145eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1146eadfd98fSLorenzo Bianconi }
1147eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1148d2679d65SLorenzo Bianconi 
1149d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1150d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1151d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1152d2679d65SLorenzo Bianconi {
1153d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1154d2679d65SLorenzo Bianconi 
1155d2679d65SLorenzo Bianconi 	if (cck) {
115696747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1157d2679d65SLorenzo Bianconi 			return 0;
1158d2679d65SLorenzo Bianconi 
1159d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
116096747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1161d2679d65SLorenzo Bianconi 		offset = 4;
1162d2679d65SLorenzo Bianconi 	}
1163d2679d65SLorenzo Bianconi 
1164d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1165d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1166d2679d65SLorenzo Bianconi 			return i;
1167d2679d65SLorenzo Bianconi 	}
1168d2679d65SLorenzo Bianconi 
1169d2679d65SLorenzo Bianconi 	return 0;
1170d2679d65SLorenzo Bianconi }
1171d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
11728b8ab5c2SLorenzo Bianconi 
11738b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
11748b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
11758b8ab5c2SLorenzo Bianconi {
1176011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11778b8ab5c2SLorenzo Bianconi 
1178011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
11798b8ab5c2SLorenzo Bianconi }
11808b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
11818b8ab5c2SLorenzo Bianconi 
11828b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
11838b8ab5c2SLorenzo Bianconi {
1184011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11858b8ab5c2SLorenzo Bianconi 
1186011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
11878b8ab5c2SLorenzo Bianconi }
11888b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1189e49c76d4SLorenzo Bianconi 
1190e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1191e49c76d4SLorenzo Bianconi {
1192beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1193beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1194e49c76d4SLorenzo Bianconi 
1195e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1196beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1197beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1198e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1199e49c76d4SLorenzo Bianconi 
1200e49c76d4SLorenzo Bianconi 	return 0;
1201e49c76d4SLorenzo Bianconi }
1202e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1203