xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision c7d2d6310969a6cfd1395d610275e391634e8bb0)
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;
282c89d3625SFelix Fietkau 
283c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
284c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
285c89d3625SFelix Fietkau 
286c89d3625SFelix Fietkau 	wiphy->available_antennas_tx = dev->phy.antenna_mask;
287c89d3625SFelix Fietkau 	wiphy->available_antennas_rx = dev->phy.antenna_mask;
288c89d3625SFelix Fietkau 
289c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
290c89d3625SFelix Fietkau 	hw->max_tx_fragments = 16;
291c89d3625SFelix Fietkau 
292c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
293c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
294c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
295c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
296c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
297c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
298c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
299c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
300c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
301c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
302c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
303c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
304c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
305c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
306c89d3625SFelix Fietkau 
307c89d3625SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
308c89d3625SFelix Fietkau 	wiphy->interface_modes =
309c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
310c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
311c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
312c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
313c89d3625SFelix Fietkau #endif
314c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
315c89d3625SFelix Fietkau }
316c89d3625SFelix Fietkau 
317c89d3625SFelix Fietkau struct mt76_phy *
318c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
319c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
320c89d3625SFelix Fietkau {
321c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
322c89d3625SFelix Fietkau 	struct mt76_phy *phy;
323c89d3625SFelix Fietkau 	unsigned int phy_size, chan_size;
324c89d3625SFelix Fietkau 	unsigned int size_2g, size_5g;
325c89d3625SFelix Fietkau 	void *priv;
326c89d3625SFelix Fietkau 
327c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
328c89d3625SFelix Fietkau 	chan_size = sizeof(dev->phy.sband_2g.chan[0]);
329c89d3625SFelix Fietkau 	size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
330c89d3625SFelix Fietkau 	size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
331c89d3625SFelix Fietkau 
332c89d3625SFelix Fietkau 	size += phy_size + size_2g + size_5g;
333c89d3625SFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
334c89d3625SFelix Fietkau 	if (!hw)
335c89d3625SFelix Fietkau 		return NULL;
336c89d3625SFelix Fietkau 
337c89d3625SFelix Fietkau 	phy = hw->priv;
338c89d3625SFelix Fietkau 	phy->dev = dev;
339c89d3625SFelix Fietkau 	phy->hw = hw;
340c89d3625SFelix Fietkau 
341c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
342c89d3625SFelix Fietkau 
343c89d3625SFelix Fietkau 	priv = hw->priv + phy_size;
344c89d3625SFelix Fietkau 
345c89d3625SFelix Fietkau 	phy->sband_2g = dev->phy.sband_2g;
346c89d3625SFelix Fietkau 	phy->sband_2g.chan = priv;
347c89d3625SFelix Fietkau 	priv += size_2g;
348c89d3625SFelix Fietkau 
349c89d3625SFelix Fietkau 	phy->sband_5g = dev->phy.sband_5g;
350c89d3625SFelix Fietkau 	phy->sband_5g.chan = priv;
351c89d3625SFelix Fietkau 	priv += size_5g;
352c89d3625SFelix Fietkau 
353c89d3625SFelix Fietkau 	phy->priv = priv;
354c89d3625SFelix Fietkau 
355c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
356c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
357c89d3625SFelix Fietkau 
358c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
359c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
360c89d3625SFelix Fietkau 
361c89d3625SFelix Fietkau 	return phy;
362c89d3625SFelix Fietkau }
363c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
364c89d3625SFelix Fietkau 
365c89d3625SFelix Fietkau int
366c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy)
367c89d3625SFelix Fietkau {
368c89d3625SFelix Fietkau 	int ret;
369c89d3625SFelix Fietkau 
370c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
371c89d3625SFelix Fietkau 	if (ret)
372c89d3625SFelix Fietkau 		return ret;
373c89d3625SFelix Fietkau 
374c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
375c89d3625SFelix Fietkau 	return 0;
376c89d3625SFelix Fietkau }
377c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
378c89d3625SFelix Fietkau 
379c89d3625SFelix Fietkau void
380c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy)
381c89d3625SFelix Fietkau {
382c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
383c89d3625SFelix Fietkau 
384c89d3625SFelix Fietkau 	dev->phy2 = NULL;
385c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
386c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
387c89d3625SFelix Fietkau }
388c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
389c89d3625SFelix Fietkau 
390a85b590cSFelix Fietkau struct mt76_dev *
391c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
392c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
393c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
394a85b590cSFelix Fietkau {
395a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
396ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
397a85b590cSFelix Fietkau 	struct mt76_dev *dev;
398e5443256SFelix Fietkau 	int i;
399a85b590cSFelix Fietkau 
400a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
401a85b590cSFelix Fietkau 	if (!hw)
402a85b590cSFelix Fietkau 		return NULL;
403a85b590cSFelix Fietkau 
404a85b590cSFelix Fietkau 	dev = hw->priv;
405a85b590cSFelix Fietkau 	dev->hw = hw;
406c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
407c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
408c0f7b25aSLorenzo Bianconi 
409ac24dd35SFelix Fietkau 	phy = &dev->phy;
410ac24dd35SFelix Fietkau 	phy->dev = dev;
411ac24dd35SFelix Fietkau 	phy->hw = hw;
412ac24dd35SFelix Fietkau 
413a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
414a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
415a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
416108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
41726e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
41888046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
419a85b590cSFelix Fietkau 
420e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
421e5443256SFelix Fietkau 
422e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
423e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
424e5443256SFelix Fietkau 
425c325c9c7SLorenzo Bianconi 	tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
426c325c9c7SLorenzo Bianconi 
427a85b590cSFelix Fietkau 	return dev;
428a85b590cSFelix Fietkau }
429a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
430a85b590cSFelix Fietkau 
43117f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
43217f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
43317f1de56SFelix Fietkau {
43417f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
435c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
43617f1de56SFelix Fietkau 	int ret;
43717f1de56SFelix Fietkau 
43817f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
439c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
44017f1de56SFelix Fietkau 
44117f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
44217f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
44317f1de56SFelix Fietkau 		if (ret)
44417f1de56SFelix Fietkau 			return ret;
44517f1de56SFelix Fietkau 	}
44617f1de56SFelix Fietkau 
44717f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
44817f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
44917f1de56SFelix Fietkau 		if (ret)
45017f1de56SFelix Fietkau 			return ret;
45117f1de56SFelix Fietkau 	}
45217f1de56SFelix Fietkau 
453c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
454c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
455c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
45617f1de56SFelix Fietkau 
457b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
45817f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
45917f1de56SFelix Fietkau 		if (ret)
46017f1de56SFelix Fietkau 			return ret;
461b374e868SArnd Bergmann 	}
46217f1de56SFelix Fietkau 
46317f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
46417f1de56SFelix Fietkau }
46517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
46617f1de56SFelix Fietkau 
46717f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
46817f1de56SFelix Fietkau {
46917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
47017f1de56SFelix Fietkau 
471d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
47236f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
47379d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
47417f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
47517f1de56SFelix Fietkau }
47617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
47717f1de56SFelix Fietkau 
478def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
479def34a2fSLorenzo Bianconi {
480def34a2fSLorenzo Bianconi 	mt76_tx_free(dev);
481def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
482def34a2fSLorenzo Bianconi }
483def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
484def34a2fSLorenzo Bianconi 
48517f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
48617f1de56SFelix Fietkau {
487011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
488011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
489011849e0SFelix Fietkau 
490011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
49117f1de56SFelix Fietkau 		dev_kfree_skb(skb);
49217f1de56SFelix Fietkau 		return;
49317f1de56SFelix Fietkau 	}
49417f1de56SFelix Fietkau 
49517f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
49617f1de56SFelix Fietkau }
49717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
49817f1de56SFelix Fietkau 
4995a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
50026e40d4cSFelix Fietkau {
5015a95ca41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
502af005f26SLorenzo Bianconi 	struct mt76_queue *q;
5035a95ca41SFelix Fietkau 	int i, offset;
50426e40d4cSFelix Fietkau 
5055a95ca41SFelix Fietkau 	offset = __MT_TXQ_MAX * (phy != &dev->phy);
5065a95ca41SFelix Fietkau 
5075a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
5085a95ca41SFelix Fietkau 		q = dev->q_tx[offset + i].q;
509af005f26SLorenzo Bianconi 		if (q && q->queued)
51026e40d4cSFelix Fietkau 			return true;
51126e40d4cSFelix Fietkau 	}
51226e40d4cSFelix Fietkau 
51326e40d4cSFelix Fietkau 	return false;
51426e40d4cSFelix Fietkau }
51539d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
51626e40d4cSFelix Fietkau 
5170fd0eb54SFelix Fietkau static struct mt76_channel_state *
51896747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
5190fd0eb54SFelix Fietkau {
5200fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
5210fd0eb54SFelix Fietkau 	int idx;
5220fd0eb54SFelix Fietkau 
5230fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
52496747a51SFelix Fietkau 		msband = &phy->sband_2g;
5250fd0eb54SFelix Fietkau 	else
52696747a51SFelix Fietkau 		msband = &phy->sband_5g;
5270fd0eb54SFelix Fietkau 
5280fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
5290fd0eb54SFelix Fietkau 	return &msband->chan[idx];
5300fd0eb54SFelix Fietkau }
5310fd0eb54SFelix Fietkau 
53296747a51SFelix Fietkau static void
53396747a51SFelix Fietkau mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
53496747a51SFelix Fietkau {
53596747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
53696747a51SFelix Fietkau 
53796747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
53896747a51SFelix Fietkau 						  phy->survey_time));
53996747a51SFelix Fietkau 	phy->survey_time = time;
54096747a51SFelix Fietkau }
54196747a51SFelix Fietkau 
5425ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
5435ce09c1aSFelix Fietkau {
544aec65e48SFelix Fietkau 	ktime_t cur_time;
545aec65e48SFelix Fietkau 
5465ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
5475ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
5485ce09c1aSFelix Fietkau 
549aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
55096747a51SFelix Fietkau 	mt76_update_survey_active_time(&dev->phy, cur_time);
55196747a51SFelix Fietkau 	if (dev->phy2)
55296747a51SFelix Fietkau 		mt76_update_survey_active_time(dev->phy2, cur_time);
553aec65e48SFelix Fietkau 
5545ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
55596747a51SFelix Fietkau 		struct mt76_channel_state *state = dev->phy.chan_state;
55696747a51SFelix Fietkau 
557237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
5585ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
5595ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
560237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
5615ce09c1aSFelix Fietkau 	}
5625ce09c1aSFelix Fietkau }
5635ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
5645ce09c1aSFelix Fietkau 
56596747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
56617f1de56SFelix Fietkau {
56796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
56896747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
56917f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
57017f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
57126e40d4cSFelix Fietkau 	int timeout = HZ / 5;
57217f1de56SFelix Fietkau 
5735a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
5745ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
57517f1de56SFelix Fietkau 
57696747a51SFelix Fietkau 	phy->chandef = *chandef;
57796747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
57817f1de56SFelix Fietkau 
57917f1de56SFelix Fietkau 	if (!offchannel)
58096747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
58117f1de56SFelix Fietkau 
58296747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
58396747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
58417f1de56SFelix Fietkau }
58517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
58617f1de56SFelix Fietkau 
58717f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
58817f1de56SFelix Fietkau 		    struct survey_info *survey)
58917f1de56SFelix Fietkau {
59096747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
59196747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
59217f1de56SFelix Fietkau 	struct mt76_sband *sband;
59317f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
59417f1de56SFelix Fietkau 	struct mt76_channel_state *state;
59517f1de56SFelix Fietkau 	int ret = 0;
59617f1de56SFelix Fietkau 
597237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
59817f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
5995ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
60017f1de56SFelix Fietkau 
60196747a51SFelix Fietkau 	sband = &phy->sband_2g;
60217f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
60317f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
60496747a51SFelix Fietkau 		sband = &phy->sband_5g;
60517f1de56SFelix Fietkau 	}
60617f1de56SFelix Fietkau 
607237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
608237312c5SLorenzo Bianconi 		ret = -ENOENT;
609237312c5SLorenzo Bianconi 		goto out;
610237312c5SLorenzo Bianconi 	}
61117f1de56SFelix Fietkau 
61217f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
61396747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
61417f1de56SFelix Fietkau 
61517f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
61617f1de56SFelix Fietkau 	survey->channel = chan;
61717f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
618ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
61996747a51SFelix Fietkau 	if (chan == phy->main_chan) {
62017f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
62117f1de56SFelix Fietkau 
6225ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
6235ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
6245ce09c1aSFelix Fietkau 	}
6255ce09c1aSFelix Fietkau 
62617f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
6276bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
628237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
629237312c5SLorenzo Bianconi 
630237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
631237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
632ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
63317f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
63417f1de56SFelix Fietkau 
635237312c5SLorenzo Bianconi out:
636237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
637237312c5SLorenzo Bianconi 
63817f1de56SFelix Fietkau 	return ret;
63917f1de56SFelix Fietkau }
64017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
64117f1de56SFelix Fietkau 
64230ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
64330ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
64430ce7f44SFelix Fietkau {
64530ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
64630ce7f44SFelix Fietkau 	int i;
64730ce7f44SFelix Fietkau 
64830ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
64930ce7f44SFelix Fietkau 
65030ce7f44SFelix Fietkau 	if (!key)
65130ce7f44SFelix Fietkau 		return;
65230ce7f44SFelix Fietkau 
65301cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
65401cfc1b4SLorenzo Bianconi 		return;
65530ce7f44SFelix Fietkau 
65601cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
65730ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
65830ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
65930ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
66030ce7f44SFelix Fietkau 	}
66130ce7f44SFelix Fietkau }
66230ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
66330ce7f44SFelix Fietkau 
664bfc394ddSFelix Fietkau static void
665bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
666bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
667bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
6684e34249eSFelix Fietkau {
669bfc394ddSFelix Fietkau 
6704e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
6714e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
6724e34249eSFelix Fietkau 
6734e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
6744e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
6754e34249eSFelix Fietkau 
6764e34249eSFelix Fietkau 	status->flag = mstat.flag;
6774e34249eSFelix Fietkau 	status->freq = mstat.freq;
6784e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
6794e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
6804e34249eSFelix Fietkau 	status->bw = mstat.bw;
6814e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
6824e34249eSFelix Fietkau 	status->nss = mstat.nss;
6834e34249eSFelix Fietkau 	status->band = mstat.band;
6844e34249eSFelix Fietkau 	status->signal = mstat.signal;
6854e34249eSFelix Fietkau 	status->chains = mstat.chains;
686d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
6874e34249eSFelix Fietkau 
6884e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
68913381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
69013381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
69113381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
69213381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
6939c68a57bSFelix Fietkau 
694bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
695bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
6964e34249eSFelix Fietkau }
6974e34249eSFelix Fietkau 
69830ce7f44SFelix Fietkau static int
69930ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
70030ce7f44SFelix Fietkau {
70130ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
70230ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
70330ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
70430ce7f44SFelix Fietkau 	int ret;
70530ce7f44SFelix Fietkau 
70630ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
70730ce7f44SFelix Fietkau 		return 0;
70830ce7f44SFelix Fietkau 
70930ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
71030ce7f44SFelix Fietkau 		return 0;
71130ce7f44SFelix Fietkau 
71230ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
71330ce7f44SFelix Fietkau 		/*
71430ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
71530ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
71630ce7f44SFelix Fietkau 		 */
71730ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *)skb->data;
71830ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
71930ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
72030ce7f44SFelix Fietkau 			return 0;
72130ce7f44SFelix Fietkau 	}
72230ce7f44SFelix Fietkau 
72330ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
72430ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
72530ce7f44SFelix Fietkau 		     sizeof(status->iv));
72630ce7f44SFelix Fietkau 	if (ret <= 0)
72730ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
72830ce7f44SFelix Fietkau 
72930ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
73030ce7f44SFelix Fietkau 
73130ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
73230ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
73330ce7f44SFelix Fietkau 
73430ce7f44SFelix Fietkau 	return 0;
73530ce7f44SFelix Fietkau }
73630ce7f44SFelix Fietkau 
737d71ef286SFelix Fietkau static void
7385ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
7395ce09c1aSFelix Fietkau 		    int len)
7405ce09c1aSFelix Fietkau {
7415ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
7425ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
7435ce09c1aSFelix Fietkau 	u32 airtime;
7445ce09c1aSFelix Fietkau 
7455ce09c1aSFelix Fietkau 	airtime = mt76_calc_rx_airtime(dev, status, len);
746237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
7475ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
748237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
7495ce09c1aSFelix Fietkau 
7505ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
7515ce09c1aSFelix Fietkau 		return;
7525ce09c1aSFelix Fietkau 
7535ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
7545ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
7555ce09c1aSFelix Fietkau }
7565ce09c1aSFelix Fietkau 
7575ce09c1aSFelix Fietkau static void
7585ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
7595ce09c1aSFelix Fietkau {
7605ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
7615ce09c1aSFelix Fietkau 	int wcid_idx;
7625ce09c1aSFelix Fietkau 
7635ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
7645ce09c1aSFelix Fietkau 		return;
7655ce09c1aSFelix Fietkau 
7665ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
767bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
7685ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
7695ce09c1aSFelix Fietkau 	else
7705ce09c1aSFelix Fietkau 		wcid = NULL;
7715ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
7725ce09c1aSFelix Fietkau 
7735ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
7745ce09c1aSFelix Fietkau 
7755ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
7765ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
7775ce09c1aSFelix Fietkau }
7785ce09c1aSFelix Fietkau 
7795ce09c1aSFelix Fietkau static void
7805ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
7815ce09c1aSFelix Fietkau {
7825ce09c1aSFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
7835ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
7845ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
7855ce09c1aSFelix Fietkau 
7865ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
7875ce09c1aSFelix Fietkau 		return;
7885ce09c1aSFelix Fietkau 
7895ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
7905ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
7915ce09c1aSFelix Fietkau 			return;
7925ce09c1aSFelix Fietkau 
7935ce09c1aSFelix Fietkau 		wcid = NULL;
7945ce09c1aSFelix Fietkau 	}
7955ce09c1aSFelix Fietkau 
7965ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
7975ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
7985ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
7995ce09c1aSFelix Fietkau 
8005ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
8015ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
8025ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
8035ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
8045ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
8055ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
8065ce09c1aSFelix Fietkau 		}
8075ce09c1aSFelix Fietkau 
8085ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
8095ce09c1aSFelix Fietkau 		return;
8105ce09c1aSFelix Fietkau 	}
8115ce09c1aSFelix Fietkau 
8125ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
8135ce09c1aSFelix Fietkau }
8145ce09c1aSFelix Fietkau 
8155ce09c1aSFelix Fietkau static void
816ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
817d71ef286SFelix Fietkau {
818d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
819d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
820d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
821bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
822d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
823d71ef286SFelix Fietkau 	bool ps;
82490fdc171SFelix Fietkau 	int i;
825d71ef286SFelix Fietkau 
826bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
82736d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
828bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
82936d91096SFelix Fietkau 		if (sta)
83036d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
83136d91096SFelix Fietkau 	}
83236d91096SFelix Fietkau 
8335ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
8345ce09c1aSFelix Fietkau 
835d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
836d71ef286SFelix Fietkau 		return;
837d71ef286SFelix Fietkau 
838d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
839d71ef286SFelix Fietkau 
84002e5a769SFelix Fietkau 	if (status->signal <= 0)
84102e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
84202e5a769SFelix Fietkau 
843ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
844ef13edc0SFelix Fietkau 
845d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
846d71ef286SFelix Fietkau 		return;
847d71ef286SFelix Fietkau 
848d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
849d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
850d71ef286SFelix Fietkau 		return;
851d71ef286SFelix Fietkau 	}
852d71ef286SFelix Fietkau 
853d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
854d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
855d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
856d71ef286SFelix Fietkau 		return;
857d71ef286SFelix Fietkau 
858d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
859d71ef286SFelix Fietkau 
860d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
861d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
862d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
863d71ef286SFelix Fietkau 
864d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
865d71ef286SFelix Fietkau 		return;
866d71ef286SFelix Fietkau 
86711b2a25fSFelix Fietkau 	if (ps)
868d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
86911b2a25fSFelix Fietkau 	else
870d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
871d71ef286SFelix Fietkau 
872d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
8739f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
87490fdc171SFelix Fietkau 
87590fdc171SFelix Fietkau 	if (ps)
87690fdc171SFelix Fietkau 		return;
87790fdc171SFelix Fietkau 
87890fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
87990fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
88090fdc171SFelix Fietkau 
88190fdc171SFelix Fietkau 		if (!sta->txq[i])
88290fdc171SFelix Fietkau 			continue;
88390fdc171SFelix Fietkau 
88490fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
88590fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
886bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
88790fdc171SFelix Fietkau 	}
888d71ef286SFelix Fietkau }
889d71ef286SFelix Fietkau 
8909d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
89181e850efSLorenzo Bianconi 		      struct napi_struct *napi)
89217f1de56SFelix Fietkau {
8939c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
894bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
8959d9d738bSFelix Fietkau 	struct sk_buff *skb;
8969d9d738bSFelix Fietkau 
897c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
8989d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
89930ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
90030ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
90130ce7f44SFelix Fietkau 			continue;
90230ce7f44SFelix Fietkau 		}
90330ce7f44SFelix Fietkau 
904bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
905bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
9069d9d738bSFelix Fietkau 	}
907c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
9089d9d738bSFelix Fietkau }
9099d9d738bSFelix Fietkau 
91081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
91181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
9129d9d738bSFelix Fietkau {
913aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
91417f1de56SFelix Fietkau 	struct sk_buff *skb;
91517f1de56SFelix Fietkau 
916aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
917aee5b8cfSFelix Fietkau 
918d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
919ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
920aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
921d71ef286SFelix Fietkau 	}
922aee5b8cfSFelix Fietkau 
92381e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
9244e34249eSFelix Fietkau }
92581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
926723b90dcSFelix Fietkau 
927e28487eaSFelix Fietkau static int
928e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
929426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
930e28487eaSFelix Fietkau {
931e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
932e28487eaSFelix Fietkau 	int ret;
933e28487eaSFelix Fietkau 	int i;
934e28487eaSFelix Fietkau 
935e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
936e28487eaSFelix Fietkau 
937e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
938e28487eaSFelix Fietkau 	if (ret)
939e28487eaSFelix Fietkau 		goto out;
940e28487eaSFelix Fietkau 
941e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
942e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
943e28487eaSFelix Fietkau 
944e28487eaSFelix Fietkau 		if (!sta->txq[i])
945e28487eaSFelix Fietkau 			continue;
946e28487eaSFelix Fietkau 
947e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
948e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
949e28487eaSFelix Fietkau 
950e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
951e28487eaSFelix Fietkau 	}
952e28487eaSFelix Fietkau 
953ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
954426e8e41SFelix Fietkau 	if (ext_phy)
955426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
956*c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
957e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
958e28487eaSFelix Fietkau 
959e28487eaSFelix Fietkau out:
960e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
961e28487eaSFelix Fietkau 
962e28487eaSFelix Fietkau 	return ret;
963e28487eaSFelix Fietkau }
964e28487eaSFelix Fietkau 
96513f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
966723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
967723b90dcSFelix Fietkau {
968723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
96913f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
970723b90dcSFelix Fietkau 
971723b90dcSFelix Fietkau 	rcu_assign_pointer(dev->wcid[idx], NULL);
972723b90dcSFelix Fietkau 	synchronize_rcu();
973723b90dcSFelix Fietkau 
97458bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
97558bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
97658bab0d4SFelix Fietkau 
977e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
978e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
979e28487eaSFelix Fietkau 
980723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
981723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
982723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
983426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
984426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
98513f61dfcSLorenzo Bianconi }
98613f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
987e28487eaSFelix Fietkau 
98813f61dfcSLorenzo Bianconi static void
98913f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
99013f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
99113f61dfcSLorenzo Bianconi {
99213f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
99313f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
994723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
995723b90dcSFelix Fietkau }
996e28487eaSFelix Fietkau 
997e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
998e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
999e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1000e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1001e28487eaSFelix Fietkau {
1002426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1003426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1004426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1005e28487eaSFelix Fietkau 
1006e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1007e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1008426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1009e28487eaSFelix Fietkau 
10109c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
10119c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
10129c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
10139c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
10149c193de5SFelix Fietkau 
1015e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1016e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1017e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1018e28487eaSFelix Fietkau 
1019e28487eaSFelix Fietkau 	return 0;
1020e28487eaSFelix Fietkau }
1021e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
10229313faacSFelix Fietkau 
10239313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10249313faacSFelix Fietkau 		     int *dbm)
10259313faacSFelix Fietkau {
1026beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1027beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
10289313faacSFelix Fietkau 
1029beaaeb6bSFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur, 2);
10309313faacSFelix Fietkau 
10319313faacSFelix Fietkau 	/* convert from per-chain power to combined
1032c19b0ca5SLorenzo Bianconi 	 * output power
10339313faacSFelix Fietkau 	 */
1034c19b0ca5SLorenzo Bianconi 	switch (n_chains) {
1035c19b0ca5SLorenzo Bianconi 	case 4:
1036c19b0ca5SLorenzo Bianconi 		*dbm += 6;
1037c19b0ca5SLorenzo Bianconi 		break;
1038c19b0ca5SLorenzo Bianconi 	case 3:
1039c19b0ca5SLorenzo Bianconi 		*dbm += 4;
1040c19b0ca5SLorenzo Bianconi 		break;
1041c19b0ca5SLorenzo Bianconi 	case 2:
10429313faacSFelix Fietkau 		*dbm += 3;
1043c19b0ca5SLorenzo Bianconi 		break;
1044c19b0ca5SLorenzo Bianconi 	default:
1045c19b0ca5SLorenzo Bianconi 		break;
1046c19b0ca5SLorenzo Bianconi 	}
10479313faacSFelix Fietkau 
10489313faacSFelix Fietkau 	return 0;
10499313faacSFelix Fietkau }
10509313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1051e7173858SFelix Fietkau 
1052e7173858SFelix Fietkau static void
1053e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1054e7173858SFelix Fietkau {
1055e7173858SFelix Fietkau 	if (vif->csa_active && ieee80211_csa_is_complete(vif))
1056e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1057e7173858SFelix Fietkau }
1058e7173858SFelix Fietkau 
1059e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1060e7173858SFelix Fietkau {
1061e7173858SFelix Fietkau 	if (!dev->csa_complete)
1062e7173858SFelix Fietkau 		return;
1063e7173858SFelix Fietkau 
1064e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1065e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1066e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1067e7173858SFelix Fietkau 
1068e7173858SFelix Fietkau 	dev->csa_complete = 0;
1069e7173858SFelix Fietkau }
1070e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1071e7173858SFelix Fietkau 
1072e7173858SFelix Fietkau static void
1073e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1074e7173858SFelix Fietkau {
1075e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1076e7173858SFelix Fietkau 
1077e7173858SFelix Fietkau 	if (!vif->csa_active)
1078e7173858SFelix Fietkau 		return;
1079e7173858SFelix Fietkau 
1080e7173858SFelix Fietkau 	dev->csa_complete |= ieee80211_csa_is_complete(vif);
1081e7173858SFelix Fietkau }
1082e7173858SFelix Fietkau 
1083e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1084e7173858SFelix Fietkau {
1085e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1086e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1087e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1088e7173858SFelix Fietkau }
1089e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
109087d53103SStanislaw Gruszka 
109187d53103SStanislaw Gruszka int
109287d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
109387d53103SStanislaw Gruszka {
109487d53103SStanislaw Gruszka 	return 0;
109587d53103SStanislaw Gruszka }
109687d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1097eadfd98fSLorenzo Bianconi 
1098eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1099eadfd98fSLorenzo Bianconi {
1100eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1101eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1102eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1103eadfd98fSLorenzo Bianconi 
1104eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1105eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1106eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1107eadfd98fSLorenzo Bianconi 
1108eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1109eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1110eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1111eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1112eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1113eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1114eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1115eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1116eadfd98fSLorenzo Bianconi 
1117eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1118eadfd98fSLorenzo Bianconi }
1119eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1120d2679d65SLorenzo Bianconi 
1121d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1122d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1123d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1124d2679d65SLorenzo Bianconi {
1125d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1126d2679d65SLorenzo Bianconi 
1127d2679d65SLorenzo Bianconi 	if (cck) {
112896747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1129d2679d65SLorenzo Bianconi 			return 0;
1130d2679d65SLorenzo Bianconi 
1131d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
113296747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1133d2679d65SLorenzo Bianconi 		offset = 4;
1134d2679d65SLorenzo Bianconi 	}
1135d2679d65SLorenzo Bianconi 
1136d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1137d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1138d2679d65SLorenzo Bianconi 			return i;
1139d2679d65SLorenzo Bianconi 	}
1140d2679d65SLorenzo Bianconi 
1141d2679d65SLorenzo Bianconi 	return 0;
1142d2679d65SLorenzo Bianconi }
1143d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
11448b8ab5c2SLorenzo Bianconi 
11458b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
11468b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
11478b8ab5c2SLorenzo Bianconi {
1148011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11498b8ab5c2SLorenzo Bianconi 
1150011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
11518b8ab5c2SLorenzo Bianconi }
11528b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
11538b8ab5c2SLorenzo Bianconi 
11548b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
11558b8ab5c2SLorenzo Bianconi {
1156011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
11578b8ab5c2SLorenzo Bianconi 
1158011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
11598b8ab5c2SLorenzo Bianconi }
11608b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1161e49c76d4SLorenzo Bianconi 
1162e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1163e49c76d4SLorenzo Bianconi {
1164beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1165beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1166e49c76d4SLorenzo Bianconi 
1167e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1168beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1169beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1170e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1171e49c76d4SLorenzo Bianconi 
1172e49c76d4SLorenzo Bianconi 	return 0;
1173e49c76d4SLorenzo Bianconi }
1174e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1175