xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision 781eef5b34c57d9d8c772e2402d07086722e89e4)
10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau  */
5*781eef5bSFelix Fietkau #include <linux/sched.h>
617f1de56SFelix Fietkau #include <linux/of.h>
717f1de56SFelix Fietkau #include "mt76.h"
817f1de56SFelix Fietkau 
917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
1017f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
1117f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1217f1de56SFelix Fietkau 	.hw_value = (_idx),			\
1317f1de56SFelix Fietkau 	.max_power = 30,			\
1417f1de56SFelix Fietkau }
1517f1de56SFelix Fietkau 
1617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
1717f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
1817f1de56SFelix Fietkau 	.center_freq = (_freq),			\
1917f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2017f1de56SFelix Fietkau 	.max_power = 30,			\
2117f1de56SFelix Fietkau }
2217f1de56SFelix Fietkau 
2317f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
2417f1de56SFelix Fietkau 	CHAN2G(1, 2412),
2517f1de56SFelix Fietkau 	CHAN2G(2, 2417),
2617f1de56SFelix Fietkau 	CHAN2G(3, 2422),
2717f1de56SFelix Fietkau 	CHAN2G(4, 2427),
2817f1de56SFelix Fietkau 	CHAN2G(5, 2432),
2917f1de56SFelix Fietkau 	CHAN2G(6, 2437),
3017f1de56SFelix Fietkau 	CHAN2G(7, 2442),
3117f1de56SFelix Fietkau 	CHAN2G(8, 2447),
3217f1de56SFelix Fietkau 	CHAN2G(9, 2452),
3317f1de56SFelix Fietkau 	CHAN2G(10, 2457),
3417f1de56SFelix Fietkau 	CHAN2G(11, 2462),
3517f1de56SFelix Fietkau 	CHAN2G(12, 2467),
3617f1de56SFelix Fietkau 	CHAN2G(13, 2472),
3717f1de56SFelix Fietkau 	CHAN2G(14, 2484),
3817f1de56SFelix Fietkau };
3917f1de56SFelix Fietkau 
4017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4117f1de56SFelix Fietkau 	CHAN5G(36, 5180),
4217f1de56SFelix Fietkau 	CHAN5G(40, 5200),
4317f1de56SFelix Fietkau 	CHAN5G(44, 5220),
4417f1de56SFelix Fietkau 	CHAN5G(48, 5240),
4517f1de56SFelix Fietkau 
4617f1de56SFelix Fietkau 	CHAN5G(52, 5260),
4717f1de56SFelix Fietkau 	CHAN5G(56, 5280),
4817f1de56SFelix Fietkau 	CHAN5G(60, 5300),
4917f1de56SFelix Fietkau 	CHAN5G(64, 5320),
5017f1de56SFelix Fietkau 
5117f1de56SFelix Fietkau 	CHAN5G(100, 5500),
5217f1de56SFelix Fietkau 	CHAN5G(104, 5520),
5317f1de56SFelix Fietkau 	CHAN5G(108, 5540),
5417f1de56SFelix Fietkau 	CHAN5G(112, 5560),
5517f1de56SFelix Fietkau 	CHAN5G(116, 5580),
5617f1de56SFelix Fietkau 	CHAN5G(120, 5600),
5717f1de56SFelix Fietkau 	CHAN5G(124, 5620),
5817f1de56SFelix Fietkau 	CHAN5G(128, 5640),
5917f1de56SFelix Fietkau 	CHAN5G(132, 5660),
6017f1de56SFelix Fietkau 	CHAN5G(136, 5680),
6117f1de56SFelix Fietkau 	CHAN5G(140, 5700),
629da82fb7SMarkus Theil 	CHAN5G(144, 5720),
6317f1de56SFelix Fietkau 
6417f1de56SFelix Fietkau 	CHAN5G(149, 5745),
6517f1de56SFelix Fietkau 	CHAN5G(153, 5765),
6617f1de56SFelix Fietkau 	CHAN5G(157, 5785),
6717f1de56SFelix Fietkau 	CHAN5G(161, 5805),
6817f1de56SFelix Fietkau 	CHAN5G(165, 5825),
699da82fb7SMarkus Theil 	CHAN5G(169, 5845),
709da82fb7SMarkus Theil 	CHAN5G(173, 5865),
7117f1de56SFelix Fietkau };
7217f1de56SFelix Fietkau 
7317f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
7417f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
7517f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
7617f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
7717f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
7817f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
7917f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
8017f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
8117f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
8217f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
8317f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
8417f1de56SFelix Fietkau };
8517f1de56SFelix Fietkau 
8617f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
8717f1de56SFelix Fietkau {
8817f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
8917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
9017f1de56SFelix Fietkau 	int led_pin;
9117f1de56SFelix Fietkau 
9217f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
9317f1de56SFelix Fietkau 		return 0;
9417f1de56SFelix Fietkau 
9517f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
9617f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
9717f1de56SFelix Fietkau 
9817f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
9917f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
10017f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
10117f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
10217f1de56SFelix Fietkau 					mt76_tpt_blink,
10317f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
10417f1de56SFelix Fietkau 
10517f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
10617f1de56SFelix Fietkau 	if (np) {
10717f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
10817f1de56SFelix Fietkau 			dev->led_pin = led_pin;
10917f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
11017f1de56SFelix Fietkau 	}
11117f1de56SFelix Fietkau 
11236f7e2b2SFelix Fietkau 	return led_classdev_register(dev->dev, &dev->led_cdev);
11336f7e2b2SFelix Fietkau }
11436f7e2b2SFelix Fietkau 
11536f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev)
11636f7e2b2SFelix Fietkau {
11736f7e2b2SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
11836f7e2b2SFelix Fietkau 		return;
11936f7e2b2SFelix Fietkau 
12036f7e2b2SFelix Fietkau 	led_classdev_unregister(&dev->led_cdev);
12117f1de56SFelix Fietkau }
12217f1de56SFelix Fietkau 
123bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
124551e1ef4SLorenzo Bianconi 				 struct ieee80211_supported_band *sband,
125551e1ef4SLorenzo Bianconi 				 bool vht)
126551e1ef4SLorenzo Bianconi {
127551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
128bb3e3fecSRyder Lee 	int i, nstream = hweight8(phy->antenna_mask);
129551e1ef4SLorenzo Bianconi 	struct ieee80211_sta_vht_cap *vht_cap;
130551e1ef4SLorenzo Bianconi 	u16 mcs_map = 0;
131551e1ef4SLorenzo Bianconi 
132551e1ef4SLorenzo Bianconi 	if (nstream > 1)
133551e1ef4SLorenzo Bianconi 		ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
134551e1ef4SLorenzo Bianconi 	else
135551e1ef4SLorenzo Bianconi 		ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
136551e1ef4SLorenzo Bianconi 
137551e1ef4SLorenzo Bianconi 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
138551e1ef4SLorenzo Bianconi 		ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
139551e1ef4SLorenzo Bianconi 
140551e1ef4SLorenzo Bianconi 	if (!vht)
141551e1ef4SLorenzo Bianconi 		return;
142551e1ef4SLorenzo Bianconi 
143551e1ef4SLorenzo Bianconi 	vht_cap = &sband->vht_cap;
144551e1ef4SLorenzo Bianconi 	if (nstream > 1)
145551e1ef4SLorenzo Bianconi 		vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
146551e1ef4SLorenzo Bianconi 	else
147551e1ef4SLorenzo Bianconi 		vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
148551e1ef4SLorenzo Bianconi 
149551e1ef4SLorenzo Bianconi 	for (i = 0; i < 8; i++) {
150551e1ef4SLorenzo Bianconi 		if (i < nstream)
151551e1ef4SLorenzo Bianconi 			mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
152551e1ef4SLorenzo Bianconi 		else
153551e1ef4SLorenzo Bianconi 			mcs_map |=
154551e1ef4SLorenzo Bianconi 				(IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
155551e1ef4SLorenzo Bianconi 	}
156551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
157551e1ef4SLorenzo Bianconi 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
158551e1ef4SLorenzo Bianconi }
159551e1ef4SLorenzo Bianconi 
160bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
1615ebdc3e0SLorenzo Bianconi {
162bb3e3fecSRyder Lee 	if (phy->dev->cap.has_2ghz)
163bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
164bb3e3fecSRyder Lee 	if (phy->dev->cap.has_5ghz)
165bb3e3fecSRyder Lee 		mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
1665ebdc3e0SLorenzo Bianconi }
1675ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
1685ebdc3e0SLorenzo Bianconi 
16917f1de56SFelix Fietkau static int
17017f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
17117f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
17217f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
17317f1de56SFelix Fietkau {
17417f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
17517f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
17617f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
17717f1de56SFelix Fietkau 	void *chanlist;
17817f1de56SFelix Fietkau 	int size;
17917f1de56SFelix Fietkau 
18017f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
18117f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
18217f1de56SFelix Fietkau 	if (!chanlist)
18317f1de56SFelix Fietkau 		return -ENOMEM;
18417f1de56SFelix Fietkau 
185a86854d0SKees Cook 	msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
18617f1de56SFelix Fietkau 				    GFP_KERNEL);
18717f1de56SFelix Fietkau 	if (!msband->chan)
18817f1de56SFelix Fietkau 		return -ENOMEM;
18917f1de56SFelix Fietkau 
19017f1de56SFelix Fietkau 	sband->channels = chanlist;
19117f1de56SFelix Fietkau 	sband->n_channels = n_chan;
19217f1de56SFelix Fietkau 	sband->bitrates = rates;
19317f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
19417f1de56SFelix Fietkau 
19517f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
19617f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
19717f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
19817f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
19917f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
20017f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
20117f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
20217f1de56SFelix Fietkau 
20317f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
20417f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
20517f1de56SFelix Fietkau 
206bb3e3fecSRyder Lee 	mt76_init_stream_cap(&dev->phy, sband, vht);
207551e1ef4SLorenzo Bianconi 
20817f1de56SFelix Fietkau 	if (!vht)
20917f1de56SFelix Fietkau 		return 0;
21017f1de56SFelix Fietkau 
21117f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
21217f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
21317f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
21417f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
21549149d3fSFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80 |
216f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
217f1103fa6SRyder Lee 			IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
21849149d3fSFelix Fietkau 			(3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
21917f1de56SFelix Fietkau 
22017f1de56SFelix Fietkau 	return 0;
22117f1de56SFelix Fietkau }
22217f1de56SFelix Fietkau 
22317f1de56SFelix Fietkau static int
22417f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
22517f1de56SFelix Fietkau 		   int n_rates)
22617f1de56SFelix Fietkau {
22796747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband;
22817f1de56SFelix Fietkau 
22996747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_2g,
23017f1de56SFelix Fietkau 			       mt76_channels_2ghz,
23117f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
23217f1de56SFelix Fietkau 			       rates, n_rates, false);
23317f1de56SFelix Fietkau }
23417f1de56SFelix Fietkau 
23517f1de56SFelix Fietkau static int
23617f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
23717f1de56SFelix Fietkau 		   int n_rates, bool vht)
23817f1de56SFelix Fietkau {
23996747a51SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband;
24017f1de56SFelix Fietkau 
24196747a51SFelix Fietkau 	return mt76_init_sband(dev, &dev->phy.sband_5g,
24217f1de56SFelix Fietkau 			       mt76_channels_5ghz,
24317f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
24417f1de56SFelix Fietkau 			       rates, n_rates, vht);
24517f1de56SFelix Fietkau }
24617f1de56SFelix Fietkau 
24717f1de56SFelix Fietkau static void
248c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
249c89d3625SFelix Fietkau 		 enum nl80211_band band)
25017f1de56SFelix Fietkau {
251c89d3625SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
25217f1de56SFelix Fietkau 	bool found = false;
25317f1de56SFelix Fietkau 	int i;
25417f1de56SFelix Fietkau 
25517f1de56SFelix Fietkau 	if (!sband)
25617f1de56SFelix Fietkau 		return;
25717f1de56SFelix Fietkau 
25817f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
25917f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
26017f1de56SFelix Fietkau 			continue;
26117f1de56SFelix Fietkau 
26217f1de56SFelix Fietkau 		found = true;
26317f1de56SFelix Fietkau 		break;
26417f1de56SFelix Fietkau 	}
26517f1de56SFelix Fietkau 
266c89d3625SFelix Fietkau 	if (found) {
267c89d3625SFelix Fietkau 		phy->chandef.chan = &sband->channels[0];
268c89d3625SFelix Fietkau 		phy->chan_state = &msband->chan[0];
26917f1de56SFelix Fietkau 		return;
270c89d3625SFelix Fietkau 	}
27117f1de56SFelix Fietkau 
27217f1de56SFelix Fietkau 	sband->n_channels = 0;
273c89d3625SFelix Fietkau 	phy->hw->wiphy->bands[band] = NULL;
27417f1de56SFelix Fietkau }
27517f1de56SFelix Fietkau 
276c89d3625SFelix Fietkau static void
277c89d3625SFelix Fietkau mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
278c89d3625SFelix Fietkau {
279c89d3625SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
280c89d3625SFelix Fietkau 
281c89d3625SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
282c89d3625SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
283c89d3625SFelix Fietkau 
284c89d3625SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
285dd89a013SLorenzo Bianconi 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
286b807b368SLorenzo Bianconi 			WIPHY_FLAG_SUPPORTS_TDLS |
287b807b368SLorenzo Bianconi 			WIPHY_FLAG_AP_UAPSD;
288c89d3625SFelix Fietkau 
289c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
290c89d3625SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
291d9c54264SFelix Fietkau 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
292c89d3625SFelix Fietkau 
293c89d3625SFelix Fietkau 	wiphy->available_antennas_tx = dev->phy.antenna_mask;
294c89d3625SFelix Fietkau 	wiphy->available_antennas_rx = dev->phy.antenna_mask;
295c89d3625SFelix Fietkau 
296c89d3625SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
297b807b368SLorenzo Bianconi 	hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
298c9619dfaSShayne Chen 
299c9619dfaSShayne Chen 	if (!hw->max_tx_fragments)
300c89d3625SFelix Fietkau 		hw->max_tx_fragments = 16;
301c89d3625SFelix Fietkau 
302c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
303c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
304c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
305c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
306c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
307c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
308b443e55fSRyder Lee 
309b443e55fSRyder Lee 	if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
310c89d3625SFelix Fietkau 		ieee80211_hw_set(hw, TX_AMSDU);
311d39b52e3SSean Wang 
312d39b52e3SSean Wang 		/* TODO: avoid linearization for SDIO */
313d39b52e3SSean Wang 		if (!mt76_is_sdio(dev))
314c89d3625SFelix Fietkau 			ieee80211_hw_set(hw, TX_FRAG_LIST);
315b443e55fSRyder Lee 	}
316d39b52e3SSean Wang 
317c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
318c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
319c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
320c89d3625SFelix Fietkau 	ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
321c89d3625SFelix Fietkau 
322c89d3625SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
323c89d3625SFelix Fietkau 	wiphy->interface_modes =
324c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
325c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
326c89d3625SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
327c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
328c89d3625SFelix Fietkau #endif
32950eb0a88SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_CLIENT) |
33050eb0a88SLorenzo Bianconi 		BIT(NL80211_IFTYPE_P2P_GO) |
331c89d3625SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
332c89d3625SFelix Fietkau }
333c89d3625SFelix Fietkau 
334c89d3625SFelix Fietkau struct mt76_phy *
335c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
336c89d3625SFelix Fietkau 	       const struct ieee80211_ops *ops)
337c89d3625SFelix Fietkau {
338c89d3625SFelix Fietkau 	struct ieee80211_hw *hw;
339c89d3625SFelix Fietkau 	struct mt76_phy *phy;
340c89d3625SFelix Fietkau 	unsigned int phy_size, chan_size;
341c89d3625SFelix Fietkau 	unsigned int size_2g, size_5g;
342c89d3625SFelix Fietkau 	void *priv;
343c89d3625SFelix Fietkau 
344c89d3625SFelix Fietkau 	phy_size = ALIGN(sizeof(*phy), 8);
345c89d3625SFelix Fietkau 	chan_size = sizeof(dev->phy.sband_2g.chan[0]);
346c89d3625SFelix Fietkau 	size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
347c89d3625SFelix Fietkau 	size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
348c89d3625SFelix Fietkau 
349c89d3625SFelix Fietkau 	size += phy_size + size_2g + size_5g;
350c89d3625SFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
351c89d3625SFelix Fietkau 	if (!hw)
352c89d3625SFelix Fietkau 		return NULL;
353c89d3625SFelix Fietkau 
354c89d3625SFelix Fietkau 	phy = hw->priv;
355c89d3625SFelix Fietkau 	phy->dev = dev;
356c89d3625SFelix Fietkau 	phy->hw = hw;
357c89d3625SFelix Fietkau 
358c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
359c89d3625SFelix Fietkau 
360c89d3625SFelix Fietkau 	priv = hw->priv + phy_size;
361c89d3625SFelix Fietkau 
362c89d3625SFelix Fietkau 	phy->sband_2g = dev->phy.sband_2g;
363c89d3625SFelix Fietkau 	phy->sband_2g.chan = priv;
364c89d3625SFelix Fietkau 	priv += size_2g;
365c89d3625SFelix Fietkau 
366c89d3625SFelix Fietkau 	phy->sband_5g = dev->phy.sband_5g;
367c89d3625SFelix Fietkau 	phy->sband_5g.chan = priv;
368c89d3625SFelix Fietkau 	priv += size_5g;
369c89d3625SFelix Fietkau 
370c89d3625SFelix Fietkau 	phy->priv = priv;
371c89d3625SFelix Fietkau 
372c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
373c89d3625SFelix Fietkau 	hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
374c89d3625SFelix Fietkau 
375c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
376c89d3625SFelix Fietkau 	mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
377c89d3625SFelix Fietkau 
378c89d3625SFelix Fietkau 	return phy;
379c89d3625SFelix Fietkau }
380c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
381c89d3625SFelix Fietkau 
382c89d3625SFelix Fietkau int
383c89d3625SFelix Fietkau mt76_register_phy(struct mt76_phy *phy)
384c89d3625SFelix Fietkau {
385c89d3625SFelix Fietkau 	int ret;
386c89d3625SFelix Fietkau 
387c89d3625SFelix Fietkau 	ret = ieee80211_register_hw(phy->hw);
388c89d3625SFelix Fietkau 	if (ret)
389c89d3625SFelix Fietkau 		return ret;
390c89d3625SFelix Fietkau 
391c89d3625SFelix Fietkau 	phy->dev->phy2 = phy;
392c89d3625SFelix Fietkau 	return 0;
393c89d3625SFelix Fietkau }
394c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
395c89d3625SFelix Fietkau 
396c89d3625SFelix Fietkau void
397c89d3625SFelix Fietkau mt76_unregister_phy(struct mt76_phy *phy)
398c89d3625SFelix Fietkau {
399c89d3625SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
400c89d3625SFelix Fietkau 
401c89d3625SFelix Fietkau 	dev->phy2 = NULL;
402c89d3625SFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
403c89d3625SFelix Fietkau 	ieee80211_unregister_hw(phy->hw);
404c89d3625SFelix Fietkau }
405c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
406c89d3625SFelix Fietkau 
407a85b590cSFelix Fietkau struct mt76_dev *
408c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
409c0f7b25aSLorenzo Bianconi 		  const struct ieee80211_ops *ops,
410c0f7b25aSLorenzo Bianconi 		  const struct mt76_driver_ops *drv_ops)
411a85b590cSFelix Fietkau {
412a85b590cSFelix Fietkau 	struct ieee80211_hw *hw;
413ac24dd35SFelix Fietkau 	struct mt76_phy *phy;
414a85b590cSFelix Fietkau 	struct mt76_dev *dev;
415e5443256SFelix Fietkau 	int i;
416a85b590cSFelix Fietkau 
417a85b590cSFelix Fietkau 	hw = ieee80211_alloc_hw(size, ops);
418a85b590cSFelix Fietkau 	if (!hw)
419a85b590cSFelix Fietkau 		return NULL;
420a85b590cSFelix Fietkau 
421a85b590cSFelix Fietkau 	dev = hw->priv;
422a85b590cSFelix Fietkau 	dev->hw = hw;
423c0f7b25aSLorenzo Bianconi 	dev->dev = pdev;
424c0f7b25aSLorenzo Bianconi 	dev->drv = drv_ops;
425c0f7b25aSLorenzo Bianconi 
426ac24dd35SFelix Fietkau 	phy = &dev->phy;
427ac24dd35SFelix Fietkau 	phy->dev = dev;
428ac24dd35SFelix Fietkau 	phy->hw = hw;
429ac24dd35SFelix Fietkau 
430a85b590cSFelix Fietkau 	spin_lock_init(&dev->rx_lock);
431a85b590cSFelix Fietkau 	spin_lock_init(&dev->lock);
432a85b590cSFelix Fietkau 	spin_lock_init(&dev->cc_lock);
433108a4861SStanislaw Gruszka 	mutex_init(&dev->mutex);
43426e40d4cSFelix Fietkau 	init_waitqueue_head(&dev->tx_wait);
43588046b2cSFelix Fietkau 	skb_queue_head_init(&dev->status_list);
436a85b590cSFelix Fietkau 
43709872957SLorenzo Bianconi 	skb_queue_head_init(&dev->mcu.res_q);
43809872957SLorenzo Bianconi 	init_waitqueue_head(&dev->mcu.wait);
43909872957SLorenzo Bianconi 	mutex_init(&dev->mcu.mutex);
440*781eef5bSFelix Fietkau 	dev->tx_worker.fn = mt76_tx_worker;
44109872957SLorenzo Bianconi 
442e5443256SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
443e5443256SFelix Fietkau 
444e5443256SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
445e5443256SFelix Fietkau 		skb_queue_head_init(&dev->rx_skb[i]);
446e5443256SFelix Fietkau 
447a86f1d01SLorenzo Bianconi 	dev->wq = alloc_ordered_workqueue("mt76", 0);
448a86f1d01SLorenzo Bianconi 	if (!dev->wq) {
449a86f1d01SLorenzo Bianconi 		ieee80211_free_hw(hw);
450a86f1d01SLorenzo Bianconi 		return NULL;
451a86f1d01SLorenzo Bianconi 	}
452a86f1d01SLorenzo Bianconi 
453a85b590cSFelix Fietkau 	return dev;
454a85b590cSFelix Fietkau }
455a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
456a85b590cSFelix Fietkau 
45717f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
45817f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
45917f1de56SFelix Fietkau {
46017f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
461c89d3625SFelix Fietkau 	struct mt76_phy *phy = &dev->phy;
46217f1de56SFelix Fietkau 	int ret;
46317f1de56SFelix Fietkau 
46417f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
465c89d3625SFelix Fietkau 	mt76_phy_init(dev, hw);
46617f1de56SFelix Fietkau 
46717f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
46817f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
46917f1de56SFelix Fietkau 		if (ret)
47017f1de56SFelix Fietkau 			return ret;
47117f1de56SFelix Fietkau 	}
47217f1de56SFelix Fietkau 
47317f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
47417f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
47517f1de56SFelix Fietkau 		if (ret)
47617f1de56SFelix Fietkau 			return ret;
47717f1de56SFelix Fietkau 	}
47817f1de56SFelix Fietkau 
479c89d3625SFelix Fietkau 	wiphy_read_of_freq_limits(hw->wiphy);
480c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
481c89d3625SFelix Fietkau 	mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
48217f1de56SFelix Fietkau 
483b374e868SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS)) {
48417f1de56SFelix Fietkau 		ret = mt76_led_init(dev);
48517f1de56SFelix Fietkau 		if (ret)
48617f1de56SFelix Fietkau 			return ret;
487b374e868SArnd Bergmann 	}
48817f1de56SFelix Fietkau 
489*781eef5bSFelix Fietkau 	ret = ieee80211_register_hw(hw);
490*781eef5bSFelix Fietkau 	if (ret)
491*781eef5bSFelix Fietkau 		return ret;
492*781eef5bSFelix Fietkau 
493*781eef5bSFelix Fietkau 	WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
494*781eef5bSFelix Fietkau 	sched_set_fifo_low(dev->tx_worker.task);
495*781eef5bSFelix Fietkau 
496*781eef5bSFelix Fietkau 	return 0;
49717f1de56SFelix Fietkau }
49817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
49917f1de56SFelix Fietkau 
50017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
50117f1de56SFelix Fietkau {
50217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
50317f1de56SFelix Fietkau 
504d68f4e43SArnd Bergmann 	if (IS_ENABLED(CONFIG_MT76_LEDS))
50536f7e2b2SFelix Fietkau 		mt76_led_cleanup(dev);
50679d1c94cSFelix Fietkau 	mt76_tx_status_check(dev, NULL, true);
50717f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
50817f1de56SFelix Fietkau }
50917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
51017f1de56SFelix Fietkau 
511def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
512def34a2fSLorenzo Bianconi {
513*781eef5bSFelix Fietkau 	mt76_worker_teardown(&dev->tx_worker);
514a86f1d01SLorenzo Bianconi 	if (dev->wq) {
515a86f1d01SLorenzo Bianconi 		destroy_workqueue(dev->wq);
516a86f1d01SLorenzo Bianconi 		dev->wq = NULL;
517a86f1d01SLorenzo Bianconi 	}
518a86f1d01SLorenzo Bianconi 	if (mt76_is_mmio(dev))
519def34a2fSLorenzo Bianconi 		mt76_tx_free(dev);
520def34a2fSLorenzo Bianconi 	ieee80211_free_hw(dev->hw);
521def34a2fSLorenzo Bianconi }
522def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
523def34a2fSLorenzo Bianconi 
52417f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
52517f1de56SFelix Fietkau {
526011849e0SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
527011849e0SFelix Fietkau 	struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy);
528011849e0SFelix Fietkau 
529011849e0SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
53017f1de56SFelix Fietkau 		dev_kfree_skb(skb);
53117f1de56SFelix Fietkau 		return;
53217f1de56SFelix Fietkau 	}
53317f1de56SFelix Fietkau 
534f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
535f0efa862SFelix Fietkau 	if (dev->test.state == MT76_TM_STATE_RX_FRAMES) {
536f0efa862SFelix Fietkau 		dev->test.rx_stats.packets[q]++;
537f0efa862SFelix Fietkau 		if (status->flag & RX_FLAG_FAILED_FCS_CRC)
538f0efa862SFelix Fietkau 			dev->test.rx_stats.fcs_error[q]++;
539f0efa862SFelix Fietkau 	}
540f0efa862SFelix Fietkau #endif
54117f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
54217f1de56SFelix Fietkau }
54317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
54417f1de56SFelix Fietkau 
5455a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
54626e40d4cSFelix Fietkau {
5475a95ca41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
548af005f26SLorenzo Bianconi 	struct mt76_queue *q;
5495a95ca41SFelix Fietkau 	int i, offset;
55026e40d4cSFelix Fietkau 
5515a95ca41SFelix Fietkau 	offset = __MT_TXQ_MAX * (phy != &dev->phy);
5525a95ca41SFelix Fietkau 
5535a95ca41SFelix Fietkau 	for (i = 0; i < __MT_TXQ_MAX; i++) {
554f099c2e5SFelix Fietkau 		q = dev->q_tx[offset + i];
555af005f26SLorenzo Bianconi 		if (q && q->queued)
55626e40d4cSFelix Fietkau 			return true;
55726e40d4cSFelix Fietkau 	}
55826e40d4cSFelix Fietkau 
55926e40d4cSFelix Fietkau 	return false;
56026e40d4cSFelix Fietkau }
56139d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
56226e40d4cSFelix Fietkau 
5630fd0eb54SFelix Fietkau static struct mt76_channel_state *
56496747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
5650fd0eb54SFelix Fietkau {
5660fd0eb54SFelix Fietkau 	struct mt76_sband *msband;
5670fd0eb54SFelix Fietkau 	int idx;
5680fd0eb54SFelix Fietkau 
5690fd0eb54SFelix Fietkau 	if (c->band == NL80211_BAND_2GHZ)
57096747a51SFelix Fietkau 		msband = &phy->sband_2g;
5710fd0eb54SFelix Fietkau 	else
57296747a51SFelix Fietkau 		msband = &phy->sband_5g;
5730fd0eb54SFelix Fietkau 
5740fd0eb54SFelix Fietkau 	idx = c - &msband->sband.channels[0];
5750fd0eb54SFelix Fietkau 	return &msband->chan[idx];
5760fd0eb54SFelix Fietkau }
5770fd0eb54SFelix Fietkau 
57804414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
57996747a51SFelix Fietkau {
58096747a51SFelix Fietkau 	struct mt76_channel_state *state = phy->chan_state;
58196747a51SFelix Fietkau 
58296747a51SFelix Fietkau 	state->cc_active += ktime_to_us(ktime_sub(time,
58396747a51SFelix Fietkau 						  phy->survey_time));
58496747a51SFelix Fietkau 	phy->survey_time = time;
58596747a51SFelix Fietkau }
58604414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
58796747a51SFelix Fietkau 
5885ce09c1aSFelix Fietkau void mt76_update_survey(struct mt76_dev *dev)
5895ce09c1aSFelix Fietkau {
590aec65e48SFelix Fietkau 	ktime_t cur_time;
591aec65e48SFelix Fietkau 
5925ce09c1aSFelix Fietkau 	if (dev->drv->update_survey)
5935ce09c1aSFelix Fietkau 		dev->drv->update_survey(dev);
5945ce09c1aSFelix Fietkau 
595aec65e48SFelix Fietkau 	cur_time = ktime_get_boottime();
59696747a51SFelix Fietkau 	mt76_update_survey_active_time(&dev->phy, cur_time);
59796747a51SFelix Fietkau 	if (dev->phy2)
59896747a51SFelix Fietkau 		mt76_update_survey_active_time(dev->phy2, cur_time);
599aec65e48SFelix Fietkau 
6005ce09c1aSFelix Fietkau 	if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
60196747a51SFelix Fietkau 		struct mt76_channel_state *state = dev->phy.chan_state;
60296747a51SFelix Fietkau 
603237312c5SLorenzo Bianconi 		spin_lock_bh(&dev->cc_lock);
6045ce09c1aSFelix Fietkau 		state->cc_bss_rx += dev->cur_cc_bss_rx;
6055ce09c1aSFelix Fietkau 		dev->cur_cc_bss_rx = 0;
606237312c5SLorenzo Bianconi 		spin_unlock_bh(&dev->cc_lock);
6075ce09c1aSFelix Fietkau 	}
6085ce09c1aSFelix Fietkau }
6095ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
6105ce09c1aSFelix Fietkau 
61196747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
61217f1de56SFelix Fietkau {
61396747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
61496747a51SFelix Fietkau 	struct ieee80211_hw *hw = phy->hw;
61517f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
61617f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
61726e40d4cSFelix Fietkau 	int timeout = HZ / 5;
61817f1de56SFelix Fietkau 
6195a95ca41SFelix Fietkau 	wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
6205ce09c1aSFelix Fietkau 	mt76_update_survey(dev);
62117f1de56SFelix Fietkau 
62296747a51SFelix Fietkau 	phy->chandef = *chandef;
62396747a51SFelix Fietkau 	phy->chan_state = mt76_channel_state(phy, chandef->chan);
62417f1de56SFelix Fietkau 
62517f1de56SFelix Fietkau 	if (!offchannel)
62696747a51SFelix Fietkau 		phy->main_chan = chandef->chan;
62717f1de56SFelix Fietkau 
62896747a51SFelix Fietkau 	if (chandef->chan != phy->main_chan)
62996747a51SFelix Fietkau 		memset(phy->chan_state, 0, sizeof(*phy->chan_state));
63017f1de56SFelix Fietkau }
63117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
63217f1de56SFelix Fietkau 
63317f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
63417f1de56SFelix Fietkau 		    struct survey_info *survey)
63517f1de56SFelix Fietkau {
63696747a51SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
63796747a51SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
63817f1de56SFelix Fietkau 	struct mt76_sband *sband;
63917f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
64017f1de56SFelix Fietkau 	struct mt76_channel_state *state;
64117f1de56SFelix Fietkau 	int ret = 0;
64217f1de56SFelix Fietkau 
643237312c5SLorenzo Bianconi 	mutex_lock(&dev->mutex);
64417f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
6455ce09c1aSFelix Fietkau 		mt76_update_survey(dev);
64617f1de56SFelix Fietkau 
64796747a51SFelix Fietkau 	sband = &phy->sband_2g;
64817f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
64917f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
65096747a51SFelix Fietkau 		sband = &phy->sband_5g;
65117f1de56SFelix Fietkau 	}
65217f1de56SFelix Fietkau 
653237312c5SLorenzo Bianconi 	if (idx >= sband->sband.n_channels) {
654237312c5SLorenzo Bianconi 		ret = -ENOENT;
655237312c5SLorenzo Bianconi 		goto out;
656237312c5SLorenzo Bianconi 	}
65717f1de56SFelix Fietkau 
65817f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
65996747a51SFelix Fietkau 	state = mt76_channel_state(phy, chan);
66017f1de56SFelix Fietkau 
66117f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
66217f1de56SFelix Fietkau 	survey->channel = chan;
66317f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
664ea565833SFelix Fietkau 	survey->filled |= dev->drv->survey_flags;
665e5051965SFelix Fietkau 	if (state->noise)
666e5051965SFelix Fietkau 		survey->filled |= SURVEY_INFO_NOISE_DBM;
667e5051965SFelix Fietkau 
66896747a51SFelix Fietkau 	if (chan == phy->main_chan) {
66917f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
67017f1de56SFelix Fietkau 
6715ce09c1aSFelix Fietkau 		if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
6725ce09c1aSFelix Fietkau 			survey->filled |= SURVEY_INFO_TIME_BSS_RX;
6735ce09c1aSFelix Fietkau 	}
6745ce09c1aSFelix Fietkau 
67517f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
6766bfa6e38SLorenzo Bianconi 	survey->time_rx = div_u64(state->cc_rx, 1000);
677237312c5SLorenzo Bianconi 	survey->time = div_u64(state->cc_active, 1000);
678e5051965SFelix Fietkau 	survey->noise = state->noise;
679237312c5SLorenzo Bianconi 
680237312c5SLorenzo Bianconi 	spin_lock_bh(&dev->cc_lock);
681237312c5SLorenzo Bianconi 	survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
682ea565833SFelix Fietkau 	survey->time_tx = div_u64(state->cc_tx, 1000);
68317f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
68417f1de56SFelix Fietkau 
685237312c5SLorenzo Bianconi out:
686237312c5SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
687237312c5SLorenzo Bianconi 
68817f1de56SFelix Fietkau 	return ret;
68917f1de56SFelix Fietkau }
69017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
69117f1de56SFelix Fietkau 
69230ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
69330ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
69430ce7f44SFelix Fietkau {
69530ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
69630ce7f44SFelix Fietkau 	int i;
69730ce7f44SFelix Fietkau 
69830ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
69930ce7f44SFelix Fietkau 
70030ce7f44SFelix Fietkau 	if (!key)
70130ce7f44SFelix Fietkau 		return;
70230ce7f44SFelix Fietkau 
70301cfc1b4SLorenzo Bianconi 	if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
70401cfc1b4SLorenzo Bianconi 		return;
70530ce7f44SFelix Fietkau 
70601cfc1b4SLorenzo Bianconi 	wcid->rx_check_pn = true;
70730ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
70830ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
70930ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
71030ce7f44SFelix Fietkau 	}
71130ce7f44SFelix Fietkau }
71230ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
71330ce7f44SFelix Fietkau 
714bfc394ddSFelix Fietkau static void
715bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
716bfc394ddSFelix Fietkau 		struct ieee80211_hw **hw,
717bfc394ddSFelix Fietkau 		struct ieee80211_sta **sta)
7184e34249eSFelix Fietkau {
7194e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
7204e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
7214e34249eSFelix Fietkau 
7224e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *)skb->cb);
7234e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
7244e34249eSFelix Fietkau 
7254e34249eSFelix Fietkau 	status->flag = mstat.flag;
7264e34249eSFelix Fietkau 	status->freq = mstat.freq;
7274e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
7284e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
7294e34249eSFelix Fietkau 	status->bw = mstat.bw;
730af4a2f2fSRyder Lee 	status->he_ru = mstat.he_ru;
731af4a2f2fSRyder Lee 	status->he_gi = mstat.he_gi;
732af4a2f2fSRyder Lee 	status->he_dcm = mstat.he_dcm;
7334e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
7344e34249eSFelix Fietkau 	status->nss = mstat.nss;
7354e34249eSFelix Fietkau 	status->band = mstat.band;
7364e34249eSFelix Fietkau 	status->signal = mstat.signal;
7374e34249eSFelix Fietkau 	status->chains = mstat.chains;
738d515fdcaSFelix Fietkau 	status->ampdu_reference = mstat.ampdu_ref;
7394e34249eSFelix Fietkau 
7404e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
74113381dcdSRyder Lee 	BUILD_BUG_ON(sizeof(status->chain_signal) !=
74213381dcdSRyder Lee 		     sizeof(mstat.chain_signal));
74313381dcdSRyder Lee 	memcpy(status->chain_signal, mstat.chain_signal,
74413381dcdSRyder Lee 	       sizeof(mstat.chain_signal));
7459c68a57bSFelix Fietkau 
746bfc394ddSFelix Fietkau 	*sta = wcid_to_sta(mstat.wcid);
747bfc394ddSFelix Fietkau 	*hw = mt76_phy_hw(dev, mstat.ext_phy);
7484e34249eSFelix Fietkau }
7494e34249eSFelix Fietkau 
75030ce7f44SFelix Fietkau static int
75130ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
75230ce7f44SFelix Fietkau {
75330ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
75430ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
75530ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
75630ce7f44SFelix Fietkau 	int ret;
75730ce7f44SFelix Fietkau 
75830ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
75930ce7f44SFelix Fietkau 		return 0;
76030ce7f44SFelix Fietkau 
76130ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
76230ce7f44SFelix Fietkau 		return 0;
76330ce7f44SFelix Fietkau 
76430ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
76530ce7f44SFelix Fietkau 		/*
76630ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
76730ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
76830ce7f44SFelix Fietkau 		 */
76977ae1d5eSRyder Lee 		hdr = mt76_skb_get_hdr(skb);
77030ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
77130ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
77230ce7f44SFelix Fietkau 			return 0;
77330ce7f44SFelix Fietkau 	}
77430ce7f44SFelix Fietkau 
77530ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
77630ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
77730ce7f44SFelix Fietkau 		     sizeof(status->iv));
77830ce7f44SFelix Fietkau 	if (ret <= 0)
77930ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
78030ce7f44SFelix Fietkau 
78130ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
78230ce7f44SFelix Fietkau 
78330ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
78430ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
78530ce7f44SFelix Fietkau 
78630ce7f44SFelix Fietkau 	return 0;
78730ce7f44SFelix Fietkau }
78830ce7f44SFelix Fietkau 
789d71ef286SFelix Fietkau static void
7905ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
7915ce09c1aSFelix Fietkau 		    int len)
7925ce09c1aSFelix Fietkau {
7935ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
79485b7a5d0SLorenzo Bianconi 	struct ieee80211_rx_status info = {
79585b7a5d0SLorenzo Bianconi 		.enc_flags = status->enc_flags,
79685b7a5d0SLorenzo Bianconi 		.rate_idx = status->rate_idx,
79785b7a5d0SLorenzo Bianconi 		.encoding = status->encoding,
79885b7a5d0SLorenzo Bianconi 		.band = status->band,
79985b7a5d0SLorenzo Bianconi 		.nss = status->nss,
80085b7a5d0SLorenzo Bianconi 		.bw = status->bw,
80185b7a5d0SLorenzo Bianconi 	};
8025ce09c1aSFelix Fietkau 	struct ieee80211_sta *sta;
8035ce09c1aSFelix Fietkau 	u32 airtime;
8045ce09c1aSFelix Fietkau 
80585b7a5d0SLorenzo Bianconi 	airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
806237312c5SLorenzo Bianconi 	spin_lock(&dev->cc_lock);
8075ce09c1aSFelix Fietkau 	dev->cur_cc_bss_rx += airtime;
808237312c5SLorenzo Bianconi 	spin_unlock(&dev->cc_lock);
8095ce09c1aSFelix Fietkau 
8105ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta)
8115ce09c1aSFelix Fietkau 		return;
8125ce09c1aSFelix Fietkau 
8135ce09c1aSFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
8145ce09c1aSFelix Fietkau 	ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
8155ce09c1aSFelix Fietkau }
8165ce09c1aSFelix Fietkau 
8175ce09c1aSFelix Fietkau static void
8185ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
8195ce09c1aSFelix Fietkau {
8205ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid;
8215ce09c1aSFelix Fietkau 	int wcid_idx;
8225ce09c1aSFelix Fietkau 
8235ce09c1aSFelix Fietkau 	if (!dev->rx_ampdu_len)
8245ce09c1aSFelix Fietkau 		return;
8255ce09c1aSFelix Fietkau 
8265ce09c1aSFelix Fietkau 	wcid_idx = dev->rx_ampdu_status.wcid_idx;
827bf5238b2SFelix Fietkau 	if (wcid_idx < ARRAY_SIZE(dev->wcid))
8285ce09c1aSFelix Fietkau 		wcid = rcu_dereference(dev->wcid[wcid_idx]);
8295ce09c1aSFelix Fietkau 	else
8305ce09c1aSFelix Fietkau 		wcid = NULL;
8315ce09c1aSFelix Fietkau 	dev->rx_ampdu_status.wcid = wcid;
8325ce09c1aSFelix Fietkau 
8335ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
8345ce09c1aSFelix Fietkau 
8355ce09c1aSFelix Fietkau 	dev->rx_ampdu_len = 0;
8365ce09c1aSFelix Fietkau 	dev->rx_ampdu_ref = 0;
8375ce09c1aSFelix Fietkau }
8385ce09c1aSFelix Fietkau 
8395ce09c1aSFelix Fietkau static void
8405ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
8415ce09c1aSFelix Fietkau {
84277ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
8435ce09c1aSFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8445ce09c1aSFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
8455ce09c1aSFelix Fietkau 
8465ce09c1aSFelix Fietkau 	if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
8475ce09c1aSFelix Fietkau 		return;
8485ce09c1aSFelix Fietkau 
8495ce09c1aSFelix Fietkau 	if (!wcid || !wcid->sta) {
8505ce09c1aSFelix Fietkau 		if (!ether_addr_equal(hdr->addr1, dev->macaddr))
8515ce09c1aSFelix Fietkau 			return;
8525ce09c1aSFelix Fietkau 
8535ce09c1aSFelix Fietkau 		wcid = NULL;
8545ce09c1aSFelix Fietkau 	}
8555ce09c1aSFelix Fietkau 
8565ce09c1aSFelix Fietkau 	if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
8575ce09c1aSFelix Fietkau 	    status->ampdu_ref != dev->rx_ampdu_ref)
8585ce09c1aSFelix Fietkau 		mt76_airtime_flush_ampdu(dev);
8595ce09c1aSFelix Fietkau 
8605ce09c1aSFelix Fietkau 	if (status->flag & RX_FLAG_AMPDU_DETAILS) {
8615ce09c1aSFelix Fietkau 		if (!dev->rx_ampdu_len ||
8625ce09c1aSFelix Fietkau 		    status->ampdu_ref != dev->rx_ampdu_ref) {
8635ce09c1aSFelix Fietkau 			dev->rx_ampdu_status = *status;
8645ce09c1aSFelix Fietkau 			dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
8655ce09c1aSFelix Fietkau 			dev->rx_ampdu_ref = status->ampdu_ref;
8665ce09c1aSFelix Fietkau 		}
8675ce09c1aSFelix Fietkau 
8685ce09c1aSFelix Fietkau 		dev->rx_ampdu_len += skb->len;
8695ce09c1aSFelix Fietkau 		return;
8705ce09c1aSFelix Fietkau 	}
8715ce09c1aSFelix Fietkau 
8725ce09c1aSFelix Fietkau 	mt76_airtime_report(dev, status, skb->len);
8735ce09c1aSFelix Fietkau }
8745ce09c1aSFelix Fietkau 
8755ce09c1aSFelix Fietkau static void
876ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
877d71ef286SFelix Fietkau {
878d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
87977ae1d5eSRyder Lee 	struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
880d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
881bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
882d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
883d71ef286SFelix Fietkau 	bool ps;
88490fdc171SFelix Fietkau 	int i;
885d71ef286SFelix Fietkau 
886bfc394ddSFelix Fietkau 	hw = mt76_phy_hw(dev, status->ext_phy);
88736d91096SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
888bfc394ddSFelix Fietkau 		sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
88936d91096SFelix Fietkau 		if (sta)
89036d91096SFelix Fietkau 			wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
89136d91096SFelix Fietkau 	}
89236d91096SFelix Fietkau 
8935ce09c1aSFelix Fietkau 	mt76_airtime_check(dev, skb);
8945ce09c1aSFelix Fietkau 
895d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
896d71ef286SFelix Fietkau 		return;
897d71ef286SFelix Fietkau 
898d71ef286SFelix Fietkau 	sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
899d71ef286SFelix Fietkau 
90002e5a769SFelix Fietkau 	if (status->signal <= 0)
90102e5a769SFelix Fietkau 		ewma_signal_add(&wcid->rssi, -status->signal);
90202e5a769SFelix Fietkau 
903ef13edc0SFelix Fietkau 	wcid->inactive_count = 0;
904ef13edc0SFelix Fietkau 
905d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
906d71ef286SFelix Fietkau 		return;
907d71ef286SFelix Fietkau 
908d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
909d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
910d71ef286SFelix Fietkau 		return;
911d71ef286SFelix Fietkau 	}
912d71ef286SFelix Fietkau 
913d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
914d71ef286SFelix Fietkau 	    !(ieee80211_is_mgmt(hdr->frame_control) ||
915d71ef286SFelix Fietkau 	      ieee80211_is_data(hdr->frame_control)))
916d71ef286SFelix Fietkau 		return;
917d71ef286SFelix Fietkau 
918d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
919d71ef286SFelix Fietkau 
920d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
921d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
922d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
923d71ef286SFelix Fietkau 
924d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
925d71ef286SFelix Fietkau 		return;
926d71ef286SFelix Fietkau 
92711b2a25fSFelix Fietkau 	if (ps)
928d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
92911b2a25fSFelix Fietkau 	else
930d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
931d71ef286SFelix Fietkau 
932d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
9339f67c277SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
93490fdc171SFelix Fietkau 
93590fdc171SFelix Fietkau 	if (ps)
93690fdc171SFelix Fietkau 		return;
93790fdc171SFelix Fietkau 
93890fdc171SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
93990fdc171SFelix Fietkau 		struct mt76_txq *mtxq;
94090fdc171SFelix Fietkau 
94190fdc171SFelix Fietkau 		if (!sta->txq[i])
94290fdc171SFelix Fietkau 			continue;
94390fdc171SFelix Fietkau 
94490fdc171SFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
94590fdc171SFelix Fietkau 		if (!skb_queue_empty(&mtxq->retry_q))
946bfc394ddSFelix Fietkau 			ieee80211_schedule_txq(hw, sta->txq[i]);
94790fdc171SFelix Fietkau 	}
948d71ef286SFelix Fietkau }
949d71ef286SFelix Fietkau 
9509d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
95181e850efSLorenzo Bianconi 		      struct napi_struct *napi)
95217f1de56SFelix Fietkau {
9539c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
954bfc394ddSFelix Fietkau 	struct ieee80211_hw *hw;
9559d9d738bSFelix Fietkau 	struct sk_buff *skb;
9569d9d738bSFelix Fietkau 
957c3d7c82aSFelix Fietkau 	spin_lock(&dev->rx_lock);
9589d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
95930ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
96030ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
96130ce7f44SFelix Fietkau 			continue;
96230ce7f44SFelix Fietkau 		}
96330ce7f44SFelix Fietkau 
964bfc394ddSFelix Fietkau 		mt76_rx_convert(dev, skb, &hw, &sta);
965bfc394ddSFelix Fietkau 		ieee80211_rx_napi(hw, sta, skb, napi);
9669d9d738bSFelix Fietkau 	}
967c3d7c82aSFelix Fietkau 	spin_unlock(&dev->rx_lock);
9689d9d738bSFelix Fietkau }
9699d9d738bSFelix Fietkau 
97081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
97181e850efSLorenzo Bianconi 			   struct napi_struct *napi)
9729d9d738bSFelix Fietkau {
973aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
97417f1de56SFelix Fietkau 	struct sk_buff *skb;
97517f1de56SFelix Fietkau 
976aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
977aee5b8cfSFelix Fietkau 
978d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
979ef13edc0SFelix Fietkau 		mt76_check_sta(dev, skb);
980aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
981d71ef286SFelix Fietkau 	}
982aee5b8cfSFelix Fietkau 
98381e850efSLorenzo Bianconi 	mt76_rx_complete(dev, &frames, napi);
9844e34249eSFelix Fietkau }
98581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
986723b90dcSFelix Fietkau 
987e28487eaSFelix Fietkau static int
988e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
989426e8e41SFelix Fietkau 	     struct ieee80211_sta *sta, bool ext_phy)
990e28487eaSFelix Fietkau {
991e28487eaSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
992e28487eaSFelix Fietkau 	int ret;
993e28487eaSFelix Fietkau 	int i;
994e28487eaSFelix Fietkau 
995e28487eaSFelix Fietkau 	mutex_lock(&dev->mutex);
996e28487eaSFelix Fietkau 
997e28487eaSFelix Fietkau 	ret = dev->drv->sta_add(dev, vif, sta);
998e28487eaSFelix Fietkau 	if (ret)
999e28487eaSFelix Fietkau 		goto out;
1000e28487eaSFelix Fietkau 
1001e28487eaSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1002e28487eaSFelix Fietkau 		struct mt76_txq *mtxq;
1003e28487eaSFelix Fietkau 
1004e28487eaSFelix Fietkau 		if (!sta->txq[i])
1005e28487eaSFelix Fietkau 			continue;
1006e28487eaSFelix Fietkau 
1007e28487eaSFelix Fietkau 		mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
1008e28487eaSFelix Fietkau 		mtxq->wcid = wcid;
1009e28487eaSFelix Fietkau 
1010e28487eaSFelix Fietkau 		mt76_txq_init(dev, sta->txq[i]);
1011e28487eaSFelix Fietkau 	}
1012e28487eaSFelix Fietkau 
1013ef13edc0SFelix Fietkau 	ewma_signal_init(&wcid->rssi);
1014426e8e41SFelix Fietkau 	if (ext_phy)
1015426e8e41SFelix Fietkau 		mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1016c7d2d631SFelix Fietkau 	wcid->ext_phy = ext_phy;
1017e28487eaSFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1018e28487eaSFelix Fietkau 
1019e28487eaSFelix Fietkau out:
1020e28487eaSFelix Fietkau 	mutex_unlock(&dev->mutex);
1021e28487eaSFelix Fietkau 
1022e28487eaSFelix Fietkau 	return ret;
1023e28487eaSFelix Fietkau }
1024e28487eaSFelix Fietkau 
102513f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1026723b90dcSFelix Fietkau 		       struct ieee80211_sta *sta)
1027723b90dcSFelix Fietkau {
1028723b90dcSFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
102913f61dfcSLorenzo Bianconi 	int i, idx = wcid->idx;
1030723b90dcSFelix Fietkau 
103158bab0d4SFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
103258bab0d4SFelix Fietkau 		mt76_rx_aggr_stop(dev, wcid, i);
103358bab0d4SFelix Fietkau 
1034e28487eaSFelix Fietkau 	if (dev->drv->sta_remove)
1035e28487eaSFelix Fietkau 		dev->drv->sta_remove(dev, vif, sta);
1036e28487eaSFelix Fietkau 
1037723b90dcSFelix Fietkau 	mt76_tx_status_check(dev, wcid, true);
1038723b90dcSFelix Fietkau 	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
1039723b90dcSFelix Fietkau 		mt76_txq_remove(dev, sta->txq[i]);
1040426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_mask, idx);
1041426e8e41SFelix Fietkau 	mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
104213f61dfcSLorenzo Bianconi }
104313f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1044e28487eaSFelix Fietkau 
104513f61dfcSLorenzo Bianconi static void
104613f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
104713f61dfcSLorenzo Bianconi 		struct ieee80211_sta *sta)
104813f61dfcSLorenzo Bianconi {
104913f61dfcSLorenzo Bianconi 	mutex_lock(&dev->mutex);
105013f61dfcSLorenzo Bianconi 	__mt76_sta_remove(dev, vif, sta);
1051723b90dcSFelix Fietkau 	mutex_unlock(&dev->mutex);
1052723b90dcSFelix Fietkau }
1053e28487eaSFelix Fietkau 
1054e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1055e28487eaSFelix Fietkau 		   struct ieee80211_sta *sta,
1056e28487eaSFelix Fietkau 		   enum ieee80211_sta_state old_state,
1057e28487eaSFelix Fietkau 		   enum ieee80211_sta_state new_state)
1058e28487eaSFelix Fietkau {
1059426e8e41SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1060426e8e41SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1061426e8e41SFelix Fietkau 	bool ext_phy = phy != &dev->phy;
1062e28487eaSFelix Fietkau 
1063e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NOTEXIST &&
1064e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NONE)
1065426e8e41SFelix Fietkau 		return mt76_sta_add(dev, vif, sta, ext_phy);
1066e28487eaSFelix Fietkau 
10679c193de5SFelix Fietkau 	if (old_state == IEEE80211_STA_AUTH &&
10689c193de5SFelix Fietkau 	    new_state == IEEE80211_STA_ASSOC &&
10699c193de5SFelix Fietkau 	    dev->drv->sta_assoc)
10709c193de5SFelix Fietkau 		dev->drv->sta_assoc(dev, vif, sta);
10719c193de5SFelix Fietkau 
1072e28487eaSFelix Fietkau 	if (old_state == IEEE80211_STA_NONE &&
1073e28487eaSFelix Fietkau 	    new_state == IEEE80211_STA_NOTEXIST)
1074e28487eaSFelix Fietkau 		mt76_sta_remove(dev, vif, sta);
1075e28487eaSFelix Fietkau 
1076e28487eaSFelix Fietkau 	return 0;
1077e28487eaSFelix Fietkau }
1078e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
10799313faacSFelix Fietkau 
108043ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
108143ba1922SFelix Fietkau 			     struct ieee80211_sta *sta)
108243ba1922SFelix Fietkau {
108343ba1922SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
108443ba1922SFelix Fietkau 	struct mt76_dev *dev = phy->dev;
108543ba1922SFelix Fietkau 	struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
108643ba1922SFelix Fietkau 
108743ba1922SFelix Fietkau 	mutex_lock(&dev->mutex);
108843ba1922SFelix Fietkau 	rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
108943ba1922SFelix Fietkau 	mutex_unlock(&dev->mutex);
109043ba1922SFelix Fietkau }
109143ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
109243ba1922SFelix Fietkau 
10939313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
10949313faacSFelix Fietkau 		     int *dbm)
10959313faacSFelix Fietkau {
1096beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1097beaaeb6bSFelix Fietkau 	int n_chains = hweight8(phy->antenna_mask);
109807cda406SFelix Fietkau 	int delta = mt76_tx_power_nss_delta(n_chains);
10999313faacSFelix Fietkau 
110007cda406SFelix Fietkau 	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
11019313faacSFelix Fietkau 
11029313faacSFelix Fietkau 	return 0;
11039313faacSFelix Fietkau }
11049313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1105e7173858SFelix Fietkau 
1106e7173858SFelix Fietkau static void
1107e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1108e7173858SFelix Fietkau {
11098552a434SJohn Crispin 	if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1110e7173858SFelix Fietkau 		ieee80211_csa_finish(vif);
1111e7173858SFelix Fietkau }
1112e7173858SFelix Fietkau 
1113e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1114e7173858SFelix Fietkau {
1115e7173858SFelix Fietkau 	if (!dev->csa_complete)
1116e7173858SFelix Fietkau 		return;
1117e7173858SFelix Fietkau 
1118e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1119e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1120e7173858SFelix Fietkau 		__mt76_csa_finish, dev);
1121e7173858SFelix Fietkau 
1122e7173858SFelix Fietkau 	dev->csa_complete = 0;
1123e7173858SFelix Fietkau }
1124e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1125e7173858SFelix Fietkau 
1126e7173858SFelix Fietkau static void
1127e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1128e7173858SFelix Fietkau {
1129e7173858SFelix Fietkau 	struct mt76_dev *dev = priv;
1130e7173858SFelix Fietkau 
1131e7173858SFelix Fietkau 	if (!vif->csa_active)
1132e7173858SFelix Fietkau 		return;
1133e7173858SFelix Fietkau 
11348552a434SJohn Crispin 	dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1135e7173858SFelix Fietkau }
1136e7173858SFelix Fietkau 
1137e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1138e7173858SFelix Fietkau {
1139e7173858SFelix Fietkau 	ieee80211_iterate_active_interfaces_atomic(dev->hw,
1140e7173858SFelix Fietkau 		IEEE80211_IFACE_ITER_RESUME_ALL,
1141e7173858SFelix Fietkau 		__mt76_csa_check, dev);
1142e7173858SFelix Fietkau }
1143e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
114487d53103SStanislaw Gruszka 
114587d53103SStanislaw Gruszka int
114687d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
114787d53103SStanislaw Gruszka {
114887d53103SStanislaw Gruszka 	return 0;
114987d53103SStanislaw Gruszka }
115087d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1151eadfd98fSLorenzo Bianconi 
1152eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1153eadfd98fSLorenzo Bianconi {
1154eadfd98fSLorenzo Bianconi 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1155eadfd98fSLorenzo Bianconi 	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1156eadfd98fSLorenzo Bianconi 	u8 *hdr, *pn = status->iv;
1157eadfd98fSLorenzo Bianconi 
1158eadfd98fSLorenzo Bianconi 	__skb_push(skb, 8);
1159eadfd98fSLorenzo Bianconi 	memmove(skb->data, skb->data + 8, hdr_len);
1160eadfd98fSLorenzo Bianconi 	hdr = skb->data + hdr_len;
1161eadfd98fSLorenzo Bianconi 
1162eadfd98fSLorenzo Bianconi 	hdr[0] = pn[5];
1163eadfd98fSLorenzo Bianconi 	hdr[1] = pn[4];
1164eadfd98fSLorenzo Bianconi 	hdr[2] = 0;
1165eadfd98fSLorenzo Bianconi 	hdr[3] = 0x20 | (key_id << 6);
1166eadfd98fSLorenzo Bianconi 	hdr[4] = pn[3];
1167eadfd98fSLorenzo Bianconi 	hdr[5] = pn[2];
1168eadfd98fSLorenzo Bianconi 	hdr[6] = pn[1];
1169eadfd98fSLorenzo Bianconi 	hdr[7] = pn[0];
1170eadfd98fSLorenzo Bianconi 
1171eadfd98fSLorenzo Bianconi 	status->flag &= ~RX_FLAG_IV_STRIPPED;
1172eadfd98fSLorenzo Bianconi }
1173eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1174d2679d65SLorenzo Bianconi 
1175d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1176d2679d65SLorenzo Bianconi 		  struct ieee80211_supported_band *sband,
1177d2679d65SLorenzo Bianconi 		  int idx, bool cck)
1178d2679d65SLorenzo Bianconi {
1179d2679d65SLorenzo Bianconi 	int i, offset = 0, len = sband->n_bitrates;
1180d2679d65SLorenzo Bianconi 
1181d2679d65SLorenzo Bianconi 	if (cck) {
118296747a51SFelix Fietkau 		if (sband == &dev->phy.sband_5g.sband)
1183d2679d65SLorenzo Bianconi 			return 0;
1184d2679d65SLorenzo Bianconi 
1185d2679d65SLorenzo Bianconi 		idx &= ~BIT(2); /* short preamble */
118696747a51SFelix Fietkau 	} else if (sband == &dev->phy.sband_2g.sband) {
1187d2679d65SLorenzo Bianconi 		offset = 4;
1188d2679d65SLorenzo Bianconi 	}
1189d2679d65SLorenzo Bianconi 
1190d2679d65SLorenzo Bianconi 	for (i = offset; i < len; i++) {
1191d2679d65SLorenzo Bianconi 		if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1192d2679d65SLorenzo Bianconi 			return i;
1193d2679d65SLorenzo Bianconi 	}
1194d2679d65SLorenzo Bianconi 
1195d2679d65SLorenzo Bianconi 	return 0;
1196d2679d65SLorenzo Bianconi }
1197d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
11988b8ab5c2SLorenzo Bianconi 
11998b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
12008b8ab5c2SLorenzo Bianconi 		  const u8 *mac)
12018b8ab5c2SLorenzo Bianconi {
1202011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
12038b8ab5c2SLorenzo Bianconi 
1204011849e0SFelix Fietkau 	set_bit(MT76_SCANNING, &phy->state);
12058b8ab5c2SLorenzo Bianconi }
12068b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
12078b8ab5c2SLorenzo Bianconi 
12088b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
12098b8ab5c2SLorenzo Bianconi {
1210011849e0SFelix Fietkau 	struct mt76_phy *phy = hw->priv;
12118b8ab5c2SLorenzo Bianconi 
1212011849e0SFelix Fietkau 	clear_bit(MT76_SCANNING, &phy->state);
12138b8ab5c2SLorenzo Bianconi }
12148b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1215e49c76d4SLorenzo Bianconi 
1216e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1217e49c76d4SLorenzo Bianconi {
1218beaaeb6bSFelix Fietkau 	struct mt76_phy *phy = hw->priv;
1219beaaeb6bSFelix Fietkau 	struct mt76_dev *dev = phy->dev;
1220e49c76d4SLorenzo Bianconi 
1221e49c76d4SLorenzo Bianconi 	mutex_lock(&dev->mutex);
1222beaaeb6bSFelix Fietkau 	*tx_ant = phy->antenna_mask;
1223beaaeb6bSFelix Fietkau 	*rx_ant = phy->antenna_mask;
1224e49c76d4SLorenzo Bianconi 	mutex_unlock(&dev->mutex);
1225e49c76d4SLorenzo Bianconi 
1226e49c76d4SLorenzo Bianconi 	return 0;
1227e49c76d4SLorenzo Bianconi }
1228e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1229