xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 85b7a5d0b2ab183504014f5bfc3c3b1e76b595d7)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
517f1de56SFelix Fietkau #include <linux/of.h>
617f1de56SFelix Fietkau #include "mt76.h"
717f1de56SFelix Fietkau 
817f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
917f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1017f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1117f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1217f1de56SFelix Fietkau 	.max_power = 30,			\
1317f1de56SFelix Fietkau }
1417f1de56SFelix Fietkau 
1517f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1617f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1717f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1817f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1917f1de56SFelix Fietkau 	.max_power = 30,			\
2017f1de56SFelix Fietkau }
2117f1de56SFelix Fietkau 
2217f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
2317f1de56SFelix Fietkau 	CHAN2G(1, 2412),
2417f1de56SFelix Fietkau 	CHAN2G(2, 2417),
2517f1de56SFelix Fietkau 	CHAN2G(3, 2422),
2617f1de56SFelix Fietkau 	CHAN2G(4, 2427),
2717f1de56SFelix Fietkau 	CHAN2G(5, 2432),
2817f1de56SFelix Fietkau 	CHAN2G(6, 2437),
2917f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3017f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3117f1de56SFelix Fietkau 	CHAN2G(9, 2452),
3217f1de56SFelix Fietkau 	CHAN2G(10, 2457),
3317f1de56SFelix Fietkau 	CHAN2G(11, 2462),
3417f1de56SFelix Fietkau 	CHAN2G(12, 2467),
3517f1de56SFelix Fietkau 	CHAN2G(13, 2472),
3617f1de56SFelix Fietkau 	CHAN2G(14, 2484),
3717f1de56SFelix Fietkau };
3817f1de56SFelix Fietkau 
3917f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4017f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4117f1de56SFelix Fietkau 	CHAN5G(40, 5200),
4217f1de56SFelix Fietkau 	CHAN5G(44, 5220),
4317f1de56SFelix Fietkau 	CHAN5G(48, 5240),
4417f1de56SFelix Fietkau 
4517f1de56SFelix Fietkau 	CHAN5G(52, 5260),
4617f1de56SFelix Fietkau 	CHAN5G(56, 5280),
4717f1de56SFelix Fietkau 	CHAN5G(60, 5300),
4817f1de56SFelix Fietkau 	CHAN5G(64, 5320),
4917f1de56SFelix Fietkau 
5017f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5117f1de56SFelix Fietkau 	CHAN5G(104, 5520),
5217f1de56SFelix Fietkau 	CHAN5G(108, 5540),
5317f1de56SFelix Fietkau 	CHAN5G(112, 5560),
5417f1de56SFelix Fietkau 	CHAN5G(116, 5580),
5517f1de56SFelix Fietkau 	CHAN5G(120, 5600),
5617f1de56SFelix Fietkau 	CHAN5G(124, 5620),
5717f1de56SFelix Fietkau 	CHAN5G(128, 5640),
5817f1de56SFelix Fietkau 	CHAN5G(132, 5660),
5917f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6017f1de56SFelix Fietkau 	CHAN5G(140, 5700),
6117f1de56SFelix Fietkau 
6217f1de56SFelix Fietkau 	CHAN5G(149, 5745),
6317f1de56SFelix Fietkau 	CHAN5G(153, 5765),
6417f1de56SFelix Fietkau 	CHAN5G(157, 5785),
6517f1de56SFelix Fietkau 	CHAN5G(161, 5805),
6617f1de56SFelix Fietkau 	CHAN5G(165, 5825),
6717f1de56SFelix Fietkau };
6817f1de56SFelix Fietkau 
6917f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
7017f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
7117f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
7217f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
7317f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
7417f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
7517f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
7617f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
7717f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
7817f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
7917f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
8017f1de56SFelix Fietkau };
8117f1de56SFelix Fietkau 
8217f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
8317f1de56SFelix Fietkau {
8417f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
8517f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
8617f1de56SFelix Fietkau 	int led_pin;
8717f1de56SFelix Fietkau 
8817f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
8917f1de56SFelix Fietkau 		return 0;
9017f1de56SFelix Fietkau 
9117f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
9217f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
9317f1de56SFelix Fietkau 
9417f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
9517f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
9617f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
9717f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
9817f1de56SFelix Fietkau 					mt76_tpt_blink,
9917f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
10017f1de56SFelix Fietkau 
10117f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
10217f1de56SFelix Fietkau 	if (np) {
10317f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
10417f1de56SFelix Fietkau 			dev->led_pin = led_pin;
10517f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
10617f1de56SFelix Fietkau 	}
10717f1de56SFelix Fietkau 
10836f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
10936f7e2b2SFelix Fietkau }
11036f7e2b2SFelix Fietkau 
11136f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
11236f7e2b2SFelix Fietkau {
11336f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
11436f7e2b2SFelix Fietkau 		return;
11536f7e2b2SFelix Fietkau 
11636f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
11717f1de56SFelix Fietkau }
11817f1de56SFelix Fietkau 
119551e1ef4SLorenzo Bianconi static void mt76_init_stream_cap(struct mt76_dev *dev,
120551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
121551e1ef4SLorenzo Bianconi 				 bool vht)
122551e1ef4SLorenzo Bianconi {
123551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
124beaaeb6bSFelix Fietkau 	int i, nstream = hweight8(dev->phy.antenna_mask);
125551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
126551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
127551e1ef4SLorenzo Bianconi 
128551e1ef4SLorenzo Bianconi 	if (nstream > 1)
129551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
130551e1ef4SLorenzo Bianconi 	else
131551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
132551e1ef4SLorenzo Bianconi 
133551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
134551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
135551e1ef4SLorenzo Bianconi 
136551e1ef4SLorenzo Bianconi 	if (!vht)
137551e1ef4SLorenzo Bianconi 		return;
138551e1ef4SLorenzo Bianconi 
139551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
140551e1ef4SLorenzo Bianconi 	if (nstream > 1)
141551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
142551e1ef4SLorenzo Bianconi 	else
143551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
144551e1ef4SLorenzo Bianconi 
145551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
146551e1ef4SLorenzo Bianconi 		if (i < nstream)
147551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
148551e1ef4SLorenzo Bianconi 		else
149551e1ef4SLorenzo Bianconi 			mcs_map |=
150551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
151551e1ef4SLorenzo Bianconi 	}
152551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
153551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
154551e1ef4SLorenzo Bianconi }
155551e1ef4SLorenzo Bianconi 
1565ebdc3e0SLorenzo Bianconi void mt76_set_stream_caps(struct mt76_dev *dev, bool vht)
1575ebdc3e0SLorenzo Bianconi {
1585ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_2ghz)
15996747a51SFelix Fietkau 		mt76_init_stream_cap(dev, &dev->phy.sband_2g.sband, false);
1605ebdc3e0SLorenzo Bianconi 	if (dev->cap.has_5ghz)
16196747a51SFelix Fietkau 		mt76_init_stream_cap(dev, &dev->phy.sband_5g.sband, vht);
1625ebdc3e0SLorenzo Bianconi }
1635ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1645ebdc3e0SLorenzo Bianconi 
16517f1de56SFelix Fietkau static int
16617f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
16717f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
16817f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
16917f1de56SFelix Fietkau {
17017f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
17117f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
17217f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
17317f1de56SFelix Fietkau 	void *chanlist;
17417f1de56SFelix Fietkau 	int size;
17517f1de56SFelix Fietkau 
17617f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
17717f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
17817f1de56SFelix Fietkau 	if (!chanlist)
17917f1de56SFelix Fietkau 		return -ENOMEM;
18017f1de56SFelix Fietkau 
181a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
18217f1de56SFelix Fietkau 				    GFP_KERNEL);
18317f1de56SFelix Fietkau 	if (!msband->chan)
18417f1de56SFelix Fietkau 		return -ENOMEM;
18517f1de56SFelix Fietkau 
18617f1de56SFelix Fietkau 	sband->channels = chanlist;
18717f1de56SFelix Fietkau 	sband->n_channels = n_chan;
18817f1de56SFelix Fietkau 	sband->bitrates = rates;
18917f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
19017f1de56SFelix Fietkau 
19117f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
19217f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
19317f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
19417f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
19517f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
19617f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
19717f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
19817f1de56SFelix Fietkau 
19917f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
20017f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20117f1de56SFelix Fietkau 	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
20217f1de56SFelix Fietkau 
203551e1ef4SLorenzo Bianconi 	mt76_init_stream_cap(dev, sband, vht);
204551e1ef4SLorenzo Bianconi 
20517f1de56SFelix Fietkau 	if (!vht)
20617f1de56SFelix Fietkau 		return 0;
20717f1de56SFelix Fietkau 
20817f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
20917f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
21017f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
21117f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
21249149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
213f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
214f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
21549149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
21617f1de56SFelix Fietkau 
21717f1de56SFelix Fietkau 	return 0;
21817f1de56SFelix Fietkau }
21917f1de56SFelix Fietkau 
22017f1de56SFelix Fietkau static int
22117f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22217f1de56SFelix Fietkau 		   int n_rates)
22317f1de56SFelix Fietkau {
22496747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband;
22517f1de56SFelix Fietkau 
22696747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_2g,
22717f1de56SFelix Fietkau 			       mt76_channels_2ghz,
22817f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
22917f1de56SFelix Fietkau 			       rates, n_rates, false);
23017f1de56SFelix Fietkau }
23117f1de56SFelix Fietkau 
23217f1de56SFelix Fietkau static int
23317f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
23417f1de56SFelix Fietkau 		   int n_rates, bool vht)
23517f1de56SFelix Fietkau {
23696747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband;
23717f1de56SFelix Fietkau 
23896747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_5g,
23917f1de56SFelix Fietkau 			       mt76_channels_5ghz,
24017f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
24117f1de56SFelix Fietkau 			       rates, n_rates, vht);
24217f1de56SFelix Fietkau }
24317f1de56SFelix Fietkau 
24417f1de56SFelix Fietkau static void
245c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
246c89d3625SFelix Fietkau 		 enum nl80211_band band)
24717f1de56SFelix Fietkau {
248c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
24917f1de56SFelix Fietkau 	bool found = false;
25017f1de56SFelix Fietkau 	int i;
25117f1de56SFelix Fietkau 
25217f1de56SFelix Fietkau 	if (!sband)
25317f1de56SFelix Fietkau 		return;
25417f1de56SFelix Fietkau 
25517f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
25617f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
25717f1de56SFelix Fietkau 			continue;
25817f1de56SFelix Fietkau 
25917f1de56SFelix Fietkau 		found = true;
26017f1de56SFelix Fietkau 		break;
26117f1de56SFelix Fietkau 	}
26217f1de56SFelix Fietkau 
263c89d3625SFelix Fietkau 	if (found) {
264c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
265c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
26617f1de56SFelix Fietkau 		return;
267c89d3625SFelix Fietkau 	}
26817f1de56SFelix Fietkau 
26917f1de56SFelix Fietkau 	sband->n_channels = 0;
270c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
27117f1de56SFelix Fietkau }
27217f1de56SFelix Fietkau 
273c89d3625SFelix Fietkau static void
274c89d3625SFelix Fietkau mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
275c89d3625SFelix Fietkau {
276c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
277c89d3625SFelix Fietkau 
278c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
279c89d3625SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
280c89d3625SFelix Fietkau 
281c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
282fecde5daSLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
283c89d3625SFelix Fietkau 
284c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
285c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
286c89d3625SFelix Fietkau 
287c89d3625SFelix Fietkau 	wiphy->available_antennas_tx = dev->phy.antenna_mask;
288c89d3625SFelix Fietkau 	wiphy->available_antennas_rx = dev->phy.antenna_mask;
289c89d3625SFelix Fietkau 
290c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
291c9619dfaSShayne Chen 
292c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
293c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
294c89d3625SFelix Fietkau 
295c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
296c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
297c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
298c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
299c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
300c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
301c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
302c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
303c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
304c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
305c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
306c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
307c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
308c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
309c89d3625SFelix Fietkau 
310c89d3625SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
311c89d3625SFelix Fietkau 	wiphy->interface_modes =
312c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
313c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
314c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
315c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
316c89d3625SFelix Fietkau #endif
317c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
318c89d3625SFelix Fietkau }
319c89d3625SFelix Fietkau 
320c89d3625SFelix Fietkau struct mt76_phy *
321c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
322c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
323c89d3625SFelix Fietkau {
324c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
325c89d3625SFelix Fietkau 	struct mt76_phy *phy;
326c89d3625SFelix Fietkau 	unsigned int phy_size, chan_size;
327c89d3625SFelix Fietkau 	unsigned int size_2g, size_5g;
328c89d3625SFelix Fietkau 	void *priv;
329c89d3625SFelix Fietkau 
330c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
331c89d3625SFelix Fietkau 	chan_size = sizeof(dev->phy.sband_2g.chan[0]);
332c89d3625SFelix Fietkau 	size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
333c89d3625SFelix Fietkau 	size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
334c89d3625SFelix Fietkau 
335c89d3625SFelix Fietkau 	size += phy_size + size_2g + size_5g;
336c89d3625SFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
337c89d3625SFelix Fietkau 	if (!hw)
338c89d3625SFelix Fietkau 		return NULL;
339c89d3625SFelix Fietkau 
340c89d3625SFelix Fietkau 	phy = hw->priv;
341c89d3625SFelix Fietkau 	phy->dev = dev;
342c89d3625SFelix Fietkau 	phy->hw = hw;
343c89d3625SFelix Fietkau 
344c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
345c89d3625SFelix Fietkau 
346c89d3625SFelix Fietkau 	priv = hw->priv + phy_size;
347c89d3625SFelix Fietkau 
348c89d3625SFelix Fietkau 	phy->sband_2g = dev->phy.sband_2g;
349c89d3625SFelix Fietkau 	phy->sband_2g.chan = priv;
350c89d3625SFelix Fietkau 	priv += size_2g;
351c89d3625SFelix Fietkau 
352c89d3625SFelix Fietkau 	phy->sband_5g = dev->phy.sband_5g;
353c89d3625SFelix Fietkau 	phy->sband_5g.chan = priv;
354c89d3625SFelix Fietkau 	priv += size_5g;
355c89d3625SFelix Fietkau 
356c89d3625SFelix Fietkau 	phy->priv = priv;
357c89d3625SFelix Fietkau 
358c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
359c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
360c89d3625SFelix Fietkau 
361c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
362c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
363c89d3625SFelix Fietkau 
364c89d3625SFelix Fietkau 	return phy;
365c89d3625SFelix Fietkau }
366c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
367c89d3625SFelix Fietkau 
368c89d3625SFelix Fietkau int
369c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy)
370c89d3625SFelix Fietkau {
371c89d3625SFelix Fietkau 	int ret;
372c89d3625SFelix Fietkau 
373c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
374c89d3625SFelix Fietkau 	if (ret)
375c89d3625SFelix Fietkau 		return ret;
376c89d3625SFelix Fietkau 
377c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
378c89d3625SFelix Fietkau 	return 0;
379c89d3625SFelix Fietkau }
380c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
381c89d3625SFelix Fietkau 
382c89d3625SFelix Fietkau void
383c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy)
384c89d3625SFelix Fietkau {
385c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
386c89d3625SFelix Fietkau 
387c89d3625SFelix Fietkau 	dev->phy2 = NULL;
388c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
389c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
390c89d3625SFelix Fietkau }
391c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
392c89d3625SFelix Fietkau 
393a85b590cSFelix Fietkau struct mt76_dev *
394c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
395c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
396c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
397a85b590cSFelix Fietkau {
398a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
399ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
400a85b590cSFelix Fietkau 	struct mt76_dev *dev;
401e5443256SFelix Fietkau 	int i;
402a85b590cSFelix Fietkau 
403a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
404a85b590cSFelix Fietkau 	if (!hw)
405a85b590cSFelix Fietkau 		return NULL;
406a85b590cSFelix Fietkau 
407a85b590cSFelix Fietkau 	dev = hw->priv;
408a85b590cSFelix Fietkau 	dev->hw = hw;
409c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
410c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
411c0f7b25aSLorenzo Bianconi 
412ac24dd35SFelix Fietkau 	phy = &dev->phy;
413ac24dd35SFelix Fietkau 	phy->dev = dev;
414ac24dd35SFelix Fietkau 	phy->hw = hw;
415ac24dd35SFelix Fietkau 
416a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
417a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
418a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
419108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
42026e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
42188046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
422a85b590cSFelix Fietkau 
423e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
424e5443256SFelix Fietkau 
425e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
426e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
427e5443256SFelix Fietkau 
428c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
429c325c9c7SLorenzo Bianconi 
430a85b590cSFelix Fietkau 	return dev;
431a85b590cSFelix Fietkau }
432a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
433a85b590cSFelix Fietkau 
43417f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
43517f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
43617f1de56SFelix Fietkau {
43717f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
438c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
43917f1de56SFelix Fietkau 	int ret;
44017f1de56SFelix Fietkau 
44117f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
442c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
44317f1de56SFelix Fietkau 
44417f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
44517f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
44617f1de56SFelix Fietkau 		if (ret)
44717f1de56SFelix Fietkau 			return ret;
44817f1de56SFelix Fietkau 	}
44917f1de56SFelix Fietkau 
45017f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
45117f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
45217f1de56SFelix Fietkau 		if (ret)
45317f1de56SFelix Fietkau 			return ret;
45417f1de56SFelix Fietkau 	}
45517f1de56SFelix Fietkau 
456c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
457c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
458c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
45917f1de56SFelix Fietkau 
460b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
46117f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
46217f1de56SFelix Fietkau 		if (ret)
46317f1de56SFelix Fietkau 			return ret;
464b374e868SArnd Bergmann 	}
46517f1de56SFelix Fietkau 
46617f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
46717f1de56SFelix Fietkau }
46817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
46917f1de56SFelix Fietkau 
47017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
47117f1de56SFelix Fietkau {
47217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
47317f1de56SFelix Fietkau 
474d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
47536f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
47679d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
47717f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
47817f1de56SFelix Fietkau }
47917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
48017f1de56SFelix Fietkau 
481def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
482def34a2fSLorenzo Bianconi {
483def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
484def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
485def34a2fSLorenzo Bianconi }
486def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
487def34a2fSLorenzo Bianconi 
48817f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
48917f1de56SFelix Fietkau {
490011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
491011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
492011849e0SFelix Fietkau 
493011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
49417f1de56SFelix Fietkau 		dev_kfree_skb(skb);
49517f1de56SFelix Fietkau 		return;
49617f1de56SFelix Fietkau 	}
49717f1de56SFelix Fietkau 
49817f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
49917f1de56SFelix Fietkau }
50017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
50117f1de56SFelix Fietkau 
5025a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
50326e40d4cSFelix Fietkau {
5045a95ca41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
505af005f26SLorenzo Bianconi 	struct mt76_queue *q;
5065a95ca41SFelix Fietkau 	int i, offset;
50726e40d4cSFelix Fietkau 
5085a95ca41SFelix Fietkau 	offset = __MT_TXQ_MAX * (phy != &dev->phy);
5095a95ca41SFelix Fietkau 
5105a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
5115a95ca41SFelix Fietkau 		q = dev->q_tx[offset + i].q;
512af005f26SLorenzo Bianconi 		if (q && q->queued)
51326e40d4cSFelix Fietkau 			return true;
51426e40d4cSFelix Fietkau 	}
51526e40d4cSFelix Fietkau 
51626e40d4cSFelix Fietkau 	return false;
51726e40d4cSFelix Fietkau }
51839d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
51926e40d4cSFelix Fietkau 
5200fd0eb54SFelix Fietkau static struct mt76_channel_state *
52196747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
5220fd0eb54SFelix Fietkau {
5230fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
5240fd0eb54SFelix Fietkau 	int idx;
5250fd0eb54SFelix Fietkau 
5260fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
52796747a51SFelix Fietkau 		msband = &phy->sband_2g;
5280fd0eb54SFelix Fietkau 	else
52996747a51SFelix Fietkau 		msband = &phy->sband_5g;
5300fd0eb54SFelix Fietkau 
5310fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
5320fd0eb54SFelix Fietkau 	return &msband->chan[idx];
5330fd0eb54SFelix Fietkau }
5340fd0eb54SFelix Fietkau 
53596747a51SFelix Fietkau static void
53696747a51SFelix Fietkau mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
53796747a51SFelix Fietkau {
53896747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
53996747a51SFelix Fietkau 
54096747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
54196747a51SFelix Fietkau 						  phy->survey_time));
54296747a51SFelix Fietkau 	phy->survey_time = time;
54396747a51SFelix Fietkau }
54496747a51SFelix Fietkau 
5455ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
5465ce09c1aSFelix Fietkau {
547aec65e48SFelix Fietkau 	ktime_t cur_time;
548aec65e48SFelix Fietkau 
5495ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
5505ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
5515ce09c1aSFelix Fietkau 
552aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
55396747a51SFelix Fietkau 	mt76_update_survey_active_time(&dev->phy, cur_time);
55496747a51SFelix Fietkau 	if (dev->phy2)
55596747a51SFelix Fietkau 		mt76_update_survey_active_time(dev->phy2, cur_time);
556aec65e48SFelix Fietkau 
5575ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
55896747a51SFelix Fietkau 		struct mt76_channel_state *state = dev->phy.chan_state;
55996747a51SFelix Fietkau 
560237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
5615ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
5625ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
563237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
5645ce09c1aSFelix Fietkau 	}
5655ce09c1aSFelix Fietkau }
5665ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
5675ce09c1aSFelix Fietkau 
56896747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
56917f1de56SFelix Fietkau {
57096747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
57196747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
57217f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
57317f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
57426e40d4cSFelix Fietkau 	int timeout = HZ / 5;
57517f1de56SFelix Fietkau 
5765a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
5775ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
57817f1de56SFelix Fietkau 
57996747a51SFelix Fietkau 	phy->chandef = *chandef;
58096747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
58117f1de56SFelix Fietkau 
58217f1de56SFelix Fietkau 	if (!offchannel)
58396747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
58417f1de56SFelix Fietkau 
58596747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
58696747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
58717f1de56SFelix Fietkau }
58817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
58917f1de56SFelix Fietkau 
59017f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
59117f1de56SFelix Fietkau 		    struct survey_info *survey)
59217f1de56SFelix Fietkau {
59396747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
59496747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
59517f1de56SFelix Fietkau 	struct mt76_sband *sband;
59617f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
59717f1de56SFelix Fietkau 	struct mt76_channel_state *state;
59817f1de56SFelix Fietkau 	int ret = 0;
59917f1de56SFelix Fietkau 
600237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
60117f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
6025ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
60317f1de56SFelix Fietkau 
60496747a51SFelix Fietkau 	sband = &phy->sband_2g;
60517f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
60617f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
60796747a51SFelix Fietkau 		sband = &phy->sband_5g;
60817f1de56SFelix Fietkau 	}
60917f1de56SFelix Fietkau 
610237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
611237312c5SLorenzo Bianconi 		ret = -ENOENT;
612237312c5SLorenzo Bianconi 		goto out;
613237312c5SLorenzo Bianconi 	}
61417f1de56SFelix Fietkau 
61517f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
61696747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
61717f1de56SFelix Fietkau 
61817f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
61917f1de56SFelix Fietkau 	survey->channel = chan;
62017f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
621ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
622e5051965SFelix Fietkau 	if (state->noise)
623e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
624e5051965SFelix Fietkau 
62596747a51SFelix Fietkau 	if (chan == phy->main_chan) {
62617f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
62717f1de56SFelix Fietkau 
6285ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
6295ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
6305ce09c1aSFelix Fietkau 	}
6315ce09c1aSFelix Fietkau 
63217f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
6336bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
634237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
635e5051965SFelix Fietkau 	survey->noise = state->noise;
636237312c5SLorenzo Bianconi 
637237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
638237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
639ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
64017f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
64117f1de56SFelix Fietkau 
642237312c5SLorenzo Bianconi out:
643237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
644237312c5SLorenzo Bianconi 
64517f1de56SFelix Fietkau 	return ret;
64617f1de56SFelix Fietkau }
64717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
64817f1de56SFelix Fietkau 
64930ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
65030ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
65130ce7f44SFelix Fietkau {
65230ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
65330ce7f44SFelix Fietkau 	int i;
65430ce7f44SFelix Fietkau 
65530ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
65630ce7f44SFelix Fietkau 
65730ce7f44SFelix Fietkau 	if (!key)
65830ce7f44SFelix Fietkau 		return;
65930ce7f44SFelix Fietkau 
66001cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
66101cfc1b4SLorenzo Bianconi 		return;
66230ce7f44SFelix Fietkau 
66301cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
66430ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
66530ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
66630ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
66730ce7f44SFelix Fietkau 	}
66830ce7f44SFelix Fietkau }
66930ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
67030ce7f44SFelix Fietkau 
671bfc394ddSFelix Fietkau static void
672bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
673bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
674bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
6754e34249eSFelix Fietkau {
676bfc394ddSFelix Fietkau 
6774e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
6784e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
6794e34249eSFelix Fietkau 
6804e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
6814e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
6824e34249eSFelix Fietkau 
6834e34249eSFelix Fietkau 	status->flag = mstat.flag;
6844e34249eSFelix Fietkau 	status->freq = mstat.freq;
6854e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
6864e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
6874e34249eSFelix Fietkau 	status->bw = mstat.bw;
6884e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
6894e34249eSFelix Fietkau 	status->nss = mstat.nss;
6904e34249eSFelix Fietkau 	status->band = mstat.band;
6914e34249eSFelix Fietkau 	status->signal = mstat.signal;
6924e34249eSFelix Fietkau 	status->chains = mstat.chains;
693d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
6944e34249eSFelix Fietkau 
6954e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
69613381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
69713381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
69813381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
69913381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
7009c68a57bSFelix Fietkau 
701bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
702bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
7034e34249eSFelix Fietkau }
7044e34249eSFelix Fietkau 
70530ce7f44SFelix Fietkau static int
70630ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
70730ce7f44SFelix Fietkau {
70830ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
70930ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
71030ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
71130ce7f44SFelix Fietkau 	int ret;
71230ce7f44SFelix Fietkau 
71330ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
71430ce7f44SFelix Fietkau 		return 0;
71530ce7f44SFelix Fietkau 
71630ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
71730ce7f44SFelix Fietkau 		return 0;
71830ce7f44SFelix Fietkau 
71930ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
72030ce7f44SFelix Fietkau 		/*
72130ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
72230ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
72330ce7f44SFelix Fietkau 		 */
72430ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *)skb->data;
72530ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
72630ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
72730ce7f44SFelix Fietkau 			return 0;
72830ce7f44SFelix Fietkau 	}
72930ce7f44SFelix Fietkau 
73030ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
73130ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
73230ce7f44SFelix Fietkau 		     sizeof(status->iv));
73330ce7f44SFelix Fietkau 	if (ret <= 0)
73430ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
73530ce7f44SFelix Fietkau 
73630ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
73730ce7f44SFelix Fietkau 
73830ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
73930ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
74030ce7f44SFelix Fietkau 
74130ce7f44SFelix Fietkau 	return 0;
74230ce7f44SFelix Fietkau }
74330ce7f44SFelix Fietkau 
744d71ef286SFelix Fietkau static void
7455ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
7465ce09c1aSFelix Fietkau 		    int len)
7475ce09c1aSFelix Fietkau {
7485ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
749*85b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
750*85b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
751*85b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
752*85b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
753*85b7a5d0SLorenzo Bianconi 		.band = status->band,
754*85b7a5d0SLorenzo Bianconi 		.nss = status->nss,
755*85b7a5d0SLorenzo Bianconi 		.bw = status->bw,
756*85b7a5d0SLorenzo Bianconi 	};
7575ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
7585ce09c1aSFelix Fietkau 	u32 airtime;
7595ce09c1aSFelix Fietkau 
760*85b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
761237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
7625ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
763237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
7645ce09c1aSFelix Fietkau 
7655ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
7665ce09c1aSFelix Fietkau 		return;
7675ce09c1aSFelix Fietkau 
7685ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
7695ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
7705ce09c1aSFelix Fietkau }
7715ce09c1aSFelix Fietkau 
7725ce09c1aSFelix Fietkau static void
7735ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
7745ce09c1aSFelix Fietkau {
7755ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
7765ce09c1aSFelix Fietkau 	int wcid_idx;
7775ce09c1aSFelix Fietkau 
7785ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
7795ce09c1aSFelix Fietkau 		return;
7805ce09c1aSFelix Fietkau 
7815ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
782bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
7835ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
7845ce09c1aSFelix Fietkau 	else
7855ce09c1aSFelix Fietkau 		wcid = NULL;
7865ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
7875ce09c1aSFelix Fietkau 
7885ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
7895ce09c1aSFelix Fietkau 
7905ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
7915ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
7925ce09c1aSFelix Fietkau }
7935ce09c1aSFelix Fietkau 
7945ce09c1aSFelix Fietkau static void
7955ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
7965ce09c1aSFelix Fietkau {
7975ce09c1aSFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
7985ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
7995ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
8005ce09c1aSFelix Fietkau 
8015ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
8025ce09c1aSFelix Fietkau 		return;
8035ce09c1aSFelix Fietkau 
8045ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
8055ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
8065ce09c1aSFelix Fietkau 			return;
8075ce09c1aSFelix Fietkau 
8085ce09c1aSFelix Fietkau 		wcid = NULL;
8095ce09c1aSFelix Fietkau 	}
8105ce09c1aSFelix Fietkau 
8115ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
8125ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
8135ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
8145ce09c1aSFelix Fietkau 
8155ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
8165ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
8175ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
8185ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
8195ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
8205ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
8215ce09c1aSFelix Fietkau 		}
8225ce09c1aSFelix Fietkau 
8235ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
8245ce09c1aSFelix Fietkau 		return;
8255ce09c1aSFelix Fietkau 	}
8265ce09c1aSFelix Fietkau 
8275ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
8285ce09c1aSFelix Fietkau }
8295ce09c1aSFelix Fietkau 
8305ce09c1aSFelix Fietkau static void
831ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
832d71ef286SFelix Fietkau {
833d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
834d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
835d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
836bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
837d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
838d71ef286SFelix Fietkau 	bool ps;
83990fdc171SFelix Fietkau 	int i;
840d71ef286SFelix Fietkau 
841bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
84236d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
843bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
84436d91096SFelix Fietkau 		if (sta)
84536d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
84636d91096SFelix Fietkau 	}
84736d91096SFelix Fietkau 
8485ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
8495ce09c1aSFelix Fietkau 
850d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
851d71ef286SFelix Fietkau 		return;
852d71ef286SFelix Fietkau 
853d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
854d71ef286SFelix Fietkau 
85502e5a769SFelix Fietkau 	if (status->signal <= 0)
85602e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
85702e5a769SFelix Fietkau 
858ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
859ef13edc0SFelix Fietkau 
860d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
861d71ef286SFelix Fietkau 		return;
862d71ef286SFelix Fietkau 
863d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
864d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
865d71ef286SFelix Fietkau 		return;
866d71ef286SFelix Fietkau 	}
867d71ef286SFelix Fietkau 
868d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
869d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
870d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
871d71ef286SFelix Fietkau 		return;
872d71ef286SFelix Fietkau 
873d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
874d71ef286SFelix Fietkau 
875d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
876d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
877d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
878d71ef286SFelix Fietkau 
879d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
880d71ef286SFelix Fietkau 		return;
881d71ef286SFelix Fietkau 
88211b2a25fSFelix Fietkau 	if (ps)
883d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
88411b2a25fSFelix Fietkau 	else
885d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
886d71ef286SFelix Fietkau 
887d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
8889f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
88990fdc171SFelix Fietkau 
89090fdc171SFelix Fietkau 	if (ps)
89190fdc171SFelix Fietkau 		return;
89290fdc171SFelix Fietkau 
89390fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
89490fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
89590fdc171SFelix Fietkau 
89690fdc171SFelix Fietkau 		if (!sta->txq[i])
89790fdc171SFelix Fietkau 			continue;
89890fdc171SFelix Fietkau 
89990fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
90090fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
901bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
90290fdc171SFelix Fietkau 	}
903d71ef286SFelix Fietkau }
904d71ef286SFelix Fietkau 
9059d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
90681e850efSLorenzo Bianconi 		      struct napi_struct *napi)
90717f1de56SFelix Fietkau {
9089c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
909bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
9109d9d738bSFelix Fietkau 	struct sk_buff *skb;
9119d9d738bSFelix Fietkau 
912c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
9139d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
91430ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
91530ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
91630ce7f44SFelix Fietkau 			continue;
91730ce7f44SFelix Fietkau 		}
91830ce7f44SFelix Fietkau 
919bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
920bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
9219d9d738bSFelix Fietkau 	}
922c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
9239d9d738bSFelix Fietkau }
9249d9d738bSFelix Fietkau 
92581e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
92681e850efSLorenzo Bianconi 			   struct napi_struct *napi)
9279d9d738bSFelix Fietkau {
928aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
92917f1de56SFelix Fietkau 	struct sk_buff *skb;
93017f1de56SFelix Fietkau 
931aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
932aee5b8cfSFelix Fietkau 
933d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
934ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
935aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
936d71ef286SFelix Fietkau 	}
937aee5b8cfSFelix Fietkau 
93881e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
9394e34249eSFelix Fietkau }
94081e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
941723b90dcSFelix Fietkau 
942e28487eaSFelix Fietkau static int
943e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
944426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
945e28487eaSFelix Fietkau {
946e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
947e28487eaSFelix Fietkau 	int ret;
948e28487eaSFelix Fietkau 	int i;
949e28487eaSFelix Fietkau 
950e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
951e28487eaSFelix Fietkau 
952e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
953e28487eaSFelix Fietkau 	if (ret)
954e28487eaSFelix Fietkau 		goto out;
955e28487eaSFelix Fietkau 
956e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
957e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
958e28487eaSFelix Fietkau 
959e28487eaSFelix Fietkau 		if (!sta->txq[i])
960e28487eaSFelix Fietkau 			continue;
961e28487eaSFelix Fietkau 
962e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
963e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
964e28487eaSFelix Fietkau 
965e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
966e28487eaSFelix Fietkau 	}
967e28487eaSFelix Fietkau 
968ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
969426e8e41SFelix Fietkau 	if (ext_phy)
970426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
971c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
972e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
973e28487eaSFelix Fietkau 
974e28487eaSFelix Fietkau out:
975e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
976e28487eaSFelix Fietkau 
977e28487eaSFelix Fietkau 	return ret;
978e28487eaSFelix Fietkau }
979e28487eaSFelix Fietkau 
98013f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
981723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
982723b90dcSFelix Fietkau {
983723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
98413f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
985723b90dcSFelix Fietkau 
986723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
987723b90dcSFelix Fietkau 	synchronize_rcu();
988723b90dcSFelix Fietkau 
98958bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
99058bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
99158bab0d4SFelix Fietkau 
992e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
993e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
994e28487eaSFelix Fietkau 
995723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
996723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
997723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
998426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
999426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
100013f61dfcSLorenzo Bianconi }
100113f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1002e28487eaSFelix Fietkau 
100313f61dfcSLorenzo Bianconi static void
100413f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
100513f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
100613f61dfcSLorenzo Bianconi {
100713f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
100813f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1009723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1010723b90dcSFelix Fietkau }
1011e28487eaSFelix Fietkau 
1012e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1013e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1014e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1015e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1016e28487eaSFelix Fietkau {
1017426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1018426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1019426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1020e28487eaSFelix Fietkau 
1021e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1022e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1023426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1024e28487eaSFelix Fietkau 
10259c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
10269c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
10279c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
10289c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
10299c193de5SFelix Fietkau 
1030e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1031e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1032e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1033e28487eaSFelix Fietkau 
1034e28487eaSFelix Fietkau 	return 0;
1035e28487eaSFelix Fietkau }
1036e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
10379313faacSFelix Fietkau 
10389313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10399313faacSFelix Fietkau 		     int *dbm)
10409313faacSFelix Fietkau {
1041beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1042beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
10439313faacSFelix Fietkau 
1044beaaeb6bSFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur, 2);
10459313faacSFelix Fietkau 
10469313faacSFelix Fietkau 	/* convert from per-chain power to combined
1047c19b0ca5SLorenzo Bianconi 	 * output power
10489313faacSFelix Fietkau 	 */
1049c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
1050c19b0ca5SLorenzo Bianconi 	case 4:
1051c19b0ca5SLorenzo Bianconi 		*dbm += 6;
1052c19b0ca5SLorenzo Bianconi 		break;
1053c19b0ca5SLorenzo Bianconi 	case 3:
1054c19b0ca5SLorenzo Bianconi 		*dbm += 4;
1055c19b0ca5SLorenzo Bianconi 		break;
1056c19b0ca5SLorenzo Bianconi 	case 2:
10579313faacSFelix Fietkau 		*dbm += 3;
1058c19b0ca5SLorenzo Bianconi 		break;
1059c19b0ca5SLorenzo Bianconi 	default:
1060c19b0ca5SLorenzo Bianconi 		break;
1061c19b0ca5SLorenzo Bianconi 	}
10629313faacSFelix Fietkau 
10639313faacSFelix Fietkau 	return 0;
10649313faacSFelix Fietkau }
10659313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1066e7173858SFelix Fietkau 
1067e7173858SFelix Fietkau static void
1068e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1069e7173858SFelix Fietkau {
1070e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
1071e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1072e7173858SFelix Fietkau }
1073e7173858SFelix Fietkau 
1074e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1075e7173858SFelix Fietkau {
1076e7173858SFelix Fietkau 	if (!dev->csa_complete)
1077e7173858SFelix Fietkau 		return;
1078e7173858SFelix Fietkau 
1079e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1080e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1081e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1082e7173858SFelix Fietkau 
1083e7173858SFelix Fietkau 	dev->csa_complete = 0;
1084e7173858SFelix Fietkau }
1085e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1086e7173858SFelix Fietkau 
1087e7173858SFelix Fietkau static void
1088e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1089e7173858SFelix Fietkau {
1090e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1091e7173858SFelix Fietkau 
1092e7173858SFelix Fietkau 	if (!vif->csa_active)
1093e7173858SFelix Fietkau 		return;
1094e7173858SFelix Fietkau 
1095e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
1096e7173858SFelix Fietkau }
1097e7173858SFelix Fietkau 
1098e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1099e7173858SFelix Fietkau {
1100e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1101e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1102e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1103e7173858SFelix Fietkau }
1104e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
110587d53103SStanislaw Gruszka 
110687d53103SStanislaw Gruszka int
110787d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
110887d53103SStanislaw Gruszka {
110987d53103SStanislaw Gruszka 	return 0;
111087d53103SStanislaw Gruszka }
111187d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1112eadfd98fSLorenzo Bianconi 
1113eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1114eadfd98fSLorenzo Bianconi {
1115eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1116eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1117eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1118eadfd98fSLorenzo Bianconi 
1119eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1120eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1121eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1122eadfd98fSLorenzo Bianconi 
1123eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1124eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1125eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1126eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1127eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1128eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1129eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1130eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1131eadfd98fSLorenzo Bianconi 
1132eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1133eadfd98fSLorenzo Bianconi }
1134eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1135d2679d65SLorenzo Bianconi 
1136d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1137d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1138d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1139d2679d65SLorenzo Bianconi {
1140d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1141d2679d65SLorenzo Bianconi 
1142d2679d65SLorenzo Bianconi 	if (cck) {
114396747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1144d2679d65SLorenzo Bianconi 			return 0;
1145d2679d65SLorenzo Bianconi 
1146d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
114796747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1148d2679d65SLorenzo Bianconi 		offset = 4;
1149d2679d65SLorenzo Bianconi 	}
1150d2679d65SLorenzo Bianconi 
1151d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1152d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1153d2679d65SLorenzo Bianconi 			return i;
1154d2679d65SLorenzo Bianconi 	}
1155d2679d65SLorenzo Bianconi 
1156d2679d65SLorenzo Bianconi 	return 0;
1157d2679d65SLorenzo Bianconi }
1158d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
11598b8ab5c2SLorenzo Bianconi 
11608b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
11618b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
11628b8ab5c2SLorenzo Bianconi {
1163011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11648b8ab5c2SLorenzo Bianconi 
1165011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
11668b8ab5c2SLorenzo Bianconi }
11678b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
11688b8ab5c2SLorenzo Bianconi 
11698b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
11708b8ab5c2SLorenzo Bianconi {
1171011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11728b8ab5c2SLorenzo Bianconi 
1173011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
11748b8ab5c2SLorenzo Bianconi }
11758b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1176e49c76d4SLorenzo Bianconi 
1177e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1178e49c76d4SLorenzo Bianconi {
1179beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1180beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1181e49c76d4SLorenzo Bianconi 
1182e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1183beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1184beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1185e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1186e49c76d4SLorenzo Bianconi 
1187e49c76d4SLorenzo Bianconi 	return 0;
1188e49c76d4SLorenzo Bianconi }
1189e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1190