10e3d6777SRyder Lee // SPDX-License-Identifier: ISC 217f1de56SFelix Fietkau /* 317f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 417f1de56SFelix Fietkau */ 5781eef5bSFelix Fietkau #include <linux/sched.h> 617f1de56SFelix Fietkau #include <linux/of.h> 72f5c3c77SLorenzo Bianconi #include <net/page_pool.h> 817f1de56SFelix Fietkau #include "mt76.h" 917f1de56SFelix Fietkau 1017f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) { \ 1117f1de56SFelix Fietkau .band = NL80211_BAND_2GHZ, \ 1217f1de56SFelix Fietkau .center_freq = (_freq), \ 1317f1de56SFelix Fietkau .hw_value = (_idx), \ 1417f1de56SFelix Fietkau .max_power = 30, \ 1517f1de56SFelix Fietkau } 1617f1de56SFelix Fietkau 1717f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) { \ 1817f1de56SFelix Fietkau .band = NL80211_BAND_5GHZ, \ 1917f1de56SFelix Fietkau .center_freq = (_freq), \ 2017f1de56SFelix Fietkau .hw_value = (_idx), \ 2117f1de56SFelix Fietkau .max_power = 30, \ 2217f1de56SFelix Fietkau } 2317f1de56SFelix Fietkau 24edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) { \ 25edf9dab8SLorenzo Bianconi .band = NL80211_BAND_6GHZ, \ 26edf9dab8SLorenzo Bianconi .center_freq = (_freq), \ 27edf9dab8SLorenzo Bianconi .hw_value = (_idx), \ 28edf9dab8SLorenzo Bianconi .max_power = 30, \ 29edf9dab8SLorenzo Bianconi } 30edf9dab8SLorenzo Bianconi 3117f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = { 3217f1de56SFelix Fietkau CHAN2G(1, 2412), 3317f1de56SFelix Fietkau CHAN2G(2, 2417), 3417f1de56SFelix Fietkau CHAN2G(3, 2422), 3517f1de56SFelix Fietkau CHAN2G(4, 2427), 3617f1de56SFelix Fietkau CHAN2G(5, 2432), 3717f1de56SFelix Fietkau CHAN2G(6, 2437), 3817f1de56SFelix Fietkau CHAN2G(7, 2442), 3917f1de56SFelix Fietkau CHAN2G(8, 2447), 4017f1de56SFelix Fietkau CHAN2G(9, 2452), 4117f1de56SFelix Fietkau CHAN2G(10, 2457), 4217f1de56SFelix Fietkau CHAN2G(11, 2462), 4317f1de56SFelix Fietkau CHAN2G(12, 2467), 4417f1de56SFelix Fietkau CHAN2G(13, 2472), 4517f1de56SFelix Fietkau CHAN2G(14, 2484), 4617f1de56SFelix Fietkau }; 4717f1de56SFelix Fietkau 4817f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = { 4917f1de56SFelix Fietkau CHAN5G(36, 5180), 5017f1de56SFelix Fietkau CHAN5G(40, 5200), 5117f1de56SFelix Fietkau CHAN5G(44, 5220), 5217f1de56SFelix Fietkau CHAN5G(48, 5240), 5317f1de56SFelix Fietkau 5417f1de56SFelix Fietkau CHAN5G(52, 5260), 5517f1de56SFelix Fietkau CHAN5G(56, 5280), 5617f1de56SFelix Fietkau CHAN5G(60, 5300), 5717f1de56SFelix Fietkau CHAN5G(64, 5320), 5817f1de56SFelix Fietkau 5917f1de56SFelix Fietkau CHAN5G(100, 5500), 6017f1de56SFelix Fietkau CHAN5G(104, 5520), 6117f1de56SFelix Fietkau CHAN5G(108, 5540), 6217f1de56SFelix Fietkau CHAN5G(112, 5560), 6317f1de56SFelix Fietkau CHAN5G(116, 5580), 6417f1de56SFelix Fietkau CHAN5G(120, 5600), 6517f1de56SFelix Fietkau CHAN5G(124, 5620), 6617f1de56SFelix Fietkau CHAN5G(128, 5640), 6717f1de56SFelix Fietkau CHAN5G(132, 5660), 6817f1de56SFelix Fietkau CHAN5G(136, 5680), 6917f1de56SFelix Fietkau CHAN5G(140, 5700), 709da82fb7SMarkus Theil CHAN5G(144, 5720), 7117f1de56SFelix Fietkau 7217f1de56SFelix Fietkau CHAN5G(149, 5745), 7317f1de56SFelix Fietkau CHAN5G(153, 5765), 7417f1de56SFelix Fietkau CHAN5G(157, 5785), 7517f1de56SFelix Fietkau CHAN5G(161, 5805), 7617f1de56SFelix Fietkau CHAN5G(165, 5825), 779da82fb7SMarkus Theil CHAN5G(169, 5845), 789da82fb7SMarkus Theil CHAN5G(173, 5865), 7917f1de56SFelix Fietkau }; 8017f1de56SFelix Fietkau 81edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = { 82edf9dab8SLorenzo Bianconi /* UNII-5 */ 83edf9dab8SLorenzo Bianconi CHAN6G(1, 5955), 84edf9dab8SLorenzo Bianconi CHAN6G(5, 5975), 85edf9dab8SLorenzo Bianconi CHAN6G(9, 5995), 86edf9dab8SLorenzo Bianconi CHAN6G(13, 6015), 87edf9dab8SLorenzo Bianconi CHAN6G(17, 6035), 88edf9dab8SLorenzo Bianconi CHAN6G(21, 6055), 89edf9dab8SLorenzo Bianconi CHAN6G(25, 6075), 90edf9dab8SLorenzo Bianconi CHAN6G(29, 6095), 91edf9dab8SLorenzo Bianconi CHAN6G(33, 6115), 92edf9dab8SLorenzo Bianconi CHAN6G(37, 6135), 93edf9dab8SLorenzo Bianconi CHAN6G(41, 6155), 94edf9dab8SLorenzo Bianconi CHAN6G(45, 6175), 95edf9dab8SLorenzo Bianconi CHAN6G(49, 6195), 96edf9dab8SLorenzo Bianconi CHAN6G(53, 6215), 97edf9dab8SLorenzo Bianconi CHAN6G(57, 6235), 98edf9dab8SLorenzo Bianconi CHAN6G(61, 6255), 99edf9dab8SLorenzo Bianconi CHAN6G(65, 6275), 100edf9dab8SLorenzo Bianconi CHAN6G(69, 6295), 101edf9dab8SLorenzo Bianconi CHAN6G(73, 6315), 102edf9dab8SLorenzo Bianconi CHAN6G(77, 6335), 103edf9dab8SLorenzo Bianconi CHAN6G(81, 6355), 104edf9dab8SLorenzo Bianconi CHAN6G(85, 6375), 105edf9dab8SLorenzo Bianconi CHAN6G(89, 6395), 106edf9dab8SLorenzo Bianconi CHAN6G(93, 6415), 107edf9dab8SLorenzo Bianconi /* UNII-6 */ 108edf9dab8SLorenzo Bianconi CHAN6G(97, 6435), 109edf9dab8SLorenzo Bianconi CHAN6G(101, 6455), 110edf9dab8SLorenzo Bianconi CHAN6G(105, 6475), 111edf9dab8SLorenzo Bianconi CHAN6G(109, 6495), 112edf9dab8SLorenzo Bianconi CHAN6G(113, 6515), 113edf9dab8SLorenzo Bianconi CHAN6G(117, 6535), 114edf9dab8SLorenzo Bianconi /* UNII-7 */ 115edf9dab8SLorenzo Bianconi CHAN6G(121, 6555), 116edf9dab8SLorenzo Bianconi CHAN6G(125, 6575), 117edf9dab8SLorenzo Bianconi CHAN6G(129, 6595), 118edf9dab8SLorenzo Bianconi CHAN6G(133, 6615), 119edf9dab8SLorenzo Bianconi CHAN6G(137, 6635), 120edf9dab8SLorenzo Bianconi CHAN6G(141, 6655), 121edf9dab8SLorenzo Bianconi CHAN6G(145, 6675), 122edf9dab8SLorenzo Bianconi CHAN6G(149, 6695), 123edf9dab8SLorenzo Bianconi CHAN6G(153, 6715), 124edf9dab8SLorenzo Bianconi CHAN6G(157, 6735), 125edf9dab8SLorenzo Bianconi CHAN6G(161, 6755), 126edf9dab8SLorenzo Bianconi CHAN6G(165, 6775), 127edf9dab8SLorenzo Bianconi CHAN6G(169, 6795), 128edf9dab8SLorenzo Bianconi CHAN6G(173, 6815), 129edf9dab8SLorenzo Bianconi CHAN6G(177, 6835), 130edf9dab8SLorenzo Bianconi CHAN6G(181, 6855), 131edf9dab8SLorenzo Bianconi CHAN6G(185, 6875), 132edf9dab8SLorenzo Bianconi /* UNII-8 */ 133edf9dab8SLorenzo Bianconi CHAN6G(189, 6895), 134edf9dab8SLorenzo Bianconi CHAN6G(193, 6915), 135edf9dab8SLorenzo Bianconi CHAN6G(197, 6935), 136edf9dab8SLorenzo Bianconi CHAN6G(201, 6955), 137edf9dab8SLorenzo Bianconi CHAN6G(205, 6975), 138edf9dab8SLorenzo Bianconi CHAN6G(209, 6995), 139edf9dab8SLorenzo Bianconi CHAN6G(213, 7015), 140edf9dab8SLorenzo Bianconi CHAN6G(217, 7035), 141edf9dab8SLorenzo Bianconi CHAN6G(221, 7055), 142edf9dab8SLorenzo Bianconi CHAN6G(225, 7075), 143edf9dab8SLorenzo Bianconi CHAN6G(229, 7095), 144edf9dab8SLorenzo Bianconi CHAN6G(233, 7115), 145edf9dab8SLorenzo Bianconi }; 146edf9dab8SLorenzo Bianconi 14717f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 14817f1de56SFelix Fietkau { .throughput = 0 * 1024, .blink_time = 334 }, 14917f1de56SFelix Fietkau { .throughput = 1 * 1024, .blink_time = 260 }, 15017f1de56SFelix Fietkau { .throughput = 5 * 1024, .blink_time = 220 }, 15117f1de56SFelix Fietkau { .throughput = 10 * 1024, .blink_time = 190 }, 15217f1de56SFelix Fietkau { .throughput = 20 * 1024, .blink_time = 170 }, 15317f1de56SFelix Fietkau { .throughput = 50 * 1024, .blink_time = 150 }, 15417f1de56SFelix Fietkau { .throughput = 70 * 1024, .blink_time = 130 }, 15517f1de56SFelix Fietkau { .throughput = 100 * 1024, .blink_time = 110 }, 15617f1de56SFelix Fietkau { .throughput = 200 * 1024, .blink_time = 80 }, 15717f1de56SFelix Fietkau { .throughput = 300 * 1024, .blink_time = 50 }, 15817f1de56SFelix Fietkau }; 15917f1de56SFelix Fietkau 16054b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = { 16154b8fdebSLorenzo Bianconi CCK_RATE(0, 10), 16254b8fdebSLorenzo Bianconi CCK_RATE(1, 20), 16354b8fdebSLorenzo Bianconi CCK_RATE(2, 55), 16454b8fdebSLorenzo Bianconi CCK_RATE(3, 110), 16554b8fdebSLorenzo Bianconi OFDM_RATE(11, 60), 16654b8fdebSLorenzo Bianconi OFDM_RATE(15, 90), 16754b8fdebSLorenzo Bianconi OFDM_RATE(10, 120), 16854b8fdebSLorenzo Bianconi OFDM_RATE(14, 180), 16954b8fdebSLorenzo Bianconi OFDM_RATE(9, 240), 17054b8fdebSLorenzo Bianconi OFDM_RATE(13, 360), 17154b8fdebSLorenzo Bianconi OFDM_RATE(8, 480), 17254b8fdebSLorenzo Bianconi OFDM_RATE(12, 540), 17354b8fdebSLorenzo Bianconi }; 17454b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates); 17554b8fdebSLorenzo Bianconi 176502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { 177502604f5SYN Chen { .start_freq = 2402, .end_freq = 2494, }, 178502604f5SYN Chen { .start_freq = 5150, .end_freq = 5350, }, 179502604f5SYN Chen { .start_freq = 5350, .end_freq = 5470, }, 180502604f5SYN Chen { .start_freq = 5470, .end_freq = 5725, }, 181502604f5SYN Chen { .start_freq = 5725, .end_freq = 5950, }, 182162d5c14SDeren Wu { .start_freq = 5945, .end_freq = 6165, }, 183162d5c14SDeren Wu { .start_freq = 6165, .end_freq = 6405, }, 184162d5c14SDeren Wu { .start_freq = 6405, .end_freq = 6525, }, 185162d5c14SDeren Wu { .start_freq = 6525, .end_freq = 6705, }, 186162d5c14SDeren Wu { .start_freq = 6705, .end_freq = 6865, }, 187162d5c14SDeren Wu { .start_freq = 6865, .end_freq = 7125, }, 188502604f5SYN Chen }; 189502604f5SYN Chen 19097f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = { 191502604f5SYN Chen .type = NL80211_SAR_TYPE_POWER, 192502604f5SYN Chen .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), 193502604f5SYN Chen .freq_ranges = &mt76_sar_freq_ranges[0], 194502604f5SYN Chen }; 195502604f5SYN Chen 1963abd46ddSLorenzo Bianconi static int mt76_led_init(struct mt76_phy *phy) 19717f1de56SFelix Fietkau { 1983abd46ddSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 1993abd46ddSLorenzo Bianconi struct ieee80211_hw *hw = phy->hw; 20017f1de56SFelix Fietkau 2013abd46ddSLorenzo Bianconi if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) 20217f1de56SFelix Fietkau return 0; 20317f1de56SFelix Fietkau 2043abd46ddSLorenzo Bianconi snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", 2053abd46ddSLorenzo Bianconi wiphy_name(hw->wiphy)); 20617f1de56SFelix Fietkau 2073abd46ddSLorenzo Bianconi phy->leds.cdev.name = phy->leds.name; 2083abd46ddSLorenzo Bianconi phy->leds.cdev.default_trigger = 20917f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 21017f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 21117f1de56SFelix Fietkau mt76_tpt_blink, 21217f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 21317f1de56SFelix Fietkau 2143abd46ddSLorenzo Bianconi if (phy == &dev->phy) { 2153abd46ddSLorenzo Bianconi struct device_node *np = dev->dev->of_node; 2163abd46ddSLorenzo Bianconi 21717f1de56SFelix Fietkau np = of_get_child_by_name(np, "led"); 21817f1de56SFelix Fietkau if (np) { 2193abd46ddSLorenzo Bianconi int led_pin; 2203abd46ddSLorenzo Bianconi 22117f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin)) 2223abd46ddSLorenzo Bianconi phy->leds.pin = led_pin; 2233abd46ddSLorenzo Bianconi phy->leds.al = of_property_read_bool(np, 2243abd46ddSLorenzo Bianconi "led-active-low"); 2250a14c1d0SLiang He of_node_put(np); 22617f1de56SFelix Fietkau } 22736f7e2b2SFelix Fietkau } 22836f7e2b2SFelix Fietkau 2293abd46ddSLorenzo Bianconi return led_classdev_register(dev->dev, &phy->leds.cdev); 2303abd46ddSLorenzo Bianconi } 2313abd46ddSLorenzo Bianconi 2323abd46ddSLorenzo Bianconi static void mt76_led_cleanup(struct mt76_phy *phy) 23336f7e2b2SFelix Fietkau { 2343abd46ddSLorenzo Bianconi if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) 23536f7e2b2SFelix Fietkau return; 23636f7e2b2SFelix Fietkau 2373abd46ddSLorenzo Bianconi led_classdev_unregister(&phy->leds.cdev); 23817f1de56SFelix Fietkau } 23917f1de56SFelix Fietkau 240bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy, 241551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 242551e1ef4SLorenzo Bianconi bool vht) 243551e1ef4SLorenzo Bianconi { 244551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 245bb3e3fecSRyder Lee int i, nstream = hweight8(phy->antenna_mask); 246551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 247551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 248551e1ef4SLorenzo Bianconi 249551e1ef4SLorenzo Bianconi if (nstream > 1) 250551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 251551e1ef4SLorenzo Bianconi else 252551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 253551e1ef4SLorenzo Bianconi 254551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 255551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 256551e1ef4SLorenzo Bianconi 257551e1ef4SLorenzo Bianconi if (!vht) 258551e1ef4SLorenzo Bianconi return; 259551e1ef4SLorenzo Bianconi 260551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 261551e1ef4SLorenzo Bianconi if (nstream > 1) 262551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 263551e1ef4SLorenzo Bianconi else 264551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 265abba3453SDeren Wu vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 266abba3453SDeren Wu IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; 267551e1ef4SLorenzo Bianconi 268551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 269551e1ef4SLorenzo Bianconi if (i < nstream) 270551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 271551e1ef4SLorenzo Bianconi else 272551e1ef4SLorenzo Bianconi mcs_map |= 273551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 274551e1ef4SLorenzo Bianconi } 275551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 276551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 277781b80f4SFelix Fietkau if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW)) 278d9fcfc14SDeren Wu vht_cap->vht_mcs.tx_highest |= 279d9fcfc14SDeren Wu cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); 280551e1ef4SLorenzo Bianconi } 281551e1ef4SLorenzo Bianconi 282bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 2835ebdc3e0SLorenzo Bianconi { 28448dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) 285bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 28648dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) 287bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 288edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) 289edf9dab8SLorenzo Bianconi mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); 2905ebdc3e0SLorenzo Bianconi } 2915ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 2925ebdc3e0SLorenzo Bianconi 29317f1de56SFelix Fietkau static int 29477af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, 29517f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 296edf9dab8SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates, 297edf9dab8SLorenzo Bianconi bool ht, bool vht) 29817f1de56SFelix Fietkau { 29917f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 30017f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 30177af762eSLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap; 30277af762eSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 30317f1de56SFelix Fietkau void *chanlist; 30417f1de56SFelix Fietkau int size; 30517f1de56SFelix Fietkau 30617f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 30717f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 30817f1de56SFelix Fietkau if (!chanlist) 30917f1de56SFelix Fietkau return -ENOMEM; 31017f1de56SFelix Fietkau 311a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 31217f1de56SFelix Fietkau GFP_KERNEL); 31317f1de56SFelix Fietkau if (!msband->chan) 31417f1de56SFelix Fietkau return -ENOMEM; 31517f1de56SFelix Fietkau 31617f1de56SFelix Fietkau sband->channels = chanlist; 31717f1de56SFelix Fietkau sband->n_channels = n_chan; 31817f1de56SFelix Fietkau sband->bitrates = rates; 31917f1de56SFelix Fietkau sband->n_bitrates = n_rates; 32017f1de56SFelix Fietkau 321edf9dab8SLorenzo Bianconi if (!ht) 322edf9dab8SLorenzo Bianconi return 0; 323edf9dab8SLorenzo Bianconi 32417f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 32517f1de56SFelix Fietkau ht_cap->ht_supported = true; 32617f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 32717f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 32817f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 32917f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 33017f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 33117f1de56SFelix Fietkau 33217f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 33317f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 33417f1de56SFelix Fietkau 33577af762eSLorenzo Bianconi mt76_init_stream_cap(phy, sband, vht); 336551e1ef4SLorenzo Bianconi 33717f1de56SFelix Fietkau if (!vht) 33817f1de56SFelix Fietkau return 0; 33917f1de56SFelix Fietkau 34017f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 34117f1de56SFelix Fietkau vht_cap->vht_supported = true; 34217f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 34317f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 34449149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 34549149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 34617f1de56SFelix Fietkau 34717f1de56SFelix Fietkau return 0; 34817f1de56SFelix Fietkau } 34917f1de56SFelix Fietkau 35017f1de56SFelix Fietkau static int 35177af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, 35217f1de56SFelix Fietkau int n_rates) 35317f1de56SFelix Fietkau { 35477af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 35517f1de56SFelix Fietkau 35677af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, 35777af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_2ghz), rates, 358edf9dab8SLorenzo Bianconi n_rates, true, false); 35917f1de56SFelix Fietkau } 36017f1de56SFelix Fietkau 36117f1de56SFelix Fietkau static int 36277af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, 36317f1de56SFelix Fietkau int n_rates, bool vht) 36417f1de56SFelix Fietkau { 36577af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 36617f1de56SFelix Fietkau 36777af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, 36877af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_5ghz), rates, 369edf9dab8SLorenzo Bianconi n_rates, true, vht); 370edf9dab8SLorenzo Bianconi } 371edf9dab8SLorenzo Bianconi 372edf9dab8SLorenzo Bianconi static int 373edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, 374edf9dab8SLorenzo Bianconi int n_rates) 375edf9dab8SLorenzo Bianconi { 376edf9dab8SLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; 377edf9dab8SLorenzo Bianconi 378edf9dab8SLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, 379edf9dab8SLorenzo Bianconi ARRAY_SIZE(mt76_channels_6ghz), rates, 380edf9dab8SLorenzo Bianconi n_rates, false, false); 38117f1de56SFelix Fietkau } 38217f1de56SFelix Fietkau 38317f1de56SFelix Fietkau static void 384c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 385c89d3625SFelix Fietkau enum nl80211_band band) 38617f1de56SFelix Fietkau { 387c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 38817f1de56SFelix Fietkau bool found = false; 38917f1de56SFelix Fietkau int i; 39017f1de56SFelix Fietkau 39117f1de56SFelix Fietkau if (!sband) 39217f1de56SFelix Fietkau return; 39317f1de56SFelix Fietkau 39417f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 39517f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 39617f1de56SFelix Fietkau continue; 39717f1de56SFelix Fietkau 39817f1de56SFelix Fietkau found = true; 39917f1de56SFelix Fietkau break; 40017f1de56SFelix Fietkau } 40117f1de56SFelix Fietkau 402c89d3625SFelix Fietkau if (found) { 403c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0]; 404c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0]; 40517f1de56SFelix Fietkau return; 406c89d3625SFelix Fietkau } 40717f1de56SFelix Fietkau 40817f1de56SFelix Fietkau sband->n_channels = 0; 409c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL; 41017f1de56SFelix Fietkau } 41117f1de56SFelix Fietkau 412d43de9cfSLorenzo Bianconi static int 41398df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) 414c89d3625SFelix Fietkau { 41598df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 416c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 417c89d3625SFelix Fietkau 418c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 41998df2baeSLorenzo Bianconi SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); 420c89d3625SFelix Fietkau 421c89d3625SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 422dd89a013SLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 423b807b368SLorenzo Bianconi WIPHY_FLAG_SUPPORTS_TDLS | 424b807b368SLorenzo Bianconi WIPHY_FLAG_AP_UAPSD; 425c89d3625SFelix Fietkau 426c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 427c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 428d9c54264SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 429c89d3625SFelix Fietkau 4300a57d636SBo Jiao wiphy->available_antennas_tx = phy->antenna_mask; 4310a57d636SBo Jiao wiphy->available_antennas_rx = phy->antenna_mask; 432c89d3625SFelix Fietkau 433d43de9cfSLorenzo Bianconi wiphy->sar_capa = &mt76_sar_capa; 434d43de9cfSLorenzo Bianconi phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, 435d43de9cfSLorenzo Bianconi sizeof(struct mt76_freq_range_power), 436d43de9cfSLorenzo Bianconi GFP_KERNEL); 437d43de9cfSLorenzo Bianconi if (!phy->frp) 438d43de9cfSLorenzo Bianconi return -ENOMEM; 439d43de9cfSLorenzo Bianconi 440c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 441b807b368SLorenzo Bianconi hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 442c9619dfaSShayne Chen 443c9619dfaSShayne Chen if (!hw->max_tx_fragments) 444c89d3625SFelix Fietkau hw->max_tx_fragments = 16; 445c89d3625SFelix Fietkau 446c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 447c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 448c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 449c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 450c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 451c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 452ed89b893SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 4535b0fb852SBen Greear 4545b0fb852SBen Greear if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) { 455c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 456c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 4575b0fb852SBen Greear } 4585b0fb852SBen Greear 459c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 460c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 461c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 462d43de9cfSLorenzo Bianconi 463d43de9cfSLorenzo Bianconi return 0; 464c89d3625SFelix Fietkau } 465c89d3625SFelix Fietkau 466c89d3625SFelix Fietkau struct mt76_phy * 467c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 468dc44c45cSLorenzo Bianconi const struct ieee80211_ops *ops, u8 band_idx) 469c89d3625SFelix Fietkau { 470c89d3625SFelix Fietkau struct ieee80211_hw *hw; 471db78a791SLorenzo Bianconi unsigned int phy_size; 472c89d3625SFelix Fietkau struct mt76_phy *phy; 473c89d3625SFelix Fietkau 474c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8); 475db78a791SLorenzo Bianconi hw = ieee80211_alloc_hw(size + phy_size, ops); 476c89d3625SFelix Fietkau if (!hw) 477c89d3625SFelix Fietkau return NULL; 478c89d3625SFelix Fietkau 479c89d3625SFelix Fietkau phy = hw->priv; 480c89d3625SFelix Fietkau phy->dev = dev; 481c89d3625SFelix Fietkau phy->hw = hw; 482db78a791SLorenzo Bianconi phy->priv = hw->priv + phy_size; 483dc44c45cSLorenzo Bianconi phy->band_idx = band_idx; 484c89d3625SFelix Fietkau 4858af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 4868af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 4878af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 4888af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 4898af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 4908af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 4918af414e8SLorenzo Bianconi #endif 4928af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 4938af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 4948af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 4958af414e8SLorenzo Bianconi 496c89d3625SFelix Fietkau return phy; 497c89d3625SFelix Fietkau } 498c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy); 499c89d3625SFelix Fietkau 500db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht, 501db78a791SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates) 502c89d3625SFelix Fietkau { 503c89d3625SFelix Fietkau int ret; 504c89d3625SFelix Fietkau 505d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, phy->hw); 506d43de9cfSLorenzo Bianconi if (ret) 507d43de9cfSLorenzo Bianconi return ret; 508db78a791SLorenzo Bianconi 509db78a791SLorenzo Bianconi if (phy->cap.has_2ghz) { 510db78a791SLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 511db78a791SLorenzo Bianconi if (ret) 512db78a791SLorenzo Bianconi return ret; 513db78a791SLorenzo Bianconi } 514db78a791SLorenzo Bianconi 515db78a791SLorenzo Bianconi if (phy->cap.has_5ghz) { 516db78a791SLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 517db78a791SLorenzo Bianconi if (ret) 518db78a791SLorenzo Bianconi return ret; 519db78a791SLorenzo Bianconi } 520db78a791SLorenzo Bianconi 521edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 522edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 523edf9dab8SLorenzo Bianconi if (ret) 524edf9dab8SLorenzo Bianconi return ret; 525edf9dab8SLorenzo Bianconi } 526edf9dab8SLorenzo Bianconi 5279e81c2c7SLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS)) { 5289e81c2c7SLorenzo Bianconi ret = mt76_led_init(phy); 5299e81c2c7SLorenzo Bianconi if (ret) 5309e81c2c7SLorenzo Bianconi return ret; 5319e81c2c7SLorenzo Bianconi } 5329e81c2c7SLorenzo Bianconi 533db78a791SLorenzo Bianconi wiphy_read_of_freq_limits(phy->hw->wiphy); 534db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 535db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 536edf9dab8SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); 537db78a791SLorenzo Bianconi 538c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw); 539c89d3625SFelix Fietkau if (ret) 540c89d3625SFelix Fietkau return ret; 541c89d3625SFelix Fietkau 542*41130c32SLorenzo Bianconi set_bit(MT76_STATE_REGISTERED, &phy->state); 543dc44c45cSLorenzo Bianconi phy->dev->phys[phy->band_idx] = phy; 544db78a791SLorenzo Bianconi 545c89d3625SFelix Fietkau return 0; 546c89d3625SFelix Fietkau } 547c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy); 548c89d3625SFelix Fietkau 549db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy) 550c89d3625SFelix Fietkau { 551c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev; 552c89d3625SFelix Fietkau 553*41130c32SLorenzo Bianconi if (!test_bit(MT76_STATE_REGISTERED, &phy->state)) 554*41130c32SLorenzo Bianconi return; 555*41130c32SLorenzo Bianconi 5569e81c2c7SLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS)) 5579e81c2c7SLorenzo Bianconi mt76_led_cleanup(phy); 558c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 559c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw); 560dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = NULL; 561c89d3625SFelix Fietkau } 562c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy); 563c89d3625SFelix Fietkau 5642f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) 5652f5c3c77SLorenzo Bianconi { 5662f5c3c77SLorenzo Bianconi struct page_pool_params pp_params = { 5672f5c3c77SLorenzo Bianconi .order = 0, 5682f5c3c77SLorenzo Bianconi .flags = PP_FLAG_PAGE_FRAG, 5692f5c3c77SLorenzo Bianconi .nid = NUMA_NO_NODE, 5702f5c3c77SLorenzo Bianconi .dev = dev->dma_dev, 5712f5c3c77SLorenzo Bianconi }; 5722f5c3c77SLorenzo Bianconi int idx = q - dev->q_rx; 5732f5c3c77SLorenzo Bianconi 5742f5c3c77SLorenzo Bianconi switch (idx) { 5752f5c3c77SLorenzo Bianconi case MT_RXQ_MAIN: 5762f5c3c77SLorenzo Bianconi case MT_RXQ_BAND1: 5772f5c3c77SLorenzo Bianconi case MT_RXQ_BAND2: 5782f5c3c77SLorenzo Bianconi pp_params.pool_size = 256; 5792f5c3c77SLorenzo Bianconi break; 5802f5c3c77SLorenzo Bianconi default: 5812f5c3c77SLorenzo Bianconi pp_params.pool_size = 16; 5822f5c3c77SLorenzo Bianconi break; 5832f5c3c77SLorenzo Bianconi } 5842f5c3c77SLorenzo Bianconi 5852f5c3c77SLorenzo Bianconi if (mt76_is_mmio(dev)) { 5862f5c3c77SLorenzo Bianconi /* rely on page_pool for DMA mapping */ 5872f5c3c77SLorenzo Bianconi pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; 5882f5c3c77SLorenzo Bianconi pp_params.dma_dir = DMA_FROM_DEVICE; 5892f5c3c77SLorenzo Bianconi pp_params.max_len = PAGE_SIZE; 5902f5c3c77SLorenzo Bianconi pp_params.offset = 0; 5912f5c3c77SLorenzo Bianconi } 5922f5c3c77SLorenzo Bianconi 5932f5c3c77SLorenzo Bianconi q->page_pool = page_pool_create(&pp_params); 5942f5c3c77SLorenzo Bianconi if (IS_ERR(q->page_pool)) { 5952f5c3c77SLorenzo Bianconi int err = PTR_ERR(q->page_pool); 5962f5c3c77SLorenzo Bianconi 5972f5c3c77SLorenzo Bianconi q->page_pool = NULL; 5982f5c3c77SLorenzo Bianconi return err; 5992f5c3c77SLorenzo Bianconi } 6002f5c3c77SLorenzo Bianconi 6012f5c3c77SLorenzo Bianconi return 0; 6022f5c3c77SLorenzo Bianconi } 6032f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool); 6042f5c3c77SLorenzo Bianconi 605a85b590cSFelix Fietkau struct mt76_dev * 606c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 607c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 608c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 609a85b590cSFelix Fietkau { 610a85b590cSFelix Fietkau struct ieee80211_hw *hw; 611ac24dd35SFelix Fietkau struct mt76_phy *phy; 612a85b590cSFelix Fietkau struct mt76_dev *dev; 613e5443256SFelix Fietkau int i; 614a85b590cSFelix Fietkau 615a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 616a85b590cSFelix Fietkau if (!hw) 617a85b590cSFelix Fietkau return NULL; 618a85b590cSFelix Fietkau 619a85b590cSFelix Fietkau dev = hw->priv; 620a85b590cSFelix Fietkau dev->hw = hw; 621c0f7b25aSLorenzo Bianconi dev->dev = pdev; 622c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 623d1ddc536SFelix Fietkau dev->dma_dev = pdev; 624c0f7b25aSLorenzo Bianconi 625ac24dd35SFelix Fietkau phy = &dev->phy; 626ac24dd35SFelix Fietkau phy->dev = dev; 627ac24dd35SFelix Fietkau phy->hw = hw; 628dc44c45cSLorenzo Bianconi phy->band_idx = MT_BAND0; 629dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = phy; 630ac24dd35SFelix Fietkau 631a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 632a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 633a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 634c34f1005SLorenzo Bianconi spin_lock_init(&dev->status_lock); 6352666beceSSujuan Chen spin_lock_init(&dev->wed_lock); 636108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 63726e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 638a85b590cSFelix Fietkau 63909872957SLorenzo Bianconi skb_queue_head_init(&dev->mcu.res_q); 64009872957SLorenzo Bianconi init_waitqueue_head(&dev->mcu.wait); 64109872957SLorenzo Bianconi mutex_init(&dev->mcu.mutex); 642781eef5bSFelix Fietkau dev->tx_worker.fn = mt76_tx_worker; 64309872957SLorenzo Bianconi 6448af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 6458af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 6468af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 6478af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 6488af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 6498af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 6508af414e8SLorenzo Bianconi #endif 6518af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 6528af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 6538af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 6548af414e8SLorenzo Bianconi 65551252cc5SLorenzo Bianconi spin_lock_init(&dev->token_lock); 65651252cc5SLorenzo Bianconi idr_init(&dev->token); 65751252cc5SLorenzo Bianconi 6582666beceSSujuan Chen spin_lock_init(&dev->rx_token_lock); 6592666beceSSujuan Chen idr_init(&dev->rx_token); 6602666beceSSujuan Chen 661bd1e3e7bSLorenzo Bianconi INIT_LIST_HEAD(&dev->wcid_list); 662bd1e3e7bSLorenzo Bianconi 663e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 6642666beceSSujuan Chen INIT_LIST_HEAD(&dev->rxwi_cache); 66561b5156bSFelix Fietkau dev->token_size = dev->drv->token_size; 666e5443256SFelix Fietkau 667e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 668e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 669e5443256SFelix Fietkau 670a86f1d01SLorenzo Bianconi dev->wq = alloc_ordered_workqueue("mt76", 0); 671a86f1d01SLorenzo Bianconi if (!dev->wq) { 672a86f1d01SLorenzo Bianconi ieee80211_free_hw(hw); 673a86f1d01SLorenzo Bianconi return NULL; 674a86f1d01SLorenzo Bianconi } 675a86f1d01SLorenzo Bianconi 676a85b590cSFelix Fietkau return dev; 677a85b590cSFelix Fietkau } 678a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 679a85b590cSFelix Fietkau 68017f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 68117f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 68217f1de56SFelix Fietkau { 68317f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 684c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy; 68517f1de56SFelix Fietkau int ret; 68617f1de56SFelix Fietkau 68717f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 688d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, hw); 689d43de9cfSLorenzo Bianconi if (ret) 690d43de9cfSLorenzo Bianconi return ret; 69117f1de56SFelix Fietkau 69248dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) { 69377af762eSLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 69417f1de56SFelix Fietkau if (ret) 69517f1de56SFelix Fietkau return ret; 69617f1de56SFelix Fietkau } 69717f1de56SFelix Fietkau 69848dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) { 69977af762eSLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 70017f1de56SFelix Fietkau if (ret) 70117f1de56SFelix Fietkau return ret; 70217f1de56SFelix Fietkau } 70317f1de56SFelix Fietkau 704edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 705edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 706edf9dab8SLorenzo Bianconi if (ret) 707edf9dab8SLorenzo Bianconi return ret; 708edf9dab8SLorenzo Bianconi } 709edf9dab8SLorenzo Bianconi 710c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy); 711c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 712c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 713edf9dab8SLorenzo Bianconi mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); 71417f1de56SFelix Fietkau 715b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 7163abd46ddSLorenzo Bianconi ret = mt76_led_init(phy); 71717f1de56SFelix Fietkau if (ret) 71817f1de56SFelix Fietkau return ret; 719b374e868SArnd Bergmann } 72017f1de56SFelix Fietkau 721781eef5bSFelix Fietkau ret = ieee80211_register_hw(hw); 722781eef5bSFelix Fietkau if (ret) 723781eef5bSFelix Fietkau return ret; 724781eef5bSFelix Fietkau 725781eef5bSFelix Fietkau WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 726*41130c32SLorenzo Bianconi set_bit(MT76_STATE_REGISTERED, &phy->state); 727781eef5bSFelix Fietkau sched_set_fifo_low(dev->tx_worker.task); 728781eef5bSFelix Fietkau 729781eef5bSFelix Fietkau return 0; 73017f1de56SFelix Fietkau } 73117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 73217f1de56SFelix Fietkau 73317f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 73417f1de56SFelix Fietkau { 73517f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 73617f1de56SFelix Fietkau 737*41130c32SLorenzo Bianconi if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state)) 738*41130c32SLorenzo Bianconi return; 739*41130c32SLorenzo Bianconi 740d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 7413abd46ddSLorenzo Bianconi mt76_led_cleanup(&dev->phy); 742c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 74317f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 74417f1de56SFelix Fietkau } 74517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 74617f1de56SFelix Fietkau 747def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 748def34a2fSLorenzo Bianconi { 749781eef5bSFelix Fietkau mt76_worker_teardown(&dev->tx_worker); 750a86f1d01SLorenzo Bianconi if (dev->wq) { 751a86f1d01SLorenzo Bianconi destroy_workqueue(dev->wq); 752a86f1d01SLorenzo Bianconi dev->wq = NULL; 753a86f1d01SLorenzo Bianconi } 754def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 755def34a2fSLorenzo Bianconi } 756def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 757def34a2fSLorenzo Bianconi 758cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) 759cc4b3c13SLorenzo Bianconi { 760cc4b3c13SLorenzo Bianconi struct sk_buff *skb = phy->rx_amsdu[q].head; 7612c2bdd23SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 762cc4b3c13SLorenzo Bianconi struct mt76_dev *dev = phy->dev; 763cc4b3c13SLorenzo Bianconi 764cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = NULL; 765cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = NULL; 7662c2bdd23SFelix Fietkau 7672c2bdd23SFelix Fietkau /* 7682c2bdd23SFelix Fietkau * Validate if the amsdu has a proper first subframe. 7692c2bdd23SFelix Fietkau * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU 7702c2bdd23SFelix Fietkau * flag of the QoS header gets flipped. In such cases, the first 7712c2bdd23SFelix Fietkau * subframe has a LLC/SNAP header in the location of the destination 7722c2bdd23SFelix Fietkau * address. 7732c2bdd23SFelix Fietkau */ 7742c2bdd23SFelix Fietkau if (skb_shinfo(skb)->frag_list) { 7752c2bdd23SFelix Fietkau int offset = 0; 7762c2bdd23SFelix Fietkau 7772c2bdd23SFelix Fietkau if (!(status->flag & RX_FLAG_8023)) { 7782c2bdd23SFelix Fietkau offset = ieee80211_get_hdrlen_from_skb(skb); 7792c2bdd23SFelix Fietkau 7802c2bdd23SFelix Fietkau if ((status->flag & 7812c2bdd23SFelix Fietkau (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == 7822c2bdd23SFelix Fietkau RX_FLAG_DECRYPTED) 7832c2bdd23SFelix Fietkau offset += 8; 7842c2bdd23SFelix Fietkau } 7852c2bdd23SFelix Fietkau 7862c2bdd23SFelix Fietkau if (ether_addr_equal(skb->data + offset, rfc1042_header)) { 7872c2bdd23SFelix Fietkau dev_kfree_skb(skb); 7882c2bdd23SFelix Fietkau return; 7892c2bdd23SFelix Fietkau } 7902c2bdd23SFelix Fietkau } 791cc4b3c13SLorenzo Bianconi __skb_queue_tail(&dev->rx_skb[q], skb); 792cc4b3c13SLorenzo Bianconi } 793cc4b3c13SLorenzo Bianconi 794cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, 795cc4b3c13SLorenzo Bianconi struct sk_buff *skb) 796cc4b3c13SLorenzo Bianconi { 797cc4b3c13SLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 798cc4b3c13SLorenzo Bianconi 799cc4b3c13SLorenzo Bianconi if (phy->rx_amsdu[q].head && 800cc4b3c13SLorenzo Bianconi (!status->amsdu || status->first_amsdu || 801cc4b3c13SLorenzo Bianconi status->seqno != phy->rx_amsdu[q].seqno)) 802cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 803cc4b3c13SLorenzo Bianconi 804cc4b3c13SLorenzo Bianconi if (!phy->rx_amsdu[q].head) { 805cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; 806cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].seqno = status->seqno; 807cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = skb; 808cc4b3c13SLorenzo Bianconi } else { 809cc4b3c13SLorenzo Bianconi *phy->rx_amsdu[q].tail = skb; 810cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb->next; 811cc4b3c13SLorenzo Bianconi } 812cc4b3c13SLorenzo Bianconi 813cc4b3c13SLorenzo Bianconi if (!status->amsdu || status->last_amsdu) 814cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 815cc4b3c13SLorenzo Bianconi } 816cc4b3c13SLorenzo Bianconi 81717f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 81817f1de56SFelix Fietkau { 819011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 820128c9b7dSLorenzo Bianconi struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); 821011849e0SFelix Fietkau 822011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 82317f1de56SFelix Fietkau dev_kfree_skb(skb); 82417f1de56SFelix Fietkau return; 82517f1de56SFelix Fietkau } 82617f1de56SFelix Fietkau 827f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE 828c918c74dSShayne Chen if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { 829c918c74dSShayne Chen phy->test.rx_stats.packets[q]++; 830f0efa862SFelix Fietkau if (status->flag & RX_FLAG_FAILED_FCS_CRC) 831c918c74dSShayne Chen phy->test.rx_stats.fcs_error[q]++; 832f0efa862SFelix Fietkau } 833f0efa862SFelix Fietkau #endif 834cc4b3c13SLorenzo Bianconi 835cc4b3c13SLorenzo Bianconi mt76_rx_release_burst(phy, q, skb); 83617f1de56SFelix Fietkau } 83717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 83817f1de56SFelix Fietkau 8395a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy) 84026e40d4cSFelix Fietkau { 841af005f26SLorenzo Bianconi struct mt76_queue *q; 84291990519SLorenzo Bianconi int i; 8435a95ca41SFelix Fietkau 8445a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) { 84591990519SLorenzo Bianconi q = phy->q_tx[i]; 846af005f26SLorenzo Bianconi if (q && q->queued) 84726e40d4cSFelix Fietkau return true; 84826e40d4cSFelix Fietkau } 84926e40d4cSFelix Fietkau 85026e40d4cSFelix Fietkau return false; 85126e40d4cSFelix Fietkau } 85239d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 85326e40d4cSFelix Fietkau 8540fd0eb54SFelix Fietkau static struct mt76_channel_state * 85596747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 8560fd0eb54SFelix Fietkau { 8570fd0eb54SFelix Fietkau struct mt76_sband *msband; 8580fd0eb54SFelix Fietkau int idx; 8590fd0eb54SFelix Fietkau 8600fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 86196747a51SFelix Fietkau msband = &phy->sband_2g; 862edf9dab8SLorenzo Bianconi else if (c->band == NL80211_BAND_6GHZ) 863edf9dab8SLorenzo Bianconi msband = &phy->sband_6g; 8640fd0eb54SFelix Fietkau else 86596747a51SFelix Fietkau msband = &phy->sband_5g; 8660fd0eb54SFelix Fietkau 8670fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 8680fd0eb54SFelix Fietkau return &msband->chan[idx]; 8690fd0eb54SFelix Fietkau } 8700fd0eb54SFelix Fietkau 87104414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 87296747a51SFelix Fietkau { 87396747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state; 87496747a51SFelix Fietkau 87596747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time, 87696747a51SFelix Fietkau phy->survey_time)); 87796747a51SFelix Fietkau phy->survey_time = time; 87896747a51SFelix Fietkau } 87904414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 88096747a51SFelix Fietkau 881c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy) 8825ce09c1aSFelix Fietkau { 883c560b137SRyder Lee struct mt76_dev *dev = phy->dev; 884aec65e48SFelix Fietkau ktime_t cur_time; 885aec65e48SFelix Fietkau 8865ce09c1aSFelix Fietkau if (dev->drv->update_survey) 887c560b137SRyder Lee dev->drv->update_survey(phy); 8885ce09c1aSFelix Fietkau 889aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 890c560b137SRyder Lee mt76_update_survey_active_time(phy, cur_time); 891aec65e48SFelix Fietkau 8925ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 893c560b137SRyder Lee struct mt76_channel_state *state = phy->chan_state; 89496747a51SFelix Fietkau 895237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 8965ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 8975ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 898237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 8995ce09c1aSFelix Fietkau } 9005ce09c1aSFelix Fietkau } 9015ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 9025ce09c1aSFelix Fietkau 90396747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy) 90417f1de56SFelix Fietkau { 90596747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 90696747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 90717f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 90817f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 90926e40d4cSFelix Fietkau int timeout = HZ / 5; 91017f1de56SFelix Fietkau 9115a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 912c560b137SRyder Lee mt76_update_survey(phy); 91317f1de56SFelix Fietkau 9143f306448SFelix Fietkau if (phy->chandef.chan->center_freq != chandef->chan->center_freq || 9153f306448SFelix Fietkau phy->chandef.width != chandef->width) 9163f306448SFelix Fietkau phy->dfs_state = MT_DFS_STATE_UNKNOWN; 9173f306448SFelix Fietkau 91896747a51SFelix Fietkau phy->chandef = *chandef; 91996747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan); 92017f1de56SFelix Fietkau 92117f1de56SFelix Fietkau if (!offchannel) 92296747a51SFelix Fietkau phy->main_chan = chandef->chan; 92317f1de56SFelix Fietkau 92496747a51SFelix Fietkau if (chandef->chan != phy->main_chan) 92596747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 92617f1de56SFelix Fietkau } 92717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 92817f1de56SFelix Fietkau 92917f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 93017f1de56SFelix Fietkau struct survey_info *survey) 93117f1de56SFelix Fietkau { 93296747a51SFelix Fietkau struct mt76_phy *phy = hw->priv; 93396747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 93417f1de56SFelix Fietkau struct mt76_sband *sband; 93517f1de56SFelix Fietkau struct ieee80211_channel *chan; 93617f1de56SFelix Fietkau struct mt76_channel_state *state; 93717f1de56SFelix Fietkau int ret = 0; 93817f1de56SFelix Fietkau 939237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 94017f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 941c560b137SRyder Lee mt76_update_survey(phy); 94217f1de56SFelix Fietkau 943edf9dab8SLorenzo Bianconi if (idx >= phy->sband_2g.sband.n_channels + 944edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels) { 945edf9dab8SLorenzo Bianconi idx -= (phy->sband_2g.sband.n_channels + 946edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels); 947edf9dab8SLorenzo Bianconi sband = &phy->sband_6g; 948edf9dab8SLorenzo Bianconi } else if (idx >= phy->sband_2g.sband.n_channels) { 949edf9dab8SLorenzo Bianconi idx -= phy->sband_2g.sband.n_channels; 95096747a51SFelix Fietkau sband = &phy->sband_5g; 951edf9dab8SLorenzo Bianconi } else { 952edf9dab8SLorenzo Bianconi sband = &phy->sband_2g; 95317f1de56SFelix Fietkau } 95417f1de56SFelix Fietkau 955237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 956237312c5SLorenzo Bianconi ret = -ENOENT; 957237312c5SLorenzo Bianconi goto out; 958237312c5SLorenzo Bianconi } 95917f1de56SFelix Fietkau 96017f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 96196747a51SFelix Fietkau state = mt76_channel_state(phy, chan); 96217f1de56SFelix Fietkau 96317f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 96417f1de56SFelix Fietkau survey->channel = chan; 96517f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 966ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 967e5051965SFelix Fietkau if (state->noise) 968e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM; 969e5051965SFelix Fietkau 97096747a51SFelix Fietkau if (chan == phy->main_chan) { 97117f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 97217f1de56SFelix Fietkau 9735ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 9745ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 9755ce09c1aSFelix Fietkau } 9765ce09c1aSFelix Fietkau 97717f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 9786bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 979237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 980e5051965SFelix Fietkau survey->noise = state->noise; 981237312c5SLorenzo Bianconi 982237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 983237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 984ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 98517f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 98617f1de56SFelix Fietkau 987237312c5SLorenzo Bianconi out: 988237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 989237312c5SLorenzo Bianconi 99017f1de56SFelix Fietkau return ret; 99117f1de56SFelix Fietkau } 99217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 99317f1de56SFelix Fietkau 99430ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 99530ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 99630ce7f44SFelix Fietkau { 99730ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 99830ce7f44SFelix Fietkau int i; 99930ce7f44SFelix Fietkau 100030ce7f44SFelix Fietkau wcid->rx_check_pn = false; 100130ce7f44SFelix Fietkau 100230ce7f44SFelix Fietkau if (!key) 100330ce7f44SFelix Fietkau return; 100430ce7f44SFelix Fietkau 100501cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 100601cfc1b4SLorenzo Bianconi return; 100730ce7f44SFelix Fietkau 100801cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 1009a1b0bbd4SXing Song 1010a1b0bbd4SXing Song /* data frame */ 101130ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 101230ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 101330ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 101430ce7f44SFelix Fietkau } 1015a1b0bbd4SXing Song 1016a1b0bbd4SXing Song /* robust management frame */ 1017a1b0bbd4SXing Song ieee80211_get_key_rx_seq(key, -1, &seq); 1018a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 1019a1b0bbd4SXing Song 102030ce7f44SFelix Fietkau } 102130ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 102230ce7f44SFelix Fietkau 1023a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal) 10244550fb9eSFelix Fietkau { 10254550fb9eSFelix Fietkau int signal = -128; 10264550fb9eSFelix Fietkau u8 chains; 10274550fb9eSFelix Fietkau 1028a71b648eSRyder Lee for (chains = chain_mask; chains; chains >>= 1, chain_signal++) { 10294550fb9eSFelix Fietkau int cur, diff; 10304550fb9eSFelix Fietkau 10316450b133SDeren Wu cur = *chain_signal; 10326450b133SDeren Wu if (!(chains & BIT(0)) || 10336450b133SDeren Wu cur > 0) 10344550fb9eSFelix Fietkau continue; 10354550fb9eSFelix Fietkau 10364550fb9eSFelix Fietkau if (cur > signal) 10374550fb9eSFelix Fietkau swap(cur, signal); 10384550fb9eSFelix Fietkau 10394550fb9eSFelix Fietkau diff = signal - cur; 10404550fb9eSFelix Fietkau if (diff == 0) 10414550fb9eSFelix Fietkau signal += 3; 10424550fb9eSFelix Fietkau else if (diff <= 2) 10434550fb9eSFelix Fietkau signal += 2; 10444550fb9eSFelix Fietkau else if (diff <= 6) 10454550fb9eSFelix Fietkau signal += 1; 10464550fb9eSFelix Fietkau } 10474550fb9eSFelix Fietkau 10484550fb9eSFelix Fietkau return signal; 10494550fb9eSFelix Fietkau } 1050a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal); 10514550fb9eSFelix Fietkau 1052bfc394ddSFelix Fietkau static void 1053bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 1054bfc394ddSFelix Fietkau struct ieee80211_hw **hw, 1055bfc394ddSFelix Fietkau struct ieee80211_sta **sta) 10564e34249eSFelix Fietkau { 10574e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 1058abe3f3daSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 10594e34249eSFelix Fietkau struct mt76_rx_status mstat; 10604e34249eSFelix Fietkau 10614e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 10624e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 10634e34249eSFelix Fietkau 10644e34249eSFelix Fietkau status->flag = mstat.flag; 10654e34249eSFelix Fietkau status->freq = mstat.freq; 10664e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 10674e34249eSFelix Fietkau status->encoding = mstat.encoding; 10684e34249eSFelix Fietkau status->bw = mstat.bw; 1069af4a2f2fSRyder Lee status->he_ru = mstat.he_ru; 1070af4a2f2fSRyder Lee status->he_gi = mstat.he_gi; 1071af4a2f2fSRyder Lee status->he_dcm = mstat.he_dcm; 10724e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 10734e34249eSFelix Fietkau status->nss = mstat.nss; 10744e34249eSFelix Fietkau status->band = mstat.band; 10754e34249eSFelix Fietkau status->signal = mstat.signal; 10764e34249eSFelix Fietkau status->chains = mstat.chains; 1077d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 10780fda6d7bSRyder Lee status->device_timestamp = mstat.timestamp; 10790fda6d7bSRyder Lee status->mactime = mstat.timestamp; 1080a71b648eSRyder Lee status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal); 10814550fb9eSFelix Fietkau if (status->signal <= -128) 10824550fb9eSFelix Fietkau status->flag |= RX_FLAG_NO_SIGNAL_VAL; 10834e34249eSFelix Fietkau 1084abe3f3daSRyder Lee if (ieee80211_is_beacon(hdr->frame_control) || 1085abe3f3daSRyder Lee ieee80211_is_probe_resp(hdr->frame_control)) 1086abe3f3daSRyder Lee status->boottime_ns = ktime_get_boottime_ns(); 1087abe3f3daSRyder Lee 10884e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 108913381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 109013381dcdSRyder Lee sizeof(mstat.chain_signal)); 109113381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 109213381dcdSRyder Lee sizeof(mstat.chain_signal)); 10939c68a57bSFelix Fietkau 1094bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid); 1095128c9b7dSLorenzo Bianconi *hw = mt76_phy_hw(dev, mstat.phy_idx); 10964e34249eSFelix Fietkau } 10974e34249eSFelix Fietkau 10983c1032e1SFelix Fietkau static void 109930ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 110030ce7f44SFelix Fietkau { 110130ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 110230ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 110330ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 1104a1b0bbd4SXing Song int security_idx; 110530ce7f44SFelix Fietkau int ret; 110630ce7f44SFelix Fietkau 110730ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 11083c1032e1SFelix Fietkau return; 110930ce7f44SFelix Fietkau 11101858e4fcSMeiChia Chiu if (status->flag & RX_FLAG_ONLY_MONITOR) 11113c1032e1SFelix Fietkau return; 11121858e4fcSMeiChia Chiu 111330ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 11143c1032e1SFelix Fietkau return; 111530ce7f44SFelix Fietkau 11167360cdecSFelix Fietkau security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 11177360cdecSFelix Fietkau if (status->flag & RX_FLAG_8023) 11187360cdecSFelix Fietkau goto skip_hdr_check; 11197360cdecSFelix Fietkau 1120a1b0bbd4SXing Song hdr = mt76_skb_get_hdr(skb); 112130ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 112230ce7f44SFelix Fietkau /* 112330ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 112430ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 112530ce7f44SFelix Fietkau */ 112630ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 112730ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 11283c1032e1SFelix Fietkau return; 112930ce7f44SFelix Fietkau } 113030ce7f44SFelix Fietkau 1131a1b0bbd4SXing Song /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): 1132a1b0bbd4SXing Song * 1133a1b0bbd4SXing Song * the recipient shall maintain a single replay counter for received 1134a1b0bbd4SXing Song * individually addressed robust Management frames that are received 1135a1b0bbd4SXing Song * with the To DS subfield equal to 0, [...] 1136a1b0bbd4SXing Song */ 1137a1b0bbd4SXing Song if (ieee80211_is_mgmt(hdr->frame_control) && 1138a1b0bbd4SXing Song !ieee80211_has_tods(hdr->frame_control)) 1139a1b0bbd4SXing Song security_idx = IEEE80211_NUM_TIDS; 1140a1b0bbd4SXing Song 11417360cdecSFelix Fietkau skip_hdr_check: 114230ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 1143a1b0bbd4SXing Song ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], 114430ce7f44SFelix Fietkau sizeof(status->iv)); 11453c1032e1SFelix Fietkau if (ret <= 0) { 11463c1032e1SFelix Fietkau status->flag |= RX_FLAG_ONLY_MONITOR; 11473c1032e1SFelix Fietkau return; 11483c1032e1SFelix Fietkau } 114930ce7f44SFelix Fietkau 1150a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); 115130ce7f44SFelix Fietkau 115230ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 115330ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 115430ce7f44SFelix Fietkau } 115530ce7f44SFelix Fietkau 1156d71ef286SFelix Fietkau static void 11575ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 11585ce09c1aSFelix Fietkau int len) 11595ce09c1aSFelix Fietkau { 11605ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 116185b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = { 116285b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags, 116385b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx, 116485b7a5d0SLorenzo Bianconi .encoding = status->encoding, 116585b7a5d0SLorenzo Bianconi .band = status->band, 116685b7a5d0SLorenzo Bianconi .nss = status->nss, 116785b7a5d0SLorenzo Bianconi .bw = status->bw, 116885b7a5d0SLorenzo Bianconi }; 11695ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 11705ce09c1aSFelix Fietkau u32 airtime; 1171e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 11725ce09c1aSFelix Fietkau 117385b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 1174237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 11755ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 1176237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 11775ce09c1aSFelix Fietkau 11785ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 11795ce09c1aSFelix Fietkau return; 11805ce09c1aSFelix Fietkau 11815ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1182e195dad1SFelix Fietkau ieee80211_sta_register_airtime(sta, tidno, 0, airtime); 11835ce09c1aSFelix Fietkau } 11845ce09c1aSFelix Fietkau 11855ce09c1aSFelix Fietkau static void 11865ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 11875ce09c1aSFelix Fietkau { 11885ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 11895ce09c1aSFelix Fietkau int wcid_idx; 11905ce09c1aSFelix Fietkau 11915ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 11925ce09c1aSFelix Fietkau return; 11935ce09c1aSFelix Fietkau 11945ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 1195bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 11965ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 11975ce09c1aSFelix Fietkau else 11985ce09c1aSFelix Fietkau wcid = NULL; 11995ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 12005ce09c1aSFelix Fietkau 12015ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 12025ce09c1aSFelix Fietkau 12035ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 12045ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 12055ce09c1aSFelix Fietkau } 12065ce09c1aSFelix Fietkau 12075ce09c1aSFelix Fietkau static void 12085ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 12095ce09c1aSFelix Fietkau { 12105ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 12115ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 12125ce09c1aSFelix Fietkau 12135ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 12145ce09c1aSFelix Fietkau return; 12155ce09c1aSFelix Fietkau 12165ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 1217e195dad1SFelix Fietkau struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1218e195dad1SFelix Fietkau 1219e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1220e195dad1SFelix Fietkau return; 1221e195dad1SFelix Fietkau 122298df2baeSLorenzo Bianconi if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) 12235ce09c1aSFelix Fietkau return; 12245ce09c1aSFelix Fietkau 12255ce09c1aSFelix Fietkau wcid = NULL; 12265ce09c1aSFelix Fietkau } 12275ce09c1aSFelix Fietkau 12285ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 12295ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 12305ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 12315ce09c1aSFelix Fietkau 12325ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 12335ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 12345ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 12355ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 12365ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 12375ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 12385ce09c1aSFelix Fietkau } 12395ce09c1aSFelix Fietkau 12405ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 12415ce09c1aSFelix Fietkau return; 12425ce09c1aSFelix Fietkau } 12435ce09c1aSFelix Fietkau 12445ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 12455ce09c1aSFelix Fietkau } 12465ce09c1aSFelix Fietkau 12475ce09c1aSFelix Fietkau static void 1248ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 1249d71ef286SFelix Fietkau { 1250d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 125177ae1d5eSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1252d71ef286SFelix Fietkau struct ieee80211_sta *sta; 1253bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 1254d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 1255e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 1256d71ef286SFelix Fietkau bool ps; 1257d71ef286SFelix Fietkau 1258128c9b7dSLorenzo Bianconi hw = mt76_phy_hw(dev, status->phy_idx); 1259e195dad1SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && 1260e195dad1SFelix Fietkau !(status->flag & RX_FLAG_8023)) { 1261bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 126236d91096SFelix Fietkau if (sta) 126336d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 126436d91096SFelix Fietkau } 126536d91096SFelix Fietkau 12665ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 12675ce09c1aSFelix Fietkau 1268d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 1269d71ef286SFelix Fietkau return; 1270d71ef286SFelix Fietkau 1271d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1272d71ef286SFelix Fietkau 127302e5a769SFelix Fietkau if (status->signal <= 0) 127402e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 127502e5a769SFelix Fietkau 1276ef13edc0SFelix Fietkau wcid->inactive_count = 0; 1277ef13edc0SFelix Fietkau 1278e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1279e195dad1SFelix Fietkau return; 1280e195dad1SFelix Fietkau 1281d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 1282d71ef286SFelix Fietkau return; 1283d71ef286SFelix Fietkau 1284d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 1285d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 1286d71ef286SFelix Fietkau return; 1287d71ef286SFelix Fietkau } 1288d71ef286SFelix Fietkau 1289d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 1290d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 1291d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 1292d71ef286SFelix Fietkau return; 1293d71ef286SFelix Fietkau 1294d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 1295d71ef286SFelix Fietkau 1296d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 1297d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 1298e195dad1SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, tidno); 1299d71ef286SFelix Fietkau 1300d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 1301d71ef286SFelix Fietkau return; 1302d71ef286SFelix Fietkau 130311b2a25fSFelix Fietkau if (ps) 1304d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 1305d71ef286SFelix Fietkau 1306d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 1307608f7c47SFelix Fietkau 1308608f7c47SFelix Fietkau if (!ps) 1309608f7c47SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 1310608f7c47SFelix Fietkau 13119f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 1312d71ef286SFelix Fietkau } 1313d71ef286SFelix Fietkau 13149d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 131581e850efSLorenzo Bianconi struct napi_struct *napi) 131617f1de56SFelix Fietkau { 13179c68a57bSFelix Fietkau struct ieee80211_sta *sta; 1318bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 13193298b1f8SFelix Fietkau struct sk_buff *skb, *tmp; 13203298b1f8SFelix Fietkau LIST_HEAD(list); 13219d9d738bSFelix Fietkau 1322c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 13239d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 1324cc4b3c13SLorenzo Bianconi struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 1325cc4b3c13SLorenzo Bianconi 13263c1032e1SFelix Fietkau mt76_check_ccmp_pn(skb); 1327cc4b3c13SLorenzo Bianconi skb_shinfo(skb)->frag_list = NULL; 1328bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta); 13293298b1f8SFelix Fietkau ieee80211_rx_list(hw, sta, skb, &list); 1330cc4b3c13SLorenzo Bianconi 1331cc4b3c13SLorenzo Bianconi /* subsequent amsdu frames */ 1332cc4b3c13SLorenzo Bianconi while (nskb) { 1333cc4b3c13SLorenzo Bianconi skb = nskb; 1334cc4b3c13SLorenzo Bianconi nskb = nskb->next; 1335cc4b3c13SLorenzo Bianconi skb->next = NULL; 1336cc4b3c13SLorenzo Bianconi 1337cc4b3c13SLorenzo Bianconi mt76_rx_convert(dev, skb, &hw, &sta); 1338cc4b3c13SLorenzo Bianconi ieee80211_rx_list(hw, sta, skb, &list); 1339cc4b3c13SLorenzo Bianconi } 13409d9d738bSFelix Fietkau } 1341c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 13423298b1f8SFelix Fietkau 13433298b1f8SFelix Fietkau if (!napi) { 13443298b1f8SFelix Fietkau netif_receive_skb_list(&list); 13453298b1f8SFelix Fietkau return; 13463298b1f8SFelix Fietkau } 13473298b1f8SFelix Fietkau 13483298b1f8SFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) { 13493298b1f8SFelix Fietkau skb_list_del_init(skb); 13503298b1f8SFelix Fietkau napi_gro_receive(napi, skb); 13513298b1f8SFelix Fietkau } 13529d9d738bSFelix Fietkau } 13539d9d738bSFelix Fietkau 135481e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 135581e850efSLorenzo Bianconi struct napi_struct *napi) 13569d9d738bSFelix Fietkau { 1357aee5b8cfSFelix Fietkau struct sk_buff_head frames; 135817f1de56SFelix Fietkau struct sk_buff *skb; 135917f1de56SFelix Fietkau 1360aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 1361aee5b8cfSFelix Fietkau 1362d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 1363ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 13644f831d18SLorenzo Bianconi if (mtk_wed_device_active(&dev->mmio.wed)) 13654f831d18SLorenzo Bianconi __skb_queue_tail(&frames, skb); 13664f831d18SLorenzo Bianconi else 1367aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 1368d71ef286SFelix Fietkau } 1369aee5b8cfSFelix Fietkau 137081e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 13714e34249eSFelix Fietkau } 137281e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 1373723b90dcSFelix Fietkau 1374e28487eaSFelix Fietkau static int 1375a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, 1376a1a99d7bSLorenzo Bianconi struct ieee80211_sta *sta) 1377e28487eaSFelix Fietkau { 1378e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 1379a1a99d7bSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 1380e28487eaSFelix Fietkau int ret; 1381e28487eaSFelix Fietkau int i; 1382e28487eaSFelix Fietkau 1383e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 1384e28487eaSFelix Fietkau 1385e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 1386e28487eaSFelix Fietkau if (ret) 1387e28487eaSFelix Fietkau goto out; 1388e28487eaSFelix Fietkau 1389e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 1390e28487eaSFelix Fietkau struct mt76_txq *mtxq; 1391e28487eaSFelix Fietkau 1392e28487eaSFelix Fietkau if (!sta->txq[i]) 1393e28487eaSFelix Fietkau continue; 1394e28487eaSFelix Fietkau 1395e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 139651fb1278SFelix Fietkau mtxq->wcid = wcid->idx; 1397e28487eaSFelix Fietkau } 1398e28487eaSFelix Fietkau 1399ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 1400a1a99d7bSLorenzo Bianconi if (phy->band_idx == MT_BAND1) 1401426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 1402a1a99d7bSLorenzo Bianconi wcid->phy_idx = phy->band_idx; 1403e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 1404e28487eaSFelix Fietkau 1405bd1e3e7bSLorenzo Bianconi mt76_packet_id_init(wcid); 1406e28487eaSFelix Fietkau out: 1407e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 1408e28487eaSFelix Fietkau 1409e28487eaSFelix Fietkau return ret; 1410e28487eaSFelix Fietkau } 1411e28487eaSFelix Fietkau 141213f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 1413723b90dcSFelix Fietkau struct ieee80211_sta *sta) 1414723b90dcSFelix Fietkau { 1415723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 141613f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 1417723b90dcSFelix Fietkau 141858bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 141958bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 142058bab0d4SFelix Fietkau 1421e28487eaSFelix Fietkau if (dev->drv->sta_remove) 1422e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 1423e28487eaSFelix Fietkau 1424bd1e3e7bSLorenzo Bianconi mt76_packet_id_flush(dev, wcid); 1425bd1e3e7bSLorenzo Bianconi 1426426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx); 1427426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 142813f61dfcSLorenzo Bianconi } 142913f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 1430e28487eaSFelix Fietkau 143113f61dfcSLorenzo Bianconi static void 143213f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 143313f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 143413f61dfcSLorenzo Bianconi { 143513f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 143613f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 1437723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 1438723b90dcSFelix Fietkau } 1439e28487eaSFelix Fietkau 1440e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1441e28487eaSFelix Fietkau struct ieee80211_sta *sta, 1442e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 1443e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 1444e28487eaSFelix Fietkau { 1445426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv; 1446426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev; 1447e28487eaSFelix Fietkau 1448e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 1449e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 1450a1a99d7bSLorenzo Bianconi return mt76_sta_add(phy, vif, sta); 1451e28487eaSFelix Fietkau 14529c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 14539c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 14549c193de5SFelix Fietkau dev->drv->sta_assoc) 14559c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 14569c193de5SFelix Fietkau 1457e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 1458e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 1459e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 1460e28487eaSFelix Fietkau 1461e28487eaSFelix Fietkau return 0; 1462e28487eaSFelix Fietkau } 1463e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 14649313faacSFelix Fietkau 146543ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 146643ba1922SFelix Fietkau struct ieee80211_sta *sta) 146743ba1922SFelix Fietkau { 146843ba1922SFelix Fietkau struct mt76_phy *phy = hw->priv; 146943ba1922SFelix Fietkau struct mt76_dev *dev = phy->dev; 147043ba1922SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 147143ba1922SFelix Fietkau 147243ba1922SFelix Fietkau mutex_lock(&dev->mutex); 1473fcfe1b5eSFelix Fietkau spin_lock_bh(&dev->status_lock); 147443ba1922SFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 1475fcfe1b5eSFelix Fietkau spin_unlock_bh(&dev->status_lock); 147643ba1922SFelix Fietkau mutex_unlock(&dev->mutex); 147743ba1922SFelix Fietkau } 147843ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 147943ba1922SFelix Fietkau 14809313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 14819313faacSFelix Fietkau int *dbm) 14829313faacSFelix Fietkau { 1483beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1484beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask); 148507cda406SFelix Fietkau int delta = mt76_tx_power_nss_delta(n_chains); 14869313faacSFelix Fietkau 148707cda406SFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 14889313faacSFelix Fietkau 14899313faacSFelix Fietkau return 0; 14909313faacSFelix Fietkau } 14919313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 1492e7173858SFelix Fietkau 1493b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw, 1494b3cb885eSLorenzo Bianconi const struct cfg80211_sar_specs *sar) 1495b3cb885eSLorenzo Bianconi { 1496b3cb885eSLorenzo Bianconi struct mt76_phy *phy = hw->priv; 1497b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; 1498b3cb885eSLorenzo Bianconi int i; 1499b3cb885eSLorenzo Bianconi 1500b3cb885eSLorenzo Bianconi if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) 1501b3cb885eSLorenzo Bianconi return -EINVAL; 1502b3cb885eSLorenzo Bianconi 1503b3cb885eSLorenzo Bianconi for (i = 0; i < sar->num_sub_specs; i++) { 1504b3cb885eSLorenzo Bianconi u32 index = sar->sub_specs[i].freq_range_index; 1505b3cb885eSLorenzo Bianconi /* SAR specifies power limitaton in 0.25dbm */ 1506b3cb885eSLorenzo Bianconi s32 power = sar->sub_specs[i].power >> 1; 1507b3cb885eSLorenzo Bianconi 1508b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1509b3cb885eSLorenzo Bianconi power = 127; 1510b3cb885eSLorenzo Bianconi 1511b3cb885eSLorenzo Bianconi phy->frp[index].range = &capa->freq_ranges[index]; 1512b3cb885eSLorenzo Bianconi phy->frp[index].power = power; 1513b3cb885eSLorenzo Bianconi } 1514b3cb885eSLorenzo Bianconi 1515b3cb885eSLorenzo Bianconi return 0; 1516b3cb885eSLorenzo Bianconi } 1517b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power); 1518b3cb885eSLorenzo Bianconi 1519b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy, 1520b3cb885eSLorenzo Bianconi struct ieee80211_channel *chan, 1521b3cb885eSLorenzo Bianconi int power) 1522b3cb885eSLorenzo Bianconi { 1523b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; 1524b3cb885eSLorenzo Bianconi int freq, i; 1525b3cb885eSLorenzo Bianconi 1526b3cb885eSLorenzo Bianconi if (!capa || !phy->frp) 1527b3cb885eSLorenzo Bianconi return power; 1528b3cb885eSLorenzo Bianconi 1529b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1530b3cb885eSLorenzo Bianconi power = 127; 1531b3cb885eSLorenzo Bianconi 1532b3cb885eSLorenzo Bianconi freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); 1533b3cb885eSLorenzo Bianconi for (i = 0 ; i < capa->num_freq_ranges; i++) { 1534b3cb885eSLorenzo Bianconi if (phy->frp[i].range && 1535b3cb885eSLorenzo Bianconi freq >= phy->frp[i].range->start_freq && 1536b3cb885eSLorenzo Bianconi freq < phy->frp[i].range->end_freq) { 1537b3cb885eSLorenzo Bianconi power = min_t(int, phy->frp[i].power, power); 1538b3cb885eSLorenzo Bianconi break; 1539b3cb885eSLorenzo Bianconi } 1540b3cb885eSLorenzo Bianconi } 1541b3cb885eSLorenzo Bianconi 1542b3cb885eSLorenzo Bianconi return power; 1543b3cb885eSLorenzo Bianconi } 1544b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power); 1545b3cb885eSLorenzo Bianconi 1546e7173858SFelix Fietkau static void 1547e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 1548e7173858SFelix Fietkau { 1549d0a9123eSJohannes Berg if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 1550e7173858SFelix Fietkau ieee80211_csa_finish(vif); 1551e7173858SFelix Fietkau } 1552e7173858SFelix Fietkau 1553e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 1554e7173858SFelix Fietkau { 1555e7173858SFelix Fietkau if (!dev->csa_complete) 1556e7173858SFelix Fietkau return; 1557e7173858SFelix Fietkau 1558e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1559e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1560e7173858SFelix Fietkau __mt76_csa_finish, dev); 1561e7173858SFelix Fietkau 1562e7173858SFelix Fietkau dev->csa_complete = 0; 1563e7173858SFelix Fietkau } 1564e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 1565e7173858SFelix Fietkau 1566e7173858SFelix Fietkau static void 1567e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 1568e7173858SFelix Fietkau { 1569e7173858SFelix Fietkau struct mt76_dev *dev = priv; 1570e7173858SFelix Fietkau 1571d0a9123eSJohannes Berg if (!vif->bss_conf.csa_active) 1572e7173858SFelix Fietkau return; 1573e7173858SFelix Fietkau 15748552a434SJohn Crispin dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 1575e7173858SFelix Fietkau } 1576e7173858SFelix Fietkau 1577e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 1578e7173858SFelix Fietkau { 1579e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1580e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1581e7173858SFelix Fietkau __mt76_csa_check, dev); 1582e7173858SFelix Fietkau } 1583e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 158487d53103SStanislaw Gruszka 158587d53103SStanislaw Gruszka int 158687d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 158787d53103SStanislaw Gruszka { 158887d53103SStanislaw Gruszka return 0; 158987d53103SStanislaw Gruszka } 159087d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 1591eadfd98fSLorenzo Bianconi 1592eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 1593eadfd98fSLorenzo Bianconi { 1594eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 1595eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 1596eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 1597eadfd98fSLorenzo Bianconi 1598eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 1599eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 1600eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 1601eadfd98fSLorenzo Bianconi 1602eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 1603eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 1604eadfd98fSLorenzo Bianconi hdr[2] = 0; 1605eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 1606eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 1607eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 1608eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 1609eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1610eadfd98fSLorenzo Bianconi 1611eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1612eadfd98fSLorenzo Bianconi } 1613eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1614d2679d65SLorenzo Bianconi 1615d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1616d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1617d2679d65SLorenzo Bianconi int idx, bool cck) 1618d2679d65SLorenzo Bianconi { 1619d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1620d2679d65SLorenzo Bianconi 1621d2679d65SLorenzo Bianconi if (cck) { 1622edf9dab8SLorenzo Bianconi if (sband != &dev->phy.sband_2g.sband) 1623d2679d65SLorenzo Bianconi return 0; 1624d2679d65SLorenzo Bianconi 1625d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 162696747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) { 1627d2679d65SLorenzo Bianconi offset = 4; 1628d2679d65SLorenzo Bianconi } 1629d2679d65SLorenzo Bianconi 1630d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1631d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1632d2679d65SLorenzo Bianconi return i; 1633d2679d65SLorenzo Bianconi } 1634d2679d65SLorenzo Bianconi 1635d2679d65SLorenzo Bianconi return 0; 1636d2679d65SLorenzo Bianconi } 1637d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 16388b8ab5c2SLorenzo Bianconi 16398b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 16408b8ab5c2SLorenzo Bianconi const u8 *mac) 16418b8ab5c2SLorenzo Bianconi { 1642011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 16438b8ab5c2SLorenzo Bianconi 1644011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state); 16458b8ab5c2SLorenzo Bianconi } 16468b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 16478b8ab5c2SLorenzo Bianconi 16488b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 16498b8ab5c2SLorenzo Bianconi { 1650011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 16518b8ab5c2SLorenzo Bianconi 1652011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state); 16538b8ab5c2SLorenzo Bianconi } 16548b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1655e49c76d4SLorenzo Bianconi 1656e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1657e49c76d4SLorenzo Bianconi { 1658beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1659beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev; 1660e49c76d4SLorenzo Bianconi 1661e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1662beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask; 1663beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask; 1664e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1665e49c76d4SLorenzo Bianconi 1666e49c76d4SLorenzo Bianconi return 0; 1667e49c76d4SLorenzo Bianconi } 1668e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1669b671da33SLorenzo Bianconi 1670b1cb42adSLorenzo Bianconi struct mt76_queue * 1671b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, 1672f68d6762SFelix Fietkau int ring_base, u32 flags) 1673b671da33SLorenzo Bianconi { 1674b671da33SLorenzo Bianconi struct mt76_queue *hwq; 1675b671da33SLorenzo Bianconi int err; 1676b671da33SLorenzo Bianconi 1677b671da33SLorenzo Bianconi hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); 1678b671da33SLorenzo Bianconi if (!hwq) 1679b1cb42adSLorenzo Bianconi return ERR_PTR(-ENOMEM); 1680b671da33SLorenzo Bianconi 1681f68d6762SFelix Fietkau hwq->flags = flags; 1682f68d6762SFelix Fietkau 1683b671da33SLorenzo Bianconi err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); 1684b671da33SLorenzo Bianconi if (err < 0) 1685b1cb42adSLorenzo Bianconi return ERR_PTR(err); 1686b671da33SLorenzo Bianconi 1687b1cb42adSLorenzo Bianconi return hwq; 1688b671da33SLorenzo Bianconi } 1689b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue); 1690e4867225SSean Wang 169133920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) 1692e4867225SSean Wang { 169333920b2bSRyder Lee int offset = 0; 1694e4867225SSean Wang 1695edf9dab8SLorenzo Bianconi if (phy->chandef.chan->band != NL80211_BAND_2GHZ) 1696e4867225SSean Wang offset = 4; 1697e4867225SSean Wang 169833920b2bSRyder Lee /* pick the lowest rate for hidden nodes */ 169933920b2bSRyder Lee if (rateidx < 0) 170033920b2bSRyder Lee rateidx = 0; 170133920b2bSRyder Lee 1702d4f3d1c4SLorenzo Bianconi rateidx += offset; 1703d4f3d1c4SLorenzo Bianconi if (rateidx >= ARRAY_SIZE(mt76_rates)) 1704d4f3d1c4SLorenzo Bianconi rateidx = offset; 1705e4867225SSean Wang 1706d4f3d1c4SLorenzo Bianconi return mt76_rates[rateidx].hw_value; 1707e4867225SSean Wang } 170833920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); 170954ae98ffSLorenzo Bianconi 171054ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, 1711731425f3SShayne Chen struct mt76_sta_stats *stats, bool eht) 171254ae98ffSLorenzo Bianconi { 171354ae98ffSLorenzo Bianconi int i, ei = wi->initial_stat_idx; 171454ae98ffSLorenzo Bianconi u64 *data = wi->data; 171554ae98ffSLorenzo Bianconi 171654ae98ffSLorenzo Bianconi wi->sta_count++; 171754ae98ffSLorenzo Bianconi 171854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; 171954ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; 172054ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; 172154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; 172254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; 172354ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; 172454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; 172554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; 172654ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; 1727731425f3SShayne Chen if (eht) { 1728731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU]; 1729731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG]; 1730731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU]; 1731731425f3SShayne Chen } 173254ae98ffSLorenzo Bianconi 1733731425f3SShayne Chen for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++) 173454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_bw[i]; 173554ae98ffSLorenzo Bianconi 1736731425f3SShayne Chen for (i = 0; i < (eht ? 14 : 12); i++) 173754ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mcs[i]; 173854ae98ffSLorenzo Bianconi 173954ae98ffSLorenzo Bianconi wi->worker_stat_count = ei - wi->initial_stat_idx; 174054ae98ffSLorenzo Bianconi } 174154ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker); 17423f306448SFelix Fietkau 1743192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index) 1744192ad406SLorenzo Bianconi { 1745192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS 1746192ad406SLorenzo Bianconi struct page_pool_stats stats = {}; 1747192ad406SLorenzo Bianconi int i; 1748192ad406SLorenzo Bianconi 1749192ad406SLorenzo Bianconi mt76_for_each_q_rx(dev, i) 1750192ad406SLorenzo Bianconi page_pool_get_stats(dev->q_rx[i].page_pool, &stats); 1751192ad406SLorenzo Bianconi 1752192ad406SLorenzo Bianconi page_pool_ethtool_stats_get(data, &stats); 1753192ad406SLorenzo Bianconi *index += page_pool_ethtool_stats_get_count(); 1754192ad406SLorenzo Bianconi #endif 1755192ad406SLorenzo Bianconi } 1756192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats); 1757192ad406SLorenzo Bianconi 17583f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) 17593f306448SFelix Fietkau { 17603f306448SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 17613f306448SFelix Fietkau struct mt76_dev *dev = phy->dev; 17623f306448SFelix Fietkau 17633f306448SFelix Fietkau if (dev->region == NL80211_DFS_UNSET || 17643f306448SFelix Fietkau test_bit(MT76_SCANNING, &phy->state)) 17653f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 17663f306448SFelix Fietkau 17673f306448SFelix Fietkau if (!hw->conf.radar_enabled) { 17683f306448SFelix Fietkau if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && 17693f306448SFelix Fietkau (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) 17703f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 17713f306448SFelix Fietkau 17723f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 17733f306448SFelix Fietkau } 17743f306448SFelix Fietkau 177500a883e6SFelix Fietkau if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) 17763f306448SFelix Fietkau return MT_DFS_STATE_CAC; 17773f306448SFelix Fietkau 17783f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 17793f306448SFelix Fietkau } 17803f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); 1781