xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 8552a434b6a05cc38006733afe6a239ad4d600a2)
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);
308d39b52e3SSean Wang 
309d39b52e3SSean Wang 	/* TODO: avoid linearization for SDIO */
310d39b52e3SSean Wang 	if (!mt76_is_sdio(dev))
311c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_FRAG_LIST);
312d39b52e3SSean Wang 
313c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
314c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
315c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
316c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
317c89d3625SFelix Fietkau 
318c89d3625SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
319c89d3625SFelix Fietkau 	wiphy->interface_modes =
320c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
321c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
322c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
323c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
324c89d3625SFelix Fietkau #endif
32550eb0a88SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
32650eb0a88SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
327c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
328c89d3625SFelix Fietkau }
329c89d3625SFelix Fietkau 
330c89d3625SFelix Fietkau struct mt76_phy *
331c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
332c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
333c89d3625SFelix Fietkau {
334c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
335c89d3625SFelix Fietkau 	struct mt76_phy *phy;
336c89d3625SFelix Fietkau 	unsigned int phy_size, chan_size;
337c89d3625SFelix Fietkau 	unsigned int size_2g, size_5g;
338c89d3625SFelix Fietkau 	void *priv;
339c89d3625SFelix Fietkau 
340c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
341c89d3625SFelix Fietkau 	chan_size = sizeof(dev->phy.sband_2g.chan[0]);
342c89d3625SFelix Fietkau 	size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
343c89d3625SFelix Fietkau 	size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
344c89d3625SFelix Fietkau 
345c89d3625SFelix Fietkau 	size += phy_size + size_2g + size_5g;
346c89d3625SFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
347c89d3625SFelix Fietkau 	if (!hw)
348c89d3625SFelix Fietkau 		return NULL;
349c89d3625SFelix Fietkau 
350c89d3625SFelix Fietkau 	phy = hw->priv;
351c89d3625SFelix Fietkau 	phy->dev = dev;
352c89d3625SFelix Fietkau 	phy->hw = hw;
353c89d3625SFelix Fietkau 
354c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
355c89d3625SFelix Fietkau 
356c89d3625SFelix Fietkau 	priv = hw->priv + phy_size;
357c89d3625SFelix Fietkau 
358c89d3625SFelix Fietkau 	phy->sband_2g = dev->phy.sband_2g;
359c89d3625SFelix Fietkau 	phy->sband_2g.chan = priv;
360c89d3625SFelix Fietkau 	priv += size_2g;
361c89d3625SFelix Fietkau 
362c89d3625SFelix Fietkau 	phy->sband_5g = dev->phy.sband_5g;
363c89d3625SFelix Fietkau 	phy->sband_5g.chan = priv;
364c89d3625SFelix Fietkau 	priv += size_5g;
365c89d3625SFelix Fietkau 
366c89d3625SFelix Fietkau 	phy->priv = priv;
367c89d3625SFelix Fietkau 
368c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
369c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
370c89d3625SFelix Fietkau 
371c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
372c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
373c89d3625SFelix Fietkau 
374c89d3625SFelix Fietkau 	return phy;
375c89d3625SFelix Fietkau }
376c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
377c89d3625SFelix Fietkau 
378c89d3625SFelix Fietkau int
379c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy)
380c89d3625SFelix Fietkau {
381c89d3625SFelix Fietkau 	int ret;
382c89d3625SFelix Fietkau 
383c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
384c89d3625SFelix Fietkau 	if (ret)
385c89d3625SFelix Fietkau 		return ret;
386c89d3625SFelix Fietkau 
387c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
388c89d3625SFelix Fietkau 	return 0;
389c89d3625SFelix Fietkau }
390c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
391c89d3625SFelix Fietkau 
392c89d3625SFelix Fietkau void
393c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy)
394c89d3625SFelix Fietkau {
395c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
396c89d3625SFelix Fietkau 
397c89d3625SFelix Fietkau 	dev->phy2 = NULL;
398c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
399c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
400c89d3625SFelix Fietkau }
401c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
402c89d3625SFelix Fietkau 
403a85b590cSFelix Fietkau struct mt76_dev *
404c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
405c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
406c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
407a85b590cSFelix Fietkau {
408a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
409ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
410a85b590cSFelix Fietkau 	struct mt76_dev *dev;
411e5443256SFelix Fietkau 	int i;
412a85b590cSFelix Fietkau 
413a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
414a85b590cSFelix Fietkau 	if (!hw)
415a85b590cSFelix Fietkau 		return NULL;
416a85b590cSFelix Fietkau 
417a85b590cSFelix Fietkau 	dev = hw->priv;
418a85b590cSFelix Fietkau 	dev->hw = hw;
419c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
420c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
421c0f7b25aSLorenzo Bianconi 
422ac24dd35SFelix Fietkau 	phy = &dev->phy;
423ac24dd35SFelix Fietkau 	phy->dev = dev;
424ac24dd35SFelix Fietkau 	phy->hw = hw;
425ac24dd35SFelix Fietkau 
426a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
427a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
428a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
429108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
43026e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
43188046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
432a85b590cSFelix Fietkau 
43309872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
43409872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
43509872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
43609872957SLorenzo Bianconi 
437e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
438e5443256SFelix Fietkau 
439e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
440e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
441e5443256SFelix Fietkau 
442c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
443c325c9c7SLorenzo Bianconi 
444a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
445a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
446a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
447a86f1d01SLorenzo Bianconi 		return NULL;
448a86f1d01SLorenzo Bianconi 	}
449a86f1d01SLorenzo Bianconi 
450a85b590cSFelix Fietkau 	return dev;
451a85b590cSFelix Fietkau }
452a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
453a85b590cSFelix Fietkau 
45417f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
45517f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
45617f1de56SFelix Fietkau {
45717f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
458c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
45917f1de56SFelix Fietkau 	int ret;
46017f1de56SFelix Fietkau 
46117f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
462c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
46317f1de56SFelix Fietkau 
46417f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
46517f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
46617f1de56SFelix Fietkau 		if (ret)
46717f1de56SFelix Fietkau 			return ret;
46817f1de56SFelix Fietkau 	}
46917f1de56SFelix Fietkau 
47017f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
47117f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
47217f1de56SFelix Fietkau 		if (ret)
47317f1de56SFelix Fietkau 			return ret;
47417f1de56SFelix Fietkau 	}
47517f1de56SFelix Fietkau 
476c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
477c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
478c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
47917f1de56SFelix Fietkau 
480b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
48117f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
48217f1de56SFelix Fietkau 		if (ret)
48317f1de56SFelix Fietkau 			return ret;
484b374e868SArnd Bergmann 	}
48517f1de56SFelix Fietkau 
48617f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
48717f1de56SFelix Fietkau }
48817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
48917f1de56SFelix Fietkau 
49017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
49117f1de56SFelix Fietkau {
49217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
49317f1de56SFelix Fietkau 
494d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
49536f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
49679d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
49717f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
49817f1de56SFelix Fietkau }
49917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
50017f1de56SFelix Fietkau 
501def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
502def34a2fSLorenzo Bianconi {
503a86f1d01SLorenzo Bianconi 	if (dev->wq) {
504a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
505a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
506a86f1d01SLorenzo Bianconi 	}
507a86f1d01SLorenzo Bianconi 	if (mt76_is_mmio(dev))
508def34a2fSLorenzo Bianconi 		mt76_tx_free(dev);
509def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
510def34a2fSLorenzo Bianconi }
511def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
512def34a2fSLorenzo Bianconi 
51317f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
51417f1de56SFelix Fietkau {
515011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
516011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
517011849e0SFelix Fietkau 
518011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
51917f1de56SFelix Fietkau 		dev_kfree_skb(skb);
52017f1de56SFelix Fietkau 		return;
52117f1de56SFelix Fietkau 	}
52217f1de56SFelix Fietkau 
523f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
524f0efa862SFelix Fietkau 	if (dev->test.state == MT76_TM_STATE_RX_FRAMES) {
525f0efa862SFelix Fietkau 		dev->test.rx_stats.packets[q]++;
526f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
527f0efa862SFelix Fietkau 			dev->test.rx_stats.fcs_error[q]++;
528f0efa862SFelix Fietkau 	}
529f0efa862SFelix Fietkau #endif
53017f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
53117f1de56SFelix Fietkau }
53217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
53317f1de56SFelix Fietkau 
5345a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
53526e40d4cSFelix Fietkau {
5365a95ca41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
537af005f26SLorenzo Bianconi 	struct mt76_queue *q;
5385a95ca41SFelix Fietkau 	int i, offset;
53926e40d4cSFelix Fietkau 
5405a95ca41SFelix Fietkau 	offset = __MT_TXQ_MAX * (phy != &dev->phy);
5415a95ca41SFelix Fietkau 
5425a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
5435a95ca41SFelix Fietkau 		q = dev->q_tx[offset + i].q;
544af005f26SLorenzo Bianconi 		if (q && q->queued)
54526e40d4cSFelix Fietkau 			return true;
54626e40d4cSFelix Fietkau 	}
54726e40d4cSFelix Fietkau 
54826e40d4cSFelix Fietkau 	return false;
54926e40d4cSFelix Fietkau }
55039d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
55126e40d4cSFelix Fietkau 
5520fd0eb54SFelix Fietkau static struct mt76_channel_state *
55396747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
5540fd0eb54SFelix Fietkau {
5550fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
5560fd0eb54SFelix Fietkau 	int idx;
5570fd0eb54SFelix Fietkau 
5580fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
55996747a51SFelix Fietkau 		msband = &phy->sband_2g;
5600fd0eb54SFelix Fietkau 	else
56196747a51SFelix Fietkau 		msband = &phy->sband_5g;
5620fd0eb54SFelix Fietkau 
5630fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
5640fd0eb54SFelix Fietkau 	return &msband->chan[idx];
5650fd0eb54SFelix Fietkau }
5660fd0eb54SFelix Fietkau 
56704414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
56896747a51SFelix Fietkau {
56996747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
57096747a51SFelix Fietkau 
57196747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
57296747a51SFelix Fietkau 						  phy->survey_time));
57396747a51SFelix Fietkau 	phy->survey_time = time;
57496747a51SFelix Fietkau }
57504414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
57696747a51SFelix Fietkau 
5775ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
5785ce09c1aSFelix Fietkau {
579aec65e48SFelix Fietkau 	ktime_t cur_time;
580aec65e48SFelix Fietkau 
5815ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
5825ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
5835ce09c1aSFelix Fietkau 
584aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
58596747a51SFelix Fietkau 	mt76_update_survey_active_time(&dev->phy, cur_time);
58696747a51SFelix Fietkau 	if (dev->phy2)
58796747a51SFelix Fietkau 		mt76_update_survey_active_time(dev->phy2, cur_time);
588aec65e48SFelix Fietkau 
5895ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
59096747a51SFelix Fietkau 		struct mt76_channel_state *state = dev->phy.chan_state;
59196747a51SFelix Fietkau 
592237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
5935ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
5945ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
595237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
5965ce09c1aSFelix Fietkau 	}
5975ce09c1aSFelix Fietkau }
5985ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
5995ce09c1aSFelix Fietkau 
60096747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
60117f1de56SFelix Fietkau {
60296747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
60396747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
60417f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
60517f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
60626e40d4cSFelix Fietkau 	int timeout = HZ / 5;
60717f1de56SFelix Fietkau 
6085a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
6095ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
61017f1de56SFelix Fietkau 
61196747a51SFelix Fietkau 	phy->chandef = *chandef;
61296747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
61317f1de56SFelix Fietkau 
61417f1de56SFelix Fietkau 	if (!offchannel)
61596747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
61617f1de56SFelix Fietkau 
61796747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
61896747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
61917f1de56SFelix Fietkau }
62017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
62117f1de56SFelix Fietkau 
62217f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
62317f1de56SFelix Fietkau 		    struct survey_info *survey)
62417f1de56SFelix Fietkau {
62596747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
62696747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
62717f1de56SFelix Fietkau 	struct mt76_sband *sband;
62817f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
62917f1de56SFelix Fietkau 	struct mt76_channel_state *state;
63017f1de56SFelix Fietkau 	int ret = 0;
63117f1de56SFelix Fietkau 
632237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
63317f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
6345ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
63517f1de56SFelix Fietkau 
63696747a51SFelix Fietkau 	sband = &phy->sband_2g;
63717f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
63817f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
63996747a51SFelix Fietkau 		sband = &phy->sband_5g;
64017f1de56SFelix Fietkau 	}
64117f1de56SFelix Fietkau 
642237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
643237312c5SLorenzo Bianconi 		ret = -ENOENT;
644237312c5SLorenzo Bianconi 		goto out;
645237312c5SLorenzo Bianconi 	}
64617f1de56SFelix Fietkau 
64717f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
64896747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
64917f1de56SFelix Fietkau 
65017f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
65117f1de56SFelix Fietkau 	survey->channel = chan;
65217f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
653ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
654e5051965SFelix Fietkau 	if (state->noise)
655e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
656e5051965SFelix Fietkau 
65796747a51SFelix Fietkau 	if (chan == phy->main_chan) {
65817f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
65917f1de56SFelix Fietkau 
6605ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
6615ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
6625ce09c1aSFelix Fietkau 	}
6635ce09c1aSFelix Fietkau 
66417f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
6656bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
666237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
667e5051965SFelix Fietkau 	survey->noise = state->noise;
668237312c5SLorenzo Bianconi 
669237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
670237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
671ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
67217f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
67317f1de56SFelix Fietkau 
674237312c5SLorenzo Bianconi out:
675237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
676237312c5SLorenzo Bianconi 
67717f1de56SFelix Fietkau 	return ret;
67817f1de56SFelix Fietkau }
67917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
68017f1de56SFelix Fietkau 
68130ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
68230ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
68330ce7f44SFelix Fietkau {
68430ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
68530ce7f44SFelix Fietkau 	int i;
68630ce7f44SFelix Fietkau 
68730ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
68830ce7f44SFelix Fietkau 
68930ce7f44SFelix Fietkau 	if (!key)
69030ce7f44SFelix Fietkau 		return;
69130ce7f44SFelix Fietkau 
69201cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
69301cfc1b4SLorenzo Bianconi 		return;
69430ce7f44SFelix Fietkau 
69501cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
69630ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
69730ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
69830ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
69930ce7f44SFelix Fietkau 	}
70030ce7f44SFelix Fietkau }
70130ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
70230ce7f44SFelix Fietkau 
703bfc394ddSFelix Fietkau static void
704bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
705bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
706bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
7074e34249eSFelix Fietkau {
7084e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
7094e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
7104e34249eSFelix Fietkau 
7114e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
7124e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
7134e34249eSFelix Fietkau 
7144e34249eSFelix Fietkau 	status->flag = mstat.flag;
7154e34249eSFelix Fietkau 	status->freq = mstat.freq;
7164e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
7174e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
7184e34249eSFelix Fietkau 	status->bw = mstat.bw;
719af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
720af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
721af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
7224e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
7234e34249eSFelix Fietkau 	status->nss = mstat.nss;
7244e34249eSFelix Fietkau 	status->band = mstat.band;
7254e34249eSFelix Fietkau 	status->signal = mstat.signal;
7264e34249eSFelix Fietkau 	status->chains = mstat.chains;
727d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
7284e34249eSFelix Fietkau 
7294e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
73013381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
73113381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
73213381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
73313381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
7349c68a57bSFelix Fietkau 
735bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
736bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
7374e34249eSFelix Fietkau }
7384e34249eSFelix Fietkau 
73930ce7f44SFelix Fietkau static int
74030ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
74130ce7f44SFelix Fietkau {
74230ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
74330ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
74430ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
74530ce7f44SFelix Fietkau 	int ret;
74630ce7f44SFelix Fietkau 
74730ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
74830ce7f44SFelix Fietkau 		return 0;
74930ce7f44SFelix Fietkau 
75030ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
75130ce7f44SFelix Fietkau 		return 0;
75230ce7f44SFelix Fietkau 
75330ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
75430ce7f44SFelix Fietkau 		/*
75530ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
75630ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
75730ce7f44SFelix Fietkau 		 */
75877ae1d5eSRyder Lee 		hdr = mt76_skb_get_hdr(skb);
75930ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
76030ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
76130ce7f44SFelix Fietkau 			return 0;
76230ce7f44SFelix Fietkau 	}
76330ce7f44SFelix Fietkau 
76430ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
76530ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
76630ce7f44SFelix Fietkau 		     sizeof(status->iv));
76730ce7f44SFelix Fietkau 	if (ret <= 0)
76830ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
76930ce7f44SFelix Fietkau 
77030ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
77130ce7f44SFelix Fietkau 
77230ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
77330ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
77430ce7f44SFelix Fietkau 
77530ce7f44SFelix Fietkau 	return 0;
77630ce7f44SFelix Fietkau }
77730ce7f44SFelix Fietkau 
778d71ef286SFelix Fietkau static void
7795ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
7805ce09c1aSFelix Fietkau 		    int len)
7815ce09c1aSFelix Fietkau {
7825ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
78385b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
78485b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
78585b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
78685b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
78785b7a5d0SLorenzo Bianconi 		.band = status->band,
78885b7a5d0SLorenzo Bianconi 		.nss = status->nss,
78985b7a5d0SLorenzo Bianconi 		.bw = status->bw,
79085b7a5d0SLorenzo Bianconi 	};
7915ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
7925ce09c1aSFelix Fietkau 	u32 airtime;
7935ce09c1aSFelix Fietkau 
79485b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
795237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
7965ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
797237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
7985ce09c1aSFelix Fietkau 
7995ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
8005ce09c1aSFelix Fietkau 		return;
8015ce09c1aSFelix Fietkau 
8025ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
8035ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
8045ce09c1aSFelix Fietkau }
8055ce09c1aSFelix Fietkau 
8065ce09c1aSFelix Fietkau static void
8075ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
8085ce09c1aSFelix Fietkau {
8095ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
8105ce09c1aSFelix Fietkau 	int wcid_idx;
8115ce09c1aSFelix Fietkau 
8125ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
8135ce09c1aSFelix Fietkau 		return;
8145ce09c1aSFelix Fietkau 
8155ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
816bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
8175ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
8185ce09c1aSFelix Fietkau 	else
8195ce09c1aSFelix Fietkau 		wcid = NULL;
8205ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
8215ce09c1aSFelix Fietkau 
8225ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
8235ce09c1aSFelix Fietkau 
8245ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
8255ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
8265ce09c1aSFelix Fietkau }
8275ce09c1aSFelix Fietkau 
8285ce09c1aSFelix Fietkau static void
8295ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
8305ce09c1aSFelix Fietkau {
83177ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
8325ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8335ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
8345ce09c1aSFelix Fietkau 
8355ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
8365ce09c1aSFelix Fietkau 		return;
8375ce09c1aSFelix Fietkau 
8385ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
8395ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
8405ce09c1aSFelix Fietkau 			return;
8415ce09c1aSFelix Fietkau 
8425ce09c1aSFelix Fietkau 		wcid = NULL;
8435ce09c1aSFelix Fietkau 	}
8445ce09c1aSFelix Fietkau 
8455ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
8465ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
8475ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
8485ce09c1aSFelix Fietkau 
8495ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
8505ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
8515ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
8525ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
8535ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
8545ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
8555ce09c1aSFelix Fietkau 		}
8565ce09c1aSFelix Fietkau 
8575ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
8585ce09c1aSFelix Fietkau 		return;
8595ce09c1aSFelix Fietkau 	}
8605ce09c1aSFelix Fietkau 
8615ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
8625ce09c1aSFelix Fietkau }
8635ce09c1aSFelix Fietkau 
8645ce09c1aSFelix Fietkau static void
865ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
866d71ef286SFelix Fietkau {
867d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
86877ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
869d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
870bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
871d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
872d71ef286SFelix Fietkau 	bool ps;
87390fdc171SFelix Fietkau 	int i;
874d71ef286SFelix Fietkau 
875bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
87636d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
877bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
87836d91096SFelix Fietkau 		if (sta)
87936d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
88036d91096SFelix Fietkau 	}
88136d91096SFelix Fietkau 
8825ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
8835ce09c1aSFelix Fietkau 
884d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
885d71ef286SFelix Fietkau 		return;
886d71ef286SFelix Fietkau 
887d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
888d71ef286SFelix Fietkau 
88902e5a769SFelix Fietkau 	if (status->signal <= 0)
89002e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
89102e5a769SFelix Fietkau 
892ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
893ef13edc0SFelix Fietkau 
894d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
895d71ef286SFelix Fietkau 		return;
896d71ef286SFelix Fietkau 
897d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
898d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
899d71ef286SFelix Fietkau 		return;
900d71ef286SFelix Fietkau 	}
901d71ef286SFelix Fietkau 
902d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
903d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
904d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
905d71ef286SFelix Fietkau 		return;
906d71ef286SFelix Fietkau 
907d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
908d71ef286SFelix Fietkau 
909d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
910d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
911d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
912d71ef286SFelix Fietkau 
913d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
914d71ef286SFelix Fietkau 		return;
915d71ef286SFelix Fietkau 
91611b2a25fSFelix Fietkau 	if (ps)
917d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
91811b2a25fSFelix Fietkau 	else
919d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
920d71ef286SFelix Fietkau 
921d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
9229f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
92390fdc171SFelix Fietkau 
92490fdc171SFelix Fietkau 	if (ps)
92590fdc171SFelix Fietkau 		return;
92690fdc171SFelix Fietkau 
92790fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
92890fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
92990fdc171SFelix Fietkau 
93090fdc171SFelix Fietkau 		if (!sta->txq[i])
93190fdc171SFelix Fietkau 			continue;
93290fdc171SFelix Fietkau 
93390fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
93490fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
935bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
93690fdc171SFelix Fietkau 	}
937d71ef286SFelix Fietkau }
938d71ef286SFelix Fietkau 
9399d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
94081e850efSLorenzo Bianconi 		      struct napi_struct *napi)
94117f1de56SFelix Fietkau {
9429c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
943bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
9449d9d738bSFelix Fietkau 	struct sk_buff *skb;
9459d9d738bSFelix Fietkau 
946c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
9479d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
94830ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
94930ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
95030ce7f44SFelix Fietkau 			continue;
95130ce7f44SFelix Fietkau 		}
95230ce7f44SFelix Fietkau 
953bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
954bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
9559d9d738bSFelix Fietkau 	}
956c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
9579d9d738bSFelix Fietkau }
9589d9d738bSFelix Fietkau 
95981e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
96081e850efSLorenzo Bianconi 			   struct napi_struct *napi)
9619d9d738bSFelix Fietkau {
962aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
96317f1de56SFelix Fietkau 	struct sk_buff *skb;
96417f1de56SFelix Fietkau 
965aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
966aee5b8cfSFelix Fietkau 
967d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
968ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
969aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
970d71ef286SFelix Fietkau 	}
971aee5b8cfSFelix Fietkau 
97281e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
9734e34249eSFelix Fietkau }
97481e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
975723b90dcSFelix Fietkau 
976e28487eaSFelix Fietkau static int
977e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
978426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
979e28487eaSFelix Fietkau {
980e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
981e28487eaSFelix Fietkau 	int ret;
982e28487eaSFelix Fietkau 	int i;
983e28487eaSFelix Fietkau 
984e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
985e28487eaSFelix Fietkau 
986e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
987e28487eaSFelix Fietkau 	if (ret)
988e28487eaSFelix Fietkau 		goto out;
989e28487eaSFelix Fietkau 
990e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
991e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
992e28487eaSFelix Fietkau 
993e28487eaSFelix Fietkau 		if (!sta->txq[i])
994e28487eaSFelix Fietkau 			continue;
995e28487eaSFelix Fietkau 
996e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
997e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
998e28487eaSFelix Fietkau 
999e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
1000e28487eaSFelix Fietkau 	}
1001e28487eaSFelix Fietkau 
1002ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1003426e8e41SFelix Fietkau 	if (ext_phy)
1004426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1005c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
1006e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1007e28487eaSFelix Fietkau 
1008e28487eaSFelix Fietkau out:
1009e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1010e28487eaSFelix Fietkau 
1011e28487eaSFelix Fietkau 	return ret;
1012e28487eaSFelix Fietkau }
1013e28487eaSFelix Fietkau 
101413f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1015723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1016723b90dcSFelix Fietkau {
1017723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
101813f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1019723b90dcSFelix Fietkau 
102058bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
102158bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
102258bab0d4SFelix Fietkau 
1023e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1024e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1025e28487eaSFelix Fietkau 
1026723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
1027723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
1028723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
1029426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1030426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
103113f61dfcSLorenzo Bianconi }
103213f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1033e28487eaSFelix Fietkau 
103413f61dfcSLorenzo Bianconi static void
103513f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
103613f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
103713f61dfcSLorenzo Bianconi {
103813f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
103913f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1040723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1041723b90dcSFelix Fietkau }
1042e28487eaSFelix Fietkau 
1043e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1044e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1045e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1046e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1047e28487eaSFelix Fietkau {
1048426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1049426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1050426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1051e28487eaSFelix Fietkau 
1052e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1053e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1054426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1055e28487eaSFelix Fietkau 
10569c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
10579c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
10589c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
10599c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
10609c193de5SFelix Fietkau 
1061e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1062e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1063e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1064e28487eaSFelix Fietkau 
1065e28487eaSFelix Fietkau 	return 0;
1066e28487eaSFelix Fietkau }
1067e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
10689313faacSFelix Fietkau 
106943ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
107043ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
107143ba1922SFelix Fietkau {
107243ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
107343ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
107443ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
107543ba1922SFelix Fietkau 
107643ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
107743ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
107843ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
107943ba1922SFelix Fietkau }
108043ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
108143ba1922SFelix Fietkau 
10829313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10839313faacSFelix Fietkau 		     int *dbm)
10849313faacSFelix Fietkau {
1085beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1086beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
108707cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
10889313faacSFelix Fietkau 
108907cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
10909313faacSFelix Fietkau 
10919313faacSFelix Fietkau 	return 0;
10929313faacSFelix Fietkau }
10939313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1094e7173858SFelix Fietkau 
1095e7173858SFelix Fietkau static void
1096e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1097e7173858SFelix Fietkau {
1098*8552a434SJohn Crispin 	if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1099e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1100e7173858SFelix Fietkau }
1101e7173858SFelix Fietkau 
1102e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1103e7173858SFelix Fietkau {
1104e7173858SFelix Fietkau 	if (!dev->csa_complete)
1105e7173858SFelix Fietkau 		return;
1106e7173858SFelix Fietkau 
1107e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1108e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1109e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1110e7173858SFelix Fietkau 
1111e7173858SFelix Fietkau 	dev->csa_complete = 0;
1112e7173858SFelix Fietkau }
1113e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1114e7173858SFelix Fietkau 
1115e7173858SFelix Fietkau static void
1116e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1117e7173858SFelix Fietkau {
1118e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1119e7173858SFelix Fietkau 
1120e7173858SFelix Fietkau 	if (!vif->csa_active)
1121e7173858SFelix Fietkau 		return;
1122e7173858SFelix Fietkau 
1123*8552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1124e7173858SFelix Fietkau }
1125e7173858SFelix Fietkau 
1126e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1127e7173858SFelix Fietkau {
1128e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1129e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1130e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1131e7173858SFelix Fietkau }
1132e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
113387d53103SStanislaw Gruszka 
113487d53103SStanislaw Gruszka int
113587d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
113687d53103SStanislaw Gruszka {
113787d53103SStanislaw Gruszka 	return 0;
113887d53103SStanislaw Gruszka }
113987d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1140eadfd98fSLorenzo Bianconi 
1141eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1142eadfd98fSLorenzo Bianconi {
1143eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1144eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1145eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1146eadfd98fSLorenzo Bianconi 
1147eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1148eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1149eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1150eadfd98fSLorenzo Bianconi 
1151eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1152eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1153eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1154eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1155eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1156eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1157eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1158eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1159eadfd98fSLorenzo Bianconi 
1160eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1161eadfd98fSLorenzo Bianconi }
1162eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1163d2679d65SLorenzo Bianconi 
1164d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1165d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1166d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1167d2679d65SLorenzo Bianconi {
1168d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1169d2679d65SLorenzo Bianconi 
1170d2679d65SLorenzo Bianconi 	if (cck) {
117196747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1172d2679d65SLorenzo Bianconi 			return 0;
1173d2679d65SLorenzo Bianconi 
1174d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
117596747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1176d2679d65SLorenzo Bianconi 		offset = 4;
1177d2679d65SLorenzo Bianconi 	}
1178d2679d65SLorenzo Bianconi 
1179d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1180d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1181d2679d65SLorenzo Bianconi 			return i;
1182d2679d65SLorenzo Bianconi 	}
1183d2679d65SLorenzo Bianconi 
1184d2679d65SLorenzo Bianconi 	return 0;
1185d2679d65SLorenzo Bianconi }
1186d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
11878b8ab5c2SLorenzo Bianconi 
11888b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
11898b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
11908b8ab5c2SLorenzo Bianconi {
1191011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11928b8ab5c2SLorenzo Bianconi 
1193011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
11948b8ab5c2SLorenzo Bianconi }
11958b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
11968b8ab5c2SLorenzo Bianconi 
11978b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
11988b8ab5c2SLorenzo Bianconi {
1199011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
12008b8ab5c2SLorenzo Bianconi 
1201011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
12028b8ab5c2SLorenzo Bianconi }
12038b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1204e49c76d4SLorenzo Bianconi 
1205e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1206e49c76d4SLorenzo Bianconi {
1207beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1208beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1209e49c76d4SLorenzo Bianconi 
1210e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1211beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1212beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1213e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1214e49c76d4SLorenzo Bianconi 
1215e49c76d4SLorenzo Bianconi 	return 0;
1216e49c76d4SLorenzo Bianconi }
1217e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1218