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 9*cbb3ec25SBjoern A. Zeeb #include <net/page_pool.h> 106c92544dSBjoern A. Zeeb #if defined(__FreeBSD__) 116c92544dSBjoern A. Zeeb #include <linux/math64.h> 12*cbb3ec25SBjoern A. Zeeb #include <linux/numa.h> 136c92544dSBjoern A. Zeeb #endif 146c92544dSBjoern A. Zeeb #include "mt76.h" 156c92544dSBjoern A. Zeeb 166c92544dSBjoern A. Zeeb #define CHAN2G(_idx, _freq) { \ 176c92544dSBjoern A. Zeeb .band = NL80211_BAND_2GHZ, \ 186c92544dSBjoern A. Zeeb .center_freq = (_freq), \ 196c92544dSBjoern A. Zeeb .hw_value = (_idx), \ 206c92544dSBjoern A. Zeeb .max_power = 30, \ 216c92544dSBjoern A. Zeeb } 226c92544dSBjoern A. Zeeb 236c92544dSBjoern A. Zeeb #define CHAN5G(_idx, _freq) { \ 246c92544dSBjoern A. Zeeb .band = NL80211_BAND_5GHZ, \ 256c92544dSBjoern A. Zeeb .center_freq = (_freq), \ 266c92544dSBjoern A. Zeeb .hw_value = (_idx), \ 276c92544dSBjoern A. Zeeb .max_power = 30, \ 286c92544dSBjoern A. Zeeb } 296c92544dSBjoern A. Zeeb 306c92544dSBjoern A. Zeeb #define CHAN6G(_idx, _freq) { \ 316c92544dSBjoern A. Zeeb .band = NL80211_BAND_6GHZ, \ 326c92544dSBjoern A. Zeeb .center_freq = (_freq), \ 336c92544dSBjoern A. Zeeb .hw_value = (_idx), \ 346c92544dSBjoern A. Zeeb .max_power = 30, \ 356c92544dSBjoern A. Zeeb } 366c92544dSBjoern A. Zeeb 376c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_2ghz[] = { 386c92544dSBjoern A. Zeeb CHAN2G(1, 2412), 396c92544dSBjoern A. Zeeb CHAN2G(2, 2417), 406c92544dSBjoern A. Zeeb CHAN2G(3, 2422), 416c92544dSBjoern A. Zeeb CHAN2G(4, 2427), 426c92544dSBjoern A. Zeeb CHAN2G(5, 2432), 436c92544dSBjoern A. Zeeb CHAN2G(6, 2437), 446c92544dSBjoern A. Zeeb CHAN2G(7, 2442), 456c92544dSBjoern A. Zeeb CHAN2G(8, 2447), 466c92544dSBjoern A. Zeeb CHAN2G(9, 2452), 476c92544dSBjoern A. Zeeb CHAN2G(10, 2457), 486c92544dSBjoern A. Zeeb CHAN2G(11, 2462), 496c92544dSBjoern A. Zeeb CHAN2G(12, 2467), 506c92544dSBjoern A. Zeeb CHAN2G(13, 2472), 516c92544dSBjoern A. Zeeb CHAN2G(14, 2484), 526c92544dSBjoern A. Zeeb }; 536c92544dSBjoern A. Zeeb 546c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_5ghz[] = { 556c92544dSBjoern A. Zeeb CHAN5G(36, 5180), 566c92544dSBjoern A. Zeeb CHAN5G(40, 5200), 576c92544dSBjoern A. Zeeb CHAN5G(44, 5220), 586c92544dSBjoern A. Zeeb CHAN5G(48, 5240), 596c92544dSBjoern A. Zeeb 606c92544dSBjoern A. Zeeb CHAN5G(52, 5260), 616c92544dSBjoern A. Zeeb CHAN5G(56, 5280), 626c92544dSBjoern A. Zeeb CHAN5G(60, 5300), 636c92544dSBjoern A. Zeeb CHAN5G(64, 5320), 646c92544dSBjoern A. Zeeb 656c92544dSBjoern A. Zeeb CHAN5G(100, 5500), 666c92544dSBjoern A. Zeeb CHAN5G(104, 5520), 676c92544dSBjoern A. Zeeb CHAN5G(108, 5540), 686c92544dSBjoern A. Zeeb CHAN5G(112, 5560), 696c92544dSBjoern A. Zeeb CHAN5G(116, 5580), 706c92544dSBjoern A. Zeeb CHAN5G(120, 5600), 716c92544dSBjoern A. Zeeb CHAN5G(124, 5620), 726c92544dSBjoern A. Zeeb CHAN5G(128, 5640), 736c92544dSBjoern A. Zeeb CHAN5G(132, 5660), 746c92544dSBjoern A. Zeeb CHAN5G(136, 5680), 756c92544dSBjoern A. Zeeb CHAN5G(140, 5700), 766c92544dSBjoern A. Zeeb CHAN5G(144, 5720), 776c92544dSBjoern A. Zeeb 786c92544dSBjoern A. Zeeb CHAN5G(149, 5745), 796c92544dSBjoern A. Zeeb CHAN5G(153, 5765), 806c92544dSBjoern A. Zeeb CHAN5G(157, 5785), 816c92544dSBjoern A. Zeeb CHAN5G(161, 5805), 826c92544dSBjoern A. Zeeb CHAN5G(165, 5825), 836c92544dSBjoern A. Zeeb CHAN5G(169, 5845), 846c92544dSBjoern A. Zeeb CHAN5G(173, 5865), 85*cbb3ec25SBjoern A. Zeeb CHAN5G(177, 5885), 866c92544dSBjoern A. Zeeb }; 876c92544dSBjoern A. Zeeb 886c92544dSBjoern A. Zeeb static const struct ieee80211_channel mt76_channels_6ghz[] = { 896c92544dSBjoern A. Zeeb /* UNII-5 */ 906c92544dSBjoern A. Zeeb CHAN6G(1, 5955), 916c92544dSBjoern A. Zeeb CHAN6G(5, 5975), 926c92544dSBjoern A. Zeeb CHAN6G(9, 5995), 936c92544dSBjoern A. Zeeb CHAN6G(13, 6015), 946c92544dSBjoern A. Zeeb CHAN6G(17, 6035), 956c92544dSBjoern A. Zeeb CHAN6G(21, 6055), 966c92544dSBjoern A. Zeeb CHAN6G(25, 6075), 976c92544dSBjoern A. Zeeb CHAN6G(29, 6095), 986c92544dSBjoern A. Zeeb CHAN6G(33, 6115), 996c92544dSBjoern A. Zeeb CHAN6G(37, 6135), 1006c92544dSBjoern A. Zeeb CHAN6G(41, 6155), 1016c92544dSBjoern A. Zeeb CHAN6G(45, 6175), 1026c92544dSBjoern A. Zeeb CHAN6G(49, 6195), 1036c92544dSBjoern A. Zeeb CHAN6G(53, 6215), 1046c92544dSBjoern A. Zeeb CHAN6G(57, 6235), 1056c92544dSBjoern A. Zeeb CHAN6G(61, 6255), 1066c92544dSBjoern A. Zeeb CHAN6G(65, 6275), 1076c92544dSBjoern A. Zeeb CHAN6G(69, 6295), 1086c92544dSBjoern A. Zeeb CHAN6G(73, 6315), 1096c92544dSBjoern A. Zeeb CHAN6G(77, 6335), 1106c92544dSBjoern A. Zeeb CHAN6G(81, 6355), 1116c92544dSBjoern A. Zeeb CHAN6G(85, 6375), 1126c92544dSBjoern A. Zeeb CHAN6G(89, 6395), 1136c92544dSBjoern A. Zeeb CHAN6G(93, 6415), 1146c92544dSBjoern A. Zeeb /* UNII-6 */ 1156c92544dSBjoern A. Zeeb CHAN6G(97, 6435), 1166c92544dSBjoern A. Zeeb CHAN6G(101, 6455), 1176c92544dSBjoern A. Zeeb CHAN6G(105, 6475), 1186c92544dSBjoern A. Zeeb CHAN6G(109, 6495), 1196c92544dSBjoern A. Zeeb CHAN6G(113, 6515), 1206c92544dSBjoern A. Zeeb CHAN6G(117, 6535), 1216c92544dSBjoern A. Zeeb /* UNII-7 */ 1226c92544dSBjoern A. Zeeb CHAN6G(121, 6555), 1236c92544dSBjoern A. Zeeb CHAN6G(125, 6575), 1246c92544dSBjoern A. Zeeb CHAN6G(129, 6595), 1256c92544dSBjoern A. Zeeb CHAN6G(133, 6615), 1266c92544dSBjoern A. Zeeb CHAN6G(137, 6635), 1276c92544dSBjoern A. Zeeb CHAN6G(141, 6655), 1286c92544dSBjoern A. Zeeb CHAN6G(145, 6675), 1296c92544dSBjoern A. Zeeb CHAN6G(149, 6695), 1306c92544dSBjoern A. Zeeb CHAN6G(153, 6715), 1316c92544dSBjoern A. Zeeb CHAN6G(157, 6735), 1326c92544dSBjoern A. Zeeb CHAN6G(161, 6755), 1336c92544dSBjoern A. Zeeb CHAN6G(165, 6775), 1346c92544dSBjoern A. Zeeb CHAN6G(169, 6795), 1356c92544dSBjoern A. Zeeb CHAN6G(173, 6815), 1366c92544dSBjoern A. Zeeb CHAN6G(177, 6835), 1376c92544dSBjoern A. Zeeb CHAN6G(181, 6855), 1386c92544dSBjoern A. Zeeb CHAN6G(185, 6875), 1396c92544dSBjoern A. Zeeb /* UNII-8 */ 1406c92544dSBjoern A. Zeeb CHAN6G(189, 6895), 1416c92544dSBjoern A. Zeeb CHAN6G(193, 6915), 1426c92544dSBjoern A. Zeeb CHAN6G(197, 6935), 1436c92544dSBjoern A. Zeeb CHAN6G(201, 6955), 1446c92544dSBjoern A. Zeeb CHAN6G(205, 6975), 1456c92544dSBjoern A. Zeeb CHAN6G(209, 6995), 1466c92544dSBjoern A. Zeeb CHAN6G(213, 7015), 1476c92544dSBjoern A. Zeeb CHAN6G(217, 7035), 1486c92544dSBjoern A. Zeeb CHAN6G(221, 7055), 1496c92544dSBjoern A. Zeeb CHAN6G(225, 7075), 1506c92544dSBjoern A. Zeeb CHAN6G(229, 7095), 1516c92544dSBjoern A. Zeeb CHAN6G(233, 7115), 1526c92544dSBjoern A. Zeeb }; 1536c92544dSBjoern A. Zeeb 1546c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 1556c92544dSBjoern A. Zeeb static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 1566c92544dSBjoern A. Zeeb { .throughput = 0 * 1024, .blink_time = 334 }, 1576c92544dSBjoern A. Zeeb { .throughput = 1 * 1024, .blink_time = 260 }, 1586c92544dSBjoern A. Zeeb { .throughput = 5 * 1024, .blink_time = 220 }, 1596c92544dSBjoern A. Zeeb { .throughput = 10 * 1024, .blink_time = 190 }, 1606c92544dSBjoern A. Zeeb { .throughput = 20 * 1024, .blink_time = 170 }, 1616c92544dSBjoern A. Zeeb { .throughput = 50 * 1024, .blink_time = 150 }, 1626c92544dSBjoern A. Zeeb { .throughput = 70 * 1024, .blink_time = 130 }, 1636c92544dSBjoern A. Zeeb { .throughput = 100 * 1024, .blink_time = 110 }, 1646c92544dSBjoern A. Zeeb { .throughput = 200 * 1024, .blink_time = 80 }, 1656c92544dSBjoern A. Zeeb { .throughput = 300 * 1024, .blink_time = 50 }, 1666c92544dSBjoern A. Zeeb }; 1676c92544dSBjoern A. Zeeb #endif 1686c92544dSBjoern A. Zeeb 1696c92544dSBjoern A. Zeeb struct ieee80211_rate mt76_rates[] = { 1706c92544dSBjoern A. Zeeb CCK_RATE(0, 10), 1716c92544dSBjoern A. Zeeb CCK_RATE(1, 20), 1726c92544dSBjoern A. Zeeb CCK_RATE(2, 55), 1736c92544dSBjoern A. Zeeb CCK_RATE(3, 110), 1746c92544dSBjoern A. Zeeb OFDM_RATE(11, 60), 1756c92544dSBjoern A. Zeeb OFDM_RATE(15, 90), 1766c92544dSBjoern A. Zeeb OFDM_RATE(10, 120), 1776c92544dSBjoern A. Zeeb OFDM_RATE(14, 180), 1786c92544dSBjoern A. Zeeb OFDM_RATE(9, 240), 1796c92544dSBjoern A. Zeeb OFDM_RATE(13, 360), 1806c92544dSBjoern A. Zeeb OFDM_RATE(8, 480), 1816c92544dSBjoern A. Zeeb OFDM_RATE(12, 540), 1826c92544dSBjoern A. Zeeb }; 1836c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rates); 1846c92544dSBjoern A. Zeeb 1856c92544dSBjoern A. Zeeb static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { 1866c92544dSBjoern A. Zeeb { .start_freq = 2402, .end_freq = 2494, }, 1876c92544dSBjoern A. Zeeb { .start_freq = 5150, .end_freq = 5350, }, 1886c92544dSBjoern A. Zeeb { .start_freq = 5350, .end_freq = 5470, }, 1896c92544dSBjoern A. Zeeb { .start_freq = 5470, .end_freq = 5725, }, 1906c92544dSBjoern A. Zeeb { .start_freq = 5725, .end_freq = 5950, }, 1916c92544dSBjoern A. Zeeb { .start_freq = 5945, .end_freq = 6165, }, 1926c92544dSBjoern A. Zeeb { .start_freq = 6165, .end_freq = 6405, }, 1936c92544dSBjoern A. Zeeb { .start_freq = 6405, .end_freq = 6525, }, 1946c92544dSBjoern A. Zeeb { .start_freq = 6525, .end_freq = 6705, }, 1956c92544dSBjoern A. Zeeb { .start_freq = 6705, .end_freq = 6865, }, 1966c92544dSBjoern A. Zeeb { .start_freq = 6865, .end_freq = 7125, }, 1976c92544dSBjoern A. Zeeb }; 1986c92544dSBjoern A. Zeeb 1996c92544dSBjoern A. Zeeb static const struct cfg80211_sar_capa mt76_sar_capa = { 2006c92544dSBjoern A. Zeeb .type = NL80211_SAR_TYPE_POWER, 2016c92544dSBjoern A. Zeeb .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), 2026c92544dSBjoern A. Zeeb .freq_ranges = &mt76_sar_freq_ranges[0], 2036c92544dSBjoern A. Zeeb }; 2046c92544dSBjoern A. Zeeb 2056c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 206*cbb3ec25SBjoern A. Zeeb static int mt76_led_init(struct mt76_phy *phy) 2076c92544dSBjoern A. Zeeb { 208*cbb3ec25SBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 209*cbb3ec25SBjoern A. Zeeb struct ieee80211_hw *hw = phy->hw; 2106c92544dSBjoern A. Zeeb 211*cbb3ec25SBjoern A. Zeeb if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) 2126c92544dSBjoern A. Zeeb return 0; 2136c92544dSBjoern A. Zeeb 214*cbb3ec25SBjoern A. Zeeb snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", 215*cbb3ec25SBjoern A. Zeeb wiphy_name(hw->wiphy)); 2166c92544dSBjoern A. Zeeb 217*cbb3ec25SBjoern A. Zeeb phy->leds.cdev.name = phy->leds.name; 218*cbb3ec25SBjoern A. Zeeb phy->leds.cdev.default_trigger = 2196c92544dSBjoern A. Zeeb ieee80211_create_tpt_led_trigger(hw, 2206c92544dSBjoern A. Zeeb IEEE80211_TPT_LEDTRIG_FL_RADIO, 2216c92544dSBjoern A. Zeeb mt76_tpt_blink, 2226c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_tpt_blink)); 2236c92544dSBjoern A. Zeeb 2246c92544dSBjoern A. Zeeb #if defined(CONFIG_OF) 225*cbb3ec25SBjoern A. Zeeb if (phy == &dev->phy) { 226*cbb3ec25SBjoern A. Zeeb struct device_node *np = dev->dev->of_node; 227*cbb3ec25SBjoern A. Zeeb 2286c92544dSBjoern A. Zeeb np = of_get_child_by_name(np, "led"); 2296c92544dSBjoern A. Zeeb if (np) { 230*cbb3ec25SBjoern A. Zeeb int led_pin; 231*cbb3ec25SBjoern A. Zeeb 2326c92544dSBjoern A. Zeeb if (!of_property_read_u32(np, "led-sources", &led_pin)) 233*cbb3ec25SBjoern A. Zeeb phy->leds.pin = led_pin; 234*cbb3ec25SBjoern A. Zeeb phy->leds.al = of_property_read_bool(np, 235*cbb3ec25SBjoern A. Zeeb "led-active-low"); 2366c92544dSBjoern A. Zeeb of_node_put(np); 2376c92544dSBjoern A. Zeeb } 238*cbb3ec25SBjoern A. Zeeb } 2396c92544dSBjoern A. Zeeb #endif 2406c92544dSBjoern A. Zeeb 241*cbb3ec25SBjoern A. Zeeb return led_classdev_register(dev->dev, &phy->leds.cdev); 2426c92544dSBjoern A. Zeeb } 2436c92544dSBjoern A. Zeeb 244*cbb3ec25SBjoern A. Zeeb static void mt76_led_cleanup(struct mt76_phy *phy) 2456c92544dSBjoern A. Zeeb { 246*cbb3ec25SBjoern A. Zeeb if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) 2476c92544dSBjoern A. Zeeb return; 2486c92544dSBjoern A. Zeeb 249*cbb3ec25SBjoern A. Zeeb led_classdev_unregister(&phy->leds.cdev); 2506c92544dSBjoern A. Zeeb } 2516c92544dSBjoern A. Zeeb #endif 2526c92544dSBjoern A. Zeeb 2536c92544dSBjoern A. Zeeb static void mt76_init_stream_cap(struct mt76_phy *phy, 2546c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband, 2556c92544dSBjoern A. Zeeb bool vht) 2566c92544dSBjoern A. Zeeb { 2576c92544dSBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 2586c92544dSBjoern A. Zeeb int i, nstream = hweight8(phy->antenna_mask); 2596c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap; 2606c92544dSBjoern A. Zeeb u16 mcs_map = 0; 2616c92544dSBjoern A. Zeeb 2626c92544dSBjoern A. Zeeb if (nstream > 1) 2636c92544dSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 2646c92544dSBjoern A. Zeeb else 2656c92544dSBjoern A. Zeeb ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 2666c92544dSBjoern A. Zeeb 2676c92544dSBjoern A. Zeeb for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 2686c92544dSBjoern A. Zeeb ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 2696c92544dSBjoern A. Zeeb 2706c92544dSBjoern A. Zeeb if (!vht) 2716c92544dSBjoern A. Zeeb return; 2726c92544dSBjoern A. Zeeb 2736c92544dSBjoern A. Zeeb vht_cap = &sband->vht_cap; 2746c92544dSBjoern A. Zeeb if (nstream > 1) 2756c92544dSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 2766c92544dSBjoern A. Zeeb else 2776c92544dSBjoern A. Zeeb vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 2786c92544dSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 2796c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; 2806c92544dSBjoern A. Zeeb 2816c92544dSBjoern A. Zeeb for (i = 0; i < 8; i++) { 2826c92544dSBjoern A. Zeeb if (i < nstream) 2836c92544dSBjoern A. Zeeb mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 2846c92544dSBjoern A. Zeeb else 2856c92544dSBjoern A. Zeeb mcs_map |= 2866c92544dSBjoern A. Zeeb (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 2876c92544dSBjoern A. Zeeb } 2886c92544dSBjoern A. Zeeb vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 2896c92544dSBjoern A. Zeeb vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 2906c92544dSBjoern A. Zeeb if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW)) 2916c92544dSBjoern A. Zeeb vht_cap->vht_mcs.tx_highest |= 2926c92544dSBjoern A. Zeeb cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); 2936c92544dSBjoern A. Zeeb } 2946c92544dSBjoern A. Zeeb 2956c92544dSBjoern A. Zeeb void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 2966c92544dSBjoern A. Zeeb { 2976c92544dSBjoern A. Zeeb if (phy->cap.has_2ghz) 2986c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 2996c92544dSBjoern A. Zeeb if (phy->cap.has_5ghz) 3006c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 3016c92544dSBjoern A. Zeeb if (phy->cap.has_6ghz) 3026c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); 3036c92544dSBjoern A. Zeeb } 3046c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 3056c92544dSBjoern A. Zeeb 3066c92544dSBjoern A. Zeeb static int 3076c92544dSBjoern A. Zeeb mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, 3086c92544dSBjoern A. Zeeb const struct ieee80211_channel *chan, int n_chan, 3096c92544dSBjoern A. Zeeb struct ieee80211_rate *rates, int n_rates, 3106c92544dSBjoern A. Zeeb bool ht, bool vht) 3116c92544dSBjoern A. Zeeb { 3126c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband = &msband->sband; 3136c92544dSBjoern A. Zeeb struct ieee80211_sta_vht_cap *vht_cap; 3146c92544dSBjoern A. Zeeb struct ieee80211_sta_ht_cap *ht_cap; 3156c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 3166c92544dSBjoern A. Zeeb void *chanlist; 3176c92544dSBjoern A. Zeeb int size; 3186c92544dSBjoern A. Zeeb 3196c92544dSBjoern A. Zeeb size = n_chan * sizeof(*chan); 3206c92544dSBjoern A. Zeeb chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 3216c92544dSBjoern A. Zeeb if (!chanlist) 3226c92544dSBjoern A. Zeeb return -ENOMEM; 3236c92544dSBjoern A. Zeeb 3246c92544dSBjoern A. Zeeb msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 3256c92544dSBjoern A. Zeeb GFP_KERNEL); 3266c92544dSBjoern A. Zeeb if (!msband->chan) 3276c92544dSBjoern A. Zeeb return -ENOMEM; 3286c92544dSBjoern A. Zeeb 3296c92544dSBjoern A. Zeeb sband->channels = chanlist; 3306c92544dSBjoern A. Zeeb sband->n_channels = n_chan; 3316c92544dSBjoern A. Zeeb sband->bitrates = rates; 3326c92544dSBjoern A. Zeeb sband->n_bitrates = n_rates; 3336c92544dSBjoern A. Zeeb 3346c92544dSBjoern A. Zeeb if (!ht) 3356c92544dSBjoern A. Zeeb return 0; 3366c92544dSBjoern A. Zeeb 3376c92544dSBjoern A. Zeeb ht_cap = &sband->ht_cap; 3386c92544dSBjoern A. Zeeb ht_cap->ht_supported = true; 3396c92544dSBjoern A. Zeeb ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 3406c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_GRN_FLD | 3416c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_SGI_20 | 3426c92544dSBjoern A. Zeeb IEEE80211_HT_CAP_SGI_40 | 3436c92544dSBjoern A. Zeeb (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 3446c92544dSBjoern A. Zeeb 3456c92544dSBjoern A. Zeeb ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 3466c92544dSBjoern A. Zeeb ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 3476c92544dSBjoern A. Zeeb 3486c92544dSBjoern A. Zeeb mt76_init_stream_cap(phy, sband, vht); 3496c92544dSBjoern A. Zeeb 3506c92544dSBjoern A. Zeeb if (!vht) 3516c92544dSBjoern A. Zeeb return 0; 3526c92544dSBjoern A. Zeeb 3536c92544dSBjoern A. Zeeb vht_cap = &sband->vht_cap; 3546c92544dSBjoern A. Zeeb vht_cap->vht_supported = true; 3556c92544dSBjoern A. Zeeb vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 3566c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_RXSTBC_1 | 3576c92544dSBjoern A. Zeeb IEEE80211_VHT_CAP_SHORT_GI_80 | 3586c92544dSBjoern A. Zeeb (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 3596c92544dSBjoern A. Zeeb 3606c92544dSBjoern A. Zeeb return 0; 3616c92544dSBjoern A. Zeeb } 3626c92544dSBjoern A. Zeeb 3636c92544dSBjoern A. Zeeb static int 3646c92544dSBjoern A. Zeeb mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, 3656c92544dSBjoern A. Zeeb int n_rates) 3666c92544dSBjoern A. Zeeb { 3676c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 3686c92544dSBjoern A. Zeeb 3696c92544dSBjoern A. Zeeb return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, 3706c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_channels_2ghz), rates, 3716c92544dSBjoern A. Zeeb n_rates, true, false); 3726c92544dSBjoern A. Zeeb } 3736c92544dSBjoern A. Zeeb 3746c92544dSBjoern A. Zeeb static int 3756c92544dSBjoern A. Zeeb mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, 3766c92544dSBjoern A. Zeeb int n_rates, bool vht) 3776c92544dSBjoern A. Zeeb { 3786c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 3796c92544dSBjoern A. Zeeb 3806c92544dSBjoern A. Zeeb return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, 3816c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_channels_5ghz), rates, 3826c92544dSBjoern A. Zeeb n_rates, true, vht); 3836c92544dSBjoern A. Zeeb } 3846c92544dSBjoern A. Zeeb 3856c92544dSBjoern A. Zeeb static int 3866c92544dSBjoern A. Zeeb mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, 3876c92544dSBjoern A. Zeeb int n_rates) 3886c92544dSBjoern A. Zeeb { 3896c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; 3906c92544dSBjoern A. Zeeb 3916c92544dSBjoern A. Zeeb return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, 3926c92544dSBjoern A. Zeeb ARRAY_SIZE(mt76_channels_6ghz), rates, 3936c92544dSBjoern A. Zeeb n_rates, false, false); 3946c92544dSBjoern A. Zeeb } 3956c92544dSBjoern A. Zeeb 3966c92544dSBjoern A. Zeeb static void 3976c92544dSBjoern A. Zeeb mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 3986c92544dSBjoern A. Zeeb enum nl80211_band band) 3996c92544dSBjoern A. Zeeb { 4006c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband = &msband->sband; 4016c92544dSBjoern A. Zeeb bool found = false; 4026c92544dSBjoern A. Zeeb int i; 4036c92544dSBjoern A. Zeeb 4046c92544dSBjoern A. Zeeb if (!sband) 4056c92544dSBjoern A. Zeeb return; 4066c92544dSBjoern A. Zeeb 4076c92544dSBjoern A. Zeeb for (i = 0; i < sband->n_channels; i++) { 4086c92544dSBjoern A. Zeeb if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 4096c92544dSBjoern A. Zeeb continue; 4106c92544dSBjoern A. Zeeb 4116c92544dSBjoern A. Zeeb found = true; 4126c92544dSBjoern A. Zeeb break; 4136c92544dSBjoern A. Zeeb } 4146c92544dSBjoern A. Zeeb 4156c92544dSBjoern A. Zeeb if (found) { 4166c92544dSBjoern A. Zeeb phy->chandef.chan = &sband->channels[0]; 4176c92544dSBjoern A. Zeeb phy->chan_state = &msband->chan[0]; 4186c92544dSBjoern A. Zeeb return; 4196c92544dSBjoern A. Zeeb } 4206c92544dSBjoern A. Zeeb 4216c92544dSBjoern A. Zeeb sband->n_channels = 0; 4226c92544dSBjoern A. Zeeb phy->hw->wiphy->bands[band] = NULL; 4236c92544dSBjoern A. Zeeb } 4246c92544dSBjoern A. Zeeb 4256c92544dSBjoern A. Zeeb static int 4266c92544dSBjoern A. Zeeb mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) 4276c92544dSBjoern A. Zeeb { 4286c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 4296c92544dSBjoern A. Zeeb struct wiphy *wiphy = hw->wiphy; 4306c92544dSBjoern A. Zeeb 4316c92544dSBjoern A. Zeeb SET_IEEE80211_DEV(hw, dev->dev); 4326c92544dSBjoern A. Zeeb SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); 4336c92544dSBjoern A. Zeeb 434*cbb3ec25SBjoern A. Zeeb wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 435*cbb3ec25SBjoern A. Zeeb NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; 4366c92544dSBjoern A. Zeeb wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 4376c92544dSBjoern A. Zeeb WIPHY_FLAG_SUPPORTS_TDLS | 4386c92544dSBjoern A. Zeeb WIPHY_FLAG_AP_UAPSD; 4396c92544dSBjoern A. Zeeb 4406c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 4416c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 4426c92544dSBjoern A. Zeeb wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 4436c92544dSBjoern A. Zeeb 4446c92544dSBjoern A. Zeeb wiphy->available_antennas_tx = phy->antenna_mask; 4456c92544dSBjoern A. Zeeb wiphy->available_antennas_rx = phy->antenna_mask; 4466c92544dSBjoern A. Zeeb 4476c92544dSBjoern A. Zeeb wiphy->sar_capa = &mt76_sar_capa; 4486c92544dSBjoern A. Zeeb phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, 4496c92544dSBjoern A. Zeeb sizeof(struct mt76_freq_range_power), 4506c92544dSBjoern A. Zeeb GFP_KERNEL); 4516c92544dSBjoern A. Zeeb if (!phy->frp) 4526c92544dSBjoern A. Zeeb return -ENOMEM; 4536c92544dSBjoern A. Zeeb 4546c92544dSBjoern A. Zeeb hw->txq_data_size = sizeof(struct mt76_txq); 4556c92544dSBjoern A. Zeeb hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 4566c92544dSBjoern A. Zeeb 4576c92544dSBjoern A. Zeeb if (!hw->max_tx_fragments) 4586c92544dSBjoern A. Zeeb hw->max_tx_fragments = 16; 4596c92544dSBjoern A. Zeeb 4606c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SIGNAL_DBM); 4616c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, AMPDU_AGGREGATION); 4626c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 4636c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 4646c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 4656c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 4666c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 467*cbb3ec25SBjoern A. Zeeb 468*cbb3ec25SBjoern A. Zeeb if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) { 4696c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, TX_AMSDU); 4706c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, TX_FRAG_LIST); 471*cbb3ec25SBjoern A. Zeeb } 472*cbb3ec25SBjoern A. Zeeb 4736c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, MFP_CAPABLE); 4746c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, AP_LINK_PS); 4756c92544dSBjoern A. Zeeb ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 4766c92544dSBjoern A. Zeeb 4776c92544dSBjoern A. Zeeb return 0; 4786c92544dSBjoern A. Zeeb } 4796c92544dSBjoern A. Zeeb 4806c92544dSBjoern A. Zeeb struct mt76_phy * 4816c92544dSBjoern A. Zeeb mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 4826c92544dSBjoern A. Zeeb const struct ieee80211_ops *ops, u8 band_idx) 4836c92544dSBjoern A. Zeeb { 4846c92544dSBjoern A. Zeeb struct ieee80211_hw *hw; 4856c92544dSBjoern A. Zeeb unsigned int phy_size; 4866c92544dSBjoern A. Zeeb struct mt76_phy *phy; 4876c92544dSBjoern A. Zeeb 4886c92544dSBjoern A. Zeeb phy_size = ALIGN(sizeof(*phy), 8); 4896c92544dSBjoern A. Zeeb hw = ieee80211_alloc_hw(size + phy_size, ops); 4906c92544dSBjoern A. Zeeb if (!hw) 4916c92544dSBjoern A. Zeeb return NULL; 4926c92544dSBjoern A. Zeeb 4936c92544dSBjoern A. Zeeb phy = hw->priv; 4946c92544dSBjoern A. Zeeb phy->dev = dev; 4956c92544dSBjoern A. Zeeb phy->hw = hw; 4966c92544dSBjoern A. Zeeb #if defined(__linux__) 4976c92544dSBjoern A. Zeeb phy->priv = hw->priv + phy_size; 4986c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 4996c92544dSBjoern A. Zeeb phy->priv = (u8 *)hw->priv + phy_size; 5006c92544dSBjoern A. Zeeb #endif 5016c92544dSBjoern A. Zeeb phy->band_idx = band_idx; 5026c92544dSBjoern A. Zeeb 5036c92544dSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 5046c92544dSBjoern A. Zeeb hw->wiphy->interface_modes = 5056c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_STATION) | 5066c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) | 5076c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 5086c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) | 5096c92544dSBjoern A. Zeeb #endif 5106c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) | 5116c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) | 5126c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_ADHOC); 5136c92544dSBjoern A. Zeeb 5146c92544dSBjoern A. Zeeb return phy; 5156c92544dSBjoern A. Zeeb } 5166c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_phy); 5176c92544dSBjoern A. Zeeb 5186c92544dSBjoern A. Zeeb int mt76_register_phy(struct mt76_phy *phy, bool vht, 5196c92544dSBjoern A. Zeeb struct ieee80211_rate *rates, int n_rates) 5206c92544dSBjoern A. Zeeb { 5216c92544dSBjoern A. Zeeb int ret; 5226c92544dSBjoern A. Zeeb 5236c92544dSBjoern A. Zeeb ret = mt76_phy_init(phy, phy->hw); 5246c92544dSBjoern A. Zeeb if (ret) 5256c92544dSBjoern A. Zeeb return ret; 5266c92544dSBjoern A. Zeeb 5276c92544dSBjoern A. Zeeb if (phy->cap.has_2ghz) { 5286c92544dSBjoern A. Zeeb ret = mt76_init_sband_2g(phy, rates, n_rates); 5296c92544dSBjoern A. Zeeb if (ret) 5306c92544dSBjoern A. Zeeb return ret; 5316c92544dSBjoern A. Zeeb } 5326c92544dSBjoern A. Zeeb 5336c92544dSBjoern A. Zeeb if (phy->cap.has_5ghz) { 5346c92544dSBjoern A. Zeeb ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 5356c92544dSBjoern A. Zeeb if (ret) 5366c92544dSBjoern A. Zeeb return ret; 5376c92544dSBjoern A. Zeeb } 5386c92544dSBjoern A. Zeeb 5396c92544dSBjoern A. Zeeb if (phy->cap.has_6ghz) { 5406c92544dSBjoern A. Zeeb ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 5416c92544dSBjoern A. Zeeb if (ret) 5426c92544dSBjoern A. Zeeb return ret; 5436c92544dSBjoern A. Zeeb } 5446c92544dSBjoern A. Zeeb 545*cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 546*cbb3ec25SBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) { 547*cbb3ec25SBjoern A. Zeeb ret = mt76_led_init(phy); 548*cbb3ec25SBjoern A. Zeeb if (ret) 549*cbb3ec25SBjoern A. Zeeb return ret; 550*cbb3ec25SBjoern A. Zeeb } 551*cbb3ec25SBjoern A. Zeeb #endif 552*cbb3ec25SBjoern A. Zeeb 5536c92544dSBjoern A. Zeeb wiphy_read_of_freq_limits(phy->hw->wiphy); 5546c92544dSBjoern A. Zeeb mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 5556c92544dSBjoern A. Zeeb mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 5566c92544dSBjoern A. Zeeb mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); 5576c92544dSBjoern A. Zeeb 5586c92544dSBjoern A. Zeeb ret = ieee80211_register_hw(phy->hw); 5596c92544dSBjoern A. Zeeb if (ret) 5606c92544dSBjoern A. Zeeb return ret; 5616c92544dSBjoern A. Zeeb 562*cbb3ec25SBjoern A. Zeeb set_bit(MT76_STATE_REGISTERED, &phy->state); 5636c92544dSBjoern A. Zeeb phy->dev->phys[phy->band_idx] = phy; 5646c92544dSBjoern A. Zeeb 5656c92544dSBjoern A. Zeeb return 0; 5666c92544dSBjoern A. Zeeb } 5676c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_phy); 5686c92544dSBjoern A. Zeeb 5696c92544dSBjoern A. Zeeb void mt76_unregister_phy(struct mt76_phy *phy) 5706c92544dSBjoern A. Zeeb { 5716c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 5726c92544dSBjoern A. Zeeb 573*cbb3ec25SBjoern A. Zeeb if (!test_bit(MT76_STATE_REGISTERED, &phy->state)) 574*cbb3ec25SBjoern A. Zeeb return; 575*cbb3ec25SBjoern A. Zeeb 576*cbb3ec25SBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 577*cbb3ec25SBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) 578*cbb3ec25SBjoern A. Zeeb mt76_led_cleanup(phy); 579*cbb3ec25SBjoern A. Zeeb #endif 5806c92544dSBjoern A. Zeeb mt76_tx_status_check(dev, true); 5816c92544dSBjoern A. Zeeb ieee80211_unregister_hw(phy->hw); 5826c92544dSBjoern A. Zeeb dev->phys[phy->band_idx] = NULL; 5836c92544dSBjoern A. Zeeb } 5846c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_phy); 5856c92544dSBjoern A. Zeeb 586*cbb3ec25SBjoern A. Zeeb int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) 587*cbb3ec25SBjoern A. Zeeb { 588*cbb3ec25SBjoern A. Zeeb struct page_pool_params pp_params = { 589*cbb3ec25SBjoern A. Zeeb .order = 0, 590*cbb3ec25SBjoern A. Zeeb .flags = PP_FLAG_PAGE_FRAG, 591*cbb3ec25SBjoern A. Zeeb .nid = NUMA_NO_NODE, 592*cbb3ec25SBjoern A. Zeeb .dev = dev->dma_dev, 593*cbb3ec25SBjoern A. Zeeb }; 594*cbb3ec25SBjoern A. Zeeb int idx = q - dev->q_rx; 595*cbb3ec25SBjoern A. Zeeb 596*cbb3ec25SBjoern A. Zeeb switch (idx) { 597*cbb3ec25SBjoern A. Zeeb case MT_RXQ_MAIN: 598*cbb3ec25SBjoern A. Zeeb case MT_RXQ_BAND1: 599*cbb3ec25SBjoern A. Zeeb case MT_RXQ_BAND2: 600*cbb3ec25SBjoern A. Zeeb pp_params.pool_size = 256; 601*cbb3ec25SBjoern A. Zeeb break; 602*cbb3ec25SBjoern A. Zeeb default: 603*cbb3ec25SBjoern A. Zeeb pp_params.pool_size = 16; 604*cbb3ec25SBjoern A. Zeeb break; 605*cbb3ec25SBjoern A. Zeeb } 606*cbb3ec25SBjoern A. Zeeb 607*cbb3ec25SBjoern A. Zeeb if (mt76_is_mmio(dev)) { 608*cbb3ec25SBjoern A. Zeeb /* rely on page_pool for DMA mapping */ 609*cbb3ec25SBjoern A. Zeeb pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; 610*cbb3ec25SBjoern A. Zeeb pp_params.dma_dir = DMA_FROM_DEVICE; 611*cbb3ec25SBjoern A. Zeeb pp_params.max_len = PAGE_SIZE; 612*cbb3ec25SBjoern A. Zeeb pp_params.offset = 0; 613*cbb3ec25SBjoern A. Zeeb } 614*cbb3ec25SBjoern A. Zeeb 615*cbb3ec25SBjoern A. Zeeb q->page_pool = page_pool_create(&pp_params); 616*cbb3ec25SBjoern A. Zeeb if (IS_ERR(q->page_pool)) { 617*cbb3ec25SBjoern A. Zeeb int err = PTR_ERR(q->page_pool); 618*cbb3ec25SBjoern A. Zeeb 619*cbb3ec25SBjoern A. Zeeb q->page_pool = NULL; 620*cbb3ec25SBjoern A. Zeeb return err; 621*cbb3ec25SBjoern A. Zeeb } 622*cbb3ec25SBjoern A. Zeeb 623*cbb3ec25SBjoern A. Zeeb return 0; 624*cbb3ec25SBjoern A. Zeeb } 625*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_create_page_pool); 626*cbb3ec25SBjoern A. Zeeb 6276c92544dSBjoern A. Zeeb struct mt76_dev * 6286c92544dSBjoern A. Zeeb mt76_alloc_device(struct device *pdev, unsigned int size, 6296c92544dSBjoern A. Zeeb const struct ieee80211_ops *ops, 6306c92544dSBjoern A. Zeeb const struct mt76_driver_ops *drv_ops) 6316c92544dSBjoern A. Zeeb { 6326c92544dSBjoern A. Zeeb struct ieee80211_hw *hw; 6336c92544dSBjoern A. Zeeb struct mt76_phy *phy; 6346c92544dSBjoern A. Zeeb struct mt76_dev *dev; 6356c92544dSBjoern A. Zeeb int i; 6366c92544dSBjoern A. Zeeb 6376c92544dSBjoern A. Zeeb hw = ieee80211_alloc_hw(size, ops); 6386c92544dSBjoern A. Zeeb if (!hw) 6396c92544dSBjoern A. Zeeb return NULL; 6406c92544dSBjoern A. Zeeb 6416c92544dSBjoern A. Zeeb dev = hw->priv; 6426c92544dSBjoern A. Zeeb dev->hw = hw; 6436c92544dSBjoern A. Zeeb dev->dev = pdev; 6446c92544dSBjoern A. Zeeb dev->drv = drv_ops; 6456c92544dSBjoern A. Zeeb dev->dma_dev = pdev; 6466c92544dSBjoern A. Zeeb 6476c92544dSBjoern A. Zeeb phy = &dev->phy; 6486c92544dSBjoern A. Zeeb phy->dev = dev; 6496c92544dSBjoern A. Zeeb phy->hw = hw; 6506c92544dSBjoern A. Zeeb phy->band_idx = MT_BAND0; 6516c92544dSBjoern A. Zeeb dev->phys[phy->band_idx] = phy; 6526c92544dSBjoern A. Zeeb 6536c92544dSBjoern A. Zeeb spin_lock_init(&dev->rx_lock); 6546c92544dSBjoern A. Zeeb spin_lock_init(&dev->lock); 6556c92544dSBjoern A. Zeeb spin_lock_init(&dev->cc_lock); 6566c92544dSBjoern A. Zeeb spin_lock_init(&dev->status_lock); 657*cbb3ec25SBjoern A. Zeeb spin_lock_init(&dev->wed_lock); 6586c92544dSBjoern A. Zeeb mutex_init(&dev->mutex); 6596c92544dSBjoern A. Zeeb init_waitqueue_head(&dev->tx_wait); 6606c92544dSBjoern A. Zeeb 6616c92544dSBjoern A. Zeeb skb_queue_head_init(&dev->mcu.res_q); 6626c92544dSBjoern A. Zeeb init_waitqueue_head(&dev->mcu.wait); 6636c92544dSBjoern A. Zeeb mutex_init(&dev->mcu.mutex); 6646c92544dSBjoern A. Zeeb dev->tx_worker.fn = mt76_tx_worker; 6656c92544dSBjoern A. Zeeb 6666c92544dSBjoern A. Zeeb hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 6676c92544dSBjoern A. Zeeb hw->wiphy->interface_modes = 6686c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_STATION) | 6696c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_AP) | 6706c92544dSBjoern A. Zeeb #ifdef CONFIG_MAC80211_MESH 6716c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_MESH_POINT) | 6726c92544dSBjoern A. Zeeb #endif 6736c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_CLIENT) | 6746c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_P2P_GO) | 6756c92544dSBjoern A. Zeeb BIT(NL80211_IFTYPE_ADHOC); 6766c92544dSBjoern A. Zeeb 6776c92544dSBjoern A. Zeeb spin_lock_init(&dev->token_lock); 6786c92544dSBjoern A. Zeeb idr_init(&dev->token); 6796c92544dSBjoern A. Zeeb 680*cbb3ec25SBjoern A. Zeeb spin_lock_init(&dev->rx_token_lock); 681*cbb3ec25SBjoern A. Zeeb idr_init(&dev->rx_token); 682*cbb3ec25SBjoern A. Zeeb 6836c92544dSBjoern A. Zeeb INIT_LIST_HEAD(&dev->wcid_list); 684*cbb3ec25SBjoern A. Zeeb INIT_LIST_HEAD(&dev->sta_poll_list); 685*cbb3ec25SBjoern A. Zeeb spin_lock_init(&dev->sta_poll_lock); 6866c92544dSBjoern A. Zeeb 6876c92544dSBjoern A. Zeeb INIT_LIST_HEAD(&dev->txwi_cache); 688*cbb3ec25SBjoern A. Zeeb INIT_LIST_HEAD(&dev->rxwi_cache); 6896c92544dSBjoern A. Zeeb dev->token_size = dev->drv->token_size; 6906c92544dSBjoern A. Zeeb 6916c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 6926c92544dSBjoern A. Zeeb skb_queue_head_init(&dev->rx_skb[i]); 6936c92544dSBjoern A. Zeeb 6946c92544dSBjoern A. Zeeb dev->wq = alloc_ordered_workqueue("mt76", 0); 6956c92544dSBjoern A. Zeeb if (!dev->wq) { 6966c92544dSBjoern A. Zeeb ieee80211_free_hw(hw); 6976c92544dSBjoern A. Zeeb return NULL; 6986c92544dSBjoern A. Zeeb } 6996c92544dSBjoern A. Zeeb 7006c92544dSBjoern A. Zeeb return dev; 7016c92544dSBjoern A. Zeeb } 7026c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_alloc_device); 7036c92544dSBjoern A. Zeeb 7046c92544dSBjoern A. Zeeb int mt76_register_device(struct mt76_dev *dev, bool vht, 7056c92544dSBjoern A. Zeeb struct ieee80211_rate *rates, int n_rates) 7066c92544dSBjoern A. Zeeb { 7076c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = dev->hw; 7086c92544dSBjoern A. Zeeb struct mt76_phy *phy = &dev->phy; 7096c92544dSBjoern A. Zeeb int ret; 7106c92544dSBjoern A. Zeeb 7116c92544dSBjoern A. Zeeb dev_set_drvdata(dev->dev, dev); 7126c92544dSBjoern A. Zeeb ret = mt76_phy_init(phy, hw); 7136c92544dSBjoern A. Zeeb if (ret) 7146c92544dSBjoern A. Zeeb return ret; 7156c92544dSBjoern A. Zeeb 7166c92544dSBjoern A. Zeeb if (phy->cap.has_2ghz) { 7176c92544dSBjoern A. Zeeb ret = mt76_init_sband_2g(phy, rates, n_rates); 7186c92544dSBjoern A. Zeeb if (ret) 7196c92544dSBjoern A. Zeeb return ret; 7206c92544dSBjoern A. Zeeb } 7216c92544dSBjoern A. Zeeb 7226c92544dSBjoern A. Zeeb if (phy->cap.has_5ghz) { 7236c92544dSBjoern A. Zeeb ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 7246c92544dSBjoern A. Zeeb if (ret) 7256c92544dSBjoern A. Zeeb return ret; 7266c92544dSBjoern A. Zeeb } 7276c92544dSBjoern A. Zeeb 7286c92544dSBjoern A. Zeeb if (phy->cap.has_6ghz) { 7296c92544dSBjoern A. Zeeb ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 7306c92544dSBjoern A. Zeeb if (ret) 7316c92544dSBjoern A. Zeeb return ret; 7326c92544dSBjoern A. Zeeb } 7336c92544dSBjoern A. Zeeb 7346c92544dSBjoern A. Zeeb wiphy_read_of_freq_limits(hw->wiphy); 7356c92544dSBjoern A. Zeeb mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 7366c92544dSBjoern A. Zeeb mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 7376c92544dSBjoern A. Zeeb mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); 7386c92544dSBjoern A. Zeeb 7396c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 7406c92544dSBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) { 741*cbb3ec25SBjoern A. Zeeb ret = mt76_led_init(phy); 7426c92544dSBjoern A. Zeeb if (ret) 7436c92544dSBjoern A. Zeeb return ret; 7446c92544dSBjoern A. Zeeb } 7456c92544dSBjoern A. Zeeb #endif 7466c92544dSBjoern A. Zeeb 7476c92544dSBjoern A. Zeeb ret = ieee80211_register_hw(hw); 7486c92544dSBjoern A. Zeeb if (ret) 7496c92544dSBjoern A. Zeeb return ret; 7506c92544dSBjoern A. Zeeb 7516c92544dSBjoern A. Zeeb WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 752*cbb3ec25SBjoern A. Zeeb set_bit(MT76_STATE_REGISTERED, &phy->state); 7536c92544dSBjoern A. Zeeb sched_set_fifo_low(dev->tx_worker.task); 7546c92544dSBjoern A. Zeeb 7556c92544dSBjoern A. Zeeb return 0; 7566c92544dSBjoern A. Zeeb } 7576c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_register_device); 7586c92544dSBjoern A. Zeeb 7596c92544dSBjoern A. Zeeb void mt76_unregister_device(struct mt76_dev *dev) 7606c92544dSBjoern A. Zeeb { 761*cbb3ec25SBjoern A. Zeeb #if defined(__linux__) 7626c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = dev->hw; 763*cbb3ec25SBjoern A. Zeeb #endif 764*cbb3ec25SBjoern A. Zeeb 765*cbb3ec25SBjoern A. Zeeb if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state)) 766*cbb3ec25SBjoern A. Zeeb return; 7676c92544dSBjoern A. Zeeb 7686c92544dSBjoern A. Zeeb #if defined(CONFIG_MT76_LEDS) 7696c92544dSBjoern A. Zeeb if (IS_ENABLED(CONFIG_MT76_LEDS)) 770*cbb3ec25SBjoern A. Zeeb mt76_led_cleanup(&dev->phy); 7716c92544dSBjoern A. Zeeb #endif 7726c92544dSBjoern A. Zeeb mt76_tx_status_check(dev, true); 773*cbb3ec25SBjoern A. Zeeb #if defined(__linux__) 7746c92544dSBjoern A. Zeeb ieee80211_unregister_hw(hw); 775*cbb3ec25SBjoern A. Zeeb #elif defined(__FreeBSD__) 776*cbb3ec25SBjoern A. Zeeb ieee80211_unregister_hw(dev->hw); 777*cbb3ec25SBjoern A. Zeeb #endif 7786c92544dSBjoern A. Zeeb } 7796c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_unregister_device); 7806c92544dSBjoern A. Zeeb 7816c92544dSBjoern A. Zeeb void mt76_free_device(struct mt76_dev *dev) 7826c92544dSBjoern A. Zeeb { 7836c92544dSBjoern A. Zeeb mt76_worker_teardown(&dev->tx_worker); 7846c92544dSBjoern A. Zeeb if (dev->wq) { 7856c92544dSBjoern A. Zeeb destroy_workqueue(dev->wq); 7866c92544dSBjoern A. Zeeb dev->wq = NULL; 7876c92544dSBjoern A. Zeeb } 7886c92544dSBjoern A. Zeeb ieee80211_free_hw(dev->hw); 7896c92544dSBjoern A. Zeeb } 7906c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_free_device); 7916c92544dSBjoern A. Zeeb 7926c92544dSBjoern A. Zeeb static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) 7936c92544dSBjoern A. Zeeb { 7946c92544dSBjoern A. Zeeb struct sk_buff *skb = phy->rx_amsdu[q].head; 7956c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 7966c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 7976c92544dSBjoern A. Zeeb 7986c92544dSBjoern A. Zeeb phy->rx_amsdu[q].head = NULL; 7996c92544dSBjoern A. Zeeb phy->rx_amsdu[q].tail = NULL; 8006c92544dSBjoern A. Zeeb 8016c92544dSBjoern A. Zeeb /* 8026c92544dSBjoern A. Zeeb * Validate if the amsdu has a proper first subframe. 8036c92544dSBjoern A. Zeeb * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU 8046c92544dSBjoern A. Zeeb * flag of the QoS header gets flipped. In such cases, the first 8056c92544dSBjoern A. Zeeb * subframe has a LLC/SNAP header in the location of the destination 8066c92544dSBjoern A. Zeeb * address. 8076c92544dSBjoern A. Zeeb */ 8086c92544dSBjoern A. Zeeb if (skb_shinfo(skb)->frag_list) { 8096c92544dSBjoern A. Zeeb int offset = 0; 8106c92544dSBjoern A. Zeeb 8116c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_8023)) { 8126c92544dSBjoern A. Zeeb offset = ieee80211_get_hdrlen_from_skb(skb); 8136c92544dSBjoern A. Zeeb 8146c92544dSBjoern A. Zeeb if ((status->flag & 8156c92544dSBjoern A. Zeeb (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == 8166c92544dSBjoern A. Zeeb RX_FLAG_DECRYPTED) 8176c92544dSBjoern A. Zeeb offset += 8; 8186c92544dSBjoern A. Zeeb } 8196c92544dSBjoern A. Zeeb 8206c92544dSBjoern A. Zeeb if (ether_addr_equal(skb->data + offset, rfc1042_header)) { 8216c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 8226c92544dSBjoern A. Zeeb return; 8236c92544dSBjoern A. Zeeb } 8246c92544dSBjoern A. Zeeb } 8256c92544dSBjoern A. Zeeb __skb_queue_tail(&dev->rx_skb[q], skb); 8266c92544dSBjoern A. Zeeb } 8276c92544dSBjoern A. Zeeb 8286c92544dSBjoern A. Zeeb static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, 8296c92544dSBjoern A. Zeeb struct sk_buff *skb) 8306c92544dSBjoern A. Zeeb { 8316c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 8326c92544dSBjoern A. Zeeb 8336c92544dSBjoern A. Zeeb if (phy->rx_amsdu[q].head && 8346c92544dSBjoern A. Zeeb (!status->amsdu || status->first_amsdu || 8356c92544dSBjoern A. Zeeb status->seqno != phy->rx_amsdu[q].seqno)) 8366c92544dSBjoern A. Zeeb mt76_rx_release_amsdu(phy, q); 8376c92544dSBjoern A. Zeeb 8386c92544dSBjoern A. Zeeb if (!phy->rx_amsdu[q].head) { 8396c92544dSBjoern A. Zeeb phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; 8406c92544dSBjoern A. Zeeb phy->rx_amsdu[q].seqno = status->seqno; 8416c92544dSBjoern A. Zeeb phy->rx_amsdu[q].head = skb; 8426c92544dSBjoern A. Zeeb } else { 8436c92544dSBjoern A. Zeeb *phy->rx_amsdu[q].tail = skb; 8446c92544dSBjoern A. Zeeb phy->rx_amsdu[q].tail = &skb->next; 8456c92544dSBjoern A. Zeeb } 8466c92544dSBjoern A. Zeeb 8476c92544dSBjoern A. Zeeb if (!status->amsdu || status->last_amsdu) 8486c92544dSBjoern A. Zeeb mt76_rx_release_amsdu(phy, q); 8496c92544dSBjoern A. Zeeb } 8506c92544dSBjoern A. Zeeb 8516c92544dSBjoern A. Zeeb void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 8526c92544dSBjoern A. Zeeb { 8536c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 8546c92544dSBjoern A. Zeeb struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); 8556c92544dSBjoern A. Zeeb 8566c92544dSBjoern A. Zeeb if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 8576c92544dSBjoern A. Zeeb dev_kfree_skb(skb); 8586c92544dSBjoern A. Zeeb return; 8596c92544dSBjoern A. Zeeb } 8606c92544dSBjoern A. Zeeb 8616c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE 8626c92544dSBjoern A. Zeeb if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { 8636c92544dSBjoern A. Zeeb phy->test.rx_stats.packets[q]++; 8646c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_FAILED_FCS_CRC) 8656c92544dSBjoern A. Zeeb phy->test.rx_stats.fcs_error[q]++; 8666c92544dSBjoern A. Zeeb } 8676c92544dSBjoern A. Zeeb #endif 8686c92544dSBjoern A. Zeeb 8696c92544dSBjoern A. Zeeb mt76_rx_release_burst(phy, q, skb); 8706c92544dSBjoern A. Zeeb } 8716c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx); 8726c92544dSBjoern A. Zeeb 8736c92544dSBjoern A. Zeeb bool mt76_has_tx_pending(struct mt76_phy *phy) 8746c92544dSBjoern A. Zeeb { 8756c92544dSBjoern A. Zeeb struct mt76_queue *q; 8766c92544dSBjoern A. Zeeb int i; 8776c92544dSBjoern A. Zeeb 8786c92544dSBjoern A. Zeeb for (i = 0; i < __MT_TXQ_MAX; i++) { 8796c92544dSBjoern A. Zeeb q = phy->q_tx[i]; 8806c92544dSBjoern A. Zeeb if (q && q->queued) 8816c92544dSBjoern A. Zeeb return true; 8826c92544dSBjoern A. Zeeb } 8836c92544dSBjoern A. Zeeb 8846c92544dSBjoern A. Zeeb return false; 8856c92544dSBjoern A. Zeeb } 8866c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 8876c92544dSBjoern A. Zeeb 8886c92544dSBjoern A. Zeeb static struct mt76_channel_state * 8896c92544dSBjoern A. Zeeb mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 8906c92544dSBjoern A. Zeeb { 8916c92544dSBjoern A. Zeeb struct mt76_sband *msband; 8926c92544dSBjoern A. Zeeb int idx; 8936c92544dSBjoern A. Zeeb 8946c92544dSBjoern A. Zeeb if (c->band == NL80211_BAND_2GHZ) 8956c92544dSBjoern A. Zeeb msband = &phy->sband_2g; 8966c92544dSBjoern A. Zeeb else if (c->band == NL80211_BAND_6GHZ) 8976c92544dSBjoern A. Zeeb msband = &phy->sband_6g; 8986c92544dSBjoern A. Zeeb else 8996c92544dSBjoern A. Zeeb msband = &phy->sband_5g; 9006c92544dSBjoern A. Zeeb 9016c92544dSBjoern A. Zeeb idx = c - &msband->sband.channels[0]; 9026c92544dSBjoern A. Zeeb return &msband->chan[idx]; 9036c92544dSBjoern A. Zeeb } 9046c92544dSBjoern A. Zeeb 9056c92544dSBjoern A. Zeeb void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 9066c92544dSBjoern A. Zeeb { 9076c92544dSBjoern A. Zeeb struct mt76_channel_state *state = phy->chan_state; 9086c92544dSBjoern A. Zeeb 9096c92544dSBjoern A. Zeeb state->cc_active += ktime_to_us(ktime_sub(time, 9106c92544dSBjoern A. Zeeb phy->survey_time)); 9116c92544dSBjoern A. Zeeb phy->survey_time = time; 9126c92544dSBjoern A. Zeeb } 9136c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 9146c92544dSBjoern A. Zeeb 9156c92544dSBjoern A. Zeeb void mt76_update_survey(struct mt76_phy *phy) 9166c92544dSBjoern A. Zeeb { 9176c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 9186c92544dSBjoern A. Zeeb ktime_t cur_time; 9196c92544dSBjoern A. Zeeb 9206c92544dSBjoern A. Zeeb if (dev->drv->update_survey) 9216c92544dSBjoern A. Zeeb dev->drv->update_survey(phy); 9226c92544dSBjoern A. Zeeb 9236c92544dSBjoern A. Zeeb cur_time = ktime_get_boottime(); 9246c92544dSBjoern A. Zeeb mt76_update_survey_active_time(phy, cur_time); 9256c92544dSBjoern A. Zeeb 9266c92544dSBjoern A. Zeeb if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 9276c92544dSBjoern A. Zeeb struct mt76_channel_state *state = phy->chan_state; 9286c92544dSBjoern A. Zeeb 9296c92544dSBjoern A. Zeeb spin_lock_bh(&dev->cc_lock); 9306c92544dSBjoern A. Zeeb state->cc_bss_rx += dev->cur_cc_bss_rx; 9316c92544dSBjoern A. Zeeb dev->cur_cc_bss_rx = 0; 9326c92544dSBjoern A. Zeeb spin_unlock_bh(&dev->cc_lock); 9336c92544dSBjoern A. Zeeb } 9346c92544dSBjoern A. Zeeb } 9356c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_update_survey); 9366c92544dSBjoern A. Zeeb 9376c92544dSBjoern A. Zeeb void mt76_set_channel(struct mt76_phy *phy) 9386c92544dSBjoern A. Zeeb { 9396c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 9406c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = phy->hw; 9416c92544dSBjoern A. Zeeb struct cfg80211_chan_def *chandef = &hw->conf.chandef; 9426c92544dSBjoern A. Zeeb bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 9436c92544dSBjoern A. Zeeb int timeout = HZ / 5; 9446c92544dSBjoern A. Zeeb 9456c92544dSBjoern A. Zeeb wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 9466c92544dSBjoern A. Zeeb mt76_update_survey(phy); 9476c92544dSBjoern A. Zeeb 9486c92544dSBjoern A. Zeeb if (phy->chandef.chan->center_freq != chandef->chan->center_freq || 9496c92544dSBjoern A. Zeeb phy->chandef.width != chandef->width) 9506c92544dSBjoern A. Zeeb phy->dfs_state = MT_DFS_STATE_UNKNOWN; 9516c92544dSBjoern A. Zeeb 9526c92544dSBjoern A. Zeeb phy->chandef = *chandef; 9536c92544dSBjoern A. Zeeb phy->chan_state = mt76_channel_state(phy, chandef->chan); 9546c92544dSBjoern A. Zeeb 9556c92544dSBjoern A. Zeeb if (!offchannel) 9566c92544dSBjoern A. Zeeb phy->main_chan = chandef->chan; 9576c92544dSBjoern A. Zeeb 9586c92544dSBjoern A. Zeeb if (chandef->chan != phy->main_chan) 9596c92544dSBjoern A. Zeeb memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 9606c92544dSBjoern A. Zeeb } 9616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_channel); 9626c92544dSBjoern A. Zeeb 9636c92544dSBjoern A. Zeeb int mt76_get_survey(struct ieee80211_hw *hw, int idx, 9646c92544dSBjoern A. Zeeb struct survey_info *survey) 9656c92544dSBjoern A. Zeeb { 9666c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 9676c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 9686c92544dSBjoern A. Zeeb struct mt76_sband *sband; 9696c92544dSBjoern A. Zeeb struct ieee80211_channel *chan; 9706c92544dSBjoern A. Zeeb struct mt76_channel_state *state; 9716c92544dSBjoern A. Zeeb int ret = 0; 9726c92544dSBjoern A. Zeeb 9736c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex); 9746c92544dSBjoern A. Zeeb if (idx == 0 && dev->drv->update_survey) 9756c92544dSBjoern A. Zeeb mt76_update_survey(phy); 9766c92544dSBjoern A. Zeeb 9776c92544dSBjoern A. Zeeb if (idx >= phy->sband_2g.sband.n_channels + 9786c92544dSBjoern A. Zeeb phy->sband_5g.sband.n_channels) { 9796c92544dSBjoern A. Zeeb idx -= (phy->sband_2g.sband.n_channels + 9806c92544dSBjoern A. Zeeb phy->sband_5g.sband.n_channels); 9816c92544dSBjoern A. Zeeb sband = &phy->sband_6g; 9826c92544dSBjoern A. Zeeb } else if (idx >= phy->sband_2g.sband.n_channels) { 9836c92544dSBjoern A. Zeeb idx -= phy->sband_2g.sband.n_channels; 9846c92544dSBjoern A. Zeeb sband = &phy->sband_5g; 9856c92544dSBjoern A. Zeeb } else { 9866c92544dSBjoern A. Zeeb sband = &phy->sband_2g; 9876c92544dSBjoern A. Zeeb } 9886c92544dSBjoern A. Zeeb 9896c92544dSBjoern A. Zeeb if (idx >= sband->sband.n_channels) { 9906c92544dSBjoern A. Zeeb ret = -ENOENT; 9916c92544dSBjoern A. Zeeb goto out; 9926c92544dSBjoern A. Zeeb } 9936c92544dSBjoern A. Zeeb 9946c92544dSBjoern A. Zeeb chan = &sband->sband.channels[idx]; 9956c92544dSBjoern A. Zeeb state = mt76_channel_state(phy, chan); 9966c92544dSBjoern A. Zeeb 9976c92544dSBjoern A. Zeeb memset(survey, 0, sizeof(*survey)); 9986c92544dSBjoern A. Zeeb survey->channel = chan; 9996c92544dSBjoern A. Zeeb survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 10006c92544dSBjoern A. Zeeb survey->filled |= dev->drv->survey_flags; 10016c92544dSBjoern A. Zeeb if (state->noise) 10026c92544dSBjoern A. Zeeb survey->filled |= SURVEY_INFO_NOISE_DBM; 10036c92544dSBjoern A. Zeeb 10046c92544dSBjoern A. Zeeb if (chan == phy->main_chan) { 10056c92544dSBjoern A. Zeeb survey->filled |= SURVEY_INFO_IN_USE; 10066c92544dSBjoern A. Zeeb 10076c92544dSBjoern A. Zeeb if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 10086c92544dSBjoern A. Zeeb survey->filled |= SURVEY_INFO_TIME_BSS_RX; 10096c92544dSBjoern A. Zeeb } 10106c92544dSBjoern A. Zeeb 10116c92544dSBjoern A. Zeeb survey->time_busy = div_u64(state->cc_busy, 1000); 10126c92544dSBjoern A. Zeeb survey->time_rx = div_u64(state->cc_rx, 1000); 10136c92544dSBjoern A. Zeeb survey->time = div_u64(state->cc_active, 1000); 10146c92544dSBjoern A. Zeeb survey->noise = state->noise; 10156c92544dSBjoern A. Zeeb 10166c92544dSBjoern A. Zeeb spin_lock_bh(&dev->cc_lock); 10176c92544dSBjoern A. Zeeb survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 10186c92544dSBjoern A. Zeeb survey->time_tx = div_u64(state->cc_tx, 1000); 10196c92544dSBjoern A. Zeeb spin_unlock_bh(&dev->cc_lock); 10206c92544dSBjoern A. Zeeb 10216c92544dSBjoern A. Zeeb out: 10226c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex); 10236c92544dSBjoern A. Zeeb 10246c92544dSBjoern A. Zeeb return ret; 10256c92544dSBjoern A. Zeeb } 10266c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_survey); 10276c92544dSBjoern A. Zeeb 10286c92544dSBjoern A. Zeeb void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 10296c92544dSBjoern A. Zeeb struct ieee80211_key_conf *key) 10306c92544dSBjoern A. Zeeb { 10316c92544dSBjoern A. Zeeb struct ieee80211_key_seq seq; 10326c92544dSBjoern A. Zeeb int i; 10336c92544dSBjoern A. Zeeb 10346c92544dSBjoern A. Zeeb wcid->rx_check_pn = false; 10356c92544dSBjoern A. Zeeb 10366c92544dSBjoern A. Zeeb if (!key) 10376c92544dSBjoern A. Zeeb return; 10386c92544dSBjoern A. Zeeb 10396c92544dSBjoern A. Zeeb if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 10406c92544dSBjoern A. Zeeb return; 10416c92544dSBjoern A. Zeeb 10426c92544dSBjoern A. Zeeb wcid->rx_check_pn = true; 10436c92544dSBjoern A. Zeeb 10446c92544dSBjoern A. Zeeb /* data frame */ 10456c92544dSBjoern A. Zeeb for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 10466c92544dSBjoern A. Zeeb ieee80211_get_key_rx_seq(key, i, &seq); 10476c92544dSBjoern A. Zeeb memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 10486c92544dSBjoern A. Zeeb } 10496c92544dSBjoern A. Zeeb 10506c92544dSBjoern A. Zeeb /* robust management frame */ 10516c92544dSBjoern A. Zeeb ieee80211_get_key_rx_seq(key, -1, &seq); 10526c92544dSBjoern A. Zeeb memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 10536c92544dSBjoern A. Zeeb 10546c92544dSBjoern A. Zeeb } 10556c92544dSBjoern A. Zeeb EXPORT_SYMBOL(mt76_wcid_key_setup); 10566c92544dSBjoern A. Zeeb 1057*cbb3ec25SBjoern A. Zeeb int mt76_rx_signal(u8 chain_mask, s8 *chain_signal) 10586c92544dSBjoern A. Zeeb { 10596c92544dSBjoern A. Zeeb int signal = -128; 10606c92544dSBjoern A. Zeeb u8 chains; 10616c92544dSBjoern A. Zeeb 1062*cbb3ec25SBjoern A. Zeeb for (chains = chain_mask; chains; chains >>= 1, chain_signal++) { 10636c92544dSBjoern A. Zeeb int cur, diff; 10646c92544dSBjoern A. Zeeb 10656c92544dSBjoern A. Zeeb cur = *chain_signal; 10666c92544dSBjoern A. Zeeb if (!(chains & BIT(0)) || 10676c92544dSBjoern A. Zeeb cur > 0) 10686c92544dSBjoern A. Zeeb continue; 10696c92544dSBjoern A. Zeeb 10706c92544dSBjoern A. Zeeb if (cur > signal) 10716c92544dSBjoern A. Zeeb swap(cur, signal); 10726c92544dSBjoern A. Zeeb 10736c92544dSBjoern A. Zeeb diff = signal - cur; 10746c92544dSBjoern A. Zeeb if (diff == 0) 10756c92544dSBjoern A. Zeeb signal += 3; 10766c92544dSBjoern A. Zeeb else if (diff <= 2) 10776c92544dSBjoern A. Zeeb signal += 2; 10786c92544dSBjoern A. Zeeb else if (diff <= 6) 10796c92544dSBjoern A. Zeeb signal += 1; 10806c92544dSBjoern A. Zeeb } 10816c92544dSBjoern A. Zeeb 10826c92544dSBjoern A. Zeeb return signal; 10836c92544dSBjoern A. Zeeb } 1084*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL(mt76_rx_signal); 10856c92544dSBjoern A. Zeeb 10866c92544dSBjoern A. Zeeb static void 10876c92544dSBjoern A. Zeeb mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 10886c92544dSBjoern A. Zeeb struct ieee80211_hw **hw, 10896c92544dSBjoern A. Zeeb struct ieee80211_sta **sta) 10906c92544dSBjoern A. Zeeb { 10916c92544dSBjoern A. Zeeb struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 10926c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 10936c92544dSBjoern A. Zeeb struct mt76_rx_status mstat; 10946c92544dSBjoern A. Zeeb 10956c92544dSBjoern A. Zeeb mstat = *((struct mt76_rx_status *)skb->cb); 10966c92544dSBjoern A. Zeeb memset(status, 0, sizeof(*status)); 10976c92544dSBjoern A. Zeeb 10986c92544dSBjoern A. Zeeb status->flag = mstat.flag; 10996c92544dSBjoern A. Zeeb status->freq = mstat.freq; 11006c92544dSBjoern A. Zeeb status->enc_flags = mstat.enc_flags; 11016c92544dSBjoern A. Zeeb status->encoding = mstat.encoding; 11026c92544dSBjoern A. Zeeb status->bw = mstat.bw; 1103*cbb3ec25SBjoern A. Zeeb if (status->encoding == RX_ENC_EHT) { 1104*cbb3ec25SBjoern A. Zeeb status->eht.ru = mstat.eht.ru; 1105*cbb3ec25SBjoern A. Zeeb status->eht.gi = mstat.eht.gi; 1106*cbb3ec25SBjoern A. Zeeb } else { 11076c92544dSBjoern A. Zeeb status->he_ru = mstat.he_ru; 11086c92544dSBjoern A. Zeeb status->he_gi = mstat.he_gi; 11096c92544dSBjoern A. Zeeb status->he_dcm = mstat.he_dcm; 1110*cbb3ec25SBjoern A. Zeeb } 11116c92544dSBjoern A. Zeeb status->rate_idx = mstat.rate_idx; 11126c92544dSBjoern A. Zeeb status->nss = mstat.nss; 11136c92544dSBjoern A. Zeeb status->band = mstat.band; 11146c92544dSBjoern A. Zeeb status->signal = mstat.signal; 11156c92544dSBjoern A. Zeeb status->chains = mstat.chains; 11166c92544dSBjoern A. Zeeb status->ampdu_reference = mstat.ampdu_ref; 11176c92544dSBjoern A. Zeeb status->device_timestamp = mstat.timestamp; 11186c92544dSBjoern A. Zeeb status->mactime = mstat.timestamp; 1119*cbb3ec25SBjoern A. Zeeb status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal); 11206c92544dSBjoern A. Zeeb if (status->signal <= -128) 11216c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_NO_SIGNAL_VAL; 11226c92544dSBjoern A. Zeeb 11236c92544dSBjoern A. Zeeb if (ieee80211_is_beacon(hdr->frame_control) || 11246c92544dSBjoern A. Zeeb ieee80211_is_probe_resp(hdr->frame_control)) 11256c92544dSBjoern A. Zeeb status->boottime_ns = ktime_get_boottime_ns(); 11266c92544dSBjoern A. Zeeb 11276c92544dSBjoern A. Zeeb BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 11286c92544dSBjoern A. Zeeb BUILD_BUG_ON(sizeof(status->chain_signal) != 11296c92544dSBjoern A. Zeeb sizeof(mstat.chain_signal)); 11306c92544dSBjoern A. Zeeb memcpy(status->chain_signal, mstat.chain_signal, 11316c92544dSBjoern A. Zeeb sizeof(mstat.chain_signal)); 11326c92544dSBjoern A. Zeeb 11336c92544dSBjoern A. Zeeb *sta = wcid_to_sta(mstat.wcid); 11346c92544dSBjoern A. Zeeb *hw = mt76_phy_hw(dev, mstat.phy_idx); 11356c92544dSBjoern A. Zeeb } 11366c92544dSBjoern A. Zeeb 11376c92544dSBjoern A. Zeeb static void 11386c92544dSBjoern A. Zeeb mt76_check_ccmp_pn(struct sk_buff *skb) 11396c92544dSBjoern A. Zeeb { 11406c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 11416c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid; 11426c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr; 11436c92544dSBjoern A. Zeeb int security_idx; 11446c92544dSBjoern A. Zeeb int ret; 11456c92544dSBjoern A. Zeeb 11466c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_DECRYPTED)) 11476c92544dSBjoern A. Zeeb return; 11486c92544dSBjoern A. Zeeb 11496c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_ONLY_MONITOR) 11506c92544dSBjoern A. Zeeb return; 11516c92544dSBjoern A. Zeeb 11526c92544dSBjoern A. Zeeb if (!wcid || !wcid->rx_check_pn) 11536c92544dSBjoern A. Zeeb return; 11546c92544dSBjoern A. Zeeb 11556c92544dSBjoern A. Zeeb security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 11566c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_8023) 11576c92544dSBjoern A. Zeeb goto skip_hdr_check; 11586c92544dSBjoern A. Zeeb 11596c92544dSBjoern A. Zeeb hdr = mt76_skb_get_hdr(skb); 11606c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 11616c92544dSBjoern A. Zeeb /* 11626c92544dSBjoern A. Zeeb * Validate the first fragment both here and in mac80211 11636c92544dSBjoern A. Zeeb * All further fragments will be validated by mac80211 only. 11646c92544dSBjoern A. Zeeb */ 11656c92544dSBjoern A. Zeeb if (ieee80211_is_frag(hdr) && 11666c92544dSBjoern A. Zeeb !ieee80211_is_first_frag(hdr->frame_control)) 11676c92544dSBjoern A. Zeeb return; 11686c92544dSBjoern A. Zeeb } 11696c92544dSBjoern A. Zeeb 11706c92544dSBjoern A. Zeeb /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): 11716c92544dSBjoern A. Zeeb * 11726c92544dSBjoern A. Zeeb * the recipient shall maintain a single replay counter for received 11736c92544dSBjoern A. Zeeb * individually addressed robust Management frames that are received 11746c92544dSBjoern A. Zeeb * with the To DS subfield equal to 0, [...] 11756c92544dSBjoern A. Zeeb */ 11766c92544dSBjoern A. Zeeb if (ieee80211_is_mgmt(hdr->frame_control) && 11776c92544dSBjoern A. Zeeb !ieee80211_has_tods(hdr->frame_control)) 11786c92544dSBjoern A. Zeeb security_idx = IEEE80211_NUM_TIDS; 11796c92544dSBjoern A. Zeeb 11806c92544dSBjoern A. Zeeb skip_hdr_check: 11816c92544dSBjoern A. Zeeb BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 11826c92544dSBjoern A. Zeeb ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], 11836c92544dSBjoern A. Zeeb sizeof(status->iv)); 11846c92544dSBjoern A. Zeeb if (ret <= 0) { 11856c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_ONLY_MONITOR; 11866c92544dSBjoern A. Zeeb return; 11876c92544dSBjoern A. Zeeb } 11886c92544dSBjoern A. Zeeb 11896c92544dSBjoern A. Zeeb memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); 11906c92544dSBjoern A. Zeeb 11916c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_IV_STRIPPED) 11926c92544dSBjoern A. Zeeb status->flag |= RX_FLAG_PN_VALIDATED; 11936c92544dSBjoern A. Zeeb } 11946c92544dSBjoern A. Zeeb 11956c92544dSBjoern A. Zeeb static void 11966c92544dSBjoern A. Zeeb mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 11976c92544dSBjoern A. Zeeb int len) 11986c92544dSBjoern A. Zeeb { 11996c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid; 12006c92544dSBjoern A. Zeeb struct ieee80211_rx_status info = { 12016c92544dSBjoern A. Zeeb .enc_flags = status->enc_flags, 12026c92544dSBjoern A. Zeeb .rate_idx = status->rate_idx, 12036c92544dSBjoern A. Zeeb .encoding = status->encoding, 12046c92544dSBjoern A. Zeeb .band = status->band, 12056c92544dSBjoern A. Zeeb .nss = status->nss, 12066c92544dSBjoern A. Zeeb .bw = status->bw, 12076c92544dSBjoern A. Zeeb }; 12086c92544dSBjoern A. Zeeb struct ieee80211_sta *sta; 12096c92544dSBjoern A. Zeeb u32 airtime; 12106c92544dSBjoern A. Zeeb u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 12116c92544dSBjoern A. Zeeb 12126c92544dSBjoern A. Zeeb airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 12136c92544dSBjoern A. Zeeb spin_lock(&dev->cc_lock); 12146c92544dSBjoern A. Zeeb dev->cur_cc_bss_rx += airtime; 12156c92544dSBjoern A. Zeeb spin_unlock(&dev->cc_lock); 12166c92544dSBjoern A. Zeeb 12176c92544dSBjoern A. Zeeb if (!wcid || !wcid->sta) 12186c92544dSBjoern A. Zeeb return; 12196c92544dSBjoern A. Zeeb 12206c92544dSBjoern A. Zeeb sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 12216c92544dSBjoern A. Zeeb ieee80211_sta_register_airtime(sta, tidno, 0, airtime); 12226c92544dSBjoern A. Zeeb } 12236c92544dSBjoern A. Zeeb 12246c92544dSBjoern A. Zeeb static void 12256c92544dSBjoern A. Zeeb mt76_airtime_flush_ampdu(struct mt76_dev *dev) 12266c92544dSBjoern A. Zeeb { 12276c92544dSBjoern A. Zeeb struct mt76_wcid *wcid; 12286c92544dSBjoern A. Zeeb int wcid_idx; 12296c92544dSBjoern A. Zeeb 12306c92544dSBjoern A. Zeeb if (!dev->rx_ampdu_len) 12316c92544dSBjoern A. Zeeb return; 12326c92544dSBjoern A. Zeeb 12336c92544dSBjoern A. Zeeb wcid_idx = dev->rx_ampdu_status.wcid_idx; 12346c92544dSBjoern A. Zeeb if (wcid_idx < ARRAY_SIZE(dev->wcid)) 12356c92544dSBjoern A. Zeeb wcid = rcu_dereference(dev->wcid[wcid_idx]); 12366c92544dSBjoern A. Zeeb else 12376c92544dSBjoern A. Zeeb wcid = NULL; 12386c92544dSBjoern A. Zeeb dev->rx_ampdu_status.wcid = wcid; 12396c92544dSBjoern A. Zeeb 12406c92544dSBjoern A. Zeeb mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 12416c92544dSBjoern A. Zeeb 12426c92544dSBjoern A. Zeeb dev->rx_ampdu_len = 0; 12436c92544dSBjoern A. Zeeb dev->rx_ampdu_ref = 0; 12446c92544dSBjoern A. Zeeb } 12456c92544dSBjoern A. Zeeb 12466c92544dSBjoern A. Zeeb static void 12476c92544dSBjoern A. Zeeb mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 12486c92544dSBjoern A. Zeeb { 12496c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 12506c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid; 12516c92544dSBjoern A. Zeeb 12526c92544dSBjoern A. Zeeb if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 12536c92544dSBjoern A. Zeeb return; 12546c92544dSBjoern A. Zeeb 12556c92544dSBjoern A. Zeeb if (!wcid || !wcid->sta) { 12566c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 12576c92544dSBjoern A. Zeeb 12586c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_8023) 12596c92544dSBjoern A. Zeeb return; 12606c92544dSBjoern A. Zeeb 12616c92544dSBjoern A. Zeeb if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) 12626c92544dSBjoern A. Zeeb return; 12636c92544dSBjoern A. Zeeb 12646c92544dSBjoern A. Zeeb wcid = NULL; 12656c92544dSBjoern A. Zeeb } 12666c92544dSBjoern A. Zeeb 12676c92544dSBjoern A. Zeeb if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 12686c92544dSBjoern A. Zeeb status->ampdu_ref != dev->rx_ampdu_ref) 12696c92544dSBjoern A. Zeeb mt76_airtime_flush_ampdu(dev); 12706c92544dSBjoern A. Zeeb 12716c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_AMPDU_DETAILS) { 12726c92544dSBjoern A. Zeeb if (!dev->rx_ampdu_len || 12736c92544dSBjoern A. Zeeb status->ampdu_ref != dev->rx_ampdu_ref) { 12746c92544dSBjoern A. Zeeb dev->rx_ampdu_status = *status; 12756c92544dSBjoern A. Zeeb dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 12766c92544dSBjoern A. Zeeb dev->rx_ampdu_ref = status->ampdu_ref; 12776c92544dSBjoern A. Zeeb } 12786c92544dSBjoern A. Zeeb 12796c92544dSBjoern A. Zeeb dev->rx_ampdu_len += skb->len; 12806c92544dSBjoern A. Zeeb return; 12816c92544dSBjoern A. Zeeb } 12826c92544dSBjoern A. Zeeb 12836c92544dSBjoern A. Zeeb mt76_airtime_report(dev, status, skb->len); 12846c92544dSBjoern A. Zeeb } 12856c92544dSBjoern A. Zeeb 12866c92544dSBjoern A. Zeeb static void 12876c92544dSBjoern A. Zeeb mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 12886c92544dSBjoern A. Zeeb { 12896c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 12906c92544dSBjoern A. Zeeb struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 12916c92544dSBjoern A. Zeeb struct ieee80211_sta *sta; 12926c92544dSBjoern A. Zeeb struct ieee80211_hw *hw; 12936c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = status->wcid; 12946c92544dSBjoern A. Zeeb u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 12956c92544dSBjoern A. Zeeb bool ps; 12966c92544dSBjoern A. Zeeb 12976c92544dSBjoern A. Zeeb hw = mt76_phy_hw(dev, status->phy_idx); 12986c92544dSBjoern A. Zeeb if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && 12996c92544dSBjoern A. Zeeb !(status->flag & RX_FLAG_8023)) { 13006c92544dSBjoern A. Zeeb sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 13016c92544dSBjoern A. Zeeb if (sta) 13026c92544dSBjoern A. Zeeb wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 13036c92544dSBjoern A. Zeeb } 13046c92544dSBjoern A. Zeeb 13056c92544dSBjoern A. Zeeb mt76_airtime_check(dev, skb); 13066c92544dSBjoern A. Zeeb 13076c92544dSBjoern A. Zeeb if (!wcid || !wcid->sta) 13086c92544dSBjoern A. Zeeb return; 13096c92544dSBjoern A. Zeeb 13106c92544dSBjoern A. Zeeb sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 13116c92544dSBjoern A. Zeeb 13126c92544dSBjoern A. Zeeb if (status->signal <= 0) 13136c92544dSBjoern A. Zeeb ewma_signal_add(&wcid->rssi, -status->signal); 13146c92544dSBjoern A. Zeeb 13156c92544dSBjoern A. Zeeb wcid->inactive_count = 0; 13166c92544dSBjoern A. Zeeb 13176c92544dSBjoern A. Zeeb if (status->flag & RX_FLAG_8023) 13186c92544dSBjoern A. Zeeb return; 13196c92544dSBjoern A. Zeeb 13206c92544dSBjoern A. Zeeb if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 13216c92544dSBjoern A. Zeeb return; 13226c92544dSBjoern A. Zeeb 13236c92544dSBjoern A. Zeeb if (ieee80211_is_pspoll(hdr->frame_control)) { 13246c92544dSBjoern A. Zeeb ieee80211_sta_pspoll(sta); 13256c92544dSBjoern A. Zeeb return; 13266c92544dSBjoern A. Zeeb } 13276c92544dSBjoern A. Zeeb 13286c92544dSBjoern A. Zeeb if (ieee80211_has_morefrags(hdr->frame_control) || 13296c92544dSBjoern A. Zeeb !(ieee80211_is_mgmt(hdr->frame_control) || 13306c92544dSBjoern A. Zeeb ieee80211_is_data(hdr->frame_control))) 13316c92544dSBjoern A. Zeeb return; 13326c92544dSBjoern A. Zeeb 13336c92544dSBjoern A. Zeeb ps = ieee80211_has_pm(hdr->frame_control); 13346c92544dSBjoern A. Zeeb 13356c92544dSBjoern A. Zeeb if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 13366c92544dSBjoern A. Zeeb ieee80211_is_qos_nullfunc(hdr->frame_control))) 13376c92544dSBjoern A. Zeeb ieee80211_sta_uapsd_trigger(sta, tidno); 13386c92544dSBjoern A. Zeeb 13396c92544dSBjoern A. Zeeb if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 13406c92544dSBjoern A. Zeeb return; 13416c92544dSBjoern A. Zeeb 13426c92544dSBjoern A. Zeeb if (ps) 13436c92544dSBjoern A. Zeeb set_bit(MT_WCID_FLAG_PS, &wcid->flags); 13446c92544dSBjoern A. Zeeb 1345*cbb3ec25SBjoern A. Zeeb if (dev->drv->sta_ps) 13466c92544dSBjoern A. Zeeb dev->drv->sta_ps(dev, sta, ps); 13476c92544dSBjoern A. Zeeb 13486c92544dSBjoern A. Zeeb if (!ps) 13496c92544dSBjoern A. Zeeb clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 13506c92544dSBjoern A. Zeeb 13516c92544dSBjoern A. Zeeb ieee80211_sta_ps_transition(sta, ps); 13526c92544dSBjoern A. Zeeb } 13536c92544dSBjoern A. Zeeb 13546c92544dSBjoern A. Zeeb void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 13556c92544dSBjoern A. Zeeb struct napi_struct *napi) 13566c92544dSBjoern A. Zeeb { 13576c92544dSBjoern A. Zeeb struct ieee80211_sta *sta; 13586c92544dSBjoern A. Zeeb struct ieee80211_hw *hw; 13596c92544dSBjoern A. Zeeb struct sk_buff *skb, *tmp; 13606c92544dSBjoern A. Zeeb #if defined(__linux__) 13616c92544dSBjoern A. Zeeb LIST_HEAD(list); 13626c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__) 13636c92544dSBjoern A. Zeeb LINUX_LIST_HEAD(list); 13646c92544dSBjoern A. Zeeb #endif 13656c92544dSBjoern A. Zeeb 13666c92544dSBjoern A. Zeeb spin_lock(&dev->rx_lock); 13676c92544dSBjoern A. Zeeb while ((skb = __skb_dequeue(frames)) != NULL) { 13686c92544dSBjoern A. Zeeb struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 13696c92544dSBjoern A. Zeeb 13706c92544dSBjoern A. Zeeb mt76_check_ccmp_pn(skb); 13716c92544dSBjoern A. Zeeb skb_shinfo(skb)->frag_list = NULL; 13726c92544dSBjoern A. Zeeb mt76_rx_convert(dev, skb, &hw, &sta); 13736c92544dSBjoern A. Zeeb ieee80211_rx_list(hw, sta, skb, &list); 13746c92544dSBjoern A. Zeeb 13756c92544dSBjoern A. Zeeb /* subsequent amsdu frames */ 13766c92544dSBjoern A. Zeeb while (nskb) { 13776c92544dSBjoern A. Zeeb skb = nskb; 13786c92544dSBjoern A. Zeeb nskb = nskb->next; 13796c92544dSBjoern A. Zeeb skb->next = NULL; 13806c92544dSBjoern A. Zeeb 13816c92544dSBjoern A. Zeeb mt76_rx_convert(dev, skb, &hw, &sta); 13826c92544dSBjoern A. Zeeb ieee80211_rx_list(hw, sta, skb, &list); 13836c92544dSBjoern A. Zeeb } 13846c92544dSBjoern A. Zeeb } 13856c92544dSBjoern A. Zeeb spin_unlock(&dev->rx_lock); 13866c92544dSBjoern A. Zeeb 13876c92544dSBjoern A. Zeeb if (!napi) { 13886c92544dSBjoern A. Zeeb netif_receive_skb_list(&list); 13896c92544dSBjoern A. Zeeb return; 13906c92544dSBjoern A. Zeeb } 13916c92544dSBjoern A. Zeeb 13926c92544dSBjoern A. Zeeb list_for_each_entry_safe(skb, tmp, &list, list) { 13936c92544dSBjoern A. Zeeb skb_list_del_init(skb); 13946c92544dSBjoern A. Zeeb napi_gro_receive(napi, skb); 13956c92544dSBjoern A. Zeeb } 13966c92544dSBjoern A. Zeeb } 13976c92544dSBjoern A. Zeeb 13986c92544dSBjoern A. Zeeb void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 13996c92544dSBjoern A. Zeeb struct napi_struct *napi) 14006c92544dSBjoern A. Zeeb { 14016c92544dSBjoern A. Zeeb struct sk_buff_head frames; 14026c92544dSBjoern A. Zeeb struct sk_buff *skb; 14036c92544dSBjoern A. Zeeb 14046c92544dSBjoern A. Zeeb __skb_queue_head_init(&frames); 14056c92544dSBjoern A. Zeeb 14066c92544dSBjoern A. Zeeb while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 14076c92544dSBjoern A. Zeeb mt76_check_sta(dev, skb); 1408*cbb3ec25SBjoern A. Zeeb if (mtk_wed_device_active(&dev->mmio.wed)) 1409*cbb3ec25SBjoern A. Zeeb __skb_queue_tail(&frames, skb); 1410*cbb3ec25SBjoern A. Zeeb else 14116c92544dSBjoern A. Zeeb mt76_rx_aggr_reorder(skb, &frames); 14126c92544dSBjoern A. Zeeb } 14136c92544dSBjoern A. Zeeb 14146c92544dSBjoern A. Zeeb mt76_rx_complete(dev, &frames, napi); 14156c92544dSBjoern A. Zeeb } 14166c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 14176c92544dSBjoern A. Zeeb 14186c92544dSBjoern A. Zeeb static int 14196c92544dSBjoern A. Zeeb mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, 14206c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 14216c92544dSBjoern A. Zeeb { 14226c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 14236c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 14246c92544dSBjoern A. Zeeb int ret; 14256c92544dSBjoern A. Zeeb int i; 14266c92544dSBjoern A. Zeeb 14276c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex); 14286c92544dSBjoern A. Zeeb 14296c92544dSBjoern A. Zeeb ret = dev->drv->sta_add(dev, vif, sta); 14306c92544dSBjoern A. Zeeb if (ret) 14316c92544dSBjoern A. Zeeb goto out; 14326c92544dSBjoern A. Zeeb 14336c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 14346c92544dSBjoern A. Zeeb struct mt76_txq *mtxq; 14356c92544dSBjoern A. Zeeb 14366c92544dSBjoern A. Zeeb if (!sta->txq[i]) 14376c92544dSBjoern A. Zeeb continue; 14386c92544dSBjoern A. Zeeb 14396c92544dSBjoern A. Zeeb mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 14406c92544dSBjoern A. Zeeb mtxq->wcid = wcid->idx; 14416c92544dSBjoern A. Zeeb } 14426c92544dSBjoern A. Zeeb 14436c92544dSBjoern A. Zeeb ewma_signal_init(&wcid->rssi); 14446c92544dSBjoern A. Zeeb if (phy->band_idx == MT_BAND1) 14456c92544dSBjoern A. Zeeb mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 14466c92544dSBjoern A. Zeeb wcid->phy_idx = phy->band_idx; 14476c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 14486c92544dSBjoern A. Zeeb 14496c92544dSBjoern A. Zeeb mt76_packet_id_init(wcid); 14506c92544dSBjoern A. Zeeb out: 14516c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex); 14526c92544dSBjoern A. Zeeb 14536c92544dSBjoern A. Zeeb return ret; 14546c92544dSBjoern A. Zeeb } 14556c92544dSBjoern A. Zeeb 14566c92544dSBjoern A. Zeeb void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 14576c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 14586c92544dSBjoern A. Zeeb { 14596c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 14606c92544dSBjoern A. Zeeb int i, idx = wcid->idx; 14616c92544dSBjoern A. Zeeb 14626c92544dSBjoern A. Zeeb for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 14636c92544dSBjoern A. Zeeb mt76_rx_aggr_stop(dev, wcid, i); 14646c92544dSBjoern A. Zeeb 14656c92544dSBjoern A. Zeeb if (dev->drv->sta_remove) 14666c92544dSBjoern A. Zeeb dev->drv->sta_remove(dev, vif, sta); 14676c92544dSBjoern A. Zeeb 14686c92544dSBjoern A. Zeeb mt76_packet_id_flush(dev, wcid); 14696c92544dSBjoern A. Zeeb 14706c92544dSBjoern A. Zeeb mt76_wcid_mask_clear(dev->wcid_mask, idx); 14716c92544dSBjoern A. Zeeb mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 14726c92544dSBjoern A. Zeeb } 14736c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(__mt76_sta_remove); 14746c92544dSBjoern A. Zeeb 14756c92544dSBjoern A. Zeeb static void 14766c92544dSBjoern A. Zeeb mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 14776c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 14786c92544dSBjoern A. Zeeb { 14796c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex); 14806c92544dSBjoern A. Zeeb __mt76_sta_remove(dev, vif, sta); 14816c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex); 14826c92544dSBjoern A. Zeeb } 14836c92544dSBjoern A. Zeeb 14846c92544dSBjoern A. Zeeb int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 14856c92544dSBjoern A. Zeeb struct ieee80211_sta *sta, 14866c92544dSBjoern A. Zeeb enum ieee80211_sta_state old_state, 14876c92544dSBjoern A. Zeeb enum ieee80211_sta_state new_state) 14886c92544dSBjoern A. Zeeb { 14896c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 14906c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 14916c92544dSBjoern A. Zeeb 14926c92544dSBjoern A. Zeeb if (old_state == IEEE80211_STA_NOTEXIST && 14936c92544dSBjoern A. Zeeb new_state == IEEE80211_STA_NONE) 14946c92544dSBjoern A. Zeeb return mt76_sta_add(phy, vif, sta); 14956c92544dSBjoern A. Zeeb 14966c92544dSBjoern A. Zeeb if (old_state == IEEE80211_STA_AUTH && 14976c92544dSBjoern A. Zeeb new_state == IEEE80211_STA_ASSOC && 14986c92544dSBjoern A. Zeeb dev->drv->sta_assoc) 14996c92544dSBjoern A. Zeeb dev->drv->sta_assoc(dev, vif, sta); 15006c92544dSBjoern A. Zeeb 15016c92544dSBjoern A. Zeeb if (old_state == IEEE80211_STA_NONE && 15026c92544dSBjoern A. Zeeb new_state == IEEE80211_STA_NOTEXIST) 15036c92544dSBjoern A. Zeeb mt76_sta_remove(dev, vif, sta); 15046c92544dSBjoern A. Zeeb 15056c92544dSBjoern A. Zeeb return 0; 15066c92544dSBjoern A. Zeeb } 15076c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_state); 15086c92544dSBjoern A. Zeeb 15096c92544dSBjoern A. Zeeb void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 15106c92544dSBjoern A. Zeeb struct ieee80211_sta *sta) 15116c92544dSBjoern A. Zeeb { 15126c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 15136c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 15146c92544dSBjoern A. Zeeb struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 15156c92544dSBjoern A. Zeeb 15166c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex); 15176c92544dSBjoern A. Zeeb spin_lock_bh(&dev->status_lock); 15186c92544dSBjoern A. Zeeb rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 15196c92544dSBjoern A. Zeeb spin_unlock_bh(&dev->status_lock); 15206c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex); 15216c92544dSBjoern A. Zeeb } 15226c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 15236c92544dSBjoern A. Zeeb 15246c92544dSBjoern A. Zeeb int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 15256c92544dSBjoern A. Zeeb int *dbm) 15266c92544dSBjoern A. Zeeb { 15276c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 15286c92544dSBjoern A. Zeeb int n_chains = hweight8(phy->antenna_mask); 15296c92544dSBjoern A. Zeeb int delta = mt76_tx_power_nss_delta(n_chains); 15306c92544dSBjoern A. Zeeb 15316c92544dSBjoern A. Zeeb *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 15326c92544dSBjoern A. Zeeb 15336c92544dSBjoern A. Zeeb return 0; 15346c92544dSBjoern A. Zeeb } 15356c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_txpower); 15366c92544dSBjoern A. Zeeb 15376c92544dSBjoern A. Zeeb int mt76_init_sar_power(struct ieee80211_hw *hw, 15386c92544dSBjoern A. Zeeb const struct cfg80211_sar_specs *sar) 15396c92544dSBjoern A. Zeeb { 15406c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 15416c92544dSBjoern A. Zeeb const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; 15426c92544dSBjoern A. Zeeb int i; 15436c92544dSBjoern A. Zeeb 15446c92544dSBjoern A. Zeeb if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) 15456c92544dSBjoern A. Zeeb return -EINVAL; 15466c92544dSBjoern A. Zeeb 15476c92544dSBjoern A. Zeeb for (i = 0; i < sar->num_sub_specs; i++) { 15486c92544dSBjoern A. Zeeb u32 index = sar->sub_specs[i].freq_range_index; 15496c92544dSBjoern A. Zeeb /* SAR specifies power limitaton in 0.25dbm */ 15506c92544dSBjoern A. Zeeb s32 power = sar->sub_specs[i].power >> 1; 15516c92544dSBjoern A. Zeeb 15526c92544dSBjoern A. Zeeb if (power > 127 || power < -127) 15536c92544dSBjoern A. Zeeb power = 127; 15546c92544dSBjoern A. Zeeb 15556c92544dSBjoern A. Zeeb phy->frp[index].range = &capa->freq_ranges[index]; 15566c92544dSBjoern A. Zeeb phy->frp[index].power = power; 15576c92544dSBjoern A. Zeeb } 15586c92544dSBjoern A. Zeeb 15596c92544dSBjoern A. Zeeb return 0; 15606c92544dSBjoern A. Zeeb } 15616c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_sar_power); 15626c92544dSBjoern A. Zeeb 15636c92544dSBjoern A. Zeeb int mt76_get_sar_power(struct mt76_phy *phy, 15646c92544dSBjoern A. Zeeb struct ieee80211_channel *chan, 15656c92544dSBjoern A. Zeeb int power) 15666c92544dSBjoern A. Zeeb { 15676c92544dSBjoern A. Zeeb const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; 15686c92544dSBjoern A. Zeeb int freq, i; 15696c92544dSBjoern A. Zeeb 15706c92544dSBjoern A. Zeeb if (!capa || !phy->frp) 15716c92544dSBjoern A. Zeeb return power; 15726c92544dSBjoern A. Zeeb 15736c92544dSBjoern A. Zeeb if (power > 127 || power < -127) 15746c92544dSBjoern A. Zeeb power = 127; 15756c92544dSBjoern A. Zeeb 15766c92544dSBjoern A. Zeeb freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); 15776c92544dSBjoern A. Zeeb for (i = 0 ; i < capa->num_freq_ranges; i++) { 15786c92544dSBjoern A. Zeeb if (phy->frp[i].range && 15796c92544dSBjoern A. Zeeb freq >= phy->frp[i].range->start_freq && 15806c92544dSBjoern A. Zeeb freq < phy->frp[i].range->end_freq) { 15816c92544dSBjoern A. Zeeb power = min_t(int, phy->frp[i].power, power); 15826c92544dSBjoern A. Zeeb break; 15836c92544dSBjoern A. Zeeb } 15846c92544dSBjoern A. Zeeb } 15856c92544dSBjoern A. Zeeb 15866c92544dSBjoern A. Zeeb return power; 15876c92544dSBjoern A. Zeeb } 15886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_sar_power); 15896c92544dSBjoern A. Zeeb 15906c92544dSBjoern A. Zeeb static void 15916c92544dSBjoern A. Zeeb __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 15926c92544dSBjoern A. Zeeb { 15936c92544dSBjoern A. Zeeb if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 15946c92544dSBjoern A. Zeeb ieee80211_csa_finish(vif); 15956c92544dSBjoern A. Zeeb } 15966c92544dSBjoern A. Zeeb 15976c92544dSBjoern A. Zeeb void mt76_csa_finish(struct mt76_dev *dev) 15986c92544dSBjoern A. Zeeb { 15996c92544dSBjoern A. Zeeb if (!dev->csa_complete) 16006c92544dSBjoern A. Zeeb return; 16016c92544dSBjoern A. Zeeb 16026c92544dSBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(dev->hw, 16036c92544dSBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL, 16046c92544dSBjoern A. Zeeb __mt76_csa_finish, dev); 16056c92544dSBjoern A. Zeeb 16066c92544dSBjoern A. Zeeb dev->csa_complete = 0; 16076c92544dSBjoern A. Zeeb } 16086c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_finish); 16096c92544dSBjoern A. Zeeb 16106c92544dSBjoern A. Zeeb static void 16116c92544dSBjoern A. Zeeb __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 16126c92544dSBjoern A. Zeeb { 16136c92544dSBjoern A. Zeeb struct mt76_dev *dev = priv; 16146c92544dSBjoern A. Zeeb 16156c92544dSBjoern A. Zeeb if (!vif->bss_conf.csa_active) 16166c92544dSBjoern A. Zeeb return; 16176c92544dSBjoern A. Zeeb 16186c92544dSBjoern A. Zeeb dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 16196c92544dSBjoern A. Zeeb } 16206c92544dSBjoern A. Zeeb 16216c92544dSBjoern A. Zeeb void mt76_csa_check(struct mt76_dev *dev) 16226c92544dSBjoern A. Zeeb { 16236c92544dSBjoern A. Zeeb ieee80211_iterate_active_interfaces_atomic(dev->hw, 16246c92544dSBjoern A. Zeeb IEEE80211_IFACE_ITER_RESUME_ALL, 16256c92544dSBjoern A. Zeeb __mt76_csa_check, dev); 16266c92544dSBjoern A. Zeeb } 16276c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_csa_check); 16286c92544dSBjoern A. Zeeb 16296c92544dSBjoern A. Zeeb int 16306c92544dSBjoern A. Zeeb mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 16316c92544dSBjoern A. Zeeb { 16326c92544dSBjoern A. Zeeb return 0; 16336c92544dSBjoern A. Zeeb } 16346c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_set_tim); 16356c92544dSBjoern A. Zeeb 16366c92544dSBjoern A. Zeeb void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 16376c92544dSBjoern A. Zeeb { 16386c92544dSBjoern A. Zeeb struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 16396c92544dSBjoern A. Zeeb int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 16406c92544dSBjoern A. Zeeb u8 *hdr, *pn = status->iv; 16416c92544dSBjoern A. Zeeb 16426c92544dSBjoern A. Zeeb __skb_push(skb, 8); 16436c92544dSBjoern A. Zeeb memmove(skb->data, skb->data + 8, hdr_len); 16446c92544dSBjoern A. Zeeb hdr = skb->data + hdr_len; 16456c92544dSBjoern A. Zeeb 16466c92544dSBjoern A. Zeeb hdr[0] = pn[5]; 16476c92544dSBjoern A. Zeeb hdr[1] = pn[4]; 16486c92544dSBjoern A. Zeeb hdr[2] = 0; 16496c92544dSBjoern A. Zeeb hdr[3] = 0x20 | (key_id << 6); 16506c92544dSBjoern A. Zeeb hdr[4] = pn[3]; 16516c92544dSBjoern A. Zeeb hdr[5] = pn[2]; 16526c92544dSBjoern A. Zeeb hdr[6] = pn[1]; 16536c92544dSBjoern A. Zeeb hdr[7] = pn[0]; 16546c92544dSBjoern A. Zeeb 16556c92544dSBjoern A. Zeeb status->flag &= ~RX_FLAG_IV_STRIPPED; 16566c92544dSBjoern A. Zeeb } 16576c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 16586c92544dSBjoern A. Zeeb 16596c92544dSBjoern A. Zeeb int mt76_get_rate(struct mt76_dev *dev, 16606c92544dSBjoern A. Zeeb struct ieee80211_supported_band *sband, 16616c92544dSBjoern A. Zeeb int idx, bool cck) 16626c92544dSBjoern A. Zeeb { 16636c92544dSBjoern A. Zeeb int i, offset = 0, len = sband->n_bitrates; 16646c92544dSBjoern A. Zeeb 16656c92544dSBjoern A. Zeeb if (cck) { 16666c92544dSBjoern A. Zeeb if (sband != &dev->phy.sband_2g.sband) 16676c92544dSBjoern A. Zeeb return 0; 16686c92544dSBjoern A. Zeeb 16696c92544dSBjoern A. Zeeb idx &= ~BIT(2); /* short preamble */ 16706c92544dSBjoern A. Zeeb } else if (sband == &dev->phy.sband_2g.sband) { 16716c92544dSBjoern A. Zeeb offset = 4; 16726c92544dSBjoern A. Zeeb } 16736c92544dSBjoern A. Zeeb 16746c92544dSBjoern A. Zeeb for (i = offset; i < len; i++) { 16756c92544dSBjoern A. Zeeb if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 16766c92544dSBjoern A. Zeeb return i; 16776c92544dSBjoern A. Zeeb } 16786c92544dSBjoern A. Zeeb 16796c92544dSBjoern A. Zeeb return 0; 16806c92544dSBjoern A. Zeeb } 16816c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_rate); 16826c92544dSBjoern A. Zeeb 16836c92544dSBjoern A. Zeeb void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 16846c92544dSBjoern A. Zeeb const u8 *mac) 16856c92544dSBjoern A. Zeeb { 16866c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 16876c92544dSBjoern A. Zeeb 16886c92544dSBjoern A. Zeeb set_bit(MT76_SCANNING, &phy->state); 16896c92544dSBjoern A. Zeeb } 16906c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan); 16916c92544dSBjoern A. Zeeb 16926c92544dSBjoern A. Zeeb void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 16936c92544dSBjoern A. Zeeb { 16946c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 16956c92544dSBjoern A. Zeeb 16966c92544dSBjoern A. Zeeb clear_bit(MT76_SCANNING, &phy->state); 16976c92544dSBjoern A. Zeeb } 16986c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 16996c92544dSBjoern A. Zeeb 17006c92544dSBjoern A. Zeeb int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 17016c92544dSBjoern A. Zeeb { 17026c92544dSBjoern A. Zeeb struct mt76_phy *phy = hw->priv; 17036c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 17046c92544dSBjoern A. Zeeb 17056c92544dSBjoern A. Zeeb mutex_lock(&dev->mutex); 17066c92544dSBjoern A. Zeeb *tx_ant = phy->antenna_mask; 17076c92544dSBjoern A. Zeeb *rx_ant = phy->antenna_mask; 17086c92544dSBjoern A. Zeeb mutex_unlock(&dev->mutex); 17096c92544dSBjoern A. Zeeb 17106c92544dSBjoern A. Zeeb return 0; 17116c92544dSBjoern A. Zeeb } 17126c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_get_antenna); 17136c92544dSBjoern A. Zeeb 17146c92544dSBjoern A. Zeeb struct mt76_queue * 17156c92544dSBjoern A. Zeeb mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, 17166c92544dSBjoern A. Zeeb int ring_base, u32 flags) 17176c92544dSBjoern A. Zeeb { 17186c92544dSBjoern A. Zeeb struct mt76_queue *hwq; 17196c92544dSBjoern A. Zeeb int err; 17206c92544dSBjoern A. Zeeb 17216c92544dSBjoern A. Zeeb hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); 17226c92544dSBjoern A. Zeeb if (!hwq) 17236c92544dSBjoern A. Zeeb return ERR_PTR(-ENOMEM); 17246c92544dSBjoern A. Zeeb 17256c92544dSBjoern A. Zeeb hwq->flags = flags; 17266c92544dSBjoern A. Zeeb 17276c92544dSBjoern A. Zeeb err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); 17286c92544dSBjoern A. Zeeb if (err < 0) 17296c92544dSBjoern A. Zeeb return ERR_PTR(err); 17306c92544dSBjoern A. Zeeb 17316c92544dSBjoern A. Zeeb return hwq; 17326c92544dSBjoern A. Zeeb } 17336c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_init_queue); 17346c92544dSBjoern A. Zeeb 17356c92544dSBjoern A. Zeeb u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) 17366c92544dSBjoern A. Zeeb { 17376c92544dSBjoern A. Zeeb int offset = 0; 17386c92544dSBjoern A. Zeeb 17396c92544dSBjoern A. Zeeb if (phy->chandef.chan->band != NL80211_BAND_2GHZ) 17406c92544dSBjoern A. Zeeb offset = 4; 17416c92544dSBjoern A. Zeeb 17426c92544dSBjoern A. Zeeb /* pick the lowest rate for hidden nodes */ 17436c92544dSBjoern A. Zeeb if (rateidx < 0) 17446c92544dSBjoern A. Zeeb rateidx = 0; 17456c92544dSBjoern A. Zeeb 17466c92544dSBjoern A. Zeeb rateidx += offset; 17476c92544dSBjoern A. Zeeb if (rateidx >= ARRAY_SIZE(mt76_rates)) 17486c92544dSBjoern A. Zeeb rateidx = offset; 17496c92544dSBjoern A. Zeeb 17506c92544dSBjoern A. Zeeb return mt76_rates[rateidx].hw_value; 17516c92544dSBjoern A. Zeeb } 17526c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); 17536c92544dSBjoern A. Zeeb 17546c92544dSBjoern A. Zeeb void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, 1755*cbb3ec25SBjoern A. Zeeb struct mt76_sta_stats *stats, bool eht) 17566c92544dSBjoern A. Zeeb { 17576c92544dSBjoern A. Zeeb int i, ei = wi->initial_stat_idx; 17586c92544dSBjoern A. Zeeb u64 *data = wi->data; 17596c92544dSBjoern A. Zeeb 17606c92544dSBjoern A. Zeeb wi->sta_count++; 17616c92544dSBjoern A. Zeeb 17626c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; 17636c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; 17646c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; 17656c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; 17666c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; 17676c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; 17686c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; 17696c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; 17706c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; 1771*cbb3ec25SBjoern A. Zeeb if (eht) { 1772*cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU]; 1773*cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG]; 1774*cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU]; 1775*cbb3ec25SBjoern A. Zeeb } 17766c92544dSBjoern A. Zeeb 1777*cbb3ec25SBjoern A. Zeeb for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++) 17786c92544dSBjoern A. Zeeb data[ei++] += stats->tx_bw[i]; 17796c92544dSBjoern A. Zeeb 1780*cbb3ec25SBjoern A. Zeeb for (i = 0; i < (eht ? 14 : 12); i++) 17816c92544dSBjoern A. Zeeb data[ei++] += stats->tx_mcs[i]; 17826c92544dSBjoern A. Zeeb 1783*cbb3ec25SBjoern A. Zeeb for (i = 0; i < 4; i++) 1784*cbb3ec25SBjoern A. Zeeb data[ei++] += stats->tx_nss[i]; 1785*cbb3ec25SBjoern A. Zeeb 17866c92544dSBjoern A. Zeeb wi->worker_stat_count = ei - wi->initial_stat_idx; 17876c92544dSBjoern A. Zeeb } 17886c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_worker); 17896c92544dSBjoern A. Zeeb 1790*cbb3ec25SBjoern A. Zeeb void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index) 1791*cbb3ec25SBjoern A. Zeeb { 1792*cbb3ec25SBjoern A. Zeeb #ifdef CONFIG_PAGE_POOL_STATS 1793*cbb3ec25SBjoern A. Zeeb struct page_pool_stats stats = {}; 1794*cbb3ec25SBjoern A. Zeeb int i; 1795*cbb3ec25SBjoern A. Zeeb 1796*cbb3ec25SBjoern A. Zeeb mt76_for_each_q_rx(dev, i) 1797*cbb3ec25SBjoern A. Zeeb page_pool_get_stats(dev->q_rx[i].page_pool, &stats); 1798*cbb3ec25SBjoern A. Zeeb 1799*cbb3ec25SBjoern A. Zeeb page_pool_ethtool_stats_get(data, &stats); 1800*cbb3ec25SBjoern A. Zeeb *index += page_pool_ethtool_stats_get_count(); 1801*cbb3ec25SBjoern A. Zeeb #endif 1802*cbb3ec25SBjoern A. Zeeb } 1803*cbb3ec25SBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats); 1804*cbb3ec25SBjoern A. Zeeb 18056c92544dSBjoern A. Zeeb enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) 18066c92544dSBjoern A. Zeeb { 18076c92544dSBjoern A. Zeeb struct ieee80211_hw *hw = phy->hw; 18086c92544dSBjoern A. Zeeb struct mt76_dev *dev = phy->dev; 18096c92544dSBjoern A. Zeeb 18106c92544dSBjoern A. Zeeb if (dev->region == NL80211_DFS_UNSET || 18116c92544dSBjoern A. Zeeb test_bit(MT76_SCANNING, &phy->state)) 18126c92544dSBjoern A. Zeeb return MT_DFS_STATE_DISABLED; 18136c92544dSBjoern A. Zeeb 18146c92544dSBjoern A. Zeeb if (!hw->conf.radar_enabled) { 18156c92544dSBjoern A. Zeeb if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && 18166c92544dSBjoern A. Zeeb (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) 18176c92544dSBjoern A. Zeeb return MT_DFS_STATE_ACTIVE; 18186c92544dSBjoern A. Zeeb 18196c92544dSBjoern A. Zeeb return MT_DFS_STATE_DISABLED; 18206c92544dSBjoern A. Zeeb } 18216c92544dSBjoern A. Zeeb 18226c92544dSBjoern A. Zeeb if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) 18236c92544dSBjoern A. Zeeb return MT_DFS_STATE_CAC; 18246c92544dSBjoern A. Zeeb 18256c92544dSBjoern A. Zeeb return MT_DFS_STATE_ACTIVE; 18266c92544dSBjoern A. Zeeb } 18276c92544dSBjoern A. Zeeb EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); 1828