16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /*
36c92544dSBjoern A. Zeeb * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
46c92544dSBjoern A. Zeeb */
56c92544dSBjoern A. Zeeb #include <linux/sched.h>
66c92544dSBjoern A. Zeeb #if defined(CONFIG_OF)
76c92544dSBjoern A. Zeeb #include <linux/of.h>
86c92544dSBjoern A. Zeeb #endif
96c92544dSBjoern A. Zeeb #if defined(__FreeBSD__)
106c92544dSBjoern A. Zeeb #include <linux/math64.h>
11cbb3ec25SBjoern A. Zeeb #include <linux/numa.h>
126c92544dSBjoern A. Zeeb #endif
136c92544dSBjoern A. Zeeb #include "mt76.h"
146c92544dSBjoern A. Zeeb
156c92544dSBjoern A. Zeeb #define CHAN2G(_idx, _freq) { \
166c92544dSBjoern A. Zeeb .band = NL80211_BAND_2GHZ, \
176c92544dSBjoern A. Zeeb .center_freq = (_freq), \
186c92544dSBjoern A. Zeeb .hw_value = (_idx), \
196c92544dSBjoern A. Zeeb .max_power = 30, \
206c92544dSBjoern A. Zeeb }
216c92544dSBjoern A. Zeeb
226c92544dSBjoern A. Zeeb #define CHAN5G(_idx, _freq) { \
236c92544dSBjoern A. Zeeb .band = NL80211_BAND_5GHZ, \
246c92544dSBjoern A. Zeeb .center_freq = (_freq), \
256c92544dSBjoern A. Zeeb .hw_value = (_idx), \
266c92544dSBjoern A. Zeeb .max_power = 30, \
276c92544dSBjoern A. Zeeb }
286c92544dSBjoern A. Zeeb
296c92544dSBjoern A. Zeeb #define CHAN6G(_idx, _freq) { \
306c92544dSBjoern A. Zeeb .band = NL80211_BAND_6GHZ, \
316c92544dSBjoern A. Zeeb .center_freq = (_freq), \
326c92544dSBjoern A. Zeeb .hw_value = (_idx), \
336c92544dSBjoern A. Zeeb .max_power = 30, \
346c92544dSBjoern A. Zeeb }
356c92544dSBjoern A. Zeeb
366c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_2ghz[] = {
376c92544dSBjoern A. Zeeb CHAN2G(1, 2412),
386c92544dSBjoern A. Zeeb CHAN2G(2, 2417),
396c92544dSBjoern A. Zeeb CHAN2G(3, 2422),
406c92544dSBjoern A. Zeeb CHAN2G(4, 2427),
416c92544dSBjoern A. Zeeb CHAN2G(5, 2432),
426c92544dSBjoern A. Zeeb CHAN2G(6, 2437),
436c92544dSBjoern A. Zeeb CHAN2G(7, 2442),
446c92544dSBjoern A. Zeeb CHAN2G(8, 2447),
456c92544dSBjoern A. Zeeb CHAN2G(9, 2452),
466c92544dSBjoern A. Zeeb CHAN2G(10, 2457),
476c92544dSBjoern A. Zeeb CHAN2G(11, 2462),
486c92544dSBjoern A. Zeeb CHAN2G(12, 2467),
496c92544dSBjoern A. Zeeb CHAN2G(13, 2472),
506c92544dSBjoern A. Zeeb CHAN2G(14, 2484),
516c92544dSBjoern A. Zeeb };
526c92544dSBjoern A. Zeeb
536c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_5ghz[] = {
546c92544dSBjoern A. Zeeb CHAN5G(36, 5180),
556c92544dSBjoern A. Zeeb CHAN5G(40, 5200),
566c92544dSBjoern A. Zeeb CHAN5G(44, 5220),
576c92544dSBjoern A. Zeeb CHAN5G(48, 5240),
586c92544dSBjoern A. Zeeb
596c92544dSBjoern A. Zeeb CHAN5G(52, 5260),
606c92544dSBjoern A. Zeeb CHAN5G(56, 5280),
616c92544dSBjoern A. Zeeb CHAN5G(60, 5300),
626c92544dSBjoern A. Zeeb CHAN5G(64, 5320),
636c92544dSBjoern A. Zeeb
646c92544dSBjoern A. Zeeb CHAN5G(100, 5500),
656c92544dSBjoern A. Zeeb CHAN5G(104, 5520),
666c92544dSBjoern A. Zeeb CHAN5G(108, 5540),
676c92544dSBjoern A. Zeeb CHAN5G(112, 5560),
686c92544dSBjoern A. Zeeb CHAN5G(116, 5580),
696c92544dSBjoern A. Zeeb CHAN5G(120, 5600),
706c92544dSBjoern A. Zeeb CHAN5G(124, 5620),
716c92544dSBjoern A. Zeeb CHAN5G(128, 5640),
726c92544dSBjoern A. Zeeb CHAN5G(132, 5660),
736c92544dSBjoern A. Zeeb CHAN5G(136, 5680),
746c92544dSBjoern A. Zeeb CHAN5G(140, 5700),
756c92544dSBjoern A. Zeeb CHAN5G(144, 5720),
766c92544dSBjoern A. Zeeb
776c92544dSBjoern A. Zeeb CHAN5G(149, 5745),
786c92544dSBjoern A. Zeeb CHAN5G(153, 5765),
796c92544dSBjoern A. Zeeb CHAN5G(157, 5785),
806c92544dSBjoern A. Zeeb CHAN5G(161, 5805),
816c92544dSBjoern A. Zeeb CHAN5G(165, 5825),
826c92544dSBjoern A. Zeeb CHAN5G(169, 5845),
836c92544dSBjoern A. Zeeb CHAN5G(173, 5865),
84cbb3ec25SBjoern A. Zeeb CHAN5G(177, 5885),
856c92544dSBjoern A. Zeeb };
866c92544dSBjoern A. Zeeb
876c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_6ghz[] = {
886c92544dSBjoern A. Zeeb /* UNII-5 */
896c92544dSBjoern A. Zeeb CHAN6G(1, 5955),
906c92544dSBjoern A. Zeeb CHAN6G(5, 5975),
916c92544dSBjoern A. Zeeb CHAN6G(9, 5995),
926c92544dSBjoern A. Zeeb CHAN6G(13, 6015),
936c92544dSBjoern A. Zeeb CHAN6G(17, 6035),
946c92544dSBjoern A. Zeeb CHAN6G(21, 6055),
956c92544dSBjoern A. Zeeb CHAN6G(25, 6075),
966c92544dSBjoern A. Zeeb CHAN6G(29, 6095),
976c92544dSBjoern A. Zeeb CHAN6G(33, 6115),
986c92544dSBjoern A. Zeeb CHAN6G(37, 6135),
996c92544dSBjoern A. Zeeb CHAN6G(41, 6155),
1006c92544dSBjoern A. Zeeb CHAN6G(45, 6175),
1016c92544dSBjoern A. Zeeb CHAN6G(49, 6195),
1026c92544dSBjoern A. Zeeb CHAN6G(53, 6215),
1036c92544dSBjoern A. Zeeb CHAN6G(57, 6235),
1046c92544dSBjoern A. Zeeb CHAN6G(61, 6255),
1056c92544dSBjoern A. Zeeb CHAN6G(65, 6275),
1066c92544dSBjoern A. Zeeb CHAN6G(69, 6295),
1076c92544dSBjoern A. Zeeb CHAN6G(73, 6315),
1086c92544dSBjoern A. Zeeb CHAN6G(77, 6335),
1096c92544dSBjoern A. Zeeb CHAN6G(81, 6355),
1106c92544dSBjoern A. Zeeb CHAN6G(85, 6375),
1116c92544dSBjoern A. Zeeb CHAN6G(89, 6395),
1126c92544dSBjoern A. Zeeb CHAN6G(93, 6415),
1136c92544dSBjoern A. Zeeb /* UNII-6 */
1146c92544dSBjoern A. Zeeb CHAN6G(97, 6435),
1156c92544dSBjoern A. Zeeb CHAN6G(101, 6455),
1166c92544dSBjoern A. Zeeb CHAN6G(105, 6475),
1176c92544dSBjoern A. Zeeb CHAN6G(109, 6495),
1186c92544dSBjoern A. Zeeb CHAN6G(113, 6515),
1196c92544dSBjoern A. Zeeb CHAN6G(117, 6535),
1206c92544dSBjoern A. Zeeb /* UNII-7 */
1216c92544dSBjoern A. Zeeb CHAN6G(121, 6555),
1226c92544dSBjoern A. Zeeb CHAN6G(125, 6575),
1236c92544dSBjoern A. Zeeb CHAN6G(129, 6595),
1246c92544dSBjoern A. Zeeb CHAN6G(133, 6615),
1256c92544dSBjoern A. Zeeb CHAN6G(137, 6635),
1266c92544dSBjoern A. Zeeb CHAN6G(141, 6655),
1276c92544dSBjoern A. Zeeb CHAN6G(145, 6675),
1286c92544dSBjoern A. Zeeb CHAN6G(149, 6695),
1296c92544dSBjoern A. Zeeb CHAN6G(153, 6715),
1306c92544dSBjoern A. Zeeb CHAN6G(157, 6735),
1316c92544dSBjoern A. Zeeb CHAN6G(161, 6755),
1326c92544dSBjoern A. Zeeb CHAN6G(165, 6775),
1336c92544dSBjoern A. Zeeb CHAN6G(169, 6795),
1346c92544dSBjoern A. Zeeb CHAN6G(173, 6815),
1356c92544dSBjoern A. Zeeb CHAN6G(177, 6835),
1366c92544dSBjoern A. Zeeb CHAN6G(181, 6855),
1376c92544dSBjoern A. Zeeb CHAN6G(185, 6875),
1386c92544dSBjoern A. Zeeb /* UNII-8 */
1396c92544dSBjoern A. Zeeb CHAN6G(189, 6895),
1406c92544dSBjoern A. Zeeb CHAN6G(193, 6915),
1416c92544dSBjoern A. Zeeb CHAN6G(197, 6935),
1426c92544dSBjoern A. Zeeb CHAN6G(201, 6955),
1436c92544dSBjoern A. Zeeb CHAN6G(205, 6975),
1446c92544dSBjoern A. Zeeb CHAN6G(209, 6995),
1456c92544dSBjoern A. Zeeb CHAN6G(213, 7015),
1466c92544dSBjoern A. Zeeb CHAN6G(217, 7035),
1476c92544dSBjoern A. Zeeb CHAN6G(221, 7055),
1486c92544dSBjoern A. Zeeb CHAN6G(225, 7075),
1496c92544dSBjoern A. Zeeb CHAN6G(229, 7095),
1506c92544dSBjoern A. Zeeb CHAN6G(233, 7115),
1516c92544dSBjoern A. Zeeb };
1526c92544dSBjoern A. Zeeb
1536c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
1546c92544dSBjoern A. Zeeb static const struct ieee80211_tpt_blink mt76_tpt_blink[] = {
1556c92544dSBjoern A. Zeeb { .throughput = 0 * 1024, .blink_time = 334 },
1566c92544dSBjoern A. Zeeb { .throughput = 1 * 1024, .blink_time = 260 },
1576c92544dSBjoern A. Zeeb { .throughput = 5 * 1024, .blink_time = 220 },
1586c92544dSBjoern A. Zeeb { .throughput = 10 * 1024, .blink_time = 190 },
1596c92544dSBjoern A. Zeeb { .throughput = 20 * 1024, .blink_time = 170 },
1606c92544dSBjoern A. Zeeb { .throughput = 50 * 1024, .blink_time = 150 },
1616c92544dSBjoern A. Zeeb { .throughput = 70 * 1024, .blink_time = 130 },
1626c92544dSBjoern A. Zeeb { .throughput = 100 * 1024, .blink_time = 110 },
1636c92544dSBjoern A. Zeeb { .throughput = 200 * 1024, .blink_time = 80 },
1646c92544dSBjoern A. Zeeb { .throughput = 300 * 1024, .blink_time = 50 },
1656c92544dSBjoern A. Zeeb };
1666c92544dSBjoern A. Zeeb #endif
1676c92544dSBjoern A. Zeeb
1686c92544dSBjoern A. Zeeb struct ieee80211_rate mt76_rates[] = {
1696c92544dSBjoern A. Zeeb CCK_RATE(0, 10),
1706c92544dSBjoern A. Zeeb CCK_RATE(1, 20),
1716c92544dSBjoern A. Zeeb CCK_RATE(2, 55),
1726c92544dSBjoern A. Zeeb CCK_RATE(3, 110),
1736c92544dSBjoern A. Zeeb OFDM_RATE(11, 60),
1746c92544dSBjoern A. Zeeb OFDM_RATE(15, 90),
1756c92544dSBjoern A. Zeeb OFDM_RATE(10, 120),
1766c92544dSBjoern A. Zeeb OFDM_RATE(14, 180),
1776c92544dSBjoern A. Zeeb OFDM_RATE(9, 240),
1786c92544dSBjoern A. Zeeb OFDM_RATE(13, 360),
1796c92544dSBjoern A. Zeeb OFDM_RATE(8, 480),
1806c92544dSBjoern A. Zeeb OFDM_RATE(12, 540),
1816c92544dSBjoern A. Zeeb };
1826c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rates);
1836c92544dSBjoern A. Zeeb
1846c92544dSBjoern A. Zeeb static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = {
1856c92544dSBjoern A. Zeeb { .start_freq = 2402, .end_freq = 2494, },
1866c92544dSBjoern A. Zeeb { .start_freq = 5150, .end_freq = 5350, },
1876c92544dSBjoern A. Zeeb { .start_freq = 5350, .end_freq = 5470, },
1886c92544dSBjoern A. Zeeb { .start_freq = 5470, .end_freq = 5725, },
1896c92544dSBjoern A. Zeeb { .start_freq = 5725, .end_freq = 5950, },
1906c92544dSBjoern A. Zeeb { .start_freq = 5945, .end_freq = 6165, },
1916c92544dSBjoern A. Zeeb { .start_freq = 6165, .end_freq = 6405, },
1926c92544dSBjoern A. Zeeb { .start_freq = 6405, .end_freq = 6525, },
1936c92544dSBjoern A. Zeeb { .start_freq = 6525, .end_freq = 6705, },
1946c92544dSBjoern A. Zeeb { .start_freq = 6705, .end_freq = 6865, },
1956c92544dSBjoern A. Zeeb { .start_freq = 6865, .end_freq = 7125, },
1966c92544dSBjoern A. Zeeb };
1976c92544dSBjoern A. Zeeb
1986c92544dSBjoern A. Zeeb static const struct cfg80211_sar_capa mt76_sar_capa = {
1996c92544dSBjoern A. Zeeb .type = NL80211_SAR_TYPE_POWER,
2006c92544dSBjoern A. Zeeb .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges),
2016c92544dSBjoern A. Zeeb .freq_ranges = &mt76_sar_freq_ranges[0],
2026c92544dSBjoern A. Zeeb };
2036c92544dSBjoern A. Zeeb
2046c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
mt76_led_init(struct mt76_phy * phy)205cbb3ec25SBjoern A. Zeeb static int mt76_led_init(struct mt76_phy *phy)
2066c92544dSBjoern A. Zeeb {
207cbb3ec25SBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
208cbb3ec25SBjoern A. Zeeb struct ieee80211_hw *hw = phy->hw;
209*8ba4d145SBjoern A. Zeeb struct device_node *np = dev->dev->of_node;
2106c92544dSBjoern A. Zeeb
211cbb3ec25SBjoern A. Zeeb if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
2126c92544dSBjoern A. Zeeb return 0;
2136c92544dSBjoern A. Zeeb
214*8ba4d145SBjoern A. Zeeb np = of_get_child_by_name(np, "led");
215*8ba4d145SBjoern A. Zeeb if (np) {
216*8ba4d145SBjoern A. Zeeb if (!of_device_is_available(np)) {
217*8ba4d145SBjoern A. Zeeb of_node_put(np);
218*8ba4d145SBjoern A. Zeeb dev_info(dev->dev,
219*8ba4d145SBjoern A. Zeeb "led registration was explicitly disabled by dts\n");
220*8ba4d145SBjoern A. Zeeb return 0;
221*8ba4d145SBjoern A. Zeeb }
222*8ba4d145SBjoern A. Zeeb
223*8ba4d145SBjoern A. Zeeb if (phy == &dev->phy) {
224*8ba4d145SBjoern A. Zeeb int led_pin;
225*8ba4d145SBjoern A. Zeeb
226*8ba4d145SBjoern A. Zeeb if (!of_property_read_u32(np, "led-sources", &led_pin))
227*8ba4d145SBjoern A. Zeeb phy->leds.pin = led_pin;
228*8ba4d145SBjoern A. Zeeb
229*8ba4d145SBjoern A. Zeeb phy->leds.al =
230*8ba4d145SBjoern A. Zeeb of_property_read_bool(np, "led-active-low");
231*8ba4d145SBjoern A. Zeeb }
232*8ba4d145SBjoern A. Zeeb
233*8ba4d145SBjoern A. Zeeb of_node_put(np);
234*8ba4d145SBjoern A. Zeeb }
235*8ba4d145SBjoern A. Zeeb
236cbb3ec25SBjoern A. Zeeb snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
237cbb3ec25SBjoern A. Zeeb wiphy_name(hw->wiphy));
2386c92544dSBjoern A. Zeeb
239cbb3ec25SBjoern A. Zeeb phy->leds.cdev.name = phy->leds.name;
240cbb3ec25SBjoern A. Zeeb phy->leds.cdev.default_trigger =
2416c92544dSBjoern A. Zeeb ieee80211_create_tpt_led_trigger(hw,
2426c92544dSBjoern A. Zeeb IEEE80211_TPT_LEDTRIG_FL_RADIO,
2436c92544dSBjoern A. Zeeb mt76_tpt_blink,
2446c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_tpt_blink));
2456c92544dSBjoern A. Zeeb
246*8ba4d145SBjoern A. Zeeb dev_info(dev->dev,
247*8ba4d145SBjoern A. Zeeb "registering led '%s'\n", phy->leds.name);
2486c92544dSBjoern A. Zeeb
249cbb3ec25SBjoern A. Zeeb return led_classdev_register(dev->dev, &phy->leds.cdev);
2506c92544dSBjoern A. Zeeb }
2516c92544dSBjoern A. Zeeb
mt76_led_cleanup(struct mt76_phy * phy)252cbb3ec25SBjoern A. Zeeb static void mt76_led_cleanup(struct mt76_phy *phy)
2536c92544dSBjoern A. Zeeb {
254cbb3ec25SBjoern A. Zeeb if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
2556c92544dSBjoern A. Zeeb return;
2566c92544dSBjoern A. Zeeb
257cbb3ec25SBjoern A. Zeeb led_classdev_unregister(&phy->leds.cdev);
2586c92544dSBjoern A. Zeeb }
2596c92544dSBjoern A. Zeeb #endif
2606c92544dSBjoern A. Zeeb
mt76_init_stream_cap(struct mt76_phy * phy,struct ieee80211_supported_band * sband,bool vht)2616c92544dSBjoern A. Zeeb static void mt76_init_stream_cap(struct mt76_phy *phy,
2626c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband,
2636c92544dSBjoern A. Zeeb bool vht)
2646c92544dSBjoern A. Zeeb {
2656c92544dSBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
2666c92544dSBjoern A. Zeeb int i, nstream = hweight8(phy->antenna_mask);
2676c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap;
2686c92544dSBjoern A. Zeeb u16 mcs_map = 0;
2696c92544dSBjoern A. Zeeb
2706c92544dSBjoern A. Zeeb if (nstream > 1)
2716c92544dSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC;
2726c92544dSBjoern A. Zeeb else
2736c92544dSBjoern A. Zeeb ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC;
2746c92544dSBjoern A. Zeeb
2756c92544dSBjoern A. Zeeb for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
2766c92544dSBjoern A. Zeeb ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0;
2776c92544dSBjoern A. Zeeb
2786c92544dSBjoern A. Zeeb if (!vht)
2796c92544dSBjoern A. Zeeb return;
2806c92544dSBjoern A. Zeeb
2816c92544dSBjoern A. Zeeb vht_cap = &sband->vht_cap;
2826c92544dSBjoern A. Zeeb if (nstream > 1)
2836c92544dSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
2846c92544dSBjoern A. Zeeb else
2856c92544dSBjoern A. Zeeb vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC;
2866c92544dSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
2876c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN;
2886c92544dSBjoern A. Zeeb
2896c92544dSBjoern A. Zeeb for (i = 0; i < 8; i++) {
2906c92544dSBjoern A. Zeeb if (i < nstream)
2916c92544dSBjoern A. Zeeb mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2));
2926c92544dSBjoern A. Zeeb else
2936c92544dSBjoern A. Zeeb mcs_map |=
2946c92544dSBjoern A. Zeeb (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2));
2956c92544dSBjoern A. Zeeb }
2966c92544dSBjoern A. Zeeb vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
2976c92544dSBjoern A. Zeeb vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
2986c92544dSBjoern A. Zeeb if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW))
2996c92544dSBjoern A. Zeeb vht_cap->vht_mcs.tx_highest |=
3006c92544dSBjoern A. Zeeb cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
3016c92544dSBjoern A. Zeeb }
3026c92544dSBjoern A. Zeeb
mt76_set_stream_caps(struct mt76_phy * phy,bool vht)3036c92544dSBjoern A. Zeeb void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
3046c92544dSBjoern A. Zeeb {
3056c92544dSBjoern A. Zeeb if (phy->cap.has_2ghz)
3066c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
3076c92544dSBjoern A. Zeeb if (phy->cap.has_5ghz)
3086c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
3096c92544dSBjoern A. Zeeb if (phy->cap.has_6ghz)
3106c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht);
3116c92544dSBjoern A. Zeeb }
3126c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
3136c92544dSBjoern A. Zeeb
3146c92544dSBjoern A. Zeeb 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)3156c92544dSBjoern A. Zeeb mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
3166c92544dSBjoern A. Zeeb const struct ieee80211_channel *chan, int n_chan,
3176c92544dSBjoern A. Zeeb struct ieee80211_rate *rates, int n_rates,
3186c92544dSBjoern A. Zeeb bool ht, bool vht)
3196c92544dSBjoern A. Zeeb {
3206c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband = &msband->sband;
3216c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap;
3226c92544dSBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_cap;
3236c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
3246c92544dSBjoern A. Zeeb void *chanlist;
3256c92544dSBjoern A. Zeeb int size;
3266c92544dSBjoern A. Zeeb
3276c92544dSBjoern A. Zeeb size = n_chan * sizeof(*chan);
3286c92544dSBjoern A. Zeeb chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL);
3296c92544dSBjoern A. Zeeb if (!chanlist)
3306c92544dSBjoern A. Zeeb return -ENOMEM;
3316c92544dSBjoern A. Zeeb
3326c92544dSBjoern A. Zeeb msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan),
3336c92544dSBjoern A. Zeeb GFP_KERNEL);
3346c92544dSBjoern A. Zeeb if (!msband->chan)
3356c92544dSBjoern A. Zeeb return -ENOMEM;
3366c92544dSBjoern A. Zeeb
3376c92544dSBjoern A. Zeeb sband->channels = chanlist;
3386c92544dSBjoern A. Zeeb sband->n_channels = n_chan;
3396c92544dSBjoern A. Zeeb sband->bitrates = rates;
3406c92544dSBjoern A. Zeeb sband->n_bitrates = n_rates;
3416c92544dSBjoern A. Zeeb
3426c92544dSBjoern A. Zeeb if (!ht)
3436c92544dSBjoern A. Zeeb return 0;
3446c92544dSBjoern A. Zeeb
3456c92544dSBjoern A. Zeeb ht_cap = &sband->ht_cap;
3466c92544dSBjoern A. Zeeb ht_cap->ht_supported = true;
3476c92544dSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
3486c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_GRN_FLD |
3496c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_SGI_20 |
3506c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_SGI_40 |
3516c92544dSBjoern A. Zeeb (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
3526c92544dSBjoern A. Zeeb
3536c92544dSBjoern A. Zeeb ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
3546c92544dSBjoern A. Zeeb ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
3556c92544dSBjoern A. Zeeb
3566c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, sband, vht);
3576c92544dSBjoern A. Zeeb
3586c92544dSBjoern A. Zeeb if (!vht)
3596c92544dSBjoern A. Zeeb return 0;
3606c92544dSBjoern A. Zeeb
3616c92544dSBjoern A. Zeeb vht_cap = &sband->vht_cap;
3626c92544dSBjoern A. Zeeb vht_cap->vht_supported = true;
3636c92544dSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC |
3646c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_RXSTBC_1 |
3656c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_80 |
3666c92544dSBjoern A. Zeeb (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
3676c92544dSBjoern A. Zeeb
3686c92544dSBjoern A. Zeeb return 0;
3696c92544dSBjoern A. Zeeb }
3706c92544dSBjoern A. Zeeb
3716c92544dSBjoern A. Zeeb static int
mt76_init_sband_2g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)3726c92544dSBjoern A. Zeeb mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3736c92544dSBjoern A. Zeeb int n_rates)
3746c92544dSBjoern A. Zeeb {
3756c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
3766c92544dSBjoern A. Zeeb
3776c92544dSBjoern A. Zeeb return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
3786c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_channels_2ghz), rates,
3796c92544dSBjoern A. Zeeb n_rates, true, false);
3806c92544dSBjoern A. Zeeb }
3816c92544dSBjoern A. Zeeb
3826c92544dSBjoern A. Zeeb static int
mt76_init_sband_5g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates,bool vht)3836c92544dSBjoern A. Zeeb mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3846c92544dSBjoern A. Zeeb int n_rates, bool vht)
3856c92544dSBjoern A. Zeeb {
3866c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
3876c92544dSBjoern A. Zeeb
3886c92544dSBjoern A. Zeeb return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
3896c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_channels_5ghz), rates,
3906c92544dSBjoern A. Zeeb n_rates, true, vht);
3916c92544dSBjoern A. Zeeb }
3926c92544dSBjoern A. Zeeb
3936c92544dSBjoern A. Zeeb static int
mt76_init_sband_6g(struct mt76_phy * phy,struct ieee80211_rate * rates,int n_rates)3946c92544dSBjoern A. Zeeb mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates,
3956c92544dSBjoern A. Zeeb int n_rates)
3966c92544dSBjoern A. Zeeb {
3976c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband;
3986c92544dSBjoern A. Zeeb
3996c92544dSBjoern A. Zeeb return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz,
4006c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_channels_6ghz), rates,
4016c92544dSBjoern A. Zeeb n_rates, false, false);
4026c92544dSBjoern A. Zeeb }
4036c92544dSBjoern A. Zeeb
4046c92544dSBjoern A. Zeeb static void
mt76_check_sband(struct mt76_phy * phy,struct mt76_sband * msband,enum nl80211_band band)4056c92544dSBjoern A. Zeeb mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
4066c92544dSBjoern A. Zeeb enum nl80211_band band)
4076c92544dSBjoern A. Zeeb {
4086c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband = &msband->sband;
4096c92544dSBjoern A. Zeeb bool found = false;
4106c92544dSBjoern A. Zeeb int i;
4116c92544dSBjoern A. Zeeb
4126c92544dSBjoern A. Zeeb if (!sband)
4136c92544dSBjoern A. Zeeb return;
4146c92544dSBjoern A. Zeeb
4156c92544dSBjoern A. Zeeb for (i = 0; i < sband->n_channels; i++) {
4166c92544dSBjoern A. Zeeb if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED)
4176c92544dSBjoern A. Zeeb continue;
4186c92544dSBjoern A. Zeeb
4196c92544dSBjoern A. Zeeb found = true;
4206c92544dSBjoern A. Zeeb break;
4216c92544dSBjoern A. Zeeb }
4226c92544dSBjoern A. Zeeb
4236c92544dSBjoern A. Zeeb if (found) {
424*8ba4d145SBjoern A. Zeeb cfg80211_chandef_create(&phy->chandef, &sband->channels[0],
425*8ba4d145SBjoern A. Zeeb NL80211_CHAN_HT20);
4266c92544dSBjoern A. Zeeb phy->chan_state = &msband->chan[0];
427*8ba4d145SBjoern A. Zeeb phy->dev->band_phys[band] = phy;
4286c92544dSBjoern A. Zeeb return;
4296c92544dSBjoern A. Zeeb }
4306c92544dSBjoern A. Zeeb
4316c92544dSBjoern A. Zeeb sband->n_channels = 0;
432*8ba4d145SBjoern A. Zeeb if (phy->hw->wiphy->bands[band] == sband)
4336c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[band] = NULL;
4346c92544dSBjoern A. Zeeb }
4356c92544dSBjoern A. Zeeb
4366c92544dSBjoern A. Zeeb static int
mt76_phy_init(struct mt76_phy * phy,struct ieee80211_hw * hw)4376c92544dSBjoern A. Zeeb mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
4386c92544dSBjoern A. Zeeb {
4396c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
4406c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy;
4416c92544dSBjoern A. Zeeb
442*8ba4d145SBjoern A. Zeeb INIT_LIST_HEAD(&phy->tx_list);
443*8ba4d145SBjoern A. Zeeb spin_lock_init(&phy->tx_lock);
444*8ba4d145SBjoern A. Zeeb INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work);
445*8ba4d145SBjoern A. Zeeb
446*8ba4d145SBjoern A. Zeeb if ((void *)phy != hw->priv)
447*8ba4d145SBjoern A. Zeeb return 0;
448*8ba4d145SBjoern A. Zeeb
4496c92544dSBjoern A. Zeeb SET_IEEE80211_DEV(hw, dev->dev);
4506c92544dSBjoern A. Zeeb SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
4516c92544dSBjoern A. Zeeb
452cbb3ec25SBjoern A. Zeeb wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
453cbb3ec25SBjoern A. Zeeb NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
4546c92544dSBjoern A. Zeeb wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
4556c92544dSBjoern A. Zeeb WIPHY_FLAG_SUPPORTS_TDLS |
4566c92544dSBjoern A. Zeeb WIPHY_FLAG_AP_UAPSD;
4576c92544dSBjoern A. Zeeb
4586c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
4596c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
4606c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
4616c92544dSBjoern A. Zeeb
4626c92544dSBjoern A. Zeeb wiphy->available_antennas_tx = phy->antenna_mask;
4636c92544dSBjoern A. Zeeb wiphy->available_antennas_rx = phy->antenna_mask;
4646c92544dSBjoern A. Zeeb
4656c92544dSBjoern A. Zeeb wiphy->sar_capa = &mt76_sar_capa;
4666c92544dSBjoern A. Zeeb phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges,
4676c92544dSBjoern A. Zeeb sizeof(struct mt76_freq_range_power),
4686c92544dSBjoern A. Zeeb GFP_KERNEL);
4696c92544dSBjoern A. Zeeb if (!phy->frp)
4706c92544dSBjoern A. Zeeb return -ENOMEM;
4716c92544dSBjoern A. Zeeb
4726c92544dSBjoern A. Zeeb hw->txq_data_size = sizeof(struct mt76_txq);
4736c92544dSBjoern A. Zeeb hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
4746c92544dSBjoern A. Zeeb
4756c92544dSBjoern A. Zeeb if (!hw->max_tx_fragments)
4766c92544dSBjoern A. Zeeb hw->max_tx_fragments = 16;
4776c92544dSBjoern A. Zeeb
4786c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SIGNAL_DBM);
4796c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, AMPDU_AGGREGATION);
4806c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_RC_TABLE);
4816c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
4826c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
4836c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
4846c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
485*8ba4d145SBjoern A. Zeeb ieee80211_hw_set(hw, SPECTRUM_MGMT);
486cbb3ec25SBjoern A. Zeeb
487*8ba4d145SBjoern A. Zeeb if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD) &&
488*8ba4d145SBjoern A. Zeeb hw->max_tx_fragments > 1) {
4896c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, TX_AMSDU);
4906c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, TX_FRAG_LIST);
491cbb3ec25SBjoern A. Zeeb }
492cbb3ec25SBjoern A. Zeeb
4936c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, MFP_CAPABLE);
4946c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, AP_LINK_PS);
4956c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
4966c92544dSBjoern A. Zeeb
4976c92544dSBjoern A. Zeeb return 0;
4986c92544dSBjoern A. Zeeb }
4996c92544dSBjoern A. Zeeb
5006c92544dSBjoern A. Zeeb struct mt76_phy *
mt76_alloc_radio_phy(struct mt76_dev * dev,unsigned int size,u8 band_idx)501*8ba4d145SBjoern A. Zeeb mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size,
502*8ba4d145SBjoern A. Zeeb u8 band_idx)
503*8ba4d145SBjoern A. Zeeb {
504*8ba4d145SBjoern A. Zeeb struct ieee80211_hw *hw = dev->phy.hw;
505*8ba4d145SBjoern A. Zeeb unsigned int phy_size;
506*8ba4d145SBjoern A. Zeeb struct mt76_phy *phy;
507*8ba4d145SBjoern A. Zeeb
508*8ba4d145SBjoern A. Zeeb phy_size = ALIGN(sizeof(*phy), 8);
509*8ba4d145SBjoern A. Zeeb phy = devm_kzalloc(dev->dev, size + phy_size, GFP_KERNEL);
510*8ba4d145SBjoern A. Zeeb if (!phy)
511*8ba4d145SBjoern A. Zeeb return NULL;
512*8ba4d145SBjoern A. Zeeb
513*8ba4d145SBjoern A. Zeeb phy->dev = dev;
514*8ba4d145SBjoern A. Zeeb phy->hw = hw;
515*8ba4d145SBjoern A. Zeeb #if defined(__linux__)
516*8ba4d145SBjoern A. Zeeb phy->priv = (void *)phy + phy_size;
517*8ba4d145SBjoern A. Zeeb #elif defined(__FreeBSD__)
518*8ba4d145SBjoern A. Zeeb phy->priv = (u8 *)phy + phy_size;
519*8ba4d145SBjoern A. Zeeb #endif
520*8ba4d145SBjoern A. Zeeb phy->band_idx = band_idx;
521*8ba4d145SBjoern A. Zeeb
522*8ba4d145SBjoern A. Zeeb return phy;
523*8ba4d145SBjoern A. Zeeb }
524*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_radio_phy);
525*8ba4d145SBjoern A. Zeeb
526*8ba4d145SBjoern A. Zeeb struct mt76_phy *
mt76_alloc_phy(struct mt76_dev * dev,unsigned int size,const struct ieee80211_ops * ops,u8 band_idx)5276c92544dSBjoern A. Zeeb mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
5286c92544dSBjoern A. Zeeb const struct ieee80211_ops *ops, u8 band_idx)
5296c92544dSBjoern A. Zeeb {
5306c92544dSBjoern A. Zeeb struct ieee80211_hw *hw;
5316c92544dSBjoern A. Zeeb unsigned int phy_size;
5326c92544dSBjoern A. Zeeb struct mt76_phy *phy;
5336c92544dSBjoern A. Zeeb
5346c92544dSBjoern A. Zeeb phy_size = ALIGN(sizeof(*phy), 8);
5356c92544dSBjoern A. Zeeb hw = ieee80211_alloc_hw(size + phy_size, ops);
5366c92544dSBjoern A. Zeeb if (!hw)
5376c92544dSBjoern A. Zeeb return NULL;
5386c92544dSBjoern A. Zeeb
5396c92544dSBjoern A. Zeeb phy = hw->priv;
5406c92544dSBjoern A. Zeeb phy->dev = dev;
5416c92544dSBjoern A. Zeeb phy->hw = hw;
5426c92544dSBjoern A. Zeeb #if defined(__linux__)
5436c92544dSBjoern A. Zeeb phy->priv = hw->priv + phy_size;
5446c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
5456c92544dSBjoern A. Zeeb phy->priv = (u8 *)hw->priv + phy_size;
5466c92544dSBjoern A. Zeeb #endif
5476c92544dSBjoern A. Zeeb phy->band_idx = band_idx;
5486c92544dSBjoern A. Zeeb
5496c92544dSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
5506c92544dSBjoern A. Zeeb hw->wiphy->interface_modes =
5516c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_STATION) |
5526c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) |
5536c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH
5546c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) |
5556c92544dSBjoern A. Zeeb #endif
5566c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) |
5576c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) |
5586c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_ADHOC);
5596c92544dSBjoern A. Zeeb
5606c92544dSBjoern A. Zeeb return phy;
5616c92544dSBjoern A. Zeeb }
5626c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_phy);
5636c92544dSBjoern A. Zeeb
mt76_register_phy(struct mt76_phy * phy,bool vht,struct ieee80211_rate * rates,int n_rates)5646c92544dSBjoern A. Zeeb int mt76_register_phy(struct mt76_phy *phy, bool vht,
5656c92544dSBjoern A. Zeeb struct ieee80211_rate *rates, int n_rates)
5666c92544dSBjoern A. Zeeb {
5676c92544dSBjoern A. Zeeb int ret;
5686c92544dSBjoern A. Zeeb
5696c92544dSBjoern A. Zeeb ret = mt76_phy_init(phy, phy->hw);
5706c92544dSBjoern A. Zeeb if (ret)
5716c92544dSBjoern A. Zeeb return ret;
5726c92544dSBjoern A. Zeeb
5736c92544dSBjoern A. Zeeb if (phy->cap.has_2ghz) {
5746c92544dSBjoern A. Zeeb ret = mt76_init_sband_2g(phy, rates, n_rates);
5756c92544dSBjoern A. Zeeb if (ret)
5766c92544dSBjoern A. Zeeb return ret;
5776c92544dSBjoern A. Zeeb }
5786c92544dSBjoern A. Zeeb
5796c92544dSBjoern A. Zeeb if (phy->cap.has_5ghz) {
5806c92544dSBjoern A. Zeeb ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
5816c92544dSBjoern A. Zeeb if (ret)
5826c92544dSBjoern A. Zeeb return ret;
5836c92544dSBjoern A. Zeeb }
5846c92544dSBjoern A. Zeeb
5856c92544dSBjoern A. Zeeb if (phy->cap.has_6ghz) {
5866c92544dSBjoern A. Zeeb ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
5876c92544dSBjoern A. Zeeb if (ret)
5886c92544dSBjoern A. Zeeb return ret;
5896c92544dSBjoern A. Zeeb }
5906c92544dSBjoern A. Zeeb
591cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
592cbb3ec25SBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) {
593cbb3ec25SBjoern A. Zeeb ret = mt76_led_init(phy);
594cbb3ec25SBjoern A. Zeeb if (ret)
595cbb3ec25SBjoern A. Zeeb return ret;
596cbb3ec25SBjoern A. Zeeb }
597cbb3ec25SBjoern A. Zeeb #endif
598cbb3ec25SBjoern A. Zeeb
5996c92544dSBjoern A. Zeeb wiphy_read_of_freq_limits(phy->hw->wiphy);
6006c92544dSBjoern A. Zeeb mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
6016c92544dSBjoern A. Zeeb mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
6026c92544dSBjoern A. Zeeb mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ);
6036c92544dSBjoern A. Zeeb
604*8ba4d145SBjoern A. Zeeb if ((void *)phy == phy->hw->priv) {
6056c92544dSBjoern A. Zeeb ret = ieee80211_register_hw(phy->hw);
6066c92544dSBjoern A. Zeeb if (ret)
6076c92544dSBjoern A. Zeeb return ret;
608*8ba4d145SBjoern A. Zeeb }
6096c92544dSBjoern A. Zeeb
610cbb3ec25SBjoern A. Zeeb set_bit(MT76_STATE_REGISTERED, &phy->state);
6116c92544dSBjoern A. Zeeb phy->dev->phys[phy->band_idx] = phy;
6126c92544dSBjoern A. Zeeb
6136c92544dSBjoern A. Zeeb return 0;
6146c92544dSBjoern A. Zeeb }
6156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_phy);
6166c92544dSBjoern A. Zeeb
mt76_unregister_phy(struct mt76_phy * phy)6176c92544dSBjoern A. Zeeb void mt76_unregister_phy(struct mt76_phy *phy)
6186c92544dSBjoern A. Zeeb {
6196c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
6206c92544dSBjoern A. Zeeb
621cbb3ec25SBjoern A. Zeeb if (!test_bit(MT76_STATE_REGISTERED, &phy->state))
622cbb3ec25SBjoern A. Zeeb return;
623cbb3ec25SBjoern A. Zeeb
624cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
625cbb3ec25SBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS))
626cbb3ec25SBjoern A. Zeeb mt76_led_cleanup(phy);
627cbb3ec25SBjoern A. Zeeb #endif
6286c92544dSBjoern A. Zeeb mt76_tx_status_check(dev, true);
6296c92544dSBjoern A. Zeeb ieee80211_unregister_hw(phy->hw);
6306c92544dSBjoern A. Zeeb dev->phys[phy->band_idx] = NULL;
6316c92544dSBjoern A. Zeeb }
6326c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_phy);
6336c92544dSBjoern A. Zeeb
mt76_create_page_pool(struct mt76_dev * dev,struct mt76_queue * q)634cbb3ec25SBjoern A. Zeeb int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
635cbb3ec25SBjoern A. Zeeb {
636*8ba4d145SBjoern A. Zeeb bool is_qrx = mt76_queue_is_rx(dev, q);
637cbb3ec25SBjoern A. Zeeb struct page_pool_params pp_params = {
638cbb3ec25SBjoern A. Zeeb .order = 0,
639*8ba4d145SBjoern A. Zeeb .flags = 0,
640cbb3ec25SBjoern A. Zeeb .nid = NUMA_NO_NODE,
641cbb3ec25SBjoern A. Zeeb .dev = dev->dma_dev,
642cbb3ec25SBjoern A. Zeeb };
643*8ba4d145SBjoern A. Zeeb int idx = is_qrx ? q - dev->q_rx : -1;
644*8ba4d145SBjoern A. Zeeb
645*8ba4d145SBjoern A. Zeeb /* Allocate page_pools just for rx/wed_tx_free queues */
646*8ba4d145SBjoern A. Zeeb if (!is_qrx && !mt76_queue_is_wed_tx_free(q))
647*8ba4d145SBjoern A. Zeeb return 0;
648cbb3ec25SBjoern A. Zeeb
649cbb3ec25SBjoern A. Zeeb switch (idx) {
650cbb3ec25SBjoern A. Zeeb case MT_RXQ_MAIN:
651cbb3ec25SBjoern A. Zeeb case MT_RXQ_BAND1:
652cbb3ec25SBjoern A. Zeeb case MT_RXQ_BAND2:
653cbb3ec25SBjoern A. Zeeb pp_params.pool_size = 256;
654cbb3ec25SBjoern A. Zeeb break;
655cbb3ec25SBjoern A. Zeeb default:
656cbb3ec25SBjoern A. Zeeb pp_params.pool_size = 16;
657cbb3ec25SBjoern A. Zeeb break;
658cbb3ec25SBjoern A. Zeeb }
659cbb3ec25SBjoern A. Zeeb
660cbb3ec25SBjoern A. Zeeb if (mt76_is_mmio(dev)) {
661cbb3ec25SBjoern A. Zeeb /* rely on page_pool for DMA mapping */
662cbb3ec25SBjoern A. Zeeb pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
663cbb3ec25SBjoern A. Zeeb pp_params.dma_dir = DMA_FROM_DEVICE;
664cbb3ec25SBjoern A. Zeeb pp_params.max_len = PAGE_SIZE;
665cbb3ec25SBjoern A. Zeeb pp_params.offset = 0;
666*8ba4d145SBjoern A. Zeeb /* NAPI is available just for rx queues */
667*8ba4d145SBjoern A. Zeeb if (idx >= 0 && idx < ARRAY_SIZE(dev->napi))
668*8ba4d145SBjoern A. Zeeb pp_params.napi = &dev->napi[idx];
669cbb3ec25SBjoern A. Zeeb }
670cbb3ec25SBjoern A. Zeeb
671cbb3ec25SBjoern A. Zeeb q->page_pool = page_pool_create(&pp_params);
672cbb3ec25SBjoern A. Zeeb if (IS_ERR(q->page_pool)) {
673cbb3ec25SBjoern A. Zeeb int err = PTR_ERR(q->page_pool);
674cbb3ec25SBjoern A. Zeeb
675cbb3ec25SBjoern A. Zeeb q->page_pool = NULL;
676cbb3ec25SBjoern A. Zeeb return err;
677cbb3ec25SBjoern A. Zeeb }
678cbb3ec25SBjoern A. Zeeb
679cbb3ec25SBjoern A. Zeeb return 0;
680cbb3ec25SBjoern A. Zeeb }
681cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_create_page_pool);
682cbb3ec25SBjoern A. Zeeb
6836c92544dSBjoern A. Zeeb struct mt76_dev *
mt76_alloc_device(struct device * pdev,unsigned int size,const struct ieee80211_ops * ops,const struct mt76_driver_ops * drv_ops)6846c92544dSBjoern A. Zeeb mt76_alloc_device(struct device *pdev, unsigned int size,
6856c92544dSBjoern A. Zeeb const struct ieee80211_ops *ops,
6866c92544dSBjoern A. Zeeb const struct mt76_driver_ops *drv_ops)
6876c92544dSBjoern A. Zeeb {
6886c92544dSBjoern A. Zeeb struct ieee80211_hw *hw;
6896c92544dSBjoern A. Zeeb struct mt76_phy *phy;
6906c92544dSBjoern A. Zeeb struct mt76_dev *dev;
6916c92544dSBjoern A. Zeeb int i;
6926c92544dSBjoern A. Zeeb
6936c92544dSBjoern A. Zeeb hw = ieee80211_alloc_hw(size, ops);
6946c92544dSBjoern A. Zeeb if (!hw)
6956c92544dSBjoern A. Zeeb return NULL;
6966c92544dSBjoern A. Zeeb
6976c92544dSBjoern A. Zeeb dev = hw->priv;
6986c92544dSBjoern A. Zeeb dev->hw = hw;
6996c92544dSBjoern A. Zeeb dev->dev = pdev;
7006c92544dSBjoern A. Zeeb dev->drv = drv_ops;
7016c92544dSBjoern A. Zeeb dev->dma_dev = pdev;
7026c92544dSBjoern A. Zeeb
7036c92544dSBjoern A. Zeeb phy = &dev->phy;
7046c92544dSBjoern A. Zeeb phy->dev = dev;
7056c92544dSBjoern A. Zeeb phy->hw = hw;
7066c92544dSBjoern A. Zeeb phy->band_idx = MT_BAND0;
7076c92544dSBjoern A. Zeeb dev->phys[phy->band_idx] = phy;
7086c92544dSBjoern A. Zeeb
7096c92544dSBjoern A. Zeeb spin_lock_init(&dev->rx_lock);
7106c92544dSBjoern A. Zeeb spin_lock_init(&dev->lock);
7116c92544dSBjoern A. Zeeb spin_lock_init(&dev->cc_lock);
7126c92544dSBjoern A. Zeeb spin_lock_init(&dev->status_lock);
713cbb3ec25SBjoern A. Zeeb spin_lock_init(&dev->wed_lock);
7146c92544dSBjoern A. Zeeb mutex_init(&dev->mutex);
7156c92544dSBjoern A. Zeeb init_waitqueue_head(&dev->tx_wait);
7166c92544dSBjoern A. Zeeb
7176c92544dSBjoern A. Zeeb skb_queue_head_init(&dev->mcu.res_q);
7186c92544dSBjoern A. Zeeb init_waitqueue_head(&dev->mcu.wait);
7196c92544dSBjoern A. Zeeb mutex_init(&dev->mcu.mutex);
7206c92544dSBjoern A. Zeeb dev->tx_worker.fn = mt76_tx_worker;
7216c92544dSBjoern A. Zeeb
7226c92544dSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
7236c92544dSBjoern A. Zeeb hw->wiphy->interface_modes =
7246c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_STATION) |
7256c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) |
7266c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH
7276c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) |
7286c92544dSBjoern A. Zeeb #endif
7296c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) |
7306c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) |
7316c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_ADHOC);
7326c92544dSBjoern A. Zeeb
7336c92544dSBjoern A. Zeeb spin_lock_init(&dev->token_lock);
7346c92544dSBjoern A. Zeeb idr_init(&dev->token);
7356c92544dSBjoern A. Zeeb
736cbb3ec25SBjoern A. Zeeb spin_lock_init(&dev->rx_token_lock);
737cbb3ec25SBjoern A. Zeeb idr_init(&dev->rx_token);
738cbb3ec25SBjoern A. Zeeb
7396c92544dSBjoern A. Zeeb INIT_LIST_HEAD(&dev->wcid_list);
740cbb3ec25SBjoern A. Zeeb INIT_LIST_HEAD(&dev->sta_poll_list);
741cbb3ec25SBjoern A. Zeeb spin_lock_init(&dev->sta_poll_lock);
7426c92544dSBjoern A. Zeeb
7436c92544dSBjoern A. Zeeb INIT_LIST_HEAD(&dev->txwi_cache);
744cbb3ec25SBjoern A. Zeeb INIT_LIST_HEAD(&dev->rxwi_cache);
7456c92544dSBjoern A. Zeeb dev->token_size = dev->drv->token_size;
746*8ba4d145SBjoern A. Zeeb INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work);
7476c92544dSBjoern A. Zeeb
7486c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
7496c92544dSBjoern A. Zeeb skb_queue_head_init(&dev->rx_skb[i]);
7506c92544dSBjoern A. Zeeb
7516c92544dSBjoern A. Zeeb dev->wq = alloc_ordered_workqueue("mt76", 0);
7526c92544dSBjoern A. Zeeb if (!dev->wq) {
7536c92544dSBjoern A. Zeeb ieee80211_free_hw(hw);
7546c92544dSBjoern A. Zeeb return NULL;
7556c92544dSBjoern A. Zeeb }
7566c92544dSBjoern A. Zeeb
7576c92544dSBjoern A. Zeeb return dev;
7586c92544dSBjoern A. Zeeb }
7596c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_device);
7606c92544dSBjoern A. Zeeb
mt76_register_device(struct mt76_dev * dev,bool vht,struct ieee80211_rate * rates,int n_rates)7616c92544dSBjoern A. Zeeb int mt76_register_device(struct mt76_dev *dev, bool vht,
7626c92544dSBjoern A. Zeeb struct ieee80211_rate *rates, int n_rates)
7636c92544dSBjoern A. Zeeb {
7646c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = dev->hw;
7656c92544dSBjoern A. Zeeb struct mt76_phy *phy = &dev->phy;
7666c92544dSBjoern A. Zeeb int ret;
7676c92544dSBjoern A. Zeeb
7686c92544dSBjoern A. Zeeb dev_set_drvdata(dev->dev, dev);
769*8ba4d145SBjoern A. Zeeb mt76_wcid_init(&dev->global_wcid, phy->band_idx);
7706c92544dSBjoern A. Zeeb ret = mt76_phy_init(phy, hw);
7716c92544dSBjoern A. Zeeb if (ret)
7726c92544dSBjoern A. Zeeb return ret;
7736c92544dSBjoern A. Zeeb
7746c92544dSBjoern A. Zeeb if (phy->cap.has_2ghz) {
7756c92544dSBjoern A. Zeeb ret = mt76_init_sband_2g(phy, rates, n_rates);
7766c92544dSBjoern A. Zeeb if (ret)
7776c92544dSBjoern A. Zeeb return ret;
7786c92544dSBjoern A. Zeeb }
7796c92544dSBjoern A. Zeeb
7806c92544dSBjoern A. Zeeb if (phy->cap.has_5ghz) {
7816c92544dSBjoern A. Zeeb ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
7826c92544dSBjoern A. Zeeb if (ret)
7836c92544dSBjoern A. Zeeb return ret;
7846c92544dSBjoern A. Zeeb }
7856c92544dSBjoern A. Zeeb
7866c92544dSBjoern A. Zeeb if (phy->cap.has_6ghz) {
7876c92544dSBjoern A. Zeeb ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4);
7886c92544dSBjoern A. Zeeb if (ret)
7896c92544dSBjoern A. Zeeb return ret;
7906c92544dSBjoern A. Zeeb }
7916c92544dSBjoern A. Zeeb
7926c92544dSBjoern A. Zeeb wiphy_read_of_freq_limits(hw->wiphy);
7936c92544dSBjoern A. Zeeb mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ);
7946c92544dSBjoern A. Zeeb mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ);
7956c92544dSBjoern A. Zeeb mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ);
7966c92544dSBjoern A. Zeeb
7976c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
7986c92544dSBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) {
799cbb3ec25SBjoern A. Zeeb ret = mt76_led_init(phy);
8006c92544dSBjoern A. Zeeb if (ret)
8016c92544dSBjoern A. Zeeb return ret;
8026c92544dSBjoern A. Zeeb }
8036c92544dSBjoern A. Zeeb #endif
8046c92544dSBjoern A. Zeeb
8056c92544dSBjoern A. Zeeb ret = ieee80211_register_hw(hw);
8066c92544dSBjoern A. Zeeb if (ret)
8076c92544dSBjoern A. Zeeb return ret;
8086c92544dSBjoern A. Zeeb
8096c92544dSBjoern A. Zeeb WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
810cbb3ec25SBjoern A. Zeeb set_bit(MT76_STATE_REGISTERED, &phy->state);
8116c92544dSBjoern A. Zeeb sched_set_fifo_low(dev->tx_worker.task);
8126c92544dSBjoern A. Zeeb
8136c92544dSBjoern A. Zeeb return 0;
8146c92544dSBjoern A. Zeeb }
8156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_device);
8166c92544dSBjoern A. Zeeb
mt76_unregister_device(struct mt76_dev * dev)8176c92544dSBjoern A. Zeeb void mt76_unregister_device(struct mt76_dev *dev)
8186c92544dSBjoern A. Zeeb {
819cbb3ec25SBjoern A. Zeeb #if defined(__linux__)
8206c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = dev->hw;
821cbb3ec25SBjoern A. Zeeb #endif
822cbb3ec25SBjoern A. Zeeb
823cbb3ec25SBjoern A. Zeeb if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state))
824cbb3ec25SBjoern A. Zeeb return;
8256c92544dSBjoern A. Zeeb
8266c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS)
8276c92544dSBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS))
828cbb3ec25SBjoern A. Zeeb mt76_led_cleanup(&dev->phy);
8296c92544dSBjoern A. Zeeb #endif
8306c92544dSBjoern A. Zeeb mt76_tx_status_check(dev, true);
831*8ba4d145SBjoern A. Zeeb mt76_wcid_cleanup(dev, &dev->global_wcid);
832cbb3ec25SBjoern A. Zeeb #if defined(__linux__)
8336c92544dSBjoern A. Zeeb ieee80211_unregister_hw(hw);
834cbb3ec25SBjoern A. Zeeb #elif defined(__FreeBSD__)
835cbb3ec25SBjoern A. Zeeb ieee80211_unregister_hw(dev->hw);
836cbb3ec25SBjoern A. Zeeb #endif
8376c92544dSBjoern A. Zeeb }
8386c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_device);
8396c92544dSBjoern A. Zeeb
mt76_free_device(struct mt76_dev * dev)8406c92544dSBjoern A. Zeeb void mt76_free_device(struct mt76_dev *dev)
8416c92544dSBjoern A. Zeeb {
8426c92544dSBjoern A. Zeeb mt76_worker_teardown(&dev->tx_worker);
8436c92544dSBjoern A. Zeeb if (dev->wq) {
8446c92544dSBjoern A. Zeeb destroy_workqueue(dev->wq);
8456c92544dSBjoern A. Zeeb dev->wq = NULL;
8466c92544dSBjoern A. Zeeb }
8476c92544dSBjoern A. Zeeb ieee80211_free_hw(dev->hw);
8486c92544dSBjoern A. Zeeb }
8496c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_free_device);
8506c92544dSBjoern A. Zeeb
851*8ba4d145SBjoern A. Zeeb static struct mt76_phy *
mt76_vif_phy(struct ieee80211_hw * hw,struct ieee80211_vif * vif)852*8ba4d145SBjoern A. Zeeb mt76_vif_phy(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
853*8ba4d145SBjoern A. Zeeb {
854*8ba4d145SBjoern A. Zeeb struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
855*8ba4d145SBjoern A. Zeeb struct mt76_chanctx *ctx;
856*8ba4d145SBjoern A. Zeeb
857*8ba4d145SBjoern A. Zeeb if (!hw->wiphy->n_radio)
858*8ba4d145SBjoern A. Zeeb return hw->priv;
859*8ba4d145SBjoern A. Zeeb
860*8ba4d145SBjoern A. Zeeb if (!mlink->ctx)
861*8ba4d145SBjoern A. Zeeb return NULL;
862*8ba4d145SBjoern A. Zeeb
863*8ba4d145SBjoern A. Zeeb ctx = (struct mt76_chanctx *)mlink->ctx->drv_priv;
864*8ba4d145SBjoern A. Zeeb return ctx->phy;
865*8ba4d145SBjoern A. Zeeb }
866*8ba4d145SBjoern A. Zeeb
mt76_rx_release_amsdu(struct mt76_phy * phy,enum mt76_rxq_id q)8676c92544dSBjoern A. Zeeb static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
8686c92544dSBjoern A. Zeeb {
8696c92544dSBjoern A. Zeeb struct sk_buff *skb = phy->rx_amsdu[q].head;
8706c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
8716c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
8726c92544dSBjoern A. Zeeb
8736c92544dSBjoern A. Zeeb phy->rx_amsdu[q].head = NULL;
8746c92544dSBjoern A. Zeeb phy->rx_amsdu[q].tail = NULL;
8756c92544dSBjoern A. Zeeb
8766c92544dSBjoern A. Zeeb /*
8776c92544dSBjoern A. Zeeb * Validate if the amsdu has a proper first subframe.
8786c92544dSBjoern A. Zeeb * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU
8796c92544dSBjoern A. Zeeb * flag of the QoS header gets flipped. In such cases, the first
8806c92544dSBjoern A. Zeeb * subframe has a LLC/SNAP header in the location of the destination
8816c92544dSBjoern A. Zeeb * address.
8826c92544dSBjoern A. Zeeb */
8836c92544dSBjoern A. Zeeb if (skb_shinfo(skb)->frag_list) {
8846c92544dSBjoern A. Zeeb int offset = 0;
8856c92544dSBjoern A. Zeeb
8866c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_8023)) {
8876c92544dSBjoern A. Zeeb offset = ieee80211_get_hdrlen_from_skb(skb);
8886c92544dSBjoern A. Zeeb
8896c92544dSBjoern A. Zeeb if ((status->flag &
8906c92544dSBjoern A. Zeeb (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) ==
8916c92544dSBjoern A. Zeeb RX_FLAG_DECRYPTED)
8926c92544dSBjoern A. Zeeb offset += 8;
8936c92544dSBjoern A. Zeeb }
8946c92544dSBjoern A. Zeeb
8956c92544dSBjoern A. Zeeb if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
8966c92544dSBjoern A. Zeeb dev_kfree_skb(skb);
8976c92544dSBjoern A. Zeeb return;
8986c92544dSBjoern A. Zeeb }
8996c92544dSBjoern A. Zeeb }
9006c92544dSBjoern A. Zeeb __skb_queue_tail(&dev->rx_skb[q], skb);
9016c92544dSBjoern A. Zeeb }
9026c92544dSBjoern A. Zeeb
mt76_rx_release_burst(struct mt76_phy * phy,enum mt76_rxq_id q,struct sk_buff * skb)9036c92544dSBjoern A. Zeeb static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q,
9046c92544dSBjoern A. Zeeb struct sk_buff *skb)
9056c92544dSBjoern A. Zeeb {
9066c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
9076c92544dSBjoern A. Zeeb
9086c92544dSBjoern A. Zeeb if (phy->rx_amsdu[q].head &&
9096c92544dSBjoern A. Zeeb (!status->amsdu || status->first_amsdu ||
9106c92544dSBjoern A. Zeeb status->seqno != phy->rx_amsdu[q].seqno))
9116c92544dSBjoern A. Zeeb mt76_rx_release_amsdu(phy, q);
9126c92544dSBjoern A. Zeeb
9136c92544dSBjoern A. Zeeb if (!phy->rx_amsdu[q].head) {
9146c92544dSBjoern A. Zeeb phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list;
9156c92544dSBjoern A. Zeeb phy->rx_amsdu[q].seqno = status->seqno;
9166c92544dSBjoern A. Zeeb phy->rx_amsdu[q].head = skb;
9176c92544dSBjoern A. Zeeb } else {
9186c92544dSBjoern A. Zeeb *phy->rx_amsdu[q].tail = skb;
9196c92544dSBjoern A. Zeeb phy->rx_amsdu[q].tail = &skb->next;
9206c92544dSBjoern A. Zeeb }
9216c92544dSBjoern A. Zeeb
9226c92544dSBjoern A. Zeeb if (!status->amsdu || status->last_amsdu)
9236c92544dSBjoern A. Zeeb mt76_rx_release_amsdu(phy, q);
9246c92544dSBjoern A. Zeeb }
9256c92544dSBjoern A. Zeeb
mt76_rx(struct mt76_dev * dev,enum mt76_rxq_id q,struct sk_buff * skb)9266c92544dSBjoern A. Zeeb void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
9276c92544dSBjoern A. Zeeb {
9286c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
9296c92544dSBjoern A. Zeeb struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx);
9306c92544dSBjoern A. Zeeb
9316c92544dSBjoern A. Zeeb if (!test_bit(MT76_STATE_RUNNING, &phy->state)) {
9326c92544dSBjoern A. Zeeb dev_kfree_skb(skb);
9336c92544dSBjoern A. Zeeb return;
9346c92544dSBjoern A. Zeeb }
9356c92544dSBjoern A. Zeeb
9366c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE
9376c92544dSBjoern A. Zeeb if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
9386c92544dSBjoern A. Zeeb phy->test.rx_stats.packets[q]++;
9396c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_FAILED_FCS_CRC)
9406c92544dSBjoern A. Zeeb phy->test.rx_stats.fcs_error[q]++;
9416c92544dSBjoern A. Zeeb }
9426c92544dSBjoern A. Zeeb #endif
9436c92544dSBjoern A. Zeeb
9446c92544dSBjoern A. Zeeb mt76_rx_release_burst(phy, q, skb);
9456c92544dSBjoern A. Zeeb }
9466c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx);
9476c92544dSBjoern A. Zeeb
mt76_has_tx_pending(struct mt76_phy * phy)9486c92544dSBjoern A. Zeeb bool mt76_has_tx_pending(struct mt76_phy *phy)
9496c92544dSBjoern A. Zeeb {
9506c92544dSBjoern A. Zeeb struct mt76_queue *q;
9516c92544dSBjoern A. Zeeb int i;
9526c92544dSBjoern A. Zeeb
9536c92544dSBjoern A. Zeeb for (i = 0; i < __MT_TXQ_MAX; i++) {
9546c92544dSBjoern A. Zeeb q = phy->q_tx[i];
9556c92544dSBjoern A. Zeeb if (q && q->queued)
9566c92544dSBjoern A. Zeeb return true;
9576c92544dSBjoern A. Zeeb }
9586c92544dSBjoern A. Zeeb
9596c92544dSBjoern A. Zeeb return false;
9606c92544dSBjoern A. Zeeb }
9616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
9626c92544dSBjoern A. Zeeb
9636c92544dSBjoern A. Zeeb static struct mt76_channel_state *
mt76_channel_state(struct mt76_phy * phy,struct ieee80211_channel * c)9646c92544dSBjoern A. Zeeb mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
9656c92544dSBjoern A. Zeeb {
9666c92544dSBjoern A. Zeeb struct mt76_sband *msband;
9676c92544dSBjoern A. Zeeb int idx;
9686c92544dSBjoern A. Zeeb
9696c92544dSBjoern A. Zeeb if (c->band == NL80211_BAND_2GHZ)
9706c92544dSBjoern A. Zeeb msband = &phy->sband_2g;
9716c92544dSBjoern A. Zeeb else if (c->band == NL80211_BAND_6GHZ)
9726c92544dSBjoern A. Zeeb msband = &phy->sband_6g;
9736c92544dSBjoern A. Zeeb else
9746c92544dSBjoern A. Zeeb msband = &phy->sband_5g;
9756c92544dSBjoern A. Zeeb
9766c92544dSBjoern A. Zeeb idx = c - &msband->sband.channels[0];
9776c92544dSBjoern A. Zeeb return &msband->chan[idx];
9786c92544dSBjoern A. Zeeb }
9796c92544dSBjoern A. Zeeb
mt76_update_survey_active_time(struct mt76_phy * phy,ktime_t time)9806c92544dSBjoern A. Zeeb void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
9816c92544dSBjoern A. Zeeb {
9826c92544dSBjoern A. Zeeb struct mt76_channel_state *state = phy->chan_state;
9836c92544dSBjoern A. Zeeb
9846c92544dSBjoern A. Zeeb state->cc_active += ktime_to_us(ktime_sub(time,
9856c92544dSBjoern A. Zeeb phy->survey_time));
9866c92544dSBjoern A. Zeeb phy->survey_time = time;
9876c92544dSBjoern A. Zeeb }
9886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey_active_time);
9896c92544dSBjoern A. Zeeb
mt76_update_survey(struct mt76_phy * phy)9906c92544dSBjoern A. Zeeb void mt76_update_survey(struct mt76_phy *phy)
9916c92544dSBjoern A. Zeeb {
9926c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
9936c92544dSBjoern A. Zeeb ktime_t cur_time;
9946c92544dSBjoern A. Zeeb
9956c92544dSBjoern A. Zeeb if (dev->drv->update_survey)
9966c92544dSBjoern A. Zeeb dev->drv->update_survey(phy);
9976c92544dSBjoern A. Zeeb
9986c92544dSBjoern A. Zeeb cur_time = ktime_get_boottime();
9996c92544dSBjoern A. Zeeb mt76_update_survey_active_time(phy, cur_time);
10006c92544dSBjoern A. Zeeb
10016c92544dSBjoern A. Zeeb if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) {
10026c92544dSBjoern A. Zeeb struct mt76_channel_state *state = phy->chan_state;
10036c92544dSBjoern A. Zeeb
10046c92544dSBjoern A. Zeeb spin_lock_bh(&dev->cc_lock);
10056c92544dSBjoern A. Zeeb state->cc_bss_rx += dev->cur_cc_bss_rx;
10066c92544dSBjoern A. Zeeb dev->cur_cc_bss_rx = 0;
10076c92544dSBjoern A. Zeeb spin_unlock_bh(&dev->cc_lock);
10086c92544dSBjoern A. Zeeb }
10096c92544dSBjoern A. Zeeb }
10106c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey);
10116c92544dSBjoern A. Zeeb
__mt76_set_channel(struct mt76_phy * phy,struct cfg80211_chan_def * chandef,bool offchannel)1012*8ba4d145SBjoern A. Zeeb int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
1013*8ba4d145SBjoern A. Zeeb bool offchannel)
10146c92544dSBjoern A. Zeeb {
10156c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
10166c92544dSBjoern A. Zeeb int timeout = HZ / 5;
1017*8ba4d145SBjoern A. Zeeb int ret;
10186c92544dSBjoern A. Zeeb
1019*8ba4d145SBjoern A. Zeeb set_bit(MT76_RESET, &phy->state);
1020*8ba4d145SBjoern A. Zeeb
1021*8ba4d145SBjoern A. Zeeb mt76_worker_disable(&dev->tx_worker);
10226c92544dSBjoern A. Zeeb wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
10236c92544dSBjoern A. Zeeb mt76_update_survey(phy);
10246c92544dSBjoern A. Zeeb
10256c92544dSBjoern A. Zeeb if (phy->chandef.chan->center_freq != chandef->chan->center_freq ||
10266c92544dSBjoern A. Zeeb phy->chandef.width != chandef->width)
10276c92544dSBjoern A. Zeeb phy->dfs_state = MT_DFS_STATE_UNKNOWN;
10286c92544dSBjoern A. Zeeb
10296c92544dSBjoern A. Zeeb phy->chandef = *chandef;
10306c92544dSBjoern A. Zeeb phy->chan_state = mt76_channel_state(phy, chandef->chan);
1031*8ba4d145SBjoern A. Zeeb phy->offchannel = offchannel;
10326c92544dSBjoern A. Zeeb
10336c92544dSBjoern A. Zeeb if (!offchannel)
1034*8ba4d145SBjoern A. Zeeb phy->main_chandef = *chandef;
10356c92544dSBjoern A. Zeeb
1036*8ba4d145SBjoern A. Zeeb if (chandef->chan != phy->main_chandef.chan)
10376c92544dSBjoern A. Zeeb memset(phy->chan_state, 0, sizeof(*phy->chan_state));
1038*8ba4d145SBjoern A. Zeeb
1039*8ba4d145SBjoern A. Zeeb ret = dev->drv->set_channel(phy);
1040*8ba4d145SBjoern A. Zeeb
1041*8ba4d145SBjoern A. Zeeb clear_bit(MT76_RESET, &phy->state);
1042*8ba4d145SBjoern A. Zeeb mt76_worker_enable(&dev->tx_worker);
1043*8ba4d145SBjoern A. Zeeb mt76_worker_schedule(&dev->tx_worker);
1044*8ba4d145SBjoern A. Zeeb
1045*8ba4d145SBjoern A. Zeeb return ret;
10466c92544dSBjoern A. Zeeb }
1047*8ba4d145SBjoern A. Zeeb
mt76_set_channel(struct mt76_phy * phy,struct cfg80211_chan_def * chandef,bool offchannel)1048*8ba4d145SBjoern A. Zeeb int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
1049*8ba4d145SBjoern A. Zeeb bool offchannel)
1050*8ba4d145SBjoern A. Zeeb {
1051*8ba4d145SBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
1052*8ba4d145SBjoern A. Zeeb int ret;
1053*8ba4d145SBjoern A. Zeeb
1054*8ba4d145SBjoern A. Zeeb cancel_delayed_work_sync(&phy->mac_work);
1055*8ba4d145SBjoern A. Zeeb
1056*8ba4d145SBjoern A. Zeeb mutex_lock(&dev->mutex);
1057*8ba4d145SBjoern A. Zeeb ret = __mt76_set_channel(phy, chandef, offchannel);
1058*8ba4d145SBjoern A. Zeeb mutex_unlock(&dev->mutex);
1059*8ba4d145SBjoern A. Zeeb
1060*8ba4d145SBjoern A. Zeeb return ret;
1061*8ba4d145SBjoern A. Zeeb }
1062*8ba4d145SBjoern A. Zeeb
mt76_update_channel(struct mt76_phy * phy)1063*8ba4d145SBjoern A. Zeeb int mt76_update_channel(struct mt76_phy *phy)
1064*8ba4d145SBjoern A. Zeeb {
1065*8ba4d145SBjoern A. Zeeb struct ieee80211_hw *hw = phy->hw;
1066*8ba4d145SBjoern A. Zeeb struct cfg80211_chan_def *chandef = &hw->conf.chandef;
1067*8ba4d145SBjoern A. Zeeb bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
1068*8ba4d145SBjoern A. Zeeb
1069*8ba4d145SBjoern A. Zeeb phy->radar_enabled = hw->conf.radar_enabled;
1070*8ba4d145SBjoern A. Zeeb
1071*8ba4d145SBjoern A. Zeeb return mt76_set_channel(phy, chandef, offchannel);
1072*8ba4d145SBjoern A. Zeeb }
1073*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_channel);
1074*8ba4d145SBjoern A. Zeeb
1075*8ba4d145SBjoern A. Zeeb static struct mt76_sband *
mt76_get_survey_sband(struct mt76_phy * phy,int * idx)1076*8ba4d145SBjoern A. Zeeb mt76_get_survey_sband(struct mt76_phy *phy, int *idx)
1077*8ba4d145SBjoern A. Zeeb {
1078*8ba4d145SBjoern A. Zeeb if (*idx < phy->sband_2g.sband.n_channels)
1079*8ba4d145SBjoern A. Zeeb return &phy->sband_2g;
1080*8ba4d145SBjoern A. Zeeb
1081*8ba4d145SBjoern A. Zeeb *idx -= phy->sband_2g.sband.n_channels;
1082*8ba4d145SBjoern A. Zeeb if (*idx < phy->sband_5g.sband.n_channels)
1083*8ba4d145SBjoern A. Zeeb return &phy->sband_5g;
1084*8ba4d145SBjoern A. Zeeb
1085*8ba4d145SBjoern A. Zeeb *idx -= phy->sband_5g.sband.n_channels;
1086*8ba4d145SBjoern A. Zeeb if (*idx < phy->sband_6g.sband.n_channels)
1087*8ba4d145SBjoern A. Zeeb return &phy->sband_6g;
1088*8ba4d145SBjoern A. Zeeb
1089*8ba4d145SBjoern A. Zeeb *idx -= phy->sband_6g.sband.n_channels;
1090*8ba4d145SBjoern A. Zeeb return NULL;
1091*8ba4d145SBjoern A. Zeeb }
10926c92544dSBjoern A. Zeeb
mt76_get_survey(struct ieee80211_hw * hw,int idx,struct survey_info * survey)10936c92544dSBjoern A. Zeeb int mt76_get_survey(struct ieee80211_hw *hw, int idx,
10946c92544dSBjoern A. Zeeb struct survey_info *survey)
10956c92544dSBjoern A. Zeeb {
10966c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
10976c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
1098*8ba4d145SBjoern A. Zeeb struct mt76_sband *sband = NULL;
10996c92544dSBjoern A. Zeeb struct ieee80211_channel *chan;
11006c92544dSBjoern A. Zeeb struct mt76_channel_state *state;
1101*8ba4d145SBjoern A. Zeeb int phy_idx = 0;
11026c92544dSBjoern A. Zeeb int ret = 0;
11036c92544dSBjoern A. Zeeb
11046c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex);
1105*8ba4d145SBjoern A. Zeeb
1106*8ba4d145SBjoern A. Zeeb for (phy_idx = 0; phy_idx < ARRAY_SIZE(dev->phys); phy_idx++) {
1107*8ba4d145SBjoern A. Zeeb sband = NULL;
1108*8ba4d145SBjoern A. Zeeb phy = dev->phys[phy_idx];
1109*8ba4d145SBjoern A. Zeeb if (!phy || phy->hw != hw)
1110*8ba4d145SBjoern A. Zeeb continue;
1111*8ba4d145SBjoern A. Zeeb
1112*8ba4d145SBjoern A. Zeeb sband = mt76_get_survey_sband(phy, &idx);
1113*8ba4d145SBjoern A. Zeeb
1114*8ba4d145SBjoern A. Zeeb if (idx == 0 && phy->dev->drv->update_survey)
11156c92544dSBjoern A. Zeeb mt76_update_survey(phy);
11166c92544dSBjoern A. Zeeb
1117*8ba4d145SBjoern A. Zeeb if (sband || !hw->wiphy->n_radio)
1118*8ba4d145SBjoern A. Zeeb break;
11196c92544dSBjoern A. Zeeb }
11206c92544dSBjoern A. Zeeb
1121*8ba4d145SBjoern A. Zeeb if (!sband) {
11226c92544dSBjoern A. Zeeb ret = -ENOENT;
11236c92544dSBjoern A. Zeeb goto out;
11246c92544dSBjoern A. Zeeb }
11256c92544dSBjoern A. Zeeb
11266c92544dSBjoern A. Zeeb chan = &sband->sband.channels[idx];
11276c92544dSBjoern A. Zeeb state = mt76_channel_state(phy, chan);
11286c92544dSBjoern A. Zeeb
11296c92544dSBjoern A. Zeeb memset(survey, 0, sizeof(*survey));
11306c92544dSBjoern A. Zeeb survey->channel = chan;
11316c92544dSBjoern A. Zeeb survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
11326c92544dSBjoern A. Zeeb survey->filled |= dev->drv->survey_flags;
11336c92544dSBjoern A. Zeeb if (state->noise)
11346c92544dSBjoern A. Zeeb survey->filled |= SURVEY_INFO_NOISE_DBM;
11356c92544dSBjoern A. Zeeb
1136*8ba4d145SBjoern A. Zeeb if (chan == phy->main_chandef.chan) {
11376c92544dSBjoern A. Zeeb survey->filled |= SURVEY_INFO_IN_USE;
11386c92544dSBjoern A. Zeeb
11396c92544dSBjoern A. Zeeb if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
11406c92544dSBjoern A. Zeeb survey->filled |= SURVEY_INFO_TIME_BSS_RX;
11416c92544dSBjoern A. Zeeb }
11426c92544dSBjoern A. Zeeb
11436c92544dSBjoern A. Zeeb survey->time_busy = div_u64(state->cc_busy, 1000);
11446c92544dSBjoern A. Zeeb survey->time_rx = div_u64(state->cc_rx, 1000);
11456c92544dSBjoern A. Zeeb survey->time = div_u64(state->cc_active, 1000);
11466c92544dSBjoern A. Zeeb survey->noise = state->noise;
11476c92544dSBjoern A. Zeeb
11486c92544dSBjoern A. Zeeb spin_lock_bh(&dev->cc_lock);
11496c92544dSBjoern A. Zeeb survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000);
11506c92544dSBjoern A. Zeeb survey->time_tx = div_u64(state->cc_tx, 1000);
11516c92544dSBjoern A. Zeeb spin_unlock_bh(&dev->cc_lock);
11526c92544dSBjoern A. Zeeb
11536c92544dSBjoern A. Zeeb out:
11546c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex);
11556c92544dSBjoern A. Zeeb
11566c92544dSBjoern A. Zeeb return ret;
11576c92544dSBjoern A. Zeeb }
11586c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_survey);
11596c92544dSBjoern A. Zeeb
mt76_wcid_key_setup(struct mt76_dev * dev,struct mt76_wcid * wcid,struct ieee80211_key_conf * key)11606c92544dSBjoern A. Zeeb void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
11616c92544dSBjoern A. Zeeb struct ieee80211_key_conf *key)
11626c92544dSBjoern A. Zeeb {
11636c92544dSBjoern A. Zeeb struct ieee80211_key_seq seq;
11646c92544dSBjoern A. Zeeb int i;
11656c92544dSBjoern A. Zeeb
11666c92544dSBjoern A. Zeeb wcid->rx_check_pn = false;
11676c92544dSBjoern A. Zeeb
11686c92544dSBjoern A. Zeeb if (!key)
11696c92544dSBjoern A. Zeeb return;
11706c92544dSBjoern A. Zeeb
11716c92544dSBjoern A. Zeeb if (key->cipher != WLAN_CIPHER_SUITE_CCMP)
11726c92544dSBjoern A. Zeeb return;
11736c92544dSBjoern A. Zeeb
11746c92544dSBjoern A. Zeeb wcid->rx_check_pn = true;
11756c92544dSBjoern A. Zeeb
11766c92544dSBjoern A. Zeeb /* data frame */
11776c92544dSBjoern A. Zeeb for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
11786c92544dSBjoern A. Zeeb ieee80211_get_key_rx_seq(key, i, &seq);
11796c92544dSBjoern A. Zeeb memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
11806c92544dSBjoern A. Zeeb }
11816c92544dSBjoern A. Zeeb
11826c92544dSBjoern A. Zeeb /* robust management frame */
11836c92544dSBjoern A. Zeeb ieee80211_get_key_rx_seq(key, -1, &seq);
11846c92544dSBjoern A. Zeeb memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn));
11856c92544dSBjoern A. Zeeb
11866c92544dSBjoern A. Zeeb }
11876c92544dSBjoern A. Zeeb EXPORT_SYMBOL(mt76_wcid_key_setup);
11886c92544dSBjoern A. Zeeb
mt76_rx_signal(u8 chain_mask,s8 * chain_signal)1189cbb3ec25SBjoern A. Zeeb int mt76_rx_signal(u8 chain_mask, s8 *chain_signal)
11906c92544dSBjoern A. Zeeb {
11916c92544dSBjoern A. Zeeb int signal = -128;
11926c92544dSBjoern A. Zeeb u8 chains;
11936c92544dSBjoern A. Zeeb
1194cbb3ec25SBjoern A. Zeeb for (chains = chain_mask; chains; chains >>= 1, chain_signal++) {
11956c92544dSBjoern A. Zeeb int cur, diff;
11966c92544dSBjoern A. Zeeb
11976c92544dSBjoern A. Zeeb cur = *chain_signal;
11986c92544dSBjoern A. Zeeb if (!(chains & BIT(0)) ||
11996c92544dSBjoern A. Zeeb cur > 0)
12006c92544dSBjoern A. Zeeb continue;
12016c92544dSBjoern A. Zeeb
12026c92544dSBjoern A. Zeeb if (cur > signal)
12036c92544dSBjoern A. Zeeb swap(cur, signal);
12046c92544dSBjoern A. Zeeb
12056c92544dSBjoern A. Zeeb diff = signal - cur;
12066c92544dSBjoern A. Zeeb if (diff == 0)
12076c92544dSBjoern A. Zeeb signal += 3;
12086c92544dSBjoern A. Zeeb else if (diff <= 2)
12096c92544dSBjoern A. Zeeb signal += 2;
12106c92544dSBjoern A. Zeeb else if (diff <= 6)
12116c92544dSBjoern A. Zeeb signal += 1;
12126c92544dSBjoern A. Zeeb }
12136c92544dSBjoern A. Zeeb
12146c92544dSBjoern A. Zeeb return signal;
12156c92544dSBjoern A. Zeeb }
1216cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL(mt76_rx_signal);
12176c92544dSBjoern A. Zeeb
12186c92544dSBjoern A. Zeeb static void
mt76_rx_convert(struct mt76_dev * dev,struct sk_buff * skb,struct ieee80211_hw ** hw,struct ieee80211_sta ** sta)12196c92544dSBjoern A. Zeeb mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
12206c92544dSBjoern A. Zeeb struct ieee80211_hw **hw,
12216c92544dSBjoern A. Zeeb struct ieee80211_sta **sta)
12226c92544dSBjoern A. Zeeb {
12236c92544dSBjoern A. Zeeb struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
12246c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
12256c92544dSBjoern A. Zeeb struct mt76_rx_status mstat;
12266c92544dSBjoern A. Zeeb
12276c92544dSBjoern A. Zeeb mstat = *((struct mt76_rx_status *)skb->cb);
12286c92544dSBjoern A. Zeeb memset(status, 0, sizeof(*status));
12296c92544dSBjoern A. Zeeb
12306c92544dSBjoern A. Zeeb status->flag = mstat.flag;
12316c92544dSBjoern A. Zeeb status->freq = mstat.freq;
12326c92544dSBjoern A. Zeeb status->enc_flags = mstat.enc_flags;
12336c92544dSBjoern A. Zeeb status->encoding = mstat.encoding;
12346c92544dSBjoern A. Zeeb status->bw = mstat.bw;
1235cbb3ec25SBjoern A. Zeeb if (status->encoding == RX_ENC_EHT) {
1236cbb3ec25SBjoern A. Zeeb status->eht.ru = mstat.eht.ru;
1237cbb3ec25SBjoern A. Zeeb status->eht.gi = mstat.eht.gi;
1238cbb3ec25SBjoern A. Zeeb } else {
12396c92544dSBjoern A. Zeeb status->he_ru = mstat.he_ru;
12406c92544dSBjoern A. Zeeb status->he_gi = mstat.he_gi;
12416c92544dSBjoern A. Zeeb status->he_dcm = mstat.he_dcm;
1242cbb3ec25SBjoern A. Zeeb }
12436c92544dSBjoern A. Zeeb status->rate_idx = mstat.rate_idx;
12446c92544dSBjoern A. Zeeb status->nss = mstat.nss;
12456c92544dSBjoern A. Zeeb status->band = mstat.band;
12466c92544dSBjoern A. Zeeb status->signal = mstat.signal;
12476c92544dSBjoern A. Zeeb status->chains = mstat.chains;
12486c92544dSBjoern A. Zeeb status->ampdu_reference = mstat.ampdu_ref;
12496c92544dSBjoern A. Zeeb status->device_timestamp = mstat.timestamp;
12506c92544dSBjoern A. Zeeb status->mactime = mstat.timestamp;
1251cbb3ec25SBjoern A. Zeeb status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal);
12526c92544dSBjoern A. Zeeb if (status->signal <= -128)
12536c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_NO_SIGNAL_VAL;
12546c92544dSBjoern A. Zeeb
12556c92544dSBjoern A. Zeeb if (ieee80211_is_beacon(hdr->frame_control) ||
12566c92544dSBjoern A. Zeeb ieee80211_is_probe_resp(hdr->frame_control))
12576c92544dSBjoern A. Zeeb status->boottime_ns = ktime_get_boottime_ns();
12586c92544dSBjoern A. Zeeb
12596c92544dSBjoern A. Zeeb BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
12606c92544dSBjoern A. Zeeb BUILD_BUG_ON(sizeof(status->chain_signal) !=
12616c92544dSBjoern A. Zeeb sizeof(mstat.chain_signal));
12626c92544dSBjoern A. Zeeb memcpy(status->chain_signal, mstat.chain_signal,
12636c92544dSBjoern A. Zeeb sizeof(mstat.chain_signal));
12646c92544dSBjoern A. Zeeb
1265*8ba4d145SBjoern A. Zeeb if (mstat.wcid) {
1266*8ba4d145SBjoern A. Zeeb status->link_valid = mstat.wcid->link_valid;
1267*8ba4d145SBjoern A. Zeeb status->link_id = mstat.wcid->link_id;
1268*8ba4d145SBjoern A. Zeeb }
1269*8ba4d145SBjoern A. Zeeb
12706c92544dSBjoern A. Zeeb *sta = wcid_to_sta(mstat.wcid);
12716c92544dSBjoern A. Zeeb *hw = mt76_phy_hw(dev, mstat.phy_idx);
12726c92544dSBjoern A. Zeeb }
12736c92544dSBjoern A. Zeeb
12746c92544dSBjoern A. Zeeb static void
mt76_check_ccmp_pn(struct sk_buff * skb)12756c92544dSBjoern A. Zeeb mt76_check_ccmp_pn(struct sk_buff *skb)
12766c92544dSBjoern A. Zeeb {
12776c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
12786c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid;
12796c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr;
12806c92544dSBjoern A. Zeeb int security_idx;
12816c92544dSBjoern A. Zeeb int ret;
12826c92544dSBjoern A. Zeeb
12836c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_DECRYPTED))
12846c92544dSBjoern A. Zeeb return;
12856c92544dSBjoern A. Zeeb
12866c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_ONLY_MONITOR)
12876c92544dSBjoern A. Zeeb return;
12886c92544dSBjoern A. Zeeb
12896c92544dSBjoern A. Zeeb if (!wcid || !wcid->rx_check_pn)
12906c92544dSBjoern A. Zeeb return;
12916c92544dSBjoern A. Zeeb
12926c92544dSBjoern A. Zeeb security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
12936c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_8023)
12946c92544dSBjoern A. Zeeb goto skip_hdr_check;
12956c92544dSBjoern A. Zeeb
12966c92544dSBjoern A. Zeeb hdr = mt76_skb_get_hdr(skb);
12976c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_IV_STRIPPED)) {
12986c92544dSBjoern A. Zeeb /*
12996c92544dSBjoern A. Zeeb * Validate the first fragment both here and in mac80211
13006c92544dSBjoern A. Zeeb * All further fragments will be validated by mac80211 only.
13016c92544dSBjoern A. Zeeb */
13026c92544dSBjoern A. Zeeb if (ieee80211_is_frag(hdr) &&
13036c92544dSBjoern A. Zeeb !ieee80211_is_first_frag(hdr->frame_control))
13046c92544dSBjoern A. Zeeb return;
13056c92544dSBjoern A. Zeeb }
13066c92544dSBjoern A. Zeeb
13076c92544dSBjoern A. Zeeb /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c):
13086c92544dSBjoern A. Zeeb *
13096c92544dSBjoern A. Zeeb * the recipient shall maintain a single replay counter for received
13106c92544dSBjoern A. Zeeb * individually addressed robust Management frames that are received
13116c92544dSBjoern A. Zeeb * with the To DS subfield equal to 0, [...]
13126c92544dSBjoern A. Zeeb */
13136c92544dSBjoern A. Zeeb if (ieee80211_is_mgmt(hdr->frame_control) &&
13146c92544dSBjoern A. Zeeb !ieee80211_has_tods(hdr->frame_control))
13156c92544dSBjoern A. Zeeb security_idx = IEEE80211_NUM_TIDS;
13166c92544dSBjoern A. Zeeb
13176c92544dSBjoern A. Zeeb skip_hdr_check:
13186c92544dSBjoern A. Zeeb BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0]));
13196c92544dSBjoern A. Zeeb ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
13206c92544dSBjoern A. Zeeb sizeof(status->iv));
13216c92544dSBjoern A. Zeeb if (ret <= 0) {
13226c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_ONLY_MONITOR;
13236c92544dSBjoern A. Zeeb return;
13246c92544dSBjoern A. Zeeb }
13256c92544dSBjoern A. Zeeb
13266c92544dSBjoern A. Zeeb memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv));
13276c92544dSBjoern A. Zeeb
13286c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_IV_STRIPPED)
13296c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_PN_VALIDATED;
13306c92544dSBjoern A. Zeeb }
13316c92544dSBjoern A. Zeeb
13326c92544dSBjoern A. Zeeb static void
mt76_airtime_report(struct mt76_dev * dev,struct mt76_rx_status * status,int len)13336c92544dSBjoern A. Zeeb mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
13346c92544dSBjoern A. Zeeb int len)
13356c92544dSBjoern A. Zeeb {
13366c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid;
13376c92544dSBjoern A. Zeeb struct ieee80211_rx_status info = {
13386c92544dSBjoern A. Zeeb .enc_flags = status->enc_flags,
13396c92544dSBjoern A. Zeeb .rate_idx = status->rate_idx,
13406c92544dSBjoern A. Zeeb .encoding = status->encoding,
13416c92544dSBjoern A. Zeeb .band = status->band,
13426c92544dSBjoern A. Zeeb .nss = status->nss,
13436c92544dSBjoern A. Zeeb .bw = status->bw,
13446c92544dSBjoern A. Zeeb };
13456c92544dSBjoern A. Zeeb struct ieee80211_sta *sta;
13466c92544dSBjoern A. Zeeb u32 airtime;
13476c92544dSBjoern A. Zeeb u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
13486c92544dSBjoern A. Zeeb
13496c92544dSBjoern A. Zeeb airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len);
13506c92544dSBjoern A. Zeeb spin_lock(&dev->cc_lock);
13516c92544dSBjoern A. Zeeb dev->cur_cc_bss_rx += airtime;
13526c92544dSBjoern A. Zeeb spin_unlock(&dev->cc_lock);
13536c92544dSBjoern A. Zeeb
13546c92544dSBjoern A. Zeeb if (!wcid || !wcid->sta)
13556c92544dSBjoern A. Zeeb return;
13566c92544dSBjoern A. Zeeb
13576c92544dSBjoern A. Zeeb sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
13586c92544dSBjoern A. Zeeb ieee80211_sta_register_airtime(sta, tidno, 0, airtime);
13596c92544dSBjoern A. Zeeb }
13606c92544dSBjoern A. Zeeb
13616c92544dSBjoern A. Zeeb static void
mt76_airtime_flush_ampdu(struct mt76_dev * dev)13626c92544dSBjoern A. Zeeb mt76_airtime_flush_ampdu(struct mt76_dev *dev)
13636c92544dSBjoern A. Zeeb {
13646c92544dSBjoern A. Zeeb struct mt76_wcid *wcid;
13656c92544dSBjoern A. Zeeb int wcid_idx;
13666c92544dSBjoern A. Zeeb
13676c92544dSBjoern A. Zeeb if (!dev->rx_ampdu_len)
13686c92544dSBjoern A. Zeeb return;
13696c92544dSBjoern A. Zeeb
13706c92544dSBjoern A. Zeeb wcid_idx = dev->rx_ampdu_status.wcid_idx;
13716c92544dSBjoern A. Zeeb if (wcid_idx < ARRAY_SIZE(dev->wcid))
13726c92544dSBjoern A. Zeeb wcid = rcu_dereference(dev->wcid[wcid_idx]);
13736c92544dSBjoern A. Zeeb else
13746c92544dSBjoern A. Zeeb wcid = NULL;
13756c92544dSBjoern A. Zeeb dev->rx_ampdu_status.wcid = wcid;
13766c92544dSBjoern A. Zeeb
13776c92544dSBjoern A. Zeeb mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
13786c92544dSBjoern A. Zeeb
13796c92544dSBjoern A. Zeeb dev->rx_ampdu_len = 0;
13806c92544dSBjoern A. Zeeb dev->rx_ampdu_ref = 0;
13816c92544dSBjoern A. Zeeb }
13826c92544dSBjoern A. Zeeb
13836c92544dSBjoern A. Zeeb static void
mt76_airtime_check(struct mt76_dev * dev,struct sk_buff * skb)13846c92544dSBjoern A. Zeeb mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
13856c92544dSBjoern A. Zeeb {
13866c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
13876c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid;
13886c92544dSBjoern A. Zeeb
13896c92544dSBjoern A. Zeeb if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
13906c92544dSBjoern A. Zeeb return;
13916c92544dSBjoern A. Zeeb
13926c92544dSBjoern A. Zeeb if (!wcid || !wcid->sta) {
13936c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
13946c92544dSBjoern A. Zeeb
13956c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_8023)
13966c92544dSBjoern A. Zeeb return;
13976c92544dSBjoern A. Zeeb
13986c92544dSBjoern A. Zeeb if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
13996c92544dSBjoern A. Zeeb return;
14006c92544dSBjoern A. Zeeb
14016c92544dSBjoern A. Zeeb wcid = NULL;
14026c92544dSBjoern A. Zeeb }
14036c92544dSBjoern A. Zeeb
14046c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
14056c92544dSBjoern A. Zeeb status->ampdu_ref != dev->rx_ampdu_ref)
14066c92544dSBjoern A. Zeeb mt76_airtime_flush_ampdu(dev);
14076c92544dSBjoern A. Zeeb
14086c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_AMPDU_DETAILS) {
14096c92544dSBjoern A. Zeeb if (!dev->rx_ampdu_len ||
14106c92544dSBjoern A. Zeeb status->ampdu_ref != dev->rx_ampdu_ref) {
14116c92544dSBjoern A. Zeeb dev->rx_ampdu_status = *status;
14126c92544dSBjoern A. Zeeb dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
14136c92544dSBjoern A. Zeeb dev->rx_ampdu_ref = status->ampdu_ref;
14146c92544dSBjoern A. Zeeb }
14156c92544dSBjoern A. Zeeb
14166c92544dSBjoern A. Zeeb dev->rx_ampdu_len += skb->len;
14176c92544dSBjoern A. Zeeb return;
14186c92544dSBjoern A. Zeeb }
14196c92544dSBjoern A. Zeeb
14206c92544dSBjoern A. Zeeb mt76_airtime_report(dev, status, skb->len);
14216c92544dSBjoern A. Zeeb }
14226c92544dSBjoern A. Zeeb
14236c92544dSBjoern A. Zeeb static void
mt76_check_sta(struct mt76_dev * dev,struct sk_buff * skb)14246c92544dSBjoern A. Zeeb mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
14256c92544dSBjoern A. Zeeb {
14266c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
14276c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
14286c92544dSBjoern A. Zeeb struct ieee80211_sta *sta;
14296c92544dSBjoern A. Zeeb struct ieee80211_hw *hw;
14306c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid;
14316c92544dSBjoern A. Zeeb u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
14326c92544dSBjoern A. Zeeb bool ps;
14336c92544dSBjoern A. Zeeb
14346c92544dSBjoern A. Zeeb hw = mt76_phy_hw(dev, status->phy_idx);
14356c92544dSBjoern A. Zeeb if (ieee80211_is_pspoll(hdr->frame_control) && !wcid &&
14366c92544dSBjoern A. Zeeb !(status->flag & RX_FLAG_8023)) {
14376c92544dSBjoern A. Zeeb sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
14386c92544dSBjoern A. Zeeb if (sta)
14396c92544dSBjoern A. Zeeb wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
14406c92544dSBjoern A. Zeeb }
14416c92544dSBjoern A. Zeeb
14426c92544dSBjoern A. Zeeb mt76_airtime_check(dev, skb);
14436c92544dSBjoern A. Zeeb
14446c92544dSBjoern A. Zeeb if (!wcid || !wcid->sta)
14456c92544dSBjoern A. Zeeb return;
14466c92544dSBjoern A. Zeeb
14476c92544dSBjoern A. Zeeb sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
14486c92544dSBjoern A. Zeeb
14496c92544dSBjoern A. Zeeb if (status->signal <= 0)
14506c92544dSBjoern A. Zeeb ewma_signal_add(&wcid->rssi, -status->signal);
14516c92544dSBjoern A. Zeeb
14526c92544dSBjoern A. Zeeb wcid->inactive_count = 0;
14536c92544dSBjoern A. Zeeb
14546c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_8023)
14556c92544dSBjoern A. Zeeb return;
14566c92544dSBjoern A. Zeeb
14576c92544dSBjoern A. Zeeb if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags))
14586c92544dSBjoern A. Zeeb return;
14596c92544dSBjoern A. Zeeb
14606c92544dSBjoern A. Zeeb if (ieee80211_is_pspoll(hdr->frame_control)) {
14616c92544dSBjoern A. Zeeb ieee80211_sta_pspoll(sta);
14626c92544dSBjoern A. Zeeb return;
14636c92544dSBjoern A. Zeeb }
14646c92544dSBjoern A. Zeeb
14656c92544dSBjoern A. Zeeb if (ieee80211_has_morefrags(hdr->frame_control) ||
14666c92544dSBjoern A. Zeeb !(ieee80211_is_mgmt(hdr->frame_control) ||
14676c92544dSBjoern A. Zeeb ieee80211_is_data(hdr->frame_control)))
14686c92544dSBjoern A. Zeeb return;
14696c92544dSBjoern A. Zeeb
14706c92544dSBjoern A. Zeeb ps = ieee80211_has_pm(hdr->frame_control);
14716c92544dSBjoern A. Zeeb
14726c92544dSBjoern A. Zeeb if (ps && (ieee80211_is_data_qos(hdr->frame_control) ||
14736c92544dSBjoern A. Zeeb ieee80211_is_qos_nullfunc(hdr->frame_control)))
14746c92544dSBjoern A. Zeeb ieee80211_sta_uapsd_trigger(sta, tidno);
14756c92544dSBjoern A. Zeeb
14766c92544dSBjoern A. Zeeb if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps)
14776c92544dSBjoern A. Zeeb return;
14786c92544dSBjoern A. Zeeb
14796c92544dSBjoern A. Zeeb if (ps)
14806c92544dSBjoern A. Zeeb set_bit(MT_WCID_FLAG_PS, &wcid->flags);
14816c92544dSBjoern A. Zeeb
1482cbb3ec25SBjoern A. Zeeb if (dev->drv->sta_ps)
14836c92544dSBjoern A. Zeeb dev->drv->sta_ps(dev, sta, ps);
14846c92544dSBjoern A. Zeeb
14856c92544dSBjoern A. Zeeb if (!ps)
14866c92544dSBjoern A. Zeeb clear_bit(MT_WCID_FLAG_PS, &wcid->flags);
14876c92544dSBjoern A. Zeeb
14886c92544dSBjoern A. Zeeb ieee80211_sta_ps_transition(sta, ps);
14896c92544dSBjoern A. Zeeb }
14906c92544dSBjoern A. Zeeb
mt76_rx_complete(struct mt76_dev * dev,struct sk_buff_head * frames,struct napi_struct * napi)14916c92544dSBjoern A. Zeeb void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
14926c92544dSBjoern A. Zeeb struct napi_struct *napi)
14936c92544dSBjoern A. Zeeb {
14946c92544dSBjoern A. Zeeb struct ieee80211_sta *sta;
14956c92544dSBjoern A. Zeeb struct ieee80211_hw *hw;
14966c92544dSBjoern A. Zeeb struct sk_buff *skb, *tmp;
14976c92544dSBjoern A. Zeeb #if defined(__linux__)
14986c92544dSBjoern A. Zeeb LIST_HEAD(list);
14996c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
15006c92544dSBjoern A. Zeeb LINUX_LIST_HEAD(list);
15016c92544dSBjoern A. Zeeb #endif
15026c92544dSBjoern A. Zeeb
15036c92544dSBjoern A. Zeeb spin_lock(&dev->rx_lock);
15046c92544dSBjoern A. Zeeb while ((skb = __skb_dequeue(frames)) != NULL) {
15056c92544dSBjoern A. Zeeb struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
15066c92544dSBjoern A. Zeeb
15076c92544dSBjoern A. Zeeb mt76_check_ccmp_pn(skb);
15086c92544dSBjoern A. Zeeb skb_shinfo(skb)->frag_list = NULL;
15096c92544dSBjoern A. Zeeb mt76_rx_convert(dev, skb, &hw, &sta);
15106c92544dSBjoern A. Zeeb ieee80211_rx_list(hw, sta, skb, &list);
15116c92544dSBjoern A. Zeeb
15126c92544dSBjoern A. Zeeb /* subsequent amsdu frames */
15136c92544dSBjoern A. Zeeb while (nskb) {
15146c92544dSBjoern A. Zeeb skb = nskb;
15156c92544dSBjoern A. Zeeb nskb = nskb->next;
15166c92544dSBjoern A. Zeeb skb->next = NULL;
15176c92544dSBjoern A. Zeeb
15186c92544dSBjoern A. Zeeb mt76_rx_convert(dev, skb, &hw, &sta);
15196c92544dSBjoern A. Zeeb ieee80211_rx_list(hw, sta, skb, &list);
15206c92544dSBjoern A. Zeeb }
15216c92544dSBjoern A. Zeeb }
15226c92544dSBjoern A. Zeeb spin_unlock(&dev->rx_lock);
15236c92544dSBjoern A. Zeeb
15246c92544dSBjoern A. Zeeb if (!napi) {
15256c92544dSBjoern A. Zeeb netif_receive_skb_list(&list);
15266c92544dSBjoern A. Zeeb return;
15276c92544dSBjoern A. Zeeb }
15286c92544dSBjoern A. Zeeb
15296c92544dSBjoern A. Zeeb list_for_each_entry_safe(skb, tmp, &list, list) {
15306c92544dSBjoern A. Zeeb skb_list_del_init(skb);
15316c92544dSBjoern A. Zeeb napi_gro_receive(napi, skb);
15326c92544dSBjoern A. Zeeb }
15336c92544dSBjoern A. Zeeb }
15346c92544dSBjoern A. Zeeb
mt76_rx_poll_complete(struct mt76_dev * dev,enum mt76_rxq_id q,struct napi_struct * napi)15356c92544dSBjoern A. Zeeb void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
15366c92544dSBjoern A. Zeeb struct napi_struct *napi)
15376c92544dSBjoern A. Zeeb {
15386c92544dSBjoern A. Zeeb struct sk_buff_head frames;
15396c92544dSBjoern A. Zeeb struct sk_buff *skb;
15406c92544dSBjoern A. Zeeb
15416c92544dSBjoern A. Zeeb __skb_queue_head_init(&frames);
15426c92544dSBjoern A. Zeeb
15436c92544dSBjoern A. Zeeb while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) {
15446c92544dSBjoern A. Zeeb mt76_check_sta(dev, skb);
1545cbb3ec25SBjoern A. Zeeb if (mtk_wed_device_active(&dev->mmio.wed))
1546cbb3ec25SBjoern A. Zeeb __skb_queue_tail(&frames, skb);
1547cbb3ec25SBjoern A. Zeeb else
15486c92544dSBjoern A. Zeeb mt76_rx_aggr_reorder(skb, &frames);
15496c92544dSBjoern A. Zeeb }
15506c92544dSBjoern A. Zeeb
15516c92544dSBjoern A. Zeeb mt76_rx_complete(dev, &frames, napi);
15526c92544dSBjoern A. Zeeb }
15536c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_poll_complete);
15546c92544dSBjoern A. Zeeb
15556c92544dSBjoern A. Zeeb static int
mt76_sta_add(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)15566c92544dSBjoern A. Zeeb mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
15576c92544dSBjoern A. Zeeb struct ieee80211_sta *sta)
15586c92544dSBjoern A. Zeeb {
15596c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
15606c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
15616c92544dSBjoern A. Zeeb int ret;
15626c92544dSBjoern A. Zeeb int i;
15636c92544dSBjoern A. Zeeb
15646c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex);
15656c92544dSBjoern A. Zeeb
15666c92544dSBjoern A. Zeeb ret = dev->drv->sta_add(dev, vif, sta);
15676c92544dSBjoern A. Zeeb if (ret)
15686c92544dSBjoern A. Zeeb goto out;
15696c92544dSBjoern A. Zeeb
15706c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
15716c92544dSBjoern A. Zeeb struct mt76_txq *mtxq;
15726c92544dSBjoern A. Zeeb
15736c92544dSBjoern A. Zeeb if (!sta->txq[i])
15746c92544dSBjoern A. Zeeb continue;
15756c92544dSBjoern A. Zeeb
15766c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
15776c92544dSBjoern A. Zeeb mtxq->wcid = wcid->idx;
15786c92544dSBjoern A. Zeeb }
15796c92544dSBjoern A. Zeeb
15806c92544dSBjoern A. Zeeb ewma_signal_init(&wcid->rssi);
15816c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
1582*8ba4d145SBjoern A. Zeeb phy->num_sta++;
15836c92544dSBjoern A. Zeeb
1584*8ba4d145SBjoern A. Zeeb mt76_wcid_init(wcid, phy->band_idx);
15856c92544dSBjoern A. Zeeb out:
15866c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex);
15876c92544dSBjoern A. Zeeb
15886c92544dSBjoern A. Zeeb return ret;
15896c92544dSBjoern A. Zeeb }
15906c92544dSBjoern A. Zeeb
__mt76_sta_remove(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1591*8ba4d145SBjoern A. Zeeb void __mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif,
15926c92544dSBjoern A. Zeeb struct ieee80211_sta *sta)
15936c92544dSBjoern A. Zeeb {
1594*8ba4d145SBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
15956c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
15966c92544dSBjoern A. Zeeb int i, idx = wcid->idx;
15976c92544dSBjoern A. Zeeb
15986c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
15996c92544dSBjoern A. Zeeb mt76_rx_aggr_stop(dev, wcid, i);
16006c92544dSBjoern A. Zeeb
16016c92544dSBjoern A. Zeeb if (dev->drv->sta_remove)
16026c92544dSBjoern A. Zeeb dev->drv->sta_remove(dev, vif, sta);
16036c92544dSBjoern A. Zeeb
1604*8ba4d145SBjoern A. Zeeb mt76_wcid_cleanup(dev, wcid);
16056c92544dSBjoern A. Zeeb
16066c92544dSBjoern A. Zeeb mt76_wcid_mask_clear(dev->wcid_mask, idx);
1607*8ba4d145SBjoern A. Zeeb phy->num_sta--;
16086c92544dSBjoern A. Zeeb }
16096c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_sta_remove);
16106c92544dSBjoern A. Zeeb
16116c92544dSBjoern A. Zeeb static void
mt76_sta_remove(struct mt76_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1612*8ba4d145SBjoern A. Zeeb mt76_sta_remove(struct mt76_phy *phy, struct ieee80211_vif *vif,
16136c92544dSBjoern A. Zeeb struct ieee80211_sta *sta)
16146c92544dSBjoern A. Zeeb {
1615*8ba4d145SBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
1616*8ba4d145SBjoern A. Zeeb
16176c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex);
1618*8ba4d145SBjoern A. Zeeb __mt76_sta_remove(phy, vif, sta);
16196c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex);
16206c92544dSBjoern A. Zeeb }
16216c92544dSBjoern A. Zeeb
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)16226c92544dSBjoern A. Zeeb int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16236c92544dSBjoern A. Zeeb struct ieee80211_sta *sta,
16246c92544dSBjoern A. Zeeb enum ieee80211_sta_state old_state,
16256c92544dSBjoern A. Zeeb enum ieee80211_sta_state new_state)
16266c92544dSBjoern A. Zeeb {
16276c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
16286c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
1629*8ba4d145SBjoern A. Zeeb enum mt76_sta_event ev;
1630*8ba4d145SBjoern A. Zeeb
1631*8ba4d145SBjoern A. Zeeb phy = mt76_vif_phy(hw, vif);
1632*8ba4d145SBjoern A. Zeeb if (!phy)
1633*8ba4d145SBjoern A. Zeeb return -EINVAL;
16346c92544dSBjoern A. Zeeb
16356c92544dSBjoern A. Zeeb if (old_state == IEEE80211_STA_NOTEXIST &&
16366c92544dSBjoern A. Zeeb new_state == IEEE80211_STA_NONE)
16376c92544dSBjoern A. Zeeb return mt76_sta_add(phy, vif, sta);
16386c92544dSBjoern A. Zeeb
16396c92544dSBjoern A. Zeeb if (old_state == IEEE80211_STA_NONE &&
16406c92544dSBjoern A. Zeeb new_state == IEEE80211_STA_NOTEXIST)
1641*8ba4d145SBjoern A. Zeeb mt76_sta_remove(phy, vif, sta);
16426c92544dSBjoern A. Zeeb
1643*8ba4d145SBjoern A. Zeeb if (!dev->drv->sta_event)
16446c92544dSBjoern A. Zeeb return 0;
1645*8ba4d145SBjoern A. Zeeb
1646*8ba4d145SBjoern A. Zeeb if (old_state == IEEE80211_STA_AUTH &&
1647*8ba4d145SBjoern A. Zeeb new_state == IEEE80211_STA_ASSOC)
1648*8ba4d145SBjoern A. Zeeb ev = MT76_STA_EVENT_ASSOC;
1649*8ba4d145SBjoern A. Zeeb else if (old_state == IEEE80211_STA_ASSOC &&
1650*8ba4d145SBjoern A. Zeeb new_state == IEEE80211_STA_AUTHORIZED)
1651*8ba4d145SBjoern A. Zeeb ev = MT76_STA_EVENT_AUTHORIZE;
1652*8ba4d145SBjoern A. Zeeb else if (old_state == IEEE80211_STA_ASSOC &&
1653*8ba4d145SBjoern A. Zeeb new_state == IEEE80211_STA_AUTH)
1654*8ba4d145SBjoern A. Zeeb ev = MT76_STA_EVENT_DISASSOC;
1655*8ba4d145SBjoern A. Zeeb else
1656*8ba4d145SBjoern A. Zeeb return 0;
1657*8ba4d145SBjoern A. Zeeb
1658*8ba4d145SBjoern A. Zeeb return dev->drv->sta_event(dev, vif, sta, ev);
16596c92544dSBjoern A. Zeeb }
16606c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_state);
16616c92544dSBjoern A. Zeeb
mt76_sta_pre_rcu_remove(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta)16626c92544dSBjoern A. Zeeb void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
16636c92544dSBjoern A. Zeeb struct ieee80211_sta *sta)
16646c92544dSBjoern A. Zeeb {
16656c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
16666c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
16676c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
16686c92544dSBjoern A. Zeeb
16696c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex);
16706c92544dSBjoern A. Zeeb spin_lock_bh(&dev->status_lock);
16716c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->wcid[wcid->idx], NULL);
16726c92544dSBjoern A. Zeeb spin_unlock_bh(&dev->status_lock);
16736c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex);
16746c92544dSBjoern A. Zeeb }
16756c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove);
16766c92544dSBjoern A. Zeeb
mt76_wcid_init(struct mt76_wcid * wcid,u8 band_idx)1677*8ba4d145SBjoern A. Zeeb void mt76_wcid_init(struct mt76_wcid *wcid, u8 band_idx)
16786c92544dSBjoern A. Zeeb {
1679*8ba4d145SBjoern A. Zeeb wcid->hw_key_idx = -1;
1680*8ba4d145SBjoern A. Zeeb wcid->phy_idx = band_idx;
16816c92544dSBjoern A. Zeeb
1682*8ba4d145SBjoern A. Zeeb INIT_LIST_HEAD(&wcid->tx_list);
1683*8ba4d145SBjoern A. Zeeb skb_queue_head_init(&wcid->tx_pending);
1684*8ba4d145SBjoern A. Zeeb skb_queue_head_init(&wcid->tx_offchannel);
1685*8ba4d145SBjoern A. Zeeb
1686*8ba4d145SBjoern A. Zeeb INIT_LIST_HEAD(&wcid->list);
1687*8ba4d145SBjoern A. Zeeb idr_init(&wcid->pktid);
1688*8ba4d145SBjoern A. Zeeb
1689*8ba4d145SBjoern A. Zeeb INIT_LIST_HEAD(&wcid->poll_list);
1690*8ba4d145SBjoern A. Zeeb }
1691*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_init);
1692*8ba4d145SBjoern A. Zeeb
mt76_wcid_cleanup(struct mt76_dev * dev,struct mt76_wcid * wcid)1693*8ba4d145SBjoern A. Zeeb void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
1694*8ba4d145SBjoern A. Zeeb {
1695*8ba4d145SBjoern A. Zeeb struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx);
1696*8ba4d145SBjoern A. Zeeb struct ieee80211_hw *hw;
1697*8ba4d145SBjoern A. Zeeb struct sk_buff_head list;
1698*8ba4d145SBjoern A. Zeeb struct sk_buff *skb;
1699*8ba4d145SBjoern A. Zeeb
1700*8ba4d145SBjoern A. Zeeb mt76_tx_status_lock(dev, &list);
1701*8ba4d145SBjoern A. Zeeb mt76_tx_status_skb_get(dev, wcid, -1, &list);
1702*8ba4d145SBjoern A. Zeeb mt76_tx_status_unlock(dev, &list);
1703*8ba4d145SBjoern A. Zeeb
1704*8ba4d145SBjoern A. Zeeb idr_destroy(&wcid->pktid);
1705*8ba4d145SBjoern A. Zeeb
1706*8ba4d145SBjoern A. Zeeb spin_lock_bh(&phy->tx_lock);
1707*8ba4d145SBjoern A. Zeeb
1708*8ba4d145SBjoern A. Zeeb if (!list_empty(&wcid->tx_list))
1709*8ba4d145SBjoern A. Zeeb list_del_init(&wcid->tx_list);
1710*8ba4d145SBjoern A. Zeeb
1711*8ba4d145SBjoern A. Zeeb spin_lock(&wcid->tx_pending.lock);
1712*8ba4d145SBjoern A. Zeeb skb_queue_splice_tail_init(&wcid->tx_pending, &list);
1713*8ba4d145SBjoern A. Zeeb spin_unlock(&wcid->tx_pending.lock);
1714*8ba4d145SBjoern A. Zeeb
1715*8ba4d145SBjoern A. Zeeb spin_unlock_bh(&phy->tx_lock);
1716*8ba4d145SBjoern A. Zeeb
1717*8ba4d145SBjoern A. Zeeb while ((skb = __skb_dequeue(&list)) != NULL) {
1718*8ba4d145SBjoern A. Zeeb hw = mt76_tx_status_get_hw(dev, skb);
1719*8ba4d145SBjoern A. Zeeb ieee80211_free_txskb(hw, skb);
1720*8ba4d145SBjoern A. Zeeb }
1721*8ba4d145SBjoern A. Zeeb }
1722*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
1723*8ba4d145SBjoern A. Zeeb
mt76_wcid_add_poll(struct mt76_dev * dev,struct mt76_wcid * wcid)1724*8ba4d145SBjoern A. Zeeb void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid)
1725*8ba4d145SBjoern A. Zeeb {
1726*8ba4d145SBjoern A. Zeeb if (test_bit(MT76_MCU_RESET, &dev->phy.state))
1727*8ba4d145SBjoern A. Zeeb return;
1728*8ba4d145SBjoern A. Zeeb
1729*8ba4d145SBjoern A. Zeeb spin_lock_bh(&dev->sta_poll_lock);
1730*8ba4d145SBjoern A. Zeeb if (list_empty(&wcid->poll_list))
1731*8ba4d145SBjoern A. Zeeb list_add_tail(&wcid->poll_list, &dev->sta_poll_list);
1732*8ba4d145SBjoern A. Zeeb spin_unlock_bh(&dev->sta_poll_lock);
1733*8ba4d145SBjoern A. Zeeb }
1734*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_wcid_add_poll);
1735*8ba4d145SBjoern A. Zeeb
mt76_get_txpower(struct ieee80211_hw * hw,struct ieee80211_vif * vif,unsigned int link_id,int * dbm)1736*8ba4d145SBjoern A. Zeeb int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1737*8ba4d145SBjoern A. Zeeb unsigned int link_id, int *dbm)
1738*8ba4d145SBjoern A. Zeeb {
1739*8ba4d145SBjoern A. Zeeb struct mt76_phy *phy = mt76_vif_phy(hw, vif);
1740*8ba4d145SBjoern A. Zeeb int n_chains, delta;
1741*8ba4d145SBjoern A. Zeeb
1742*8ba4d145SBjoern A. Zeeb if (!phy)
1743*8ba4d145SBjoern A. Zeeb return -EINVAL;
1744*8ba4d145SBjoern A. Zeeb
1745*8ba4d145SBjoern A. Zeeb n_chains = hweight16(phy->chainmask);
1746*8ba4d145SBjoern A. Zeeb delta = mt76_tx_power_nss_delta(n_chains);
17476c92544dSBjoern A. Zeeb *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
17486c92544dSBjoern A. Zeeb
17496c92544dSBjoern A. Zeeb return 0;
17506c92544dSBjoern A. Zeeb }
17516c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_txpower);
17526c92544dSBjoern A. Zeeb
mt76_init_sar_power(struct ieee80211_hw * hw,const struct cfg80211_sar_specs * sar)17536c92544dSBjoern A. Zeeb int mt76_init_sar_power(struct ieee80211_hw *hw,
17546c92544dSBjoern A. Zeeb const struct cfg80211_sar_specs *sar)
17556c92544dSBjoern A. Zeeb {
17566c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
17576c92544dSBjoern A. Zeeb const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa;
17586c92544dSBjoern A. Zeeb int i;
17596c92544dSBjoern A. Zeeb
17606c92544dSBjoern A. Zeeb if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs)
17616c92544dSBjoern A. Zeeb return -EINVAL;
17626c92544dSBjoern A. Zeeb
17636c92544dSBjoern A. Zeeb for (i = 0; i < sar->num_sub_specs; i++) {
17646c92544dSBjoern A. Zeeb u32 index = sar->sub_specs[i].freq_range_index;
17656c92544dSBjoern A. Zeeb /* SAR specifies power limitaton in 0.25dbm */
17666c92544dSBjoern A. Zeeb s32 power = sar->sub_specs[i].power >> 1;
17676c92544dSBjoern A. Zeeb
17686c92544dSBjoern A. Zeeb if (power > 127 || power < -127)
17696c92544dSBjoern A. Zeeb power = 127;
17706c92544dSBjoern A. Zeeb
17716c92544dSBjoern A. Zeeb phy->frp[index].range = &capa->freq_ranges[index];
17726c92544dSBjoern A. Zeeb phy->frp[index].power = power;
17736c92544dSBjoern A. Zeeb }
17746c92544dSBjoern A. Zeeb
17756c92544dSBjoern A. Zeeb return 0;
17766c92544dSBjoern A. Zeeb }
17776c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_sar_power);
17786c92544dSBjoern A. Zeeb
mt76_get_sar_power(struct mt76_phy * phy,struct ieee80211_channel * chan,int power)17796c92544dSBjoern A. Zeeb int mt76_get_sar_power(struct mt76_phy *phy,
17806c92544dSBjoern A. Zeeb struct ieee80211_channel *chan,
17816c92544dSBjoern A. Zeeb int power)
17826c92544dSBjoern A. Zeeb {
17836c92544dSBjoern A. Zeeb const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa;
17846c92544dSBjoern A. Zeeb int freq, i;
17856c92544dSBjoern A. Zeeb
17866c92544dSBjoern A. Zeeb if (!capa || !phy->frp)
17876c92544dSBjoern A. Zeeb return power;
17886c92544dSBjoern A. Zeeb
17896c92544dSBjoern A. Zeeb if (power > 127 || power < -127)
17906c92544dSBjoern A. Zeeb power = 127;
17916c92544dSBjoern A. Zeeb
17926c92544dSBjoern A. Zeeb freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band);
17936c92544dSBjoern A. Zeeb for (i = 0 ; i < capa->num_freq_ranges; i++) {
17946c92544dSBjoern A. Zeeb if (phy->frp[i].range &&
17956c92544dSBjoern A. Zeeb freq >= phy->frp[i].range->start_freq &&
17966c92544dSBjoern A. Zeeb freq < phy->frp[i].range->end_freq) {
17976c92544dSBjoern A. Zeeb power = min_t(int, phy->frp[i].power, power);
17986c92544dSBjoern A. Zeeb break;
17996c92544dSBjoern A. Zeeb }
18006c92544dSBjoern A. Zeeb }
18016c92544dSBjoern A. Zeeb
18026c92544dSBjoern A. Zeeb return power;
18036c92544dSBjoern A. Zeeb }
18046c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_sar_power);
18056c92544dSBjoern A. Zeeb
18066c92544dSBjoern A. Zeeb static void
__mt76_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)18076c92544dSBjoern A. Zeeb __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
18086c92544dSBjoern A. Zeeb {
1809*8ba4d145SBjoern A. Zeeb if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0))
1810*8ba4d145SBjoern A. Zeeb ieee80211_csa_finish(vif, 0);
18116c92544dSBjoern A. Zeeb }
18126c92544dSBjoern A. Zeeb
mt76_csa_finish(struct mt76_dev * dev)18136c92544dSBjoern A. Zeeb void mt76_csa_finish(struct mt76_dev *dev)
18146c92544dSBjoern A. Zeeb {
18156c92544dSBjoern A. Zeeb if (!dev->csa_complete)
18166c92544dSBjoern A. Zeeb return;
18176c92544dSBjoern A. Zeeb
18186c92544dSBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(dev->hw,
18196c92544dSBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL,
18206c92544dSBjoern A. Zeeb __mt76_csa_finish, dev);
18216c92544dSBjoern A. Zeeb
18226c92544dSBjoern A. Zeeb dev->csa_complete = 0;
18236c92544dSBjoern A. Zeeb }
18246c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_finish);
18256c92544dSBjoern A. Zeeb
18266c92544dSBjoern A. Zeeb static void
__mt76_csa_check(void * priv,u8 * mac,struct ieee80211_vif * vif)18276c92544dSBjoern A. Zeeb __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
18286c92544dSBjoern A. Zeeb {
18296c92544dSBjoern A. Zeeb struct mt76_dev *dev = priv;
18306c92544dSBjoern A. Zeeb
18316c92544dSBjoern A. Zeeb if (!vif->bss_conf.csa_active)
18326c92544dSBjoern A. Zeeb return;
18336c92544dSBjoern A. Zeeb
1834*8ba4d145SBjoern A. Zeeb dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0);
18356c92544dSBjoern A. Zeeb }
18366c92544dSBjoern A. Zeeb
mt76_csa_check(struct mt76_dev * dev)18376c92544dSBjoern A. Zeeb void mt76_csa_check(struct mt76_dev *dev)
18386c92544dSBjoern A. Zeeb {
18396c92544dSBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(dev->hw,
18406c92544dSBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL,
18416c92544dSBjoern A. Zeeb __mt76_csa_check, dev);
18426c92544dSBjoern A. Zeeb }
18436c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_check);
18446c92544dSBjoern A. Zeeb
18456c92544dSBjoern A. Zeeb int
mt76_set_tim(struct ieee80211_hw * hw,struct ieee80211_sta * sta,bool set)18466c92544dSBjoern A. Zeeb mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
18476c92544dSBjoern A. Zeeb {
18486c92544dSBjoern A. Zeeb return 0;
18496c92544dSBjoern A. Zeeb }
18506c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_tim);
18516c92544dSBjoern A. Zeeb
mt76_insert_ccmp_hdr(struct sk_buff * skb,u8 key_id)18526c92544dSBjoern A. Zeeb void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id)
18536c92544dSBjoern A. Zeeb {
18546c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
18556c92544dSBjoern A. Zeeb int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
18566c92544dSBjoern A. Zeeb u8 *hdr, *pn = status->iv;
18576c92544dSBjoern A. Zeeb
18586c92544dSBjoern A. Zeeb __skb_push(skb, 8);
18596c92544dSBjoern A. Zeeb memmove(skb->data, skb->data + 8, hdr_len);
18606c92544dSBjoern A. Zeeb hdr = skb->data + hdr_len;
18616c92544dSBjoern A. Zeeb
18626c92544dSBjoern A. Zeeb hdr[0] = pn[5];
18636c92544dSBjoern A. Zeeb hdr[1] = pn[4];
18646c92544dSBjoern A. Zeeb hdr[2] = 0;
18656c92544dSBjoern A. Zeeb hdr[3] = 0x20 | (key_id << 6);
18666c92544dSBjoern A. Zeeb hdr[4] = pn[3];
18676c92544dSBjoern A. Zeeb hdr[5] = pn[2];
18686c92544dSBjoern A. Zeeb hdr[6] = pn[1];
18696c92544dSBjoern A. Zeeb hdr[7] = pn[0];
18706c92544dSBjoern A. Zeeb
18716c92544dSBjoern A. Zeeb status->flag &= ~RX_FLAG_IV_STRIPPED;
18726c92544dSBjoern A. Zeeb }
18736c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr);
18746c92544dSBjoern A. Zeeb
mt76_get_rate(struct mt76_dev * dev,struct ieee80211_supported_band * sband,int idx,bool cck)18756c92544dSBjoern A. Zeeb int mt76_get_rate(struct mt76_dev *dev,
18766c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband,
18776c92544dSBjoern A. Zeeb int idx, bool cck)
18786c92544dSBjoern A. Zeeb {
1879*8ba4d145SBjoern A. Zeeb bool is_2g = sband->band == NL80211_BAND_2GHZ;
18806c92544dSBjoern A. Zeeb int i, offset = 0, len = sband->n_bitrates;
18816c92544dSBjoern A. Zeeb
18826c92544dSBjoern A. Zeeb if (cck) {
1883*8ba4d145SBjoern A. Zeeb if (!is_2g)
18846c92544dSBjoern A. Zeeb return 0;
18856c92544dSBjoern A. Zeeb
18866c92544dSBjoern A. Zeeb idx &= ~BIT(2); /* short preamble */
1887*8ba4d145SBjoern A. Zeeb } else if (is_2g) {
18886c92544dSBjoern A. Zeeb offset = 4;
18896c92544dSBjoern A. Zeeb }
18906c92544dSBjoern A. Zeeb
18916c92544dSBjoern A. Zeeb for (i = offset; i < len; i++) {
18926c92544dSBjoern A. Zeeb if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx)
18936c92544dSBjoern A. Zeeb return i;
18946c92544dSBjoern A. Zeeb }
18956c92544dSBjoern A. Zeeb
18966c92544dSBjoern A. Zeeb return 0;
18976c92544dSBjoern A. Zeeb }
18986c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_rate);
18996c92544dSBjoern A. Zeeb
mt76_sw_scan(struct ieee80211_hw * hw,struct ieee80211_vif * vif,const u8 * mac)19006c92544dSBjoern A. Zeeb void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
19016c92544dSBjoern A. Zeeb const u8 *mac)
19026c92544dSBjoern A. Zeeb {
19036c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
19046c92544dSBjoern A. Zeeb
19056c92544dSBjoern A. Zeeb set_bit(MT76_SCANNING, &phy->state);
19066c92544dSBjoern A. Zeeb }
19076c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan);
19086c92544dSBjoern A. Zeeb
mt76_sw_scan_complete(struct ieee80211_hw * hw,struct ieee80211_vif * vif)19096c92544dSBjoern A. Zeeb void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
19106c92544dSBjoern A. Zeeb {
19116c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
19126c92544dSBjoern A. Zeeb
19136c92544dSBjoern A. Zeeb clear_bit(MT76_SCANNING, &phy->state);
19146c92544dSBjoern A. Zeeb }
19156c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
19166c92544dSBjoern A. Zeeb
mt76_get_antenna(struct ieee80211_hw * hw,u32 * tx_ant,u32 * rx_ant)19176c92544dSBjoern A. Zeeb int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
19186c92544dSBjoern A. Zeeb {
19196c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv;
19206c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
1921*8ba4d145SBjoern A. Zeeb int i;
19226c92544dSBjoern A. Zeeb
19236c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex);
1924*8ba4d145SBjoern A. Zeeb *tx_ant = 0;
1925*8ba4d145SBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->phys); i++)
1926*8ba4d145SBjoern A. Zeeb if (dev->phys[i] && dev->phys[i]->hw == hw)
1927*8ba4d145SBjoern A. Zeeb *tx_ant |= dev->phys[i]->chainmask;
1928*8ba4d145SBjoern A. Zeeb *rx_ant = *tx_ant;
19296c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex);
19306c92544dSBjoern A. Zeeb
19316c92544dSBjoern A. Zeeb return 0;
19326c92544dSBjoern A. Zeeb }
19336c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_antenna);
19346c92544dSBjoern A. Zeeb
19356c92544dSBjoern A. Zeeb struct mt76_queue *
mt76_init_queue(struct mt76_dev * dev,int qid,int idx,int n_desc,int ring_base,void * wed,u32 flags)19366c92544dSBjoern A. Zeeb mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
1937*8ba4d145SBjoern A. Zeeb int ring_base, void *wed, u32 flags)
19386c92544dSBjoern A. Zeeb {
19396c92544dSBjoern A. Zeeb struct mt76_queue *hwq;
19406c92544dSBjoern A. Zeeb int err;
19416c92544dSBjoern A. Zeeb
19426c92544dSBjoern A. Zeeb hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
19436c92544dSBjoern A. Zeeb if (!hwq)
19446c92544dSBjoern A. Zeeb return ERR_PTR(-ENOMEM);
19456c92544dSBjoern A. Zeeb
19466c92544dSBjoern A. Zeeb hwq->flags = flags;
1947*8ba4d145SBjoern A. Zeeb hwq->wed = wed;
19486c92544dSBjoern A. Zeeb
19496c92544dSBjoern A. Zeeb err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
19506c92544dSBjoern A. Zeeb if (err < 0)
19516c92544dSBjoern A. Zeeb return ERR_PTR(err);
19526c92544dSBjoern A. Zeeb
19536c92544dSBjoern A. Zeeb return hwq;
19546c92544dSBjoern A. Zeeb }
19556c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_queue);
19566c92544dSBjoern A. Zeeb
mt76_ethtool_worker(struct mt76_ethtool_worker_info * wi,struct mt76_sta_stats * stats,bool eht)19576c92544dSBjoern A. Zeeb void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
1958cbb3ec25SBjoern A. Zeeb struct mt76_sta_stats *stats, bool eht)
19596c92544dSBjoern A. Zeeb {
19606c92544dSBjoern A. Zeeb int i, ei = wi->initial_stat_idx;
19616c92544dSBjoern A. Zeeb u64 *data = wi->data;
19626c92544dSBjoern A. Zeeb
19636c92544dSBjoern A. Zeeb wi->sta_count++;
19646c92544dSBjoern A. Zeeb
19656c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK];
19666c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM];
19676c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT];
19686c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF];
19696c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT];
19706c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU];
19716c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
19726c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
19736c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
1974cbb3ec25SBjoern A. Zeeb if (eht) {
1975cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
1976cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
1977cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
1978cbb3ec25SBjoern A. Zeeb }
19796c92544dSBjoern A. Zeeb
1980cbb3ec25SBjoern A. Zeeb for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
19816c92544dSBjoern A. Zeeb data[ei++] += stats->tx_bw[i];
19826c92544dSBjoern A. Zeeb
1983cbb3ec25SBjoern A. Zeeb for (i = 0; i < (eht ? 14 : 12); i++)
19846c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mcs[i];
19856c92544dSBjoern A. Zeeb
1986cbb3ec25SBjoern A. Zeeb for (i = 0; i < 4; i++)
1987cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_nss[i];
1988cbb3ec25SBjoern A. Zeeb
19896c92544dSBjoern A. Zeeb wi->worker_stat_count = ei - wi->initial_stat_idx;
19906c92544dSBjoern A. Zeeb }
19916c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
19926c92544dSBjoern A. Zeeb
mt76_ethtool_page_pool_stats(struct mt76_dev * dev,u64 * data,int * index)1993cbb3ec25SBjoern A. Zeeb void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
1994cbb3ec25SBjoern A. Zeeb {
1995cbb3ec25SBjoern A. Zeeb #ifdef CONFIG_PAGE_POOL_STATS
1996cbb3ec25SBjoern A. Zeeb struct page_pool_stats stats = {};
1997cbb3ec25SBjoern A. Zeeb int i;
1998cbb3ec25SBjoern A. Zeeb
1999cbb3ec25SBjoern A. Zeeb mt76_for_each_q_rx(dev, i)
2000cbb3ec25SBjoern A. Zeeb page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
2001cbb3ec25SBjoern A. Zeeb
2002cbb3ec25SBjoern A. Zeeb page_pool_ethtool_stats_get(data, &stats);
2003cbb3ec25SBjoern A. Zeeb *index += page_pool_ethtool_stats_get_count();
2004cbb3ec25SBjoern A. Zeeb #endif
2005cbb3ec25SBjoern A. Zeeb }
2006cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
2007cbb3ec25SBjoern A. Zeeb
mt76_phy_dfs_state(struct mt76_phy * phy)20086c92544dSBjoern A. Zeeb enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
20096c92544dSBjoern A. Zeeb {
20106c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = phy->hw;
20116c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev;
20126c92544dSBjoern A. Zeeb
20136c92544dSBjoern A. Zeeb if (dev->region == NL80211_DFS_UNSET ||
20146c92544dSBjoern A. Zeeb test_bit(MT76_SCANNING, &phy->state))
20156c92544dSBjoern A. Zeeb return MT_DFS_STATE_DISABLED;
20166c92544dSBjoern A. Zeeb
2017*8ba4d145SBjoern A. Zeeb if (!phy->radar_enabled) {
20186c92544dSBjoern A. Zeeb if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
20196c92544dSBjoern A. Zeeb (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
20206c92544dSBjoern A. Zeeb return MT_DFS_STATE_ACTIVE;
20216c92544dSBjoern A. Zeeb
20226c92544dSBjoern A. Zeeb return MT_DFS_STATE_DISABLED;
20236c92544dSBjoern A. Zeeb }
20246c92544dSBjoern A. Zeeb
20256c92544dSBjoern A. Zeeb if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP))
20266c92544dSBjoern A. Zeeb return MT_DFS_STATE_CAC;
20276c92544dSBjoern A. Zeeb
20286c92544dSBjoern A. Zeeb return MT_DFS_STATE_ACTIVE;
20296c92544dSBjoern A. Zeeb }
20306c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
2031*8ba4d145SBjoern A. Zeeb
mt76_vif_cleanup(struct mt76_dev * dev,struct ieee80211_vif * vif)2032*8ba4d145SBjoern A. Zeeb void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
2033*8ba4d145SBjoern A. Zeeb {
2034*8ba4d145SBjoern A. Zeeb struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
2035*8ba4d145SBjoern A. Zeeb struct mt76_vif_data *mvif = mlink->mvif;
2036*8ba4d145SBjoern A. Zeeb
2037*8ba4d145SBjoern A. Zeeb rcu_assign_pointer(mvif->link[0], NULL);
2038*8ba4d145SBjoern A. Zeeb mt76_abort_scan(dev);
2039*8ba4d145SBjoern A. Zeeb if (mvif->roc_phy)
2040*8ba4d145SBjoern A. Zeeb mt76_abort_roc(mvif->roc_phy);
2041*8ba4d145SBjoern A. Zeeb }
2042*8ba4d145SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_vif_cleanup);
2043