xref: /linux/drivers/net/wireless/mediatek/mt76/mac80211.c (revision d71ef28636e435079028c1ed255fa92d8ff6ed76)
117f1de56SFelix Fietkau /*
217f1de56SFelix Fietkau  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
317f1de56SFelix Fietkau  *
417f1de56SFelix Fietkau  * Permission to use, copy, modify, and/or distribute this software for any
517f1de56SFelix Fietkau  * purpose with or without fee is hereby granted, provided that the above
617f1de56SFelix Fietkau  * copyright notice and this permission notice appear in all copies.
717f1de56SFelix Fietkau  *
817f1de56SFelix Fietkau  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
917f1de56SFelix Fietkau  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1017f1de56SFelix Fietkau  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1117f1de56SFelix Fietkau  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1217f1de56SFelix Fietkau  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1317f1de56SFelix Fietkau  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1417f1de56SFelix Fietkau  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1517f1de56SFelix Fietkau  */
1617f1de56SFelix Fietkau #include <linux/of.h>
1717f1de56SFelix Fietkau #include "mt76.h"
1817f1de56SFelix Fietkau 
1917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) {			\
2017f1de56SFelix Fietkau 	.band = NL80211_BAND_2GHZ,		\
2117f1de56SFelix Fietkau 	.center_freq = (_freq),			\
2217f1de56SFelix Fietkau 	.hw_value = (_idx),			\
2317f1de56SFelix Fietkau 	.max_power = 30,			\
2417f1de56SFelix Fietkau }
2517f1de56SFelix Fietkau 
2617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) {			\
2717f1de56SFelix Fietkau 	.band = NL80211_BAND_5GHZ,		\
2817f1de56SFelix Fietkau 	.center_freq = (_freq),			\
2917f1de56SFelix Fietkau 	.hw_value = (_idx),			\
3017f1de56SFelix Fietkau 	.max_power = 30,			\
3117f1de56SFelix Fietkau }
3217f1de56SFelix Fietkau 
3317f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3417f1de56SFelix Fietkau 	CHAN2G(1, 2412),
3517f1de56SFelix Fietkau 	CHAN2G(2, 2417),
3617f1de56SFelix Fietkau 	CHAN2G(3, 2422),
3717f1de56SFelix Fietkau 	CHAN2G(4, 2427),
3817f1de56SFelix Fietkau 	CHAN2G(5, 2432),
3917f1de56SFelix Fietkau 	CHAN2G(6, 2437),
4017f1de56SFelix Fietkau 	CHAN2G(7, 2442),
4117f1de56SFelix Fietkau 	CHAN2G(8, 2447),
4217f1de56SFelix Fietkau 	CHAN2G(9, 2452),
4317f1de56SFelix Fietkau 	CHAN2G(10, 2457),
4417f1de56SFelix Fietkau 	CHAN2G(11, 2462),
4517f1de56SFelix Fietkau 	CHAN2G(12, 2467),
4617f1de56SFelix Fietkau 	CHAN2G(13, 2472),
4717f1de56SFelix Fietkau 	CHAN2G(14, 2484),
4817f1de56SFelix Fietkau };
4917f1de56SFelix Fietkau 
5017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
5117f1de56SFelix Fietkau 	CHAN5G(36, 5180),
5217f1de56SFelix Fietkau 	CHAN5G(40, 5200),
5317f1de56SFelix Fietkau 	CHAN5G(44, 5220),
5417f1de56SFelix Fietkau 	CHAN5G(48, 5240),
5517f1de56SFelix Fietkau 
5617f1de56SFelix Fietkau 	CHAN5G(52, 5260),
5717f1de56SFelix Fietkau 	CHAN5G(56, 5280),
5817f1de56SFelix Fietkau 	CHAN5G(60, 5300),
5917f1de56SFelix Fietkau 	CHAN5G(64, 5320),
6017f1de56SFelix Fietkau 
6117f1de56SFelix Fietkau 	CHAN5G(100, 5500),
6217f1de56SFelix Fietkau 	CHAN5G(104, 5520),
6317f1de56SFelix Fietkau 	CHAN5G(108, 5540),
6417f1de56SFelix Fietkau 	CHAN5G(112, 5560),
6517f1de56SFelix Fietkau 	CHAN5G(116, 5580),
6617f1de56SFelix Fietkau 	CHAN5G(120, 5600),
6717f1de56SFelix Fietkau 	CHAN5G(124, 5620),
6817f1de56SFelix Fietkau 	CHAN5G(128, 5640),
6917f1de56SFelix Fietkau 	CHAN5G(132, 5660),
7017f1de56SFelix Fietkau 	CHAN5G(136, 5680),
7117f1de56SFelix Fietkau 	CHAN5G(140, 5700),
7217f1de56SFelix Fietkau 
7317f1de56SFelix Fietkau 	CHAN5G(149, 5745),
7417f1de56SFelix Fietkau 	CHAN5G(153, 5765),
7517f1de56SFelix Fietkau 	CHAN5G(157, 5785),
7617f1de56SFelix Fietkau 	CHAN5G(161, 5805),
7717f1de56SFelix Fietkau 	CHAN5G(165, 5825),
7817f1de56SFelix Fietkau };
7917f1de56SFelix Fietkau 
8017f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
8117f1de56SFelix Fietkau 	{ .throughput =   0 * 1024, .blink_time = 334 },
8217f1de56SFelix Fietkau 	{ .throughput =   1 * 1024, .blink_time = 260 },
8317f1de56SFelix Fietkau 	{ .throughput =   5 * 1024, .blink_time = 220 },
8417f1de56SFelix Fietkau 	{ .throughput =  10 * 1024, .blink_time = 190 },
8517f1de56SFelix Fietkau 	{ .throughput =  20 * 1024, .blink_time = 170 },
8617f1de56SFelix Fietkau 	{ .throughput =  50 * 1024, .blink_time = 150 },
8717f1de56SFelix Fietkau 	{ .throughput =  70 * 1024, .blink_time = 130 },
8817f1de56SFelix Fietkau 	{ .throughput = 100 * 1024, .blink_time = 110 },
8917f1de56SFelix Fietkau 	{ .throughput = 200 * 1024, .blink_time =  80 },
9017f1de56SFelix Fietkau 	{ .throughput = 300 * 1024, .blink_time =  50 },
9117f1de56SFelix Fietkau };
9217f1de56SFelix Fietkau 
9317f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev)
9417f1de56SFelix Fietkau {
9517f1de56SFelix Fietkau 	struct device_node *np = dev->dev->of_node;
9617f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
9717f1de56SFelix Fietkau 	int led_pin;
9817f1de56SFelix Fietkau 
9917f1de56SFelix Fietkau 	if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set)
10017f1de56SFelix Fietkau 		return 0;
10117f1de56SFelix Fietkau 
10217f1de56SFelix Fietkau 	snprintf(dev->led_name, sizeof(dev->led_name),
10317f1de56SFelix Fietkau 		 "mt76-%s", wiphy_name(hw->wiphy));
10417f1de56SFelix Fietkau 
10517f1de56SFelix Fietkau 	dev->led_cdev.name = dev->led_name;
10617f1de56SFelix Fietkau 	dev->led_cdev.default_trigger =
10717f1de56SFelix Fietkau 		ieee80211_create_tpt_led_trigger(hw,
10817f1de56SFelix Fietkau 					IEEE80211_TPT_LEDTRIG_FL_RADIO,
10917f1de56SFelix Fietkau 					mt76_tpt_blink,
11017f1de56SFelix Fietkau 					ARRAY_SIZE(mt76_tpt_blink));
11117f1de56SFelix Fietkau 
11217f1de56SFelix Fietkau 	np = of_get_child_by_name(np, "led");
11317f1de56SFelix Fietkau 	if (np) {
11417f1de56SFelix Fietkau 		if (!of_property_read_u32(np, "led-sources", &led_pin))
11517f1de56SFelix Fietkau 			dev->led_pin = led_pin;
11617f1de56SFelix Fietkau 		dev->led_al = of_property_read_bool(np, "led-active-low");
11717f1de56SFelix Fietkau 	}
11817f1de56SFelix Fietkau 
11917f1de56SFelix Fietkau 	return devm_led_classdev_register(dev->dev, &dev->led_cdev);
12017f1de56SFelix Fietkau }
12117f1de56SFelix Fietkau 
12217f1de56SFelix Fietkau static int
12317f1de56SFelix Fietkau mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
12417f1de56SFelix Fietkau 		const struct ieee80211_channel *chan, int n_chan,
12517f1de56SFelix Fietkau 		struct ieee80211_rate *rates, int n_rates, bool vht)
12617f1de56SFelix Fietkau {
12717f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = &msband->sband;
12817f1de56SFelix Fietkau 	struct ieee80211_sta_ht_cap *ht_cap;
12917f1de56SFelix Fietkau 	struct ieee80211_sta_vht_cap *vht_cap;
13017f1de56SFelix Fietkau 	void *chanlist;
13117f1de56SFelix Fietkau 	u16 mcs_map;
13217f1de56SFelix Fietkau 	int size;
13317f1de56SFelix Fietkau 
13417f1de56SFelix Fietkau 	size = n_chan * sizeof(*chan);
13517f1de56SFelix Fietkau 	chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
13617f1de56SFelix Fietkau 	if (!chanlist)
13717f1de56SFelix Fietkau 		return -ENOMEM;
13817f1de56SFelix Fietkau 
13917f1de56SFelix Fietkau 	msband->chan = devm_kzalloc(dev->dev, n_chan * sizeof(*msband->chan),
14017f1de56SFelix Fietkau 				    GFP_KERNEL);
14117f1de56SFelix Fietkau 	if (!msband->chan)
14217f1de56SFelix Fietkau 		return -ENOMEM;
14317f1de56SFelix Fietkau 
14417f1de56SFelix Fietkau 	sband->channels = chanlist;
14517f1de56SFelix Fietkau 	sband->n_channels = n_chan;
14617f1de56SFelix Fietkau 	sband->bitrates = rates;
14717f1de56SFelix Fietkau 	sband->n_bitrates = n_rates;
14817f1de56SFelix Fietkau 	dev->chandef.chan = &sband->channels[0];
14917f1de56SFelix Fietkau 
15017f1de56SFelix Fietkau 	ht_cap = &sband->ht_cap;
15117f1de56SFelix Fietkau 	ht_cap->ht_supported = true;
15217f1de56SFelix Fietkau 	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
15317f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_GRN_FLD |
15417f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_20 |
15517f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_SGI_40 |
15617f1de56SFelix Fietkau 		       IEEE80211_HT_CAP_TX_STBC |
15717f1de56SFelix Fietkau 		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
15817f1de56SFelix Fietkau 
15917f1de56SFelix Fietkau 	ht_cap->mcs.rx_mask[0] = 0xff;
16017f1de56SFelix Fietkau 	ht_cap->mcs.rx_mask[1] = 0xff;
16117f1de56SFelix Fietkau 	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
16217f1de56SFelix Fietkau 	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
16317f1de56SFelix Fietkau 	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
16417f1de56SFelix Fietkau 
16517f1de56SFelix Fietkau 	if (!vht)
16617f1de56SFelix Fietkau 		return 0;
16717f1de56SFelix Fietkau 
16817f1de56SFelix Fietkau 	vht_cap = &sband->vht_cap;
16917f1de56SFelix Fietkau 	vht_cap->vht_supported = true;
17017f1de56SFelix Fietkau 
17117f1de56SFelix Fietkau 	mcs_map = (IEEE80211_VHT_MCS_SUPPORT_0_9 << (0 * 2)) |
17217f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_SUPPORT_0_9 << (1 * 2)) |
17317f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_NOT_SUPPORTED << (2 * 2)) |
17417f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_NOT_SUPPORTED << (3 * 2)) |
17517f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_NOT_SUPPORTED << (4 * 2)) |
17617f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_NOT_SUPPORTED << (5 * 2)) |
17717f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_NOT_SUPPORTED << (6 * 2)) |
17817f1de56SFelix Fietkau 		  (IEEE80211_VHT_MCS_NOT_SUPPORTED << (7 * 2));
17917f1de56SFelix Fietkau 
18017f1de56SFelix Fietkau 	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
18117f1de56SFelix Fietkau 	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
18217f1de56SFelix Fietkau 	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
18317f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_TXSTBC |
18417f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_RXSTBC_1 |
18517f1de56SFelix Fietkau 			IEEE80211_VHT_CAP_SHORT_GI_80;
18617f1de56SFelix Fietkau 
18717f1de56SFelix Fietkau 	return 0;
18817f1de56SFelix Fietkau }
18917f1de56SFelix Fietkau 
19017f1de56SFelix Fietkau static int
19117f1de56SFelix Fietkau mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
19217f1de56SFelix Fietkau 		   int n_rates)
19317f1de56SFelix Fietkau {
19417f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband;
19517f1de56SFelix Fietkau 
19617f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_2g,
19717f1de56SFelix Fietkau 			       mt76_channels_2ghz,
19817f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_2ghz),
19917f1de56SFelix Fietkau 			       rates, n_rates, false);
20017f1de56SFelix Fietkau }
20117f1de56SFelix Fietkau 
20217f1de56SFelix Fietkau static int
20317f1de56SFelix Fietkau mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
20417f1de56SFelix Fietkau 		   int n_rates, bool vht)
20517f1de56SFelix Fietkau {
20617f1de56SFelix Fietkau 	dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband;
20717f1de56SFelix Fietkau 
20817f1de56SFelix Fietkau 	return mt76_init_sband(dev, &dev->sband_5g,
20917f1de56SFelix Fietkau 			       mt76_channels_5ghz,
21017f1de56SFelix Fietkau 			       ARRAY_SIZE(mt76_channels_5ghz),
21117f1de56SFelix Fietkau 			       rates, n_rates, vht);
21217f1de56SFelix Fietkau }
21317f1de56SFelix Fietkau 
21417f1de56SFelix Fietkau static void
21517f1de56SFelix Fietkau mt76_check_sband(struct mt76_dev *dev, int band)
21617f1de56SFelix Fietkau {
21717f1de56SFelix Fietkau 	struct ieee80211_supported_band *sband = dev->hw->wiphy->bands[band];
21817f1de56SFelix Fietkau 	bool found = false;
21917f1de56SFelix Fietkau 	int i;
22017f1de56SFelix Fietkau 
22117f1de56SFelix Fietkau 	if (!sband)
22217f1de56SFelix Fietkau 		return;
22317f1de56SFelix Fietkau 
22417f1de56SFelix Fietkau 	for (i = 0; i < sband->n_channels; i++) {
22517f1de56SFelix Fietkau 		if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
22617f1de56SFelix Fietkau 			continue;
22717f1de56SFelix Fietkau 
22817f1de56SFelix Fietkau 		found = true;
22917f1de56SFelix Fietkau 		break;
23017f1de56SFelix Fietkau 	}
23117f1de56SFelix Fietkau 
23217f1de56SFelix Fietkau 	if (found)
23317f1de56SFelix Fietkau 		return;
23417f1de56SFelix Fietkau 
23517f1de56SFelix Fietkau 	sband->n_channels = 0;
23617f1de56SFelix Fietkau 	dev->hw->wiphy->bands[band] = NULL;
23717f1de56SFelix Fietkau }
23817f1de56SFelix Fietkau 
23917f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
24017f1de56SFelix Fietkau 			 struct ieee80211_rate *rates, int n_rates)
24117f1de56SFelix Fietkau {
24217f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
24317f1de56SFelix Fietkau 	struct wiphy *wiphy = hw->wiphy;
24417f1de56SFelix Fietkau 	int ret;
24517f1de56SFelix Fietkau 
24617f1de56SFelix Fietkau 	dev_set_drvdata(dev->dev, dev);
24717f1de56SFelix Fietkau 
24817f1de56SFelix Fietkau 	spin_lock_init(&dev->lock);
24917f1de56SFelix Fietkau 	spin_lock_init(&dev->cc_lock);
25017f1de56SFelix Fietkau 	INIT_LIST_HEAD(&dev->txwi_cache);
25117f1de56SFelix Fietkau 
25217f1de56SFelix Fietkau 	SET_IEEE80211_DEV(hw, dev->dev);
25317f1de56SFelix Fietkau 	SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
25417f1de56SFelix Fietkau 
25517f1de56SFelix Fietkau 	wiphy->interface_modes =
25617f1de56SFelix Fietkau 		BIT(NL80211_IFTYPE_STATION) |
25717f1de56SFelix Fietkau 		BIT(NL80211_IFTYPE_AP) |
25817f1de56SFelix Fietkau #ifdef CONFIG_MAC80211_MESH
25917f1de56SFelix Fietkau 		BIT(NL80211_IFTYPE_MESH_POINT) |
26017f1de56SFelix Fietkau #endif
26117f1de56SFelix Fietkau 		BIT(NL80211_IFTYPE_ADHOC);
26217f1de56SFelix Fietkau 
26317f1de56SFelix Fietkau 	wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
26417f1de56SFelix Fietkau 
26517f1de56SFelix Fietkau 	hw->txq_data_size = sizeof(struct mt76_txq);
26617f1de56SFelix Fietkau 	hw->max_tx_fragments = 16;
26717f1de56SFelix Fietkau 
26817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SIGNAL_DBM);
26917f1de56SFelix Fietkau 	ieee80211_hw_set(hw, PS_NULLFUNC_STACK);
27017f1de56SFelix Fietkau 	ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
27117f1de56SFelix Fietkau 	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
27217f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
27317f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
27417f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
27517f1de56SFelix Fietkau 	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
27617f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_AMSDU);
27717f1de56SFelix Fietkau 	ieee80211_hw_set(hw, TX_FRAG_LIST);
27817f1de56SFelix Fietkau 	ieee80211_hw_set(hw, MFP_CAPABLE);
279*d71ef286SFelix Fietkau 	ieee80211_hw_set(hw, AP_LINK_PS);
28017f1de56SFelix Fietkau 
28117f1de56SFelix Fietkau 	wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
28217f1de56SFelix Fietkau 
28317f1de56SFelix Fietkau 	if (dev->cap.has_2ghz) {
28417f1de56SFelix Fietkau 		ret = mt76_init_sband_2g(dev, rates, n_rates);
28517f1de56SFelix Fietkau 		if (ret)
28617f1de56SFelix Fietkau 			return ret;
28717f1de56SFelix Fietkau 	}
28817f1de56SFelix Fietkau 
28917f1de56SFelix Fietkau 	if (dev->cap.has_5ghz) {
29017f1de56SFelix Fietkau 		ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
29117f1de56SFelix Fietkau 		if (ret)
29217f1de56SFelix Fietkau 			return ret;
29317f1de56SFelix Fietkau 	}
29417f1de56SFelix Fietkau 
29517f1de56SFelix Fietkau 	wiphy_read_of_freq_limits(dev->hw->wiphy);
29617f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_2GHZ);
29717f1de56SFelix Fietkau 	mt76_check_sband(dev, NL80211_BAND_5GHZ);
29817f1de56SFelix Fietkau 
29917f1de56SFelix Fietkau 	ret = mt76_led_init(dev);
30017f1de56SFelix Fietkau 	if (ret)
30117f1de56SFelix Fietkau 		return ret;
30217f1de56SFelix Fietkau 
30317f1de56SFelix Fietkau 	return ieee80211_register_hw(hw);
30417f1de56SFelix Fietkau }
30517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
30617f1de56SFelix Fietkau 
30717f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
30817f1de56SFelix Fietkau {
30917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
31017f1de56SFelix Fietkau 
31117f1de56SFelix Fietkau 	ieee80211_unregister_hw(hw);
31217f1de56SFelix Fietkau 	mt76_tx_free(dev);
31317f1de56SFelix Fietkau }
31417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
31517f1de56SFelix Fietkau 
31617f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
31717f1de56SFelix Fietkau {
31817f1de56SFelix Fietkau 	if (!test_bit(MT76_STATE_RUNNING, &dev->state)) {
31917f1de56SFelix Fietkau 		dev_kfree_skb(skb);
32017f1de56SFelix Fietkau 		return;
32117f1de56SFelix Fietkau 	}
32217f1de56SFelix Fietkau 
32317f1de56SFelix Fietkau 	__skb_queue_tail(&dev->rx_skb[q], skb);
32417f1de56SFelix Fietkau }
32517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
32617f1de56SFelix Fietkau 
32717f1de56SFelix Fietkau void mt76_set_channel(struct mt76_dev *dev)
32817f1de56SFelix Fietkau {
32917f1de56SFelix Fietkau 	struct ieee80211_hw *hw = dev->hw;
33017f1de56SFelix Fietkau 	struct cfg80211_chan_def *chandef = &hw->conf.chandef;
33117f1de56SFelix Fietkau 	struct mt76_channel_state *state;
33217f1de56SFelix Fietkau 	bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
33317f1de56SFelix Fietkau 
33417f1de56SFelix Fietkau 	if (dev->drv->update_survey)
33517f1de56SFelix Fietkau 		dev->drv->update_survey(dev);
33617f1de56SFelix Fietkau 
33717f1de56SFelix Fietkau 	dev->chandef = *chandef;
33817f1de56SFelix Fietkau 
33917f1de56SFelix Fietkau 	if (!offchannel)
34017f1de56SFelix Fietkau 		dev->main_chan = chandef->chan;
34117f1de56SFelix Fietkau 
34217f1de56SFelix Fietkau 	if (chandef->chan != dev->main_chan) {
34317f1de56SFelix Fietkau 		state = mt76_channel_state(dev, chandef->chan);
34417f1de56SFelix Fietkau 		memset(state, 0, sizeof(*state));
34517f1de56SFelix Fietkau 	}
34617f1de56SFelix Fietkau }
34717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
34817f1de56SFelix Fietkau 
34917f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
35017f1de56SFelix Fietkau 		    struct survey_info *survey)
35117f1de56SFelix Fietkau {
35217f1de56SFelix Fietkau 	struct mt76_dev *dev = hw->priv;
35317f1de56SFelix Fietkau 	struct mt76_sband *sband;
35417f1de56SFelix Fietkau 	struct ieee80211_channel *chan;
35517f1de56SFelix Fietkau 	struct mt76_channel_state *state;
35617f1de56SFelix Fietkau 	int ret = 0;
35717f1de56SFelix Fietkau 
35817f1de56SFelix Fietkau 	if (idx == 0 && dev->drv->update_survey)
35917f1de56SFelix Fietkau 		dev->drv->update_survey(dev);
36017f1de56SFelix Fietkau 
36117f1de56SFelix Fietkau 	sband = &dev->sband_2g;
36217f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels) {
36317f1de56SFelix Fietkau 		idx -= sband->sband.n_channels;
36417f1de56SFelix Fietkau 		sband = &dev->sband_5g;
36517f1de56SFelix Fietkau 	}
36617f1de56SFelix Fietkau 
36717f1de56SFelix Fietkau 	if (idx >= sband->sband.n_channels)
36817f1de56SFelix Fietkau 		return -ENOENT;
36917f1de56SFelix Fietkau 
37017f1de56SFelix Fietkau 	chan = &sband->sband.channels[idx];
37117f1de56SFelix Fietkau 	state = mt76_channel_state(dev, chan);
37217f1de56SFelix Fietkau 
37317f1de56SFelix Fietkau 	memset(survey, 0, sizeof(*survey));
37417f1de56SFelix Fietkau 	survey->channel = chan;
37517f1de56SFelix Fietkau 	survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
37617f1de56SFelix Fietkau 	if (chan == dev->main_chan)
37717f1de56SFelix Fietkau 		survey->filled |= SURVEY_INFO_IN_USE;
37817f1de56SFelix Fietkau 
37917f1de56SFelix Fietkau 	spin_lock_bh(&dev->cc_lock);
38017f1de56SFelix Fietkau 	survey->time = div_u64(state->cc_active, 1000);
38117f1de56SFelix Fietkau 	survey->time_busy = div_u64(state->cc_busy, 1000);
38217f1de56SFelix Fietkau 	spin_unlock_bh(&dev->cc_lock);
38317f1de56SFelix Fietkau 
38417f1de56SFelix Fietkau 	return ret;
38517f1de56SFelix Fietkau }
38617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
38717f1de56SFelix Fietkau 
38830ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
38930ce7f44SFelix Fietkau 			 struct ieee80211_key_conf *key)
39030ce7f44SFelix Fietkau {
39130ce7f44SFelix Fietkau 	struct ieee80211_key_seq seq;
39230ce7f44SFelix Fietkau 	int i;
39330ce7f44SFelix Fietkau 
39430ce7f44SFelix Fietkau 	wcid->rx_check_pn = false;
39530ce7f44SFelix Fietkau 
39630ce7f44SFelix Fietkau 	if (!key)
39730ce7f44SFelix Fietkau 		return;
39830ce7f44SFelix Fietkau 
39930ce7f44SFelix Fietkau 	if (key->cipher == WLAN_CIPHER_SUITE_CCMP)
40030ce7f44SFelix Fietkau 		wcid->rx_check_pn = true;
40130ce7f44SFelix Fietkau 
40230ce7f44SFelix Fietkau 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
40330ce7f44SFelix Fietkau 		ieee80211_get_key_rx_seq(key, i, &seq);
40430ce7f44SFelix Fietkau 		memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
40530ce7f44SFelix Fietkau 	}
40630ce7f44SFelix Fietkau }
40730ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
40830ce7f44SFelix Fietkau 
4099d9d738bSFelix Fietkau static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
4104e34249eSFelix Fietkau {
4114e34249eSFelix Fietkau 	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
4124e34249eSFelix Fietkau 	struct mt76_rx_status mstat;
4134e34249eSFelix Fietkau 
4144e34249eSFelix Fietkau 	mstat = *((struct mt76_rx_status *) skb->cb);
4154e34249eSFelix Fietkau 	memset(status, 0, sizeof(*status));
4164e34249eSFelix Fietkau 
4174e34249eSFelix Fietkau 	status->flag = mstat.flag;
4184e34249eSFelix Fietkau 	status->freq = mstat.freq;
4194e34249eSFelix Fietkau 	status->enc_flags = mstat.enc_flags;
4204e34249eSFelix Fietkau 	status->encoding = mstat.encoding;
4214e34249eSFelix Fietkau 	status->bw = mstat.bw;
4224e34249eSFelix Fietkau 	status->rate_idx = mstat.rate_idx;
4234e34249eSFelix Fietkau 	status->nss = mstat.nss;
4244e34249eSFelix Fietkau 	status->band = mstat.band;
4254e34249eSFelix Fietkau 	status->signal = mstat.signal;
4264e34249eSFelix Fietkau 	status->chains = mstat.chains;
4274e34249eSFelix Fietkau 
4284e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
4294e34249eSFelix Fietkau 	BUILD_BUG_ON(sizeof(status->chain_signal) != sizeof(mstat.chain_signal));
4304e34249eSFelix Fietkau 	memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal));
4319c68a57bSFelix Fietkau 
4329c68a57bSFelix Fietkau 	return wcid_to_sta(mstat.wcid);
4334e34249eSFelix Fietkau }
4344e34249eSFelix Fietkau 
43530ce7f44SFelix Fietkau static int
43630ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
43730ce7f44SFelix Fietkau {
43830ce7f44SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
43930ce7f44SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
44030ce7f44SFelix Fietkau 	struct ieee80211_hdr *hdr;
44130ce7f44SFelix Fietkau 	int ret;
44230ce7f44SFelix Fietkau 
44330ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_DECRYPTED))
44430ce7f44SFelix Fietkau 		return 0;
44530ce7f44SFelix Fietkau 
44630ce7f44SFelix Fietkau 	if (!wcid || !wcid->rx_check_pn)
44730ce7f44SFelix Fietkau 		return 0;
44830ce7f44SFelix Fietkau 
44930ce7f44SFelix Fietkau 	if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
45030ce7f44SFelix Fietkau 		/*
45130ce7f44SFelix Fietkau 		 * Validate the first fragment both here and in mac80211
45230ce7f44SFelix Fietkau 		 * All further fragments will be validated by mac80211 only.
45330ce7f44SFelix Fietkau 		 */
45430ce7f44SFelix Fietkau 		hdr = (struct ieee80211_hdr *) skb->data;
45530ce7f44SFelix Fietkau 		if (ieee80211_is_frag(hdr) &&
45630ce7f44SFelix Fietkau 		    !ieee80211_is_first_frag(hdr->frame_control))
45730ce7f44SFelix Fietkau 			return 0;
45830ce7f44SFelix Fietkau 	}
45930ce7f44SFelix Fietkau 
46030ce7f44SFelix Fietkau 	BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
46130ce7f44SFelix Fietkau 	ret = memcmp(status->iv, wcid->rx_key_pn[status->tid],
46230ce7f44SFelix Fietkau 		     sizeof(status->iv));
46330ce7f44SFelix Fietkau 	if (ret <= 0)
46430ce7f44SFelix Fietkau 		return -EINVAL; /* replay */
46530ce7f44SFelix Fietkau 
46630ce7f44SFelix Fietkau 	memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv));
46730ce7f44SFelix Fietkau 
46830ce7f44SFelix Fietkau 	if (status->flag & RX_FLAG_IV_STRIPPED)
46930ce7f44SFelix Fietkau 		status->flag |= RX_FLAG_PN_VALIDATED;
47030ce7f44SFelix Fietkau 
47130ce7f44SFelix Fietkau 	return 0;
47230ce7f44SFelix Fietkau }
47330ce7f44SFelix Fietkau 
474*d71ef286SFelix Fietkau static void
475*d71ef286SFelix Fietkau mt76_check_ps(struct mt76_dev *dev, struct sk_buff *skb)
476*d71ef286SFelix Fietkau {
477*d71ef286SFelix Fietkau 	struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb;
478*d71ef286SFelix Fietkau 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
479*d71ef286SFelix Fietkau 	struct ieee80211_sta *sta;
480*d71ef286SFelix Fietkau 	struct mt76_wcid *wcid = status->wcid;
481*d71ef286SFelix Fietkau 	bool ps;
482*d71ef286SFelix Fietkau 
483*d71ef286SFelix Fietkau 	if (!wcid || !wcid->sta)
484*d71ef286SFelix Fietkau 		return;
485*d71ef286SFelix Fietkau 
486*d71ef286SFelix Fietkau 	sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv);
487*d71ef286SFelix Fietkau 
488*d71ef286SFelix Fietkau 	if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
489*d71ef286SFelix Fietkau 		return;
490*d71ef286SFelix Fietkau 
491*d71ef286SFelix Fietkau 	if (ieee80211_is_pspoll(hdr->frame_control)) {
492*d71ef286SFelix Fietkau 		ieee80211_sta_pspoll(sta);
493*d71ef286SFelix Fietkau 		return;
494*d71ef286SFelix Fietkau 	}
495*d71ef286SFelix Fietkau 
496*d71ef286SFelix Fietkau 	if (ieee80211_has_morefrags(hdr->frame_control) ||
497*d71ef286SFelix Fietkau 		!(ieee80211_is_mgmt(hdr->frame_control) ||
498*d71ef286SFelix Fietkau 		  ieee80211_is_data(hdr->frame_control)))
499*d71ef286SFelix Fietkau 		return;
500*d71ef286SFelix Fietkau 
501*d71ef286SFelix Fietkau 	ps = ieee80211_has_pm(hdr->frame_control);
502*d71ef286SFelix Fietkau 
503*d71ef286SFelix Fietkau 	if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
504*d71ef286SFelix Fietkau 		   ieee80211_is_qos_nullfunc(hdr->frame_control)))
505*d71ef286SFelix Fietkau 		ieee80211_sta_uapsd_trigger(sta, status->tid);
506*d71ef286SFelix Fietkau 
507*d71ef286SFelix Fietkau 	if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
508*d71ef286SFelix Fietkau 		return;
509*d71ef286SFelix Fietkau 
510*d71ef286SFelix Fietkau 	if (ps) {
511*d71ef286SFelix Fietkau 		set_bit(MT_WCID_FLAG_PS, &wcid->flags);
512*d71ef286SFelix Fietkau 		mt76_stop_tx_queues(dev, sta, true);
513*d71ef286SFelix Fietkau 	} else {
514*d71ef286SFelix Fietkau 		clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
515*d71ef286SFelix Fietkau 	}
516*d71ef286SFelix Fietkau 
517*d71ef286SFelix Fietkau 	ieee80211_sta_ps_transition(sta, ps);
518*d71ef286SFelix Fietkau 	dev->drv->sta_ps(dev, sta, ps);
519*d71ef286SFelix Fietkau }
520*d71ef286SFelix Fietkau 
5219d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
5229d9d738bSFelix Fietkau 		      int queue)
52317f1de56SFelix Fietkau {
5249d9d738bSFelix Fietkau 	struct napi_struct *napi = NULL;
5259c68a57bSFelix Fietkau 	struct ieee80211_sta *sta;
5269d9d738bSFelix Fietkau 	struct sk_buff *skb;
5279d9d738bSFelix Fietkau 
5289d9d738bSFelix Fietkau 	if (queue >= 0)
5299d9d738bSFelix Fietkau 	    napi = &dev->napi[queue];
5309d9d738bSFelix Fietkau 
5319d9d738bSFelix Fietkau 	while ((skb = __skb_dequeue(frames)) != NULL) {
53230ce7f44SFelix Fietkau 		if (mt76_check_ccmp_pn(skb)) {
53330ce7f44SFelix Fietkau 			dev_kfree_skb(skb);
53430ce7f44SFelix Fietkau 			continue;
53530ce7f44SFelix Fietkau 		}
53630ce7f44SFelix Fietkau 
5379d9d738bSFelix Fietkau 		sta = mt76_rx_convert(skb);
5389d9d738bSFelix Fietkau 		ieee80211_rx_napi(dev->hw, sta, skb, napi);
5399d9d738bSFelix Fietkau 	}
5409d9d738bSFelix Fietkau }
5419d9d738bSFelix Fietkau 
5429d9d738bSFelix Fietkau void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q)
5439d9d738bSFelix Fietkau {
544aee5b8cfSFelix Fietkau 	struct sk_buff_head frames;
54517f1de56SFelix Fietkau 	struct sk_buff *skb;
54617f1de56SFelix Fietkau 
547aee5b8cfSFelix Fietkau 	__skb_queue_head_init(&frames);
548aee5b8cfSFelix Fietkau 
549*d71ef286SFelix Fietkau 	while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
550*d71ef286SFelix Fietkau 		mt76_check_ps(dev, skb);
551aee5b8cfSFelix Fietkau 		mt76_rx_aggr_reorder(skb, &frames);
552*d71ef286SFelix Fietkau 	}
553aee5b8cfSFelix Fietkau 
5549d9d738bSFelix Fietkau 	mt76_rx_complete(dev, &frames, q);
5554e34249eSFelix Fietkau }
556