10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau */
5781eef5bSFelix 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
23edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) { \
24edf9dab8SLorenzo Bianconi .band = NL80211_BAND_6GHZ, \
25edf9dab8SLorenzo Bianconi .center_freq = (_freq), \
26edf9dab8SLorenzo Bianconi .hw_value = (_idx), \
27edf9dab8SLorenzo Bianconi .max_power = 30, \
28edf9dab8SLorenzo Bianconi }
29edf9dab8SLorenzo Bianconi
3017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = {
3117f1de56SFelix Fietkau CHAN2G(1, 2412),
3217f1de56SFelix Fietkau CHAN2G(2, 2417),
3317f1de56SFelix Fietkau CHAN2G(3, 2422),
3417f1de56SFelix Fietkau CHAN2G(4, 2427),
3517f1de56SFelix Fietkau CHAN2G(5, 2432),
3617f1de56SFelix Fietkau CHAN2G(6, 2437),
3717f1de56SFelix Fietkau CHAN2G(7, 2442),
3817f1de56SFelix Fietkau CHAN2G(8, 2447),
3917f1de56SFelix Fietkau CHAN2G(9, 2452),
4017f1de56SFelix Fietkau CHAN2G(10, 2457),
4117f1de56SFelix Fietkau CHAN2G(11, 2462),
4217f1de56SFelix Fietkau CHAN2G(12, 2467),
4317f1de56SFelix Fietkau CHAN2G(13, 2472),
4417f1de56SFelix Fietkau CHAN2G(14, 2484),
4517f1de56SFelix Fietkau };
4617f1de56SFelix Fietkau
4717f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = {
4817f1de56SFelix Fietkau CHAN5G(36, 5180),
4917f1de56SFelix Fietkau CHAN5G(40, 5200),
5017f1de56SFelix Fietkau CHAN5G(44, 5220),
5117f1de56SFelix Fietkau CHAN5G(48, 5240),
5217f1de56SFelix Fietkau
5317f1de56SFelix Fietkau CHAN5G(52, 5260),
5417f1de56SFelix Fietkau CHAN5G(56, 5280),
5517f1de56SFelix Fietkau CHAN5G(60, 5300),
5617f1de56SFelix Fietkau CHAN5G(64, 5320),
5717f1de56SFelix Fietkau
5817f1de56SFelix Fietkau CHAN5G(100, 5500),
5917f1de56SFelix Fietkau CHAN5G(104, 5520),
6017f1de56SFelix Fietkau CHAN5G(108, 5540),
6117f1de56SFelix Fietkau CHAN5G(112, 5560),
6217f1de56SFelix Fietkau CHAN5G(116, 5580),
6317f1de56SFelix Fietkau CHAN5G(120, 5600),
6417f1de56SFelix Fietkau CHAN5G(124, 5620),
6517f1de56SFelix Fietkau CHAN5G(128, 5640),
6617f1de56SFelix Fietkau CHAN5G(132, 5660),
6717f1de56SFelix Fietkau CHAN5G(136, 5680),
6817f1de56SFelix Fietkau CHAN5G(140, 5700),
699da82fb7SMarkus Theil CHAN5G(144, 5720),
7017f1de56SFelix Fietkau
7117f1de56SFelix Fietkau CHAN5G(149, 5745),
7217f1de56SFelix Fietkau CHAN5G(153, 5765),
7317f1de56SFelix Fietkau CHAN5G(157, 5785),
7417f1de56SFelix Fietkau CHAN5G(161, 5805),
7517f1de56SFelix Fietkau CHAN5G(165, 5825),
769da82fb7SMarkus Theil CHAN5G(169, 5845),
779da82fb7SMarkus Theil CHAN5G(173, 5865),
7862561a47SRyder Lee CHAN5G(177, 5885),
7917f1de56SFelix Fietkau };
8017f1de56SFelix Fietkau
81edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = {
82edf9dab8SLorenzo Bianconi /* UNII-5 */
83edf9dab8SLorenzo Bianconi CHAN6G(1, 5955),
84edf9dab8SLorenzo Bianconi CHAN6G(5, 5975),
85edf9dab8SLorenzo Bianconi CHAN6G(9, 5995),
86edf9dab8SLorenzo Bianconi CHAN6G(13, 6015),
87edf9dab8SLorenzo Bianconi CHAN6G(17, 6035),
88edf9dab8SLorenzo Bianconi CHAN6G(21, 6055),
89edf9dab8SLorenzo Bianconi CHAN6G(25, 6075),
90edf9dab8SLorenzo Bianconi CHAN6G(29, 6095),
91edf9dab8SLorenzo Bianconi CHAN6G(33, 6115),
92edf9dab8SLorenzo Bianconi CHAN6G(37, 6135),
93edf9dab8SLorenzo Bianconi CHAN6G(41, 6155),
94edf9dab8SLorenzo Bianconi CHAN6G(45, 6175),
95edf9dab8SLorenzo Bianconi CHAN6G(49, 6195),
96edf9dab8SLorenzo Bianconi CHAN6G(53, 6215),
97edf9dab8SLorenzo Bianconi CHAN6G(57, 6235),
98edf9dab8SLorenzo Bianconi CHAN6G(61, 6255),
99edf9dab8SLorenzo Bianconi CHAN6G(65, 6275),
100edf9dab8SLorenzo Bianconi CHAN6G(69, 6295),
101edf9dab8SLorenzo Bianconi CHAN6G(73, 6315),
102edf9dab8SLorenzo Bianconi CHAN6G(77, 6335),
103edf9dab8SLorenzo Bianconi CHAN6G(81, 6355),
104edf9dab8SLorenzo Bianconi CHAN6G(85, 6375),
105edf9dab8SLorenzo Bianconi CHAN6G(89, 6395),
106edf9dab8SLorenzo Bianconi CHAN6G(93, 6415),
107edf9dab8SLorenzo Bianconi /* UNII-6 */
108edf9dab8SLorenzo Bianconi CHAN6G(97, 6435),
109edf9dab8SLorenzo Bianconi CHAN6G(101, 6455),
110edf9dab8SLorenzo Bianconi CHAN6G(105, 6475),
111edf9dab8SLorenzo Bianconi CHAN6G(109, 6495),
112edf9dab8SLorenzo Bianconi CHAN6G(113, 6515),
113edf9dab8SLorenzo Bianconi CHAN6G(117, 6535),
114edf9dab8SLorenzo Bianconi /* UNII-7 */
115edf9dab8SLorenzo Bianconi CHAN6G(121, 6555),
116edf9dab8SLorenzo Bianconi CHAN6G(125, 6575),
117edf9dab8SLorenzo Bianconi CHAN6G(129, 6595),
118edf9dab8SLorenzo Bianconi CHAN6G(133, 6615),
119edf9dab8SLorenzo Bianconi CHAN6G(137, 6635),
120edf9dab8SLorenzo Bianconi CHAN6G(141, 6655),
121edf9dab8SLorenzo Bianconi CHAN6G(145, 6675),
122edf9dab8SLorenzo Bianconi CHAN6G(149, 6695),
123edf9dab8SLorenzo Bianconi CHAN6G(153, 6715),
124edf9dab8SLorenzo Bianconi CHAN6G(157, 6735),
125edf9dab8SLorenzo Bianconi CHAN6G(161, 6755),
126edf9dab8SLorenzo Bianconi CHAN6G(165, 6775),
127edf9dab8SLorenzo Bianconi CHAN6G(169, 6795),
128edf9dab8SLorenzo Bianconi CHAN6G(173, 6815),
129edf9dab8SLorenzo Bianconi CHAN6G(177, 6835),
130edf9dab8SLorenzo Bianconi CHAN6G(181, 6855),
131edf9dab8SLorenzo Bianconi CHAN6G(185, 6875),
132edf9dab8SLorenzo Bianconi /* UNII-8 */
133edf9dab8SLorenzo Bianconi CHAN6G(189, 6895),
134edf9dab8SLorenzo Bianconi CHAN6G(193, 6915),
135edf9dab8SLorenzo Bianconi CHAN6G(197, 6935),
136edf9dab8SLorenzo Bianconi CHAN6G(201, 6955),
137edf9dab8SLorenzo Bianconi CHAN6G(205, 6975),
138edf9dab8SLorenzo Bianconi CHAN6G(209, 6995),
139edf9dab8SLorenzo Bianconi CHAN6G(213, 7015),
140edf9dab8SLorenzo Bianconi CHAN6G(217, 7035),
141edf9dab8SLorenzo Bianconi CHAN6G(221, 7055),
142edf9dab8SLorenzo Bianconi CHAN6G(225, 7075),
143edf9dab8SLorenzo Bianconi CHAN6G(229, 7095),
144edf9dab8SLorenzo Bianconi CHAN6G(233, 7115),
145edf9dab8SLorenzo Bianconi };
146edf9dab8SLorenzo Bianconi
14717f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
14817f1de56SFelix Fietkau { .throughput = 0 * 1024, .blink_time = 334 },
14917f1de56SFelix Fietkau { .throughput = 1 * 1024, .blink_time = 260 },
15017f1de56SFelix Fietkau { .throughput = 5 * 1024, .blink_time = 220 },
15117f1de56SFelix Fietkau { .throughput = 10 * 1024, .blink_time = 190 },
15217f1de56SFelix Fietkau { .throughput = 20 * 1024, .blink_time = 170 },
15317f1de56SFelix Fietkau { .throughput = 50 * 1024, .blink_time = 150 },
15417f1de56SFelix Fietkau { .throughput = 70 * 1024, .blink_time = 130 },
15517f1de56SFelix Fietkau { .throughput = 100 * 1024, .blink_time = 110 },
15617f1de56SFelix Fietkau { .throughput = 200 * 1024, .blink_time = 80 },
15717f1de56SFelix Fietkau { .throughput = 300 * 1024, .blink_time = 50 },
15817f1de56SFelix Fietkau };
15917f1de56SFelix Fietkau
16054b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = {
16154b8fdebSLorenzo Bianconi CCK_RATE(0, 10),
16254b8fdebSLorenzo Bianconi CCK_RATE(1, 20),
16354b8fdebSLorenzo Bianconi CCK_RATE(2, 55),
16454b8fdebSLorenzo Bianconi CCK_RATE(3, 110),
16554b8fdebSLorenzo Bianconi OFDM_RATE(11, 60),
16654b8fdebSLorenzo Bianconi OFDM_RATE(15, 90),
16754b8fdebSLorenzo Bianconi OFDM_RATE(10, 120),
16854b8fdebSLorenzo Bianconi OFDM_RATE(14, 180),
16954b8fdebSLorenzo Bianconi OFDM_RATE(9, 240),
17054b8fdebSLorenzo Bianconi OFDM_RATE(13, 360),
17154b8fdebSLorenzo Bianconi OFDM_RATE(8, 480),
17254b8fdebSLorenzo Bianconi OFDM_RATE(12, 540),
17354b8fdebSLorenzo Bianconi };
17454b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates);
17554b8fdebSLorenzo Bianconi
176502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
177502604f5SYN Chen { .start_freq = 2402, .end_freq = 2494, },
178502604f5SYN Chen { .start_freq = 5150, .end_freq = 5350, },
179502604f5SYN Chen { .start_freq = 5350, .end_freq = 5470, },
180502604f5SYN Chen { .start_freq = 5470, .end_freq = 5725, },
181502604f5SYN Chen { .start_freq = 5725, .end_freq = 5950, },
182162d5c14SDeren Wu { .start_freq = 5945, .end_freq = 6165, },
183162d5c14SDeren Wu { .start_freq = 6165, .end_freq = 6405, },
184162d5c14SDeren Wu { .start_freq = 6405, .end_freq = 6525, },
185162d5c14SDeren Wu { .start_freq = 6525, .end_freq = 6705, },
186162d5c14SDeren Wu { .start_freq = 6705, .end_freq = 6865, },
187162d5c14SDeren Wu { .start_freq = 6865, .end_freq = 7125, },
188502604f5SYN Chen };
189502604f5SYN Chen
19097f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = {
191502604f5SYN Chen .type = NL80211_SAR_TYPE_POWER,
192502604f5SYN Chen .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
193502604f5SYN Chen .freq_ranges = &mt76_sar_freq_ranges[0],
194502604f5SYN Chen };
195502604f5SYN Chen
mt76_led_init(struct mt76_phy * phy)1963abd46ddSLorenzo Bianconi static int mt76_led_init(struct mt76_phy *phy)
19717f1de56SFelix Fietkau {
1983abd46ddSLorenzo Bianconi struct mt76_dev *dev = phy->dev;
1993abd46ddSLorenzo Bianconi struct ieee80211_hw *hw = phy->hw;
20017f1de56SFelix Fietkau
2013abd46ddSLorenzo Bianconi if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
20217f1de56SFelix Fietkau return 0;
20317f1de56SFelix Fietkau
2043abd46ddSLorenzo Bianconi snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
2053abd46ddSLorenzo Bianconi wiphy_name(hw->wiphy));
20617f1de56SFelix Fietkau
2073abd46ddSLorenzo Bianconi phy->leds.cdev.name = phy->leds.name;
2083abd46ddSLorenzo Bianconi phy->leds.cdev.default_trigger =
20917f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw,
21017f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO,
21117f1de56SFelix Fietkau mt76_tpt_blink,
21217f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink));
21317f1de56SFelix Fietkau
2143abd46ddSLorenzo Bianconi if (phy == &dev->phy) {
2153abd46ddSLorenzo Bianconi struct device_node *np = dev->dev->of_node;
2163abd46ddSLorenzo Bianconi
21717f1de56SFelix Fietkau np = of_get_child_by_name(np, "led");
21817f1de56SFelix Fietkau if (np) {
2193abd46ddSLorenzo Bianconi int led_pin;
2203abd46ddSLorenzo Bianconi
22117f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin))
2223abd46ddSLorenzo Bianconi phy->leds.pin = led_pin;
2233abd46ddSLorenzo Bianconi phy->leds.al = of_property_read_bool(np,
2243abd46ddSLorenzo Bianconi "led-active-low");
2250a14c1d0SLiang He of_node_put(np);
22617f1de56SFelix Fietkau }
22736f7e2b2SFelix Fietkau }
22836f7e2b2SFelix Fietkau
2293abd46ddSLorenzo Bianconi return led_classdev_register(dev->dev, &phy->leds.cdev);
2303abd46ddSLorenzo Bianconi }
2313abd46ddSLorenzo Bianconi
mt76_led_cleanup(struct mt76_phy * phy)2323abd46ddSLorenzo Bianconi static void mt76_led_cleanup(struct mt76_phy *phy)
23336f7e2b2SFelix Fietkau {
2343abd46ddSLorenzo Bianconi if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
23536f7e2b2SFelix Fietkau return;
23636f7e2b2SFelix Fietkau
2373abd46ddSLorenzo Bianconi led_classdev_unregister(&phy->leds.cdev);
23817f1de56SFelix Fietkau }
23917f1de56SFelix Fietkau
mt76_init_stream_cap(struct mt76_phy * phy,struct ieee80211_supported_band * sband,bool vht)240bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy,
241551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband,
242551e1ef4SLorenzo Bianconi bool vht)
243551e1ef4SLorenzo Bianconi {
244551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
245bb3e3fecSRyder Lee int i, nstream = hweight8(phy->antenna_mask);
246551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap;
247551e1ef4SLorenzo Bianconi u16 mcs_map = 0;
248551e1ef4SLorenzo Bianconi
249551e1ef4SLorenzo Bianconi if (nstream > 1)
250551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
251551e1ef4SLorenzo Bianconi else
252551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
253551e1ef4SLorenzo Bianconi
254551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
255551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
256551e1ef4SLorenzo Bianconi
257551e1ef4SLorenzo Bianconi if (!vht)
258551e1ef4SLorenzo Bianconi return;
259551e1ef4SLorenzo Bianconi
260551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap;
261551e1ef4SLorenzo Bianconi if (nstream > 1)
262551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
263551e1ef4SLorenzo Bianconi else
264551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
265abba3453SDeren Wu vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
266abba3453SDeren Wu IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
267551e1ef4SLorenzo Bianconi
268551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) {
269551e1ef4SLorenzo Bianconi if (i < nstream)
270551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
271551e1ef4SLorenzo Bianconi else
272551e1ef4SLorenzo Bianconi mcs_map |=
273551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
274551e1ef4SLorenzo Bianconi }
275551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
276551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
277781b80f4SFelix Fietkau if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
278d9fcfc14SDeren Wu vht_cap->vht_mcs.tx_highest |=
279d9fcfc14SDeren Wu cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
280551e1ef4SLorenzo Bianconi }
281551e1ef4SLorenzo Bianconi
mt76_set_stream_caps(struct mt76_phy * phy,bool vht)282bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
2835ebdc3e0SLorenzo Bianconi {
28448dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz)
285bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
28648dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz)
287bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
288edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz)
289edf9dab8SLorenzo Bianconi mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
2905ebdc3e0SLorenzo Bianconi }
2915ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
2925ebdc3e0SLorenzo Bianconi
29317f1de56SFelix Fietkau static int
mt76_init_sband(struct mt76_phy * phy,struct mt76_sband * msband,const struct ieee80211_channel * chan,int n_chan,struct ieee80211_rate * rates,int n_rates,bool ht,bool vht)29477af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
29517f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan,
296edf9dab8SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates,
297edf9dab8SLorenzo Bianconi bool ht, bool vht)
29817f1de56SFelix Fietkau {
29917f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband;
30017f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap;
30177af762eSLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap;
30277af762eSLorenzo Bianconi struct mt76_dev *dev = phy->dev;
30317f1de56SFelix Fietkau void *chanlist;
30417f1de56SFelix Fietkau int size;
30517f1de56SFelix Fietkau
30617f1de56SFelix Fietkau size = n_chan * sizeof(*chan);
30717f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
30817f1de56SFelix Fietkau if (!chanlist)
30917f1de56SFelix Fietkau return -ENOMEM;
31017f1de56SFelix Fietkau
311a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
31217f1de56SFelix Fietkau GFP_KERNEL);
31317f1de56SFelix Fietkau if (!msband->chan)
31417f1de56SFelix Fietkau return -ENOMEM;
31517f1de56SFelix Fietkau
31617f1de56SFelix Fietkau sband->channels = chanlist;
31717f1de56SFelix Fietkau sband->n_channels = n_chan;
31817f1de56SFelix Fietkau sband->bitrates = rates;
31917f1de56SFelix Fietkau sband->n_bitrates = n_rates;
32017f1de56SFelix Fietkau
321edf9dab8SLorenzo Bianconi if (!ht)
322edf9dab8SLorenzo Bianconi return 0;
323edf9dab8SLorenzo Bianconi
32417f1de56SFelix Fietkau ht_cap = &sband->ht_cap;
32517f1de56SFelix Fietkau ht_cap->ht_supported = true;
32617f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
32717f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD |
32817f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 |
32917f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 |
33017f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
33117f1de56SFelix Fietkau
33217f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
33317f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
33417f1de56SFelix Fietkau
33577af762eSLorenzo Bianconi mt76_init_stream_cap(phy, sband, vht);
336551e1ef4SLorenzo Bianconi
33717f1de56SFelix Fietkau if (!vht)
33817f1de56SFelix Fietkau return 0;
33917f1de56SFelix Fietkau
34017f1de56SFelix Fietkau vht_cap = &sband->vht_cap;
34117f1de56SFelix Fietkau vht_cap->vht_supported = true;
34217f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
34317f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 |
34449149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 |
34549149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
34617f1de56SFelix Fietkau
34717f1de56SFelix Fietkau return 0;
34817f1de56SFelix Fietkau }
34917f1de56SFelix Fietkau
35017f1de56SFelix Fietkau static int
mt76_init_sband_2g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)35177af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
35217f1de56SFelix Fietkau int n_rates)
35317f1de56SFelix Fietkau {
35477af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
35517f1de56SFelix Fietkau
35677af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
35777af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_2ghz), rates,
358edf9dab8SLorenzo Bianconi n_rates, true, false);
35917f1de56SFelix Fietkau }
36017f1de56SFelix Fietkau
36117f1de56SFelix Fietkau static int
mt76_init_sband_5g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates,bool vht)36277af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
36317f1de56SFelix Fietkau int n_rates, bool vht)
36417f1de56SFelix Fietkau {
36577af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
36617f1de56SFelix Fietkau
36777af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
36877af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_5ghz), rates,
369edf9dab8SLorenzo Bianconi n_rates, true, vht);
370edf9dab8SLorenzo Bianconi }
371edf9dab8SLorenzo Bianconi
372edf9dab8SLorenzo Bianconi static int
mt76_init_sband_6g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)373edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
374edf9dab8SLorenzo Bianconi int n_rates)
375edf9dab8SLorenzo Bianconi {
376edf9dab8SLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
377edf9dab8SLorenzo Bianconi
378edf9dab8SLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
379edf9dab8SLorenzo Bianconi ARRAY_SIZE(mt76_channels_6ghz), rates,
380edf9dab8SLorenzo Bianconi n_rates, false, false);
38117f1de56SFelix Fietkau }
38217f1de56SFelix Fietkau
38317f1de56SFelix Fietkau static void
mt76_check_sband(struct mt76_phy * phy,struct mt76_sband * msband,enum nl80211_band band)384c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
385c89d3625SFelix Fietkau enum nl80211_band band)
38617f1de56SFelix Fietkau {
387c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband;
38817f1de56SFelix Fietkau bool found = false;
38917f1de56SFelix Fietkau int i;
39017f1de56SFelix Fietkau
39117f1de56SFelix Fietkau if (!sband)
39217f1de56SFelix Fietkau return;
39317f1de56SFelix Fietkau
39417f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) {
39517f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
39617f1de56SFelix Fietkau continue;
39717f1de56SFelix Fietkau
39817f1de56SFelix Fietkau found = true;
39917f1de56SFelix Fietkau break;
40017f1de56SFelix Fietkau }
40117f1de56SFelix Fietkau
402c89d3625SFelix Fietkau if (found) {
403c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0];
404c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0];
40517f1de56SFelix Fietkau return;
406c89d3625SFelix Fietkau }
40717f1de56SFelix Fietkau
40817f1de56SFelix Fietkau sband->n_channels = 0;
409c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL;
41017f1de56SFelix Fietkau }
41117f1de56SFelix Fietkau
412d43de9cfSLorenzo Bianconi static int
mt76_phy_init(struct mt76_phy * phy,struct ieee80211_hw * hw)41398df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
414c89d3625SFelix Fietkau {
41598df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev;
416c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy;
417c89d3625SFelix Fietkau
418d2defcddSFelix Fietkau INIT_LIST_HEAD(&phy->tx_list);
419d2defcddSFelix Fietkau spin_lock_init(&phy->tx_lock);
420d2defcddSFelix Fietkau
421c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev);
42298df2baeSLorenzo Bianconi SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
423c89d3625SFelix Fietkau
424c278a64aSRyder Lee wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
425c278a64aSRyder Lee NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
426dd89a013SLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
427b807b368SLorenzo Bianconi WIPHY_FLAG_SUPPORTS_TDLS |
428b807b368SLorenzo Bianconi WIPHY_FLAG_AP_UAPSD;
429c89d3625SFelix Fietkau
430c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
431c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
432d9c54264SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
433c89d3625SFelix Fietkau
4340a57d636SBo Jiao wiphy->available_antennas_tx = phy->antenna_mask;
4350a57d636SBo Jiao wiphy->available_antennas_rx = phy->antenna_mask;
436c89d3625SFelix Fietkau
437d43de9cfSLorenzo Bianconi wiphy->sar_capa = &mt76_sar_capa;
438d43de9cfSLorenzo Bianconi phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
439d43de9cfSLorenzo Bianconi sizeof(struct mt76_freq_range_power),
440d43de9cfSLorenzo Bianconi GFP_KERNEL);
441d43de9cfSLorenzo Bianconi if (!phy->frp)
442d43de9cfSLorenzo Bianconi return -ENOMEM;
443d43de9cfSLorenzo Bianconi
444c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq);
445b807b368SLorenzo Bianconi hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
446c9619dfaSShayne Chen
447c9619dfaSShayne Chen if (!hw->max_tx_fragments)
448c89d3625SFelix Fietkau hw->max_tx_fragments = 16;
449c89d3625SFelix Fietkau
450c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM);
451c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION);
452c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
453c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
454c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
455c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
456ed89b893SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
4575b0fb852SBen Greear
4585b0fb852SBen Greear if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
459c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU);
460c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST);
4615b0fb852SBen Greear }
4625b0fb852SBen Greear
463c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE);
464c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS);
465c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
466d43de9cfSLorenzo Bianconi
467d43de9cfSLorenzo Bianconi return 0;
468c89d3625SFelix Fietkau }
469c89d3625SFelix Fietkau
470c89d3625SFelix Fietkau struct mt76_phy *
mt76_alloc_phy(struct mt76_dev * dev,unsigned int size,const struct ieee80211_ops * ops,u8 band_idx)471c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
472dc44c45cSLorenzo Bianconi const struct ieee80211_ops *ops, u8 band_idx)
473c89d3625SFelix Fietkau {
474c89d3625SFelix Fietkau struct ieee80211_hw *hw;
475db78a791SLorenzo Bianconi unsigned int phy_size;
476c89d3625SFelix Fietkau struct mt76_phy *phy;
477c89d3625SFelix Fietkau
478c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8);
479db78a791SLorenzo Bianconi hw = ieee80211_alloc_hw(size + phy_size, ops);
480c89d3625SFelix Fietkau if (!hw)
481c89d3625SFelix Fietkau return NULL;
482c89d3625SFelix Fietkau
483c89d3625SFelix Fietkau phy = hw->priv;
484c89d3625SFelix Fietkau phy->dev = dev;
485c89d3625SFelix Fietkau phy->hw = hw;
486db78a791SLorenzo Bianconi phy->priv = hw->priv + phy_size;
487dc44c45cSLorenzo Bianconi phy->band_idx = band_idx;
488c89d3625SFelix Fietkau
4898af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
4908af414e8SLorenzo Bianconi hw->wiphy->interface_modes =
4918af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) |
4928af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) |
4938af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
4948af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) |
4958af414e8SLorenzo Bianconi #endif
4968af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) |
4978af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) |
4988af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC);
4998af414e8SLorenzo Bianconi
500c89d3625SFelix Fietkau return phy;
501c89d3625SFelix Fietkau }
502c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy);
503c89d3625SFelix Fietkau
mt76_register_phy(struct mt76_phy * phy,bool vht,struct ieee80211_rate * rates,int n_rates)504db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht,
505db78a791SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates)
506c89d3625SFelix Fietkau {
507c89d3625SFelix Fietkau int ret;
508c89d3625SFelix Fietkau
509d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, phy->hw);
510d43de9cfSLorenzo Bianconi if (ret)
511d43de9cfSLorenzo Bianconi return ret;
512db78a791SLorenzo Bianconi
513db78a791SLorenzo Bianconi if (phy->cap.has_2ghz) {
514db78a791SLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates);
515db78a791SLorenzo Bianconi if (ret)
516db78a791SLorenzo Bianconi return ret;
517db78a791SLorenzo Bianconi }
518db78a791SLorenzo Bianconi
519db78a791SLorenzo Bianconi if (phy->cap.has_5ghz) {
520db78a791SLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
521db78a791SLorenzo Bianconi if (ret)
522db78a791SLorenzo Bianconi return ret;
523db78a791SLorenzo Bianconi }
524db78a791SLorenzo Bianconi
525edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) {
526edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
527edf9dab8SLorenzo Bianconi if (ret)
528edf9dab8SLorenzo Bianconi return ret;
529edf9dab8SLorenzo Bianconi }
530edf9dab8SLorenzo Bianconi
5319e81c2c7SLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS)) {
5329e81c2c7SLorenzo Bianconi ret = mt76_led_init(phy);
5339e81c2c7SLorenzo Bianconi if (ret)
5349e81c2c7SLorenzo Bianconi return ret;
5359e81c2c7SLorenzo Bianconi }
5369e81c2c7SLorenzo Bianconi
537db78a791SLorenzo Bianconi wiphy_read_of_freq_limits(phy->hw->wiphy);
538db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
539db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
540edf9dab8SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
541db78a791SLorenzo Bianconi
542c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw);
543c89d3625SFelix Fietkau if (ret)
544c89d3625SFelix Fietkau return ret;
545c89d3625SFelix Fietkau
54641130c32SLorenzo Bianconi set_bit(MT76_STATE_REGISTERED, &phy->state);
547dc44c45cSLorenzo Bianconi phy->dev->phys[phy->band_idx] = phy;
548db78a791SLorenzo Bianconi
549c89d3625SFelix Fietkau return 0;
550c89d3625SFelix Fietkau }
551c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy);
552c89d3625SFelix Fietkau
mt76_unregister_phy(struct mt76_phy * phy)553db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy)
554c89d3625SFelix Fietkau {
555c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev;
556c89d3625SFelix Fietkau
55741130c32SLorenzo Bianconi if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
55841130c32SLorenzo Bianconi return;
55941130c32SLorenzo Bianconi
5609e81c2c7SLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS))
5619e81c2c7SLorenzo Bianconi mt76_led_cleanup(phy);
562c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true);
563c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw);
564dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = NULL;
565c89d3625SFelix Fietkau }
566c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy);
567c89d3625SFelix Fietkau
mt76_create_page_pool(struct mt76_dev * dev,struct mt76_queue * q)5682f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
5692f5c3c77SLorenzo Bianconi {
5702f5c3c77SLorenzo Bianconi struct page_pool_params pp_params = {
5712f5c3c77SLorenzo Bianconi .order = 0,
5722f5c3c77SLorenzo Bianconi .flags = PP_FLAG_PAGE_FRAG,
5732f5c3c77SLorenzo Bianconi .nid = NUMA_NO_NODE,
5742f5c3c77SLorenzo Bianconi .dev = dev->dma_dev,
5752f5c3c77SLorenzo Bianconi };
5762f5c3c77SLorenzo Bianconi int idx = q - dev->q_rx;
5772f5c3c77SLorenzo Bianconi
5782f5c3c77SLorenzo Bianconi switch (idx) {
5792f5c3c77SLorenzo Bianconi case MT_RXQ_MAIN:
5802f5c3c77SLorenzo Bianconi case MT_RXQ_BAND1:
5812f5c3c77SLorenzo Bianconi case MT_RXQ_BAND2:
5822f5c3c77SLorenzo Bianconi pp_params.pool_size = 256;
5832f5c3c77SLorenzo Bianconi break;
5842f5c3c77SLorenzo Bianconi default:
5852f5c3c77SLorenzo Bianconi pp_params.pool_size = 16;
5862f5c3c77SLorenzo Bianconi break;
5872f5c3c77SLorenzo Bianconi }
5882f5c3c77SLorenzo Bianconi
5892f5c3c77SLorenzo Bianconi if (mt76_is_mmio(dev)) {
5902f5c3c77SLorenzo Bianconi /* rely on page_pool for DMA mapping */
5912f5c3c77SLorenzo Bianconi pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
5922f5c3c77SLorenzo Bianconi pp_params.dma_dir = DMA_FROM_DEVICE;
5932f5c3c77SLorenzo Bianconi pp_params.max_len = PAGE_SIZE;
5942f5c3c77SLorenzo Bianconi pp_params.offset = 0;
5952f5c3c77SLorenzo Bianconi }
5962f5c3c77SLorenzo Bianconi
5972f5c3c77SLorenzo Bianconi q->page_pool = page_pool_create(&pp_params);
5982f5c3c77SLorenzo Bianconi if (IS_ERR(q->page_pool)) {
5992f5c3c77SLorenzo Bianconi int err = PTR_ERR(q->page_pool);
6002f5c3c77SLorenzo Bianconi
6012f5c3c77SLorenzo Bianconi q->page_pool = NULL;
6022f5c3c77SLorenzo Bianconi return err;
6032f5c3c77SLorenzo Bianconi }
6042f5c3c77SLorenzo Bianconi
6052f5c3c77SLorenzo Bianconi return 0;
6062f5c3c77SLorenzo Bianconi }
6072f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool);
6082f5c3c77SLorenzo Bianconi
609a85b590cSFelix Fietkau struct mt76_dev *
mt76_alloc_device(struct device * pdev,unsigned int size,const struct ieee80211_ops * ops,const struct mt76_driver_ops * drv_ops)610c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size,
611c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops,
612c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops)
613a85b590cSFelix Fietkau {
614a85b590cSFelix Fietkau struct ieee80211_hw *hw;
615ac24dd35SFelix Fietkau struct mt76_phy *phy;
616a85b590cSFelix Fietkau struct mt76_dev *dev;
617e5443256SFelix Fietkau int i;
618a85b590cSFelix Fietkau
619a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops);
620a85b590cSFelix Fietkau if (!hw)
621a85b590cSFelix Fietkau return NULL;
622a85b590cSFelix Fietkau
623a85b590cSFelix Fietkau dev = hw->priv;
624a85b590cSFelix Fietkau dev->hw = hw;
625c0f7b25aSLorenzo Bianconi dev->dev = pdev;
626c0f7b25aSLorenzo Bianconi dev->drv = drv_ops;
627d1ddc536SFelix Fietkau dev->dma_dev = pdev;
628c0f7b25aSLorenzo Bianconi
629ac24dd35SFelix Fietkau phy = &dev->phy;
630ac24dd35SFelix Fietkau phy->dev = dev;
631ac24dd35SFelix Fietkau phy->hw = hw;
632dc44c45cSLorenzo Bianconi phy->band_idx = MT_BAND0;
633dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = phy;
634ac24dd35SFelix Fietkau
635a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock);
636a85b590cSFelix Fietkau spin_lock_init(&dev->lock);
637a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock);
638c34f1005SLorenzo Bianconi spin_lock_init(&dev->status_lock);
6392666beceSSujuan Chen spin_lock_init(&dev->wed_lock);
640108a4861SStanislaw Gruszka mutex_init(&dev->mutex);
64126e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait);
642a85b590cSFelix Fietkau
64309872957SLorenzo Bianconi skb_queue_head_init(&dev->mcu.res_q);
64409872957SLorenzo Bianconi init_waitqueue_head(&dev->mcu.wait);
64509872957SLorenzo Bianconi mutex_init(&dev->mcu.mutex);
646781eef5bSFelix Fietkau dev->tx_worker.fn = mt76_tx_worker;
64709872957SLorenzo Bianconi
6488af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
6498af414e8SLorenzo Bianconi hw->wiphy->interface_modes =
6508af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) |
6518af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) |
6528af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH
6538af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) |
6548af414e8SLorenzo Bianconi #endif
6558af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) |
6568af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) |
6578af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC);
6588af414e8SLorenzo Bianconi
65951252cc5SLorenzo Bianconi spin_lock_init(&dev->token_lock);
66051252cc5SLorenzo Bianconi idr_init(&dev->token);
66151252cc5SLorenzo Bianconi
6622666beceSSujuan Chen spin_lock_init(&dev->rx_token_lock);
6632666beceSSujuan Chen idr_init(&dev->rx_token);
6642666beceSSujuan Chen
665bd1e3e7bSLorenzo Bianconi INIT_LIST_HEAD(&dev->wcid_list);
666fbba711cSLorenzo Bianconi INIT_LIST_HEAD(&dev->sta_poll_list);
667fbba711cSLorenzo Bianconi spin_lock_init(&dev->sta_poll_lock);
668bd1e3e7bSLorenzo Bianconi
669e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache);
6702666beceSSujuan Chen INIT_LIST_HEAD(&dev->rxwi_cache);
67161b5156bSFelix Fietkau dev->token_size = dev->drv->token_size;
672e5443256SFelix Fietkau
673e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
674e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]);
675e5443256SFelix Fietkau
676a86f1d01SLorenzo Bianconi dev->wq = alloc_ordered_workqueue("mt76", 0);
677a86f1d01SLorenzo Bianconi if (!dev->wq) {
678a86f1d01SLorenzo Bianconi ieee80211_free_hw(hw);
679a86f1d01SLorenzo Bianconi return NULL;
680a86f1d01SLorenzo Bianconi }
681a86f1d01SLorenzo Bianconi
682a85b590cSFelix Fietkau return dev;
683a85b590cSFelix Fietkau }
684a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device);
685a85b590cSFelix Fietkau
mt76_register_device(struct mt76_dev * dev,bool vht,struct ieee80211_rate * rates,int n_rates)68617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht,
68717f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates)
68817f1de56SFelix Fietkau {
68917f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw;
690c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy;
69117f1de56SFelix Fietkau int ret;
69217f1de56SFelix Fietkau
69317f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev);
694d2defcddSFelix Fietkau mt76_wcid_init(&dev->global_wcid);
695d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, hw);
696d43de9cfSLorenzo Bianconi if (ret)
697d43de9cfSLorenzo Bianconi return ret;
69817f1de56SFelix Fietkau
69948dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) {
70077af762eSLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates);
70117f1de56SFelix Fietkau if (ret)
70217f1de56SFelix Fietkau return ret;
70317f1de56SFelix Fietkau }
70417f1de56SFelix Fietkau
70548dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) {
70677af762eSLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
70717f1de56SFelix Fietkau if (ret)
70817f1de56SFelix Fietkau return ret;
70917f1de56SFelix Fietkau }
71017f1de56SFelix Fietkau
711edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) {
712edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
713edf9dab8SLorenzo Bianconi if (ret)
714edf9dab8SLorenzo Bianconi return ret;
715edf9dab8SLorenzo Bianconi }
716edf9dab8SLorenzo Bianconi
717c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy);
718c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
719c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
720edf9dab8SLorenzo Bianconi mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
72117f1de56SFelix Fietkau
722b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) {
7233abd46ddSLorenzo Bianconi ret = mt76_led_init(phy);
72417f1de56SFelix Fietkau if (ret)
72517f1de56SFelix Fietkau return ret;
726b374e868SArnd Bergmann }
72717f1de56SFelix Fietkau
728781eef5bSFelix Fietkau ret = ieee80211_register_hw(hw);
729781eef5bSFelix Fietkau if (ret)
730781eef5bSFelix Fietkau return ret;
731781eef5bSFelix Fietkau
732781eef5bSFelix Fietkau WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
73341130c32SLorenzo Bianconi set_bit(MT76_STATE_REGISTERED, &phy->state);
734781eef5bSFelix Fietkau sched_set_fifo_low(dev->tx_worker.task);
735781eef5bSFelix Fietkau
736781eef5bSFelix Fietkau return 0;
73717f1de56SFelix Fietkau }
73817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device);
73917f1de56SFelix Fietkau
mt76_unregister_device(struct mt76_dev * dev)74017f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev)
74117f1de56SFelix Fietkau {
74217f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw;
74317f1de56SFelix Fietkau
74441130c32SLorenzo Bianconi if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
74541130c32SLorenzo Bianconi return;
74641130c32SLorenzo Bianconi
747d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS))
7483abd46ddSLorenzo Bianconi mt76_led_cleanup(&dev->phy);
749c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true);
750d2defcddSFelix Fietkau mt76_wcid_cleanup(dev, &dev->global_wcid);
75117f1de56SFelix Fietkau ieee80211_unregister_hw(hw);
75217f1de56SFelix Fietkau }
75317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device);
75417f1de56SFelix Fietkau
mt76_free_device(struct mt76_dev * dev)755def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev)
756def34a2fSLorenzo Bianconi {
757781eef5bSFelix Fietkau mt76_worker_teardown(&dev->tx_worker);
758a86f1d01SLorenzo Bianconi if (dev->wq) {
759a86f1d01SLorenzo Bianconi destroy_workqueue(dev->wq);
760a86f1d01SLorenzo Bianconi dev->wq = NULL;
761a86f1d01SLorenzo Bianconi }
762def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw);
763def34a2fSLorenzo Bianconi }
764def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device);
765def34a2fSLorenzo Bianconi
mt76_rx_release_amsdu(struct mt76_phy * phy,enum mt76_rxq_id q)766cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
767cc4b3c13SLorenzo Bianconi {
768cc4b3c13SLorenzo Bianconi struct sk_buff *skb = phy->rx_amsdu[q].head;
7692c2bdd23SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
770cc4b3c13SLorenzo Bianconi struct mt76_dev *dev = phy->dev;
771cc4b3c13SLorenzo Bianconi
772cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = NULL;
773cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = NULL;
7742c2bdd23SFelix Fietkau
7752c2bdd23SFelix Fietkau /*
7762c2bdd23SFelix Fietkau * Validate if the amsdu has a proper first subframe.
7772c2bdd23SFelix Fietkau * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
7782c2bdd23SFelix Fietkau * flag of the QoS header gets flipped. In such cases, the first
7792c2bdd23SFelix Fietkau * subframe has a LLC/SNAP header in the location of the destination
7802c2bdd23SFelix Fietkau * address.
7812c2bdd23SFelix Fietkau */
7822c2bdd23SFelix Fietkau if (skb_shinfo(skb)->frag_list) {
7832c2bdd23SFelix Fietkau int offset = 0;
7842c2bdd23SFelix Fietkau
7852c2bdd23SFelix Fietkau if (!(status->flag & RX_FLAG_8023)) {
7862c2bdd23SFelix Fietkau offset = ieee80211_get_hdrlen_from_skb(skb);
7872c2bdd23SFelix Fietkau
7882c2bdd23SFelix Fietkau if ((status->flag &
7892c2bdd23SFelix Fietkau (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
7902c2bdd23SFelix Fietkau RX_FLAG_DECRYPTED)
7912c2bdd23SFelix Fietkau offset += 8;
7922c2bdd23SFelix Fietkau }
7932c2bdd23SFelix Fietkau
7942c2bdd23SFelix Fietkau if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
7952c2bdd23SFelix Fietkau dev_kfree_skb(skb);
7962c2bdd23SFelix Fietkau return;
7972c2bdd23SFelix Fietkau }
7982c2bdd23SFelix Fietkau }
799cc4b3c13SLorenzo Bianconi __skb_queue_tail(&dev->rx_skb[q], skb);
800cc4b3c13SLorenzo Bianconi }
801cc4b3c13SLorenzo Bianconi
mt76_rx_release_burst(struct mt76_phy * phy,enum mt76_rxq_id q,struct sk_buff * skb)802cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
803cc4b3c13SLorenzo Bianconi struct sk_buff *skb)
804cc4b3c13SLorenzo Bianconi {
805cc4b3c13SLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
806cc4b3c13SLorenzo Bianconi
807cc4b3c13SLorenzo Bianconi if (phy->rx_amsdu[q].head &&
808cc4b3c13SLorenzo Bianconi (!status->amsdu || status->first_amsdu ||
809cc4b3c13SLorenzo Bianconi status->seqno != phy->rx_amsdu[q].seqno))
810cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q);
811cc4b3c13SLorenzo Bianconi
812cc4b3c13SLorenzo Bianconi if (!phy->rx_amsdu[q].head) {
813cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
814cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].seqno = status->seqno;
815cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = skb;
816cc4b3c13SLorenzo Bianconi } else {
817cc4b3c13SLorenzo Bianconi *phy->rx_amsdu[q].tail = skb;
818cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb->next;
819cc4b3c13SLorenzo Bianconi }
820cc4b3c13SLorenzo Bianconi
821cc4b3c13SLorenzo Bianconi if (!status->amsdu || status->last_amsdu)
822cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q);
823cc4b3c13SLorenzo Bianconi }
824cc4b3c13SLorenzo Bianconi
mt76_rx(struct mt76_dev * dev,enum mt76_rxq_id q,struct sk_buff * skb)82517f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
82617f1de56SFelix Fietkau {
827011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
828128c9b7dSLorenzo Bianconi struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
829011849e0SFelix Fietkau
830011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
83117f1de56SFelix Fietkau dev_kfree_skb(skb);
83217f1de56SFelix Fietkau return;
83317f1de56SFelix Fietkau }
83417f1de56SFelix Fietkau
835f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
836c918c74dSShayne Chen if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
837c918c74dSShayne Chen phy->test.rx_stats.packets[q]++;
838f0efa862SFelix Fietkau if (status->flag & RX_FLAG_FAILED_FCS_CRC)
839c918c74dSShayne Chen phy->test.rx_stats.fcs_error[q]++;
840f0efa862SFelix Fietkau }
841f0efa862SFelix Fietkau #endif
842cc4b3c13SLorenzo Bianconi
843cc4b3c13SLorenzo Bianconi mt76_rx_release_burst(phy, q, skb);
84417f1de56SFelix Fietkau }
84517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx);
84617f1de56SFelix Fietkau
mt76_has_tx_pending(struct mt76_phy * phy)8475a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy)
84826e40d4cSFelix Fietkau {
849af005f26SLorenzo Bianconi struct mt76_queue *q;
85091990519SLorenzo Bianconi int i;
8515a95ca41SFelix Fietkau
8525a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) {
85391990519SLorenzo Bianconi q = phy->q_tx[i];
854af005f26SLorenzo Bianconi if (q && q->queued)
85526e40d4cSFelix Fietkau return true;
85626e40d4cSFelix Fietkau }
85726e40d4cSFelix Fietkau
85826e40d4cSFelix Fietkau return false;
85926e40d4cSFelix Fietkau }
86039d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
86126e40d4cSFelix Fietkau
8620fd0eb54SFelix Fietkau static struct mt76_channel_state *
mt76_channel_state(struct mt76_phy * phy,struct ieee80211_channel * c)86396747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
8640fd0eb54SFelix Fietkau {
8650fd0eb54SFelix Fietkau struct mt76_sband *msband;
8660fd0eb54SFelix Fietkau int idx;
8670fd0eb54SFelix Fietkau
8680fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ)
86996747a51SFelix Fietkau msband = &phy->sband_2g;
870edf9dab8SLorenzo Bianconi else if (c->band == NL80211_BAND_6GHZ)
871edf9dab8SLorenzo Bianconi msband = &phy->sband_6g;
8720fd0eb54SFelix Fietkau else
87396747a51SFelix Fietkau msband = &phy->sband_5g;
8740fd0eb54SFelix Fietkau
8750fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0];
8760fd0eb54SFelix Fietkau return &msband->chan[idx];
8770fd0eb54SFelix Fietkau }
8780fd0eb54SFelix Fietkau
mt76_update_survey_active_time(struct mt76_phy * phy,ktime_t time)87904414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
88096747a51SFelix Fietkau {
88196747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state;
88296747a51SFelix Fietkau
88396747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time,
88496747a51SFelix Fietkau phy->survey_time));
88596747a51SFelix Fietkau phy->survey_time = time;
88696747a51SFelix Fietkau }
88704414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
88896747a51SFelix Fietkau
mt76_update_survey(struct mt76_phy * phy)889c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy)
8905ce09c1aSFelix Fietkau {
891c560b137SRyder Lee struct mt76_dev *dev = phy->dev;
892aec65e48SFelix Fietkau ktime_t cur_time;
893aec65e48SFelix Fietkau
8945ce09c1aSFelix Fietkau if (dev->drv->update_survey)
895c560b137SRyder Lee dev->drv->update_survey(phy);
8965ce09c1aSFelix Fietkau
897aec65e48SFelix Fietkau cur_time = ktime_get_boottime();
898c560b137SRyder Lee mt76_update_survey_active_time(phy, cur_time);
899aec65e48SFelix Fietkau
9005ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
901c560b137SRyder Lee struct mt76_channel_state *state = phy->chan_state;
90296747a51SFelix Fietkau
903237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock);
9045ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx;
9055ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0;
906237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock);
9075ce09c1aSFelix Fietkau }
9085ce09c1aSFelix Fietkau }
9095ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey);
9105ce09c1aSFelix Fietkau
mt76_set_channel(struct mt76_phy * phy)91196747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy)
91217f1de56SFelix Fietkau {
91396747a51SFelix Fietkau struct mt76_dev *dev = phy->dev;
91496747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw;
91517f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef;
91617f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
91726e40d4cSFelix Fietkau int timeout = HZ / 5;
91817f1de56SFelix Fietkau
9195a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
920c560b137SRyder Lee mt76_update_survey(phy);
92117f1de56SFelix Fietkau
9223f306448SFelix Fietkau if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
9233f306448SFelix Fietkau phy->chandef.width != chandef->width)
9243f306448SFelix Fietkau phy->dfs_state = MT_DFS_STATE_UNKNOWN;
9253f306448SFelix Fietkau
92696747a51SFelix Fietkau phy->chandef = *chandef;
92796747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan);
92817f1de56SFelix Fietkau
92917f1de56SFelix Fietkau if (!offchannel)
93096747a51SFelix Fietkau phy->main_chan = chandef->chan;
93117f1de56SFelix Fietkau
93296747a51SFelix Fietkau if (chandef->chan != phy->main_chan)
93396747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state));
93417f1de56SFelix Fietkau }
93517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel);
93617f1de56SFelix Fietkau
mt76_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)93717f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx,
93817f1de56SFelix Fietkau struct survey_info *survey)
93917f1de56SFelix Fietkau {
94096747a51SFelix Fietkau struct mt76_phy *phy = hw->priv;
94196747a51SFelix Fietkau struct mt76_dev *dev = phy->dev;
94217f1de56SFelix Fietkau struct mt76_sband *sband;
94317f1de56SFelix Fietkau struct ieee80211_channel *chan;
94417f1de56SFelix Fietkau struct mt76_channel_state *state;
94517f1de56SFelix Fietkau int ret = 0;
94617f1de56SFelix Fietkau
947237312c5SLorenzo Bianconi mutex_lock(&dev->mutex);
94817f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey)
949c560b137SRyder Lee mt76_update_survey(phy);
95017f1de56SFelix Fietkau
951edf9dab8SLorenzo Bianconi if (idx >= phy->sband_2g.sband.n_channels +
952edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels) {
953edf9dab8SLorenzo Bianconi idx -= (phy->sband_2g.sband.n_channels +
954edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels);
955edf9dab8SLorenzo Bianconi sband = &phy->sband_6g;
956edf9dab8SLorenzo Bianconi } else if (idx >= phy->sband_2g.sband.n_channels) {
957edf9dab8SLorenzo Bianconi idx -= phy->sband_2g.sband.n_channels;
95896747a51SFelix Fietkau sband = &phy->sband_5g;
959edf9dab8SLorenzo Bianconi } else {
960edf9dab8SLorenzo Bianconi sband = &phy->sband_2g;
96117f1de56SFelix Fietkau }
96217f1de56SFelix Fietkau
963237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) {
964237312c5SLorenzo Bianconi ret = -ENOENT;
965237312c5SLorenzo Bianconi goto out;
966237312c5SLorenzo Bianconi }
96717f1de56SFelix Fietkau
96817f1de56SFelix Fietkau chan = &sband->sband.channels[idx];
96996747a51SFelix Fietkau state = mt76_channel_state(phy, chan);
97017f1de56SFelix Fietkau
97117f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey));
97217f1de56SFelix Fietkau survey->channel = chan;
97317f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
974ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags;
975e5051965SFelix Fietkau if (state->noise)
976e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM;
977e5051965SFelix Fietkau
97896747a51SFelix Fietkau if (chan == phy->main_chan) {
97917f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE;
98017f1de56SFelix Fietkau
9815ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
9825ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX;
9835ce09c1aSFelix Fietkau }
9845ce09c1aSFelix Fietkau
98517f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000);
9866bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000);
987237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000);
988e5051965SFelix Fietkau survey->noise = state->noise;
989237312c5SLorenzo Bianconi
990237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock);
991237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
992ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000);
99317f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock);
99417f1de56SFelix Fietkau
995237312c5SLorenzo Bianconi out:
996237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex);
997237312c5SLorenzo Bianconi
99817f1de56SFelix Fietkau return ret;
99917f1de56SFelix Fietkau }
100017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey);
100117f1de56SFelix Fietkau
mt76_wcid_key_setup(struct mt76_dev * dev,struct mt76_wcid * wcid,struct ieee80211_key_conf * key)100230ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
100330ce7f44SFelix Fietkau struct ieee80211_key_conf *key)
100430ce7f44SFelix Fietkau {
100530ce7f44SFelix Fietkau struct ieee80211_key_seq seq;
100630ce7f44SFelix Fietkau int i;
100730ce7f44SFelix Fietkau
100830ce7f44SFelix Fietkau wcid->rx_check_pn = false;
100930ce7f44SFelix Fietkau
101030ce7f44SFelix Fietkau if (!key)
101130ce7f44SFelix Fietkau return;
101230ce7f44SFelix Fietkau
101301cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
101401cfc1b4SLorenzo Bianconi return;
101530ce7f44SFelix Fietkau
101601cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true;
1017a1b0bbd4SXing Song
1018a1b0bbd4SXing Song /* data frame */
101930ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
102030ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq);
102130ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
102230ce7f44SFelix Fietkau }
1023a1b0bbd4SXing Song
1024a1b0bbd4SXing Song /* robust management frame */
1025a1b0bbd4SXing Song ieee80211_get_key_rx_seq(key, -1, &seq);
1026a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
1027a1b0bbd4SXing Song
102830ce7f44SFelix Fietkau }
102930ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup);
103030ce7f44SFelix Fietkau
mt76_rx_signal(u8 chain_mask,s8 * chain_signal)1031a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
10324550fb9eSFelix Fietkau {
10334550fb9eSFelix Fietkau int signal = -128;
10344550fb9eSFelix Fietkau u8 chains;
10354550fb9eSFelix Fietkau
1036a71b648eSRyder Lee for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
10374550fb9eSFelix Fietkau int cur, diff;
10384550fb9eSFelix Fietkau
10396450b133SDeren Wu cur = *chain_signal;
10406450b133SDeren Wu if (!(chains & BIT(0)) ||
10416450b133SDeren Wu cur > 0)
10424550fb9eSFelix Fietkau continue;
10434550fb9eSFelix Fietkau
10444550fb9eSFelix Fietkau if (cur > signal)
10454550fb9eSFelix Fietkau swap(cur, signal);
10464550fb9eSFelix Fietkau
10474550fb9eSFelix Fietkau diff = signal - cur;
10484550fb9eSFelix Fietkau if (diff == 0)
10494550fb9eSFelix Fietkau signal += 3;
10504550fb9eSFelix Fietkau else if (diff <= 2)
10514550fb9eSFelix Fietkau signal += 2;
10524550fb9eSFelix Fietkau else if (diff <= 6)
10534550fb9eSFelix Fietkau signal += 1;
10544550fb9eSFelix Fietkau }
10554550fb9eSFelix Fietkau
10564550fb9eSFelix Fietkau return signal;
10574550fb9eSFelix Fietkau }
1058a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal);
10594550fb9eSFelix Fietkau
1060bfc394ddSFelix Fietkau static void
mt76_rx_convert(struct mt76_dev * dev,struct sk_buff * skb,struct ieee80211_hw ** hw,struct ieee80211_sta ** sta)1061bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
1062bfc394ddSFelix Fietkau struct ieee80211_hw **hw,
1063bfc394ddSFelix Fietkau struct ieee80211_sta **sta)
10644e34249eSFelix Fietkau {
10654e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
1066abe3f3daSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
10674e34249eSFelix Fietkau struct mt76_rx_status mstat;
10684e34249eSFelix Fietkau
10694e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb);
10704e34249eSFelix Fietkau memset(status, 0, sizeof(*status));
10714e34249eSFelix Fietkau
10724e34249eSFelix Fietkau status->flag = mstat.flag;
10734e34249eSFelix Fietkau status->freq = mstat.freq;
10744e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags;
10754e34249eSFelix Fietkau status->encoding = mstat.encoding;
10764e34249eSFelix Fietkau status->bw = mstat.bw;
1077021af945SShayne Chen if (status->encoding == RX_ENC_EHT) {
1078021af945SShayne Chen status->eht.ru = mstat.eht.ru;
1079021af945SShayne Chen status->eht.gi = mstat.eht.gi;
1080021af945SShayne Chen } else {
1081af4a2f2fSRyder Lee status->he_ru = mstat.he_ru;
1082af4a2f2fSRyder Lee status->he_gi = mstat.he_gi;
1083af4a2f2fSRyder Lee status->he_dcm = mstat.he_dcm;
1084021af945SShayne Chen }
10854e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx;
10864e34249eSFelix Fietkau status->nss = mstat.nss;
10874e34249eSFelix Fietkau status->band = mstat.band;
10884e34249eSFelix Fietkau status->signal = mstat.signal;
10894e34249eSFelix Fietkau status->chains = mstat.chains;
1090d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref;
10910fda6d7bSRyder Lee status->device_timestamp = mstat.timestamp;
10920fda6d7bSRyder Lee status->mactime = mstat.timestamp;
1093a71b648eSRyder Lee status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
10944550fb9eSFelix Fietkau if (status->signal <= -128)
10954550fb9eSFelix Fietkau status->flag |= RX_FLAG_NO_SIGNAL_VAL;
10964e34249eSFelix Fietkau
1097abe3f3daSRyder Lee if (ieee80211_is_beacon(hdr->frame_control) ||
1098abe3f3daSRyder Lee ieee80211_is_probe_resp(hdr->frame_control))
1099abe3f3daSRyder Lee status->boottime_ns = ktime_get_boottime_ns();
1100abe3f3daSRyder Lee
11014e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
110213381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) !=
110313381dcdSRyder Lee sizeof(mstat.chain_signal));
110413381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal,
110513381dcdSRyder Lee sizeof(mstat.chain_signal));
11069c68a57bSFelix Fietkau
1107bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid);
1108128c9b7dSLorenzo Bianconi *hw = mt76_phy_hw(dev, mstat.phy_idx);
11094e34249eSFelix Fietkau }
11104e34249eSFelix Fietkau
11113c1032e1SFelix Fietkau static void
mt76_check_ccmp_pn(struct sk_buff * skb)111230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb)
111330ce7f44SFelix Fietkau {
111430ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
111530ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid;
111630ce7f44SFelix Fietkau struct ieee80211_hdr *hdr;
1117a1b0bbd4SXing Song int security_idx;
111830ce7f44SFelix Fietkau int ret;
111930ce7f44SFelix Fietkau
112030ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED))
11213c1032e1SFelix Fietkau return;
112230ce7f44SFelix Fietkau
11231858e4fcSMeiChia Chiu if (status->flag & RX_FLAG_ONLY_MONITOR)
11243c1032e1SFelix Fietkau return;
11251858e4fcSMeiChia Chiu
112630ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn)
11273c1032e1SFelix Fietkau return;
112830ce7f44SFelix Fietkau
11297360cdecSFelix Fietkau security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11307360cdecSFelix Fietkau if (status->flag & RX_FLAG_8023)
11317360cdecSFelix Fietkau goto skip_hdr_check;
11327360cdecSFelix Fietkau
1133a1b0bbd4SXing Song hdr = mt76_skb_get_hdr(skb);
113430ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
113530ce7f44SFelix Fietkau /*
113630ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211
113730ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only.
113830ce7f44SFelix Fietkau */
113930ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) &&
114030ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control))
11413c1032e1SFelix Fietkau return;
114230ce7f44SFelix Fietkau }
114330ce7f44SFelix Fietkau
1144a1b0bbd4SXing Song /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
1145a1b0bbd4SXing Song *
1146a1b0bbd4SXing Song * the recipient shall maintain a single replay counter for received
1147a1b0bbd4SXing Song * individually addressed robust Management frames that are received
1148a1b0bbd4SXing Song * with the To DS subfield equal to 0, [...]
1149a1b0bbd4SXing Song */
1150a1b0bbd4SXing Song if (ieee80211_is_mgmt(hdr->frame_control) &&
1151a1b0bbd4SXing Song !ieee80211_has_tods(hdr->frame_control))
1152a1b0bbd4SXing Song security_idx = IEEE80211_NUM_TIDS;
1153a1b0bbd4SXing Song
11547360cdecSFelix Fietkau skip_hdr_check:
115530ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
1156a1b0bbd4SXing Song ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
115730ce7f44SFelix Fietkau sizeof(status->iv));
11583c1032e1SFelix Fietkau if (ret <= 0) {
11593c1032e1SFelix Fietkau status->flag |= RX_FLAG_ONLY_MONITOR;
11603c1032e1SFelix Fietkau return;
11613c1032e1SFelix Fietkau }
116230ce7f44SFelix Fietkau
1163a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
116430ce7f44SFelix Fietkau
116530ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED)
116630ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED;
116730ce7f44SFelix Fietkau }
116830ce7f44SFelix Fietkau
1169d71ef286SFelix Fietkau static void
mt76_airtime_report(struct mt76_dev * dev,struct mt76_rx_status * status,int len)11705ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
11715ce09c1aSFelix Fietkau int len)
11725ce09c1aSFelix Fietkau {
11735ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid;
117485b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = {
117585b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags,
117685b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx,
117785b7a5d0SLorenzo Bianconi .encoding = status->encoding,
117885b7a5d0SLorenzo Bianconi .band = status->band,
117985b7a5d0SLorenzo Bianconi .nss = status->nss,
118085b7a5d0SLorenzo Bianconi .bw = status->bw,
118185b7a5d0SLorenzo Bianconi };
11825ce09c1aSFelix Fietkau struct ieee80211_sta *sta;
11835ce09c1aSFelix Fietkau u32 airtime;
1184e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
11855ce09c1aSFelix Fietkau
118685b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
1187237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock);
11885ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime;
1189237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock);
11905ce09c1aSFelix Fietkau
11915ce09c1aSFelix Fietkau if (!wcid || !wcid->sta)
11925ce09c1aSFelix Fietkau return;
11935ce09c1aSFelix Fietkau
11945ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1195e195dad1SFelix Fietkau ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
11965ce09c1aSFelix Fietkau }
11975ce09c1aSFelix Fietkau
11985ce09c1aSFelix Fietkau static void
mt76_airtime_flush_ampdu(struct mt76_dev * dev)11995ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev)
12005ce09c1aSFelix Fietkau {
12015ce09c1aSFelix Fietkau struct mt76_wcid *wcid;
12025ce09c1aSFelix Fietkau int wcid_idx;
12035ce09c1aSFelix Fietkau
12045ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len)
12055ce09c1aSFelix Fietkau return;
12065ce09c1aSFelix Fietkau
12075ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx;
1208bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid))
12095ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]);
12105ce09c1aSFelix Fietkau else
12115ce09c1aSFelix Fietkau wcid = NULL;
12125ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid;
12135ce09c1aSFelix Fietkau
12145ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
12155ce09c1aSFelix Fietkau
12165ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0;
12175ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0;
12185ce09c1aSFelix Fietkau }
12195ce09c1aSFelix Fietkau
12205ce09c1aSFelix Fietkau static void
mt76_airtime_check(struct mt76_dev * dev,struct sk_buff * skb)12215ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
12225ce09c1aSFelix Fietkau {
12235ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12245ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid;
12255ce09c1aSFelix Fietkau
12265ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
12275ce09c1aSFelix Fietkau return;
12285ce09c1aSFelix Fietkau
12295ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) {
1230e195dad1SFelix Fietkau struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1231e195dad1SFelix Fietkau
1232e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023)
1233e195dad1SFelix Fietkau return;
1234e195dad1SFelix Fietkau
123598df2baeSLorenzo Bianconi if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
12365ce09c1aSFelix Fietkau return;
12375ce09c1aSFelix Fietkau
12385ce09c1aSFelix Fietkau wcid = NULL;
12395ce09c1aSFelix Fietkau }
12405ce09c1aSFelix Fietkau
12415ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
12425ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref)
12435ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev);
12445ce09c1aSFelix Fietkau
12455ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) {
12465ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len ||
12475ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) {
12485ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status;
12495ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
12505ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref;
12515ce09c1aSFelix Fietkau }
12525ce09c1aSFelix Fietkau
12535ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len;
12545ce09c1aSFelix Fietkau return;
12555ce09c1aSFelix Fietkau }
12565ce09c1aSFelix Fietkau
12575ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len);
12585ce09c1aSFelix Fietkau }
12595ce09c1aSFelix Fietkau
12605ce09c1aSFelix Fietkau static void
mt76_check_sta(struct mt76_dev * dev,struct sk_buff * skb)1261ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
1262d71ef286SFelix Fietkau {
1263d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
126477ae1d5eSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
1265d71ef286SFelix Fietkau struct ieee80211_sta *sta;
1266bfc394ddSFelix Fietkau struct ieee80211_hw *hw;
1267d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid;
1268e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
1269d71ef286SFelix Fietkau bool ps;
1270d71ef286SFelix Fietkau
1271128c9b7dSLorenzo Bianconi hw = mt76_phy_hw(dev, status->phy_idx);
1272e195dad1SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
1273e195dad1SFelix Fietkau !(status->flag & RX_FLAG_8023)) {
1274bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
127536d91096SFelix Fietkau if (sta)
127636d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
127736d91096SFelix Fietkau }
127836d91096SFelix Fietkau
12795ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb);
12805ce09c1aSFelix Fietkau
1281d71ef286SFelix Fietkau if (!wcid || !wcid->sta)
1282d71ef286SFelix Fietkau return;
1283d71ef286SFelix Fietkau
1284d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
1285d71ef286SFelix Fietkau
128602e5a769SFelix Fietkau if (status->signal <= 0)
128702e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal);
128802e5a769SFelix Fietkau
1289ef13edc0SFelix Fietkau wcid->inactive_count = 0;
1290ef13edc0SFelix Fietkau
1291e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023)
1292e195dad1SFelix Fietkau return;
1293e195dad1SFelix Fietkau
1294d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
1295d71ef286SFelix Fietkau return;
1296d71ef286SFelix Fietkau
1297d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) {
1298d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta);
1299d71ef286SFelix Fietkau return;
1300d71ef286SFelix Fietkau }
1301d71ef286SFelix Fietkau
1302d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) ||
1303d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) ||
1304d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control)))
1305d71ef286SFelix Fietkau return;
1306d71ef286SFelix Fietkau
1307d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control);
1308d71ef286SFelix Fietkau
1309d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
1310d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control)))
1311e195dad1SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, tidno);
1312d71ef286SFelix Fietkau
1313d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
1314d71ef286SFelix Fietkau return;
1315d71ef286SFelix Fietkau
131611b2a25fSFelix Fietkau if (ps)
1317d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags);
1318d71ef286SFelix Fietkau
1319f28c3139SLorenzo Bianconi if (dev->drv->sta_ps)
1320d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps);
1321608f7c47SFelix Fietkau
1322608f7c47SFelix Fietkau if (!ps)
1323608f7c47SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
1324608f7c47SFelix Fietkau
13259f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps);
1326d71ef286SFelix Fietkau }
1327d71ef286SFelix Fietkau
mt76_rx_complete(struct mt76_dev * dev,struct sk_buff_head * frames,struct napi_struct * napi)13289d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
132981e850efSLorenzo Bianconi struct napi_struct *napi)
133017f1de56SFelix Fietkau {
13319c68a57bSFelix Fietkau struct ieee80211_sta *sta;
1332bfc394ddSFelix Fietkau struct ieee80211_hw *hw;
13333298b1f8SFelix Fietkau struct sk_buff *skb, *tmp;
13343298b1f8SFelix Fietkau LIST_HEAD(list);
13359d9d738bSFelix Fietkau
1336c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock);
13379d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) {
1338cc4b3c13SLorenzo Bianconi struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
1339cc4b3c13SLorenzo Bianconi
13403c1032e1SFelix Fietkau mt76_check_ccmp_pn(skb);
1341cc4b3c13SLorenzo Bianconi skb_shinfo(skb)->frag_list = NULL;
1342bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta);
13433298b1f8SFelix Fietkau ieee80211_rx_list(hw, sta, skb, &list);
1344cc4b3c13SLorenzo Bianconi
1345cc4b3c13SLorenzo Bianconi /* subsequent amsdu frames */
1346cc4b3c13SLorenzo Bianconi while (nskb) {
1347cc4b3c13SLorenzo Bianconi skb = nskb;
1348cc4b3c13SLorenzo Bianconi nskb = nskb->next;
1349cc4b3c13SLorenzo Bianconi skb->next = NULL;
1350cc4b3c13SLorenzo Bianconi
1351cc4b3c13SLorenzo Bianconi mt76_rx_convert(dev, skb, &hw, &sta);
1352cc4b3c13SLorenzo Bianconi ieee80211_rx_list(hw, sta, skb, &list);
1353cc4b3c13SLorenzo Bianconi }
13549d9d738bSFelix Fietkau }
1355c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock);
13563298b1f8SFelix Fietkau
13573298b1f8SFelix Fietkau if (!napi) {
13583298b1f8SFelix Fietkau netif_receive_skb_list(&list);
13593298b1f8SFelix Fietkau return;
13603298b1f8SFelix Fietkau }
13613298b1f8SFelix Fietkau
13623298b1f8SFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) {
13633298b1f8SFelix Fietkau skb_list_del_init(skb);
13643298b1f8SFelix Fietkau napi_gro_receive(napi, skb);
13653298b1f8SFelix Fietkau }
13669d9d738bSFelix Fietkau }
13679d9d738bSFelix Fietkau
mt76_rx_poll_complete(struct mt76_dev * dev,enum mt76_rxq_id q,struct napi_struct * napi)136881e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
136981e850efSLorenzo Bianconi struct napi_struct *napi)
13709d9d738bSFelix Fietkau {
1371aee5b8cfSFelix Fietkau struct sk_buff_head frames;
137217f1de56SFelix Fietkau struct sk_buff *skb;
137317f1de56SFelix Fietkau
1374aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames);
1375aee5b8cfSFelix Fietkau
1376d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
1377ef13edc0SFelix Fietkau mt76_check_sta(dev, skb);
13784f831d18SLorenzo Bianconi if (mtk_wed_device_active(&dev->mmio.wed))
13794f831d18SLorenzo Bianconi __skb_queue_tail(&frames, skb);
13804f831d18SLorenzo Bianconi else
1381aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames);
1382d71ef286SFelix Fietkau }
1383aee5b8cfSFelix Fietkau
138481e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi);
13854e34249eSFelix Fietkau }
138681e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
1387723b90dcSFelix Fietkau
1388e28487eaSFelix Fietkau static int
mt76_sta_add(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1389a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
1390a1a99d7bSLorenzo Bianconi struct ieee80211_sta *sta)
1391e28487eaSFelix Fietkau {
1392e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
1393a1a99d7bSLorenzo Bianconi struct mt76_dev *dev = phy->dev;
1394e28487eaSFelix Fietkau int ret;
1395e28487eaSFelix Fietkau int i;
1396e28487eaSFelix Fietkau
1397e28487eaSFelix Fietkau mutex_lock(&dev->mutex);
1398e28487eaSFelix Fietkau
1399e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta);
1400e28487eaSFelix Fietkau if (ret)
1401e28487eaSFelix Fietkau goto out;
1402e28487eaSFelix Fietkau
1403e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
1404e28487eaSFelix Fietkau struct mt76_txq *mtxq;
1405e28487eaSFelix Fietkau
1406e28487eaSFelix Fietkau if (!sta->txq[i])
1407e28487eaSFelix Fietkau continue;
1408e28487eaSFelix Fietkau
1409e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
141051fb1278SFelix Fietkau mtxq->wcid = wcid->idx;
1411e28487eaSFelix Fietkau }
1412e28487eaSFelix Fietkau
1413ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi);
1414a1a99d7bSLorenzo Bianconi if (phy->band_idx == MT_BAND1)
1415426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx);
1416a1a99d7bSLorenzo Bianconi wcid->phy_idx = phy->band_idx;
1417e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1418e28487eaSFelix Fietkau
1419d2defcddSFelix Fietkau mt76_wcid_init(wcid);
1420e28487eaSFelix Fietkau out:
1421e28487eaSFelix Fietkau mutex_unlock(&dev->mutex);
1422e28487eaSFelix Fietkau
1423e28487eaSFelix Fietkau return ret;
1424e28487eaSFelix Fietkau }
1425e28487eaSFelix Fietkau
__mt76_sta_remove(struct mt76_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)142613f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
1427723b90dcSFelix Fietkau struct ieee80211_sta *sta)
1428723b90dcSFelix Fietkau {
1429723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
143013f61dfcSLorenzo Bianconi int i, idx = wcid->idx;
1431723b90dcSFelix Fietkau
143258bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
143358bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i);
143458bab0d4SFelix Fietkau
1435e28487eaSFelix Fietkau if (dev->drv->sta_remove)
1436e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta);
1437e28487eaSFelix Fietkau
1438d2defcddSFelix Fietkau mt76_wcid_cleanup(dev, wcid);
1439bd1e3e7bSLorenzo Bianconi
1440426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx);
1441426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
144213f61dfcSLorenzo Bianconi }
144313f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove);
1444e28487eaSFelix Fietkau
144513f61dfcSLorenzo Bianconi static void
mt76_sta_remove(struct mt76_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)144613f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
144713f61dfcSLorenzo Bianconi struct ieee80211_sta *sta)
144813f61dfcSLorenzo Bianconi {
144913f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex);
145013f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta);
1451723b90dcSFelix Fietkau mutex_unlock(&dev->mutex);
1452723b90dcSFelix Fietkau }
1453e28487eaSFelix Fietkau
mt76_sta_state(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,enum ieee80211_sta_state old_state,enum ieee80211_sta_state new_state)1454e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1455e28487eaSFelix Fietkau struct ieee80211_sta *sta,
1456e28487eaSFelix Fietkau enum ieee80211_sta_state old_state,
1457e28487eaSFelix Fietkau enum ieee80211_sta_state new_state)
1458e28487eaSFelix Fietkau {
1459426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv;
1460426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev;
1461e28487eaSFelix Fietkau
1462e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST &&
1463e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE)
1464a1a99d7bSLorenzo Bianconi return mt76_sta_add(phy, vif, sta);
1465e28487eaSFelix Fietkau
14669c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH &&
14679c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC &&
14689c193de5SFelix Fietkau dev->drv->sta_assoc)
14699c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta);
14709c193de5SFelix Fietkau
1471e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE &&
1472e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST)
1473e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta);
1474e28487eaSFelix Fietkau
1475e28487eaSFelix Fietkau return 0;
1476e28487eaSFelix Fietkau }
1477e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state);
14789313faacSFelix Fietkau
mt76_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)147943ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
148043ba1922SFelix Fietkau struct ieee80211_sta *sta)
148143ba1922SFelix Fietkau {
148243ba1922SFelix Fietkau struct mt76_phy *phy = hw->priv;
148343ba1922SFelix Fietkau struct mt76_dev *dev = phy->dev;
148443ba1922SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
148543ba1922SFelix Fietkau
148643ba1922SFelix Fietkau mutex_lock(&dev->mutex);
1487fcfe1b5eSFelix Fietkau spin_lock_bh(&dev->status_lock);
148843ba1922SFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
1489fcfe1b5eSFelix Fietkau spin_unlock_bh(&dev->status_lock);
149043ba1922SFelix Fietkau mutex_unlock(&dev->mutex);
149143ba1922SFelix Fietkau }
149243ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
149343ba1922SFelix Fietkau
mt76_wcid_init(struct mt76_wcid * wcid)1494d2defcddSFelix Fietkau void mt76_wcid_init(struct mt76_wcid *wcid)
1495d2defcddSFelix Fietkau {
1496d2defcddSFelix Fietkau INIT_LIST_HEAD(&wcid->tx_list);
1497d2defcddSFelix Fietkau skb_queue_head_init(&wcid->tx_pending);
1498d2defcddSFelix Fietkau
1499d2defcddSFelix Fietkau INIT_LIST_HEAD(&wcid->list);
1500d2defcddSFelix Fietkau idr_init(&wcid->pktid);
1501d2defcddSFelix Fietkau }
1502d2defcddSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_init);
1503d2defcddSFelix Fietkau
mt76_wcid_cleanup(struct mt76_dev * dev,struct mt76_wcid * wcid)1504d2defcddSFelix Fietkau void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
1505d2defcddSFelix Fietkau {
1506*818dd118SBjørn Mork struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx);
1507d2defcddSFelix Fietkau struct ieee80211_hw *hw;
1508d2defcddSFelix Fietkau struct sk_buff_head list;
1509d2defcddSFelix Fietkau struct sk_buff *skb;
1510d2defcddSFelix Fietkau
1511d2defcddSFelix Fietkau mt76_tx_status_lock(dev, &list);
1512d2defcddSFelix Fietkau mt76_tx_status_skb_get(dev, wcid, -1, &list);
1513d2defcddSFelix Fietkau mt76_tx_status_unlock(dev, &list);
1514d2defcddSFelix Fietkau
1515d2defcddSFelix Fietkau idr_destroy(&wcid->pktid);
1516d2defcddSFelix Fietkau
1517d2defcddSFelix Fietkau spin_lock_bh(&phy->tx_lock);
1518d2defcddSFelix Fietkau
1519d2defcddSFelix Fietkau if (!list_empty(&wcid->tx_list))
1520d2defcddSFelix Fietkau list_del_init(&wcid->tx_list);
1521d2defcddSFelix Fietkau
1522d2defcddSFelix Fietkau spin_lock(&wcid->tx_pending.lock);
1523d2defcddSFelix Fietkau skb_queue_splice_tail_init(&wcid->tx_pending, &list);
1524d2defcddSFelix Fietkau spin_unlock(&wcid->tx_pending.lock);
1525d2defcddSFelix Fietkau
1526d2defcddSFelix Fietkau spin_unlock_bh(&phy->tx_lock);
1527d2defcddSFelix Fietkau
1528d2defcddSFelix Fietkau while ((skb = __skb_dequeue(&list)) != NULL) {
1529d2defcddSFelix Fietkau hw = mt76_tx_status_get_hw(dev, skb);
1530d2defcddSFelix Fietkau ieee80211_free_txskb(hw, skb);
1531d2defcddSFelix Fietkau }
1532d2defcddSFelix Fietkau }
1533d2defcddSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
1534d2defcddSFelix Fietkau
mt76_get_txpower(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int * dbm)15359313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
15369313faacSFelix Fietkau int *dbm)
15379313faacSFelix Fietkau {
1538beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv;
1539beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask);
154007cda406SFelix Fietkau int delta = mt76_tx_power_nss_delta(n_chains);
15419313faacSFelix Fietkau
154207cda406SFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
15439313faacSFelix Fietkau
15449313faacSFelix Fietkau return 0;
15459313faacSFelix Fietkau }
15469313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower);
1547e7173858SFelix Fietkau
mt76_init_sar_power(struct ieee80211_hw * hw,const struct cfg80211_sar_specs * sar)1548b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw,
1549b3cb885eSLorenzo Bianconi const struct cfg80211_sar_specs *sar)
1550b3cb885eSLorenzo Bianconi {
1551b3cb885eSLorenzo Bianconi struct mt76_phy *phy = hw->priv;
1552b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
1553b3cb885eSLorenzo Bianconi int i;
1554b3cb885eSLorenzo Bianconi
1555b3cb885eSLorenzo Bianconi if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
1556b3cb885eSLorenzo Bianconi return -EINVAL;
1557b3cb885eSLorenzo Bianconi
1558b3cb885eSLorenzo Bianconi for (i = 0; i < sar->num_sub_specs; i++) {
1559b3cb885eSLorenzo Bianconi u32 index = sar->sub_specs[i].freq_range_index;
1560b3cb885eSLorenzo Bianconi /* SAR specifies power limitaton in 0.25dbm */
1561b3cb885eSLorenzo Bianconi s32 power = sar->sub_specs[i].power >> 1;
1562b3cb885eSLorenzo Bianconi
1563b3cb885eSLorenzo Bianconi if (power > 127 || power < -127)
1564b3cb885eSLorenzo Bianconi power = 127;
1565b3cb885eSLorenzo Bianconi
1566b3cb885eSLorenzo Bianconi phy->frp[index].range = &capa->freq_ranges[index];
1567b3cb885eSLorenzo Bianconi phy->frp[index].power = power;
1568b3cb885eSLorenzo Bianconi }
1569b3cb885eSLorenzo Bianconi
1570b3cb885eSLorenzo Bianconi return 0;
1571b3cb885eSLorenzo Bianconi }
1572b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power);
1573b3cb885eSLorenzo Bianconi
mt76_get_sar_power(struct mt76_phy * phy,struct ieee80211_channel * chan,int power)1574b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy,
1575b3cb885eSLorenzo Bianconi struct ieee80211_channel *chan,
1576b3cb885eSLorenzo Bianconi int power)
1577b3cb885eSLorenzo Bianconi {
1578b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
1579b3cb885eSLorenzo Bianconi int freq, i;
1580b3cb885eSLorenzo Bianconi
1581b3cb885eSLorenzo Bianconi if (!capa || !phy->frp)
1582b3cb885eSLorenzo Bianconi return power;
1583b3cb885eSLorenzo Bianconi
1584b3cb885eSLorenzo Bianconi if (power > 127 || power < -127)
1585b3cb885eSLorenzo Bianconi power = 127;
1586b3cb885eSLorenzo Bianconi
1587b3cb885eSLorenzo Bianconi freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
1588b3cb885eSLorenzo Bianconi for (i = 0 ; i < capa->num_freq_ranges; i++) {
1589b3cb885eSLorenzo Bianconi if (phy->frp[i].range &&
1590b3cb885eSLorenzo Bianconi freq >= phy->frp[i].range->start_freq &&
1591b3cb885eSLorenzo Bianconi freq < phy->frp[i].range->end_freq) {
1592b3cb885eSLorenzo Bianconi power = min_t(int, phy->frp[i].power, power);
1593b3cb885eSLorenzo Bianconi break;
1594b3cb885eSLorenzo Bianconi }
1595b3cb885eSLorenzo Bianconi }
1596b3cb885eSLorenzo Bianconi
1597b3cb885eSLorenzo Bianconi return power;
1598b3cb885eSLorenzo Bianconi }
1599b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power);
1600b3cb885eSLorenzo Bianconi
1601e7173858SFelix Fietkau static void
__mt76_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)1602e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
1603e7173858SFelix Fietkau {
1604d0a9123eSJohannes Berg if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
1605e7173858SFelix Fietkau ieee80211_csa_finish(vif);
1606e7173858SFelix Fietkau }
1607e7173858SFelix Fietkau
mt76_csa_finish(struct mt76_dev * dev)1608e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev)
1609e7173858SFelix Fietkau {
1610e7173858SFelix Fietkau if (!dev->csa_complete)
1611e7173858SFelix Fietkau return;
1612e7173858SFelix Fietkau
1613e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw,
1614e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL,
1615e7173858SFelix Fietkau __mt76_csa_finish, dev);
1616e7173858SFelix Fietkau
1617e7173858SFelix Fietkau dev->csa_complete = 0;
1618e7173858SFelix Fietkau }
1619e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish);
1620e7173858SFelix Fietkau
1621e7173858SFelix Fietkau static void
__mt76_csa_check(void * priv,u8 * mac,struct ieee80211_vif * vif)1622e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
1623e7173858SFelix Fietkau {
1624e7173858SFelix Fietkau struct mt76_dev *dev = priv;
1625e7173858SFelix Fietkau
1626d0a9123eSJohannes Berg if (!vif->bss_conf.csa_active)
1627e7173858SFelix Fietkau return;
1628e7173858SFelix Fietkau
16298552a434SJohn Crispin dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
1630e7173858SFelix Fietkau }
1631e7173858SFelix Fietkau
mt76_csa_check(struct mt76_dev * dev)1632e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev)
1633e7173858SFelix Fietkau {
1634e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw,
1635e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL,
1636e7173858SFelix Fietkau __mt76_csa_check, dev);
1637e7173858SFelix Fietkau }
1638e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check);
163987d53103SStanislaw Gruszka
164087d53103SStanislaw Gruszka int
mt76_set_tim(struct ieee80211_hw * hw,struct ieee80211_sta * sta,bool set)164187d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
164287d53103SStanislaw Gruszka {
164387d53103SStanislaw Gruszka return 0;
164487d53103SStanislaw Gruszka }
164587d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim);
1646eadfd98fSLorenzo Bianconi
mt76_insert_ccmp_hdr(struct sk_buff * skb,u8 key_id)1647eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
1648eadfd98fSLorenzo Bianconi {
1649eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
1650eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
1651eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv;
1652eadfd98fSLorenzo Bianconi
1653eadfd98fSLorenzo Bianconi __skb_push(skb, 8);
1654eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len);
1655eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len;
1656eadfd98fSLorenzo Bianconi
1657eadfd98fSLorenzo Bianconi hdr[0] = pn[5];
1658eadfd98fSLorenzo Bianconi hdr[1] = pn[4];
1659eadfd98fSLorenzo Bianconi hdr[2] = 0;
1660eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6);
1661eadfd98fSLorenzo Bianconi hdr[4] = pn[3];
1662eadfd98fSLorenzo Bianconi hdr[5] = pn[2];
1663eadfd98fSLorenzo Bianconi hdr[6] = pn[1];
1664eadfd98fSLorenzo Bianconi hdr[7] = pn[0];
1665eadfd98fSLorenzo Bianconi
1666eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED;
1667eadfd98fSLorenzo Bianconi }
1668eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
1669d2679d65SLorenzo Bianconi
mt76_get_rate(struct mt76_dev * dev,struct ieee80211_supported_band * sband,int idx,bool cck)1670d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev,
1671d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband,
1672d2679d65SLorenzo Bianconi int idx, bool cck)
1673d2679d65SLorenzo Bianconi {
1674d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates;
1675d2679d65SLorenzo Bianconi
1676d2679d65SLorenzo Bianconi if (cck) {
1677edf9dab8SLorenzo Bianconi if (sband != &dev->phy.sband_2g.sband)
1678d2679d65SLorenzo Bianconi return 0;
1679d2679d65SLorenzo Bianconi
1680d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */
168196747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) {
1682d2679d65SLorenzo Bianconi offset = 4;
1683d2679d65SLorenzo Bianconi }
1684d2679d65SLorenzo Bianconi
1685d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) {
1686d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
1687d2679d65SLorenzo Bianconi return i;
1688d2679d65SLorenzo Bianconi }
1689d2679d65SLorenzo Bianconi
1690d2679d65SLorenzo Bianconi return 0;
1691d2679d65SLorenzo Bianconi }
1692d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate);
16938b8ab5c2SLorenzo Bianconi
mt76_sw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * mac)16948b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16958b8ab5c2SLorenzo Bianconi const u8 *mac)
16968b8ab5c2SLorenzo Bianconi {
1697011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv;
16988b8ab5c2SLorenzo Bianconi
1699011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state);
17008b8ab5c2SLorenzo Bianconi }
17018b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan);
17028b8ab5c2SLorenzo Bianconi
mt76_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)17038b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
17048b8ab5c2SLorenzo Bianconi {
1705011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv;
17068b8ab5c2SLorenzo Bianconi
1707011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state);
17088b8ab5c2SLorenzo Bianconi }
17098b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
1710e49c76d4SLorenzo Bianconi
mt76_get_antenna(struct ieee80211_hw * hw,u32 * tx_ant,u32 * rx_ant)1711e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
1712e49c76d4SLorenzo Bianconi {
1713beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv;
1714beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev;
1715e49c76d4SLorenzo Bianconi
1716e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex);
1717beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask;
1718beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask;
1719e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex);
1720e49c76d4SLorenzo Bianconi
1721e49c76d4SLorenzo Bianconi return 0;
1722e49c76d4SLorenzo Bianconi }
1723e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna);
1724b671da33SLorenzo Bianconi
1725b1cb42adSLorenzo Bianconi struct mt76_queue *
mt76_init_queue(struct mt76_dev * dev,int qid,int idx,int n_desc,int ring_base,u32 flags)1726b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1727f68d6762SFelix Fietkau int ring_base, u32 flags)
1728b671da33SLorenzo Bianconi {
1729b671da33SLorenzo Bianconi struct mt76_queue *hwq;
1730b671da33SLorenzo Bianconi int err;
1731b671da33SLorenzo Bianconi
1732b671da33SLorenzo Bianconi hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
1733b671da33SLorenzo Bianconi if (!hwq)
1734b1cb42adSLorenzo Bianconi return ERR_PTR(-ENOMEM);
1735b671da33SLorenzo Bianconi
1736f68d6762SFelix Fietkau hwq->flags = flags;
1737f68d6762SFelix Fietkau
1738b671da33SLorenzo Bianconi err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
1739b671da33SLorenzo Bianconi if (err < 0)
1740b1cb42adSLorenzo Bianconi return ERR_PTR(err);
1741b671da33SLorenzo Bianconi
1742b1cb42adSLorenzo Bianconi return hwq;
1743b671da33SLorenzo Bianconi }
1744b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue);
1745e4867225SSean Wang
mt76_calculate_default_rate(struct mt76_phy * phy,struct ieee80211_vif * vif,int rateidx)1746e1d9e0e7SSean Wang u16 mt76_calculate_default_rate(struct mt76_phy *phy,
1747e1d9e0e7SSean Wang struct ieee80211_vif *vif, int rateidx)
1748e4867225SSean Wang {
1749e1d9e0e7SSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
1750e1d9e0e7SSean Wang struct cfg80211_chan_def *chandef = mvif->ctx ?
1751e1d9e0e7SSean Wang &mvif->ctx->def :
1752e1d9e0e7SSean Wang &phy->chandef;
175333920b2bSRyder Lee int offset = 0;
1754e4867225SSean Wang
1755e1d9e0e7SSean Wang if (chandef->chan->band != NL80211_BAND_2GHZ)
1756e4867225SSean Wang offset = 4;
1757e4867225SSean Wang
175833920b2bSRyder Lee /* pick the lowest rate for hidden nodes */
175933920b2bSRyder Lee if (rateidx < 0)
176033920b2bSRyder Lee rateidx = 0;
176133920b2bSRyder Lee
1762d4f3d1c4SLorenzo Bianconi rateidx += offset;
1763d4f3d1c4SLorenzo Bianconi if (rateidx >= ARRAY_SIZE(mt76_rates))
1764d4f3d1c4SLorenzo Bianconi rateidx = offset;
1765e4867225SSean Wang
1766d4f3d1c4SLorenzo Bianconi return mt76_rates[rateidx].hw_value;
1767e4867225SSean Wang }
176833920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
176954ae98ffSLorenzo Bianconi
mt76_ethtool_worker(struct mt76_ethtool_worker_info * wi,struct mt76_sta_stats * stats,bool eht)177054ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1771731425f3SShayne Chen struct mt76_sta_stats *stats, bool eht)
177254ae98ffSLorenzo Bianconi {
177354ae98ffSLorenzo Bianconi int i, ei = wi->initial_stat_idx;
177454ae98ffSLorenzo Bianconi u64 *data = wi->data;
177554ae98ffSLorenzo Bianconi
177654ae98ffSLorenzo Bianconi wi->sta_count++;
177754ae98ffSLorenzo Bianconi
177854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
177954ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
178054ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
178154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
178254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
178354ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
178454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
178554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
178654ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1787731425f3SShayne Chen if (eht) {
1788731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1789731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1790731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1791731425f3SShayne Chen }
179254ae98ffSLorenzo Bianconi
1793731425f3SShayne Chen for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
179454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_bw[i];
179554ae98ffSLorenzo Bianconi
1796731425f3SShayne Chen for (i = 0; i < (eht ? 14 : 12); i++)
179754ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mcs[i];
179854ae98ffSLorenzo Bianconi
1799749c2c2bSRyder Lee for (i = 0; i < 4; i++)
1800749c2c2bSRyder Lee data[ei++] += stats->tx_nss[i];
1801749c2c2bSRyder Lee
180254ae98ffSLorenzo Bianconi wi->worker_stat_count = ei - wi->initial_stat_idx;
180354ae98ffSLorenzo Bianconi }
180454ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
18053f306448SFelix Fietkau
mt76_ethtool_page_pool_stats(struct mt76_dev * dev,u64 * data,int * index)1806192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1807192ad406SLorenzo Bianconi {
1808192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS
1809192ad406SLorenzo Bianconi struct page_pool_stats stats = {};
1810192ad406SLorenzo Bianconi int i;
1811192ad406SLorenzo Bianconi
1812192ad406SLorenzo Bianconi mt76_for_each_q_rx(dev, i)
1813192ad406SLorenzo Bianconi page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
1814192ad406SLorenzo Bianconi
1815192ad406SLorenzo Bianconi page_pool_ethtool_stats_get(data, &stats);
1816192ad406SLorenzo Bianconi *index += page_pool_ethtool_stats_get_count();
1817192ad406SLorenzo Bianconi #endif
1818192ad406SLorenzo Bianconi }
1819192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
1820192ad406SLorenzo Bianconi
mt76_phy_dfs_state(struct mt76_phy * phy)18213f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
18223f306448SFelix Fietkau {
18233f306448SFelix Fietkau struct ieee80211_hw *hw = phy->hw;
18243f306448SFelix Fietkau struct mt76_dev *dev = phy->dev;
18253f306448SFelix Fietkau
18263f306448SFelix Fietkau if (dev->region == NL80211_DFS_UNSET ||
18273f306448SFelix Fietkau test_bit(MT76_SCANNING, &phy->state))
18283f306448SFelix Fietkau return MT_DFS_STATE_DISABLED;
18293f306448SFelix Fietkau
18303f306448SFelix Fietkau if (!hw->conf.radar_enabled) {
18313f306448SFelix Fietkau if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
18323f306448SFelix Fietkau (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
18333f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE;
18343f306448SFelix Fietkau
18353f306448SFelix Fietkau return MT_DFS_STATE_DISABLED;
18363f306448SFelix Fietkau }
18373f306448SFelix Fietkau
183800a883e6SFelix Fietkau if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
18393f306448SFelix Fietkau return MT_DFS_STATE_CAC;
18403f306448SFelix Fietkau
18413f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE;
18423f306448SFelix Fietkau }
18433f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
1844