10e3d6777SRyder Lee // SPDX-License-Identifier: ISC 217f1de56SFelix Fietkau /* 317f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 417f1de56SFelix Fietkau */ 5781eef5bSFelix Fietkau #include <linux/sched.h> 617f1de56SFelix Fietkau #include <linux/of.h> 717f1de56SFelix Fietkau #include "mt76.h" 817f1de56SFelix Fietkau 917f1de56SFelix Fietkau #define CHAN2G(_idx, _freq) { \ 1017f1de56SFelix Fietkau .band = NL80211_BAND_2GHZ, \ 1117f1de56SFelix Fietkau .center_freq = (_freq), \ 1217f1de56SFelix Fietkau .hw_value = (_idx), \ 1317f1de56SFelix Fietkau .max_power = 30, \ 1417f1de56SFelix Fietkau } 1517f1de56SFelix Fietkau 1617f1de56SFelix Fietkau #define CHAN5G(_idx, _freq) { \ 1717f1de56SFelix Fietkau .band = NL80211_BAND_5GHZ, \ 1817f1de56SFelix Fietkau .center_freq = (_freq), \ 1917f1de56SFelix Fietkau .hw_value = (_idx), \ 2017f1de56SFelix Fietkau .max_power = 30, \ 2117f1de56SFelix Fietkau } 2217f1de56SFelix Fietkau 23edf9dab8SLorenzo Bianconi #define CHAN6G(_idx, _freq) { \ 24edf9dab8SLorenzo Bianconi .band = NL80211_BAND_6GHZ, \ 25edf9dab8SLorenzo Bianconi .center_freq = (_freq), \ 26edf9dab8SLorenzo Bianconi .hw_value = (_idx), \ 27edf9dab8SLorenzo Bianconi .max_power = 30, \ 28edf9dab8SLorenzo Bianconi } 29edf9dab8SLorenzo Bianconi 3017f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_2ghz[] = { 3117f1de56SFelix Fietkau CHAN2G(1, 2412), 3217f1de56SFelix Fietkau CHAN2G(2, 2417), 3317f1de56SFelix Fietkau CHAN2G(3, 2422), 3417f1de56SFelix Fietkau CHAN2G(4, 2427), 3517f1de56SFelix Fietkau CHAN2G(5, 2432), 3617f1de56SFelix Fietkau CHAN2G(6, 2437), 3717f1de56SFelix Fietkau CHAN2G(7, 2442), 3817f1de56SFelix Fietkau CHAN2G(8, 2447), 3917f1de56SFelix Fietkau CHAN2G(9, 2452), 4017f1de56SFelix Fietkau CHAN2G(10, 2457), 4117f1de56SFelix Fietkau CHAN2G(11, 2462), 4217f1de56SFelix Fietkau CHAN2G(12, 2467), 4317f1de56SFelix Fietkau CHAN2G(13, 2472), 4417f1de56SFelix Fietkau CHAN2G(14, 2484), 4517f1de56SFelix Fietkau }; 4617f1de56SFelix Fietkau 4717f1de56SFelix Fietkau static const struct ieee80211_channel mt76_channels_5ghz[] = { 4817f1de56SFelix Fietkau CHAN5G(36, 5180), 4917f1de56SFelix Fietkau CHAN5G(40, 5200), 5017f1de56SFelix Fietkau CHAN5G(44, 5220), 5117f1de56SFelix Fietkau CHAN5G(48, 5240), 5217f1de56SFelix Fietkau 5317f1de56SFelix Fietkau CHAN5G(52, 5260), 5417f1de56SFelix Fietkau CHAN5G(56, 5280), 5517f1de56SFelix Fietkau CHAN5G(60, 5300), 5617f1de56SFelix Fietkau CHAN5G(64, 5320), 5717f1de56SFelix Fietkau 5817f1de56SFelix Fietkau CHAN5G(100, 5500), 5917f1de56SFelix Fietkau CHAN5G(104, 5520), 6017f1de56SFelix Fietkau CHAN5G(108, 5540), 6117f1de56SFelix Fietkau CHAN5G(112, 5560), 6217f1de56SFelix Fietkau CHAN5G(116, 5580), 6317f1de56SFelix Fietkau CHAN5G(120, 5600), 6417f1de56SFelix Fietkau CHAN5G(124, 5620), 6517f1de56SFelix Fietkau CHAN5G(128, 5640), 6617f1de56SFelix Fietkau CHAN5G(132, 5660), 6717f1de56SFelix Fietkau CHAN5G(136, 5680), 6817f1de56SFelix Fietkau CHAN5G(140, 5700), 699da82fb7SMarkus Theil CHAN5G(144, 5720), 7017f1de56SFelix Fietkau 7117f1de56SFelix Fietkau CHAN5G(149, 5745), 7217f1de56SFelix Fietkau CHAN5G(153, 5765), 7317f1de56SFelix Fietkau CHAN5G(157, 5785), 7417f1de56SFelix Fietkau CHAN5G(161, 5805), 7517f1de56SFelix Fietkau CHAN5G(165, 5825), 769da82fb7SMarkus Theil CHAN5G(169, 5845), 779da82fb7SMarkus Theil CHAN5G(173, 5865), 7862561a47SRyder Lee CHAN5G(177, 5885), 7917f1de56SFelix Fietkau }; 8017f1de56SFelix Fietkau 81edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = { 82edf9dab8SLorenzo Bianconi /* UNII-5 */ 83edf9dab8SLorenzo Bianconi CHAN6G(1, 5955), 84edf9dab8SLorenzo Bianconi CHAN6G(5, 5975), 85edf9dab8SLorenzo Bianconi CHAN6G(9, 5995), 86edf9dab8SLorenzo Bianconi CHAN6G(13, 6015), 87edf9dab8SLorenzo Bianconi CHAN6G(17, 6035), 88edf9dab8SLorenzo Bianconi CHAN6G(21, 6055), 89edf9dab8SLorenzo Bianconi CHAN6G(25, 6075), 90edf9dab8SLorenzo Bianconi CHAN6G(29, 6095), 91edf9dab8SLorenzo Bianconi CHAN6G(33, 6115), 92edf9dab8SLorenzo Bianconi CHAN6G(37, 6135), 93edf9dab8SLorenzo Bianconi CHAN6G(41, 6155), 94edf9dab8SLorenzo Bianconi CHAN6G(45, 6175), 95edf9dab8SLorenzo Bianconi CHAN6G(49, 6195), 96edf9dab8SLorenzo Bianconi CHAN6G(53, 6215), 97edf9dab8SLorenzo Bianconi CHAN6G(57, 6235), 98edf9dab8SLorenzo Bianconi CHAN6G(61, 6255), 99edf9dab8SLorenzo Bianconi CHAN6G(65, 6275), 100edf9dab8SLorenzo Bianconi CHAN6G(69, 6295), 101edf9dab8SLorenzo Bianconi CHAN6G(73, 6315), 102edf9dab8SLorenzo Bianconi CHAN6G(77, 6335), 103edf9dab8SLorenzo Bianconi CHAN6G(81, 6355), 104edf9dab8SLorenzo Bianconi CHAN6G(85, 6375), 105edf9dab8SLorenzo Bianconi CHAN6G(89, 6395), 106edf9dab8SLorenzo Bianconi CHAN6G(93, 6415), 107edf9dab8SLorenzo Bianconi /* UNII-6 */ 108edf9dab8SLorenzo Bianconi CHAN6G(97, 6435), 109edf9dab8SLorenzo Bianconi CHAN6G(101, 6455), 110edf9dab8SLorenzo Bianconi CHAN6G(105, 6475), 111edf9dab8SLorenzo Bianconi CHAN6G(109, 6495), 112edf9dab8SLorenzo Bianconi CHAN6G(113, 6515), 113edf9dab8SLorenzo Bianconi CHAN6G(117, 6535), 114edf9dab8SLorenzo Bianconi /* UNII-7 */ 115edf9dab8SLorenzo Bianconi CHAN6G(121, 6555), 116edf9dab8SLorenzo Bianconi CHAN6G(125, 6575), 117edf9dab8SLorenzo Bianconi CHAN6G(129, 6595), 118edf9dab8SLorenzo Bianconi CHAN6G(133, 6615), 119edf9dab8SLorenzo Bianconi CHAN6G(137, 6635), 120edf9dab8SLorenzo Bianconi CHAN6G(141, 6655), 121edf9dab8SLorenzo Bianconi CHAN6G(145, 6675), 122edf9dab8SLorenzo Bianconi CHAN6G(149, 6695), 123edf9dab8SLorenzo Bianconi CHAN6G(153, 6715), 124edf9dab8SLorenzo Bianconi CHAN6G(157, 6735), 125edf9dab8SLorenzo Bianconi CHAN6G(161, 6755), 126edf9dab8SLorenzo Bianconi CHAN6G(165, 6775), 127edf9dab8SLorenzo Bianconi CHAN6G(169, 6795), 128edf9dab8SLorenzo Bianconi CHAN6G(173, 6815), 129edf9dab8SLorenzo Bianconi CHAN6G(177, 6835), 130edf9dab8SLorenzo Bianconi CHAN6G(181, 6855), 131edf9dab8SLorenzo Bianconi CHAN6G(185, 6875), 132edf9dab8SLorenzo Bianconi /* UNII-8 */ 133edf9dab8SLorenzo Bianconi CHAN6G(189, 6895), 134edf9dab8SLorenzo Bianconi CHAN6G(193, 6915), 135edf9dab8SLorenzo Bianconi CHAN6G(197, 6935), 136edf9dab8SLorenzo Bianconi CHAN6G(201, 6955), 137edf9dab8SLorenzo Bianconi CHAN6G(205, 6975), 138edf9dab8SLorenzo Bianconi CHAN6G(209, 6995), 139edf9dab8SLorenzo Bianconi CHAN6G(213, 7015), 140edf9dab8SLorenzo Bianconi CHAN6G(217, 7035), 141edf9dab8SLorenzo Bianconi CHAN6G(221, 7055), 142edf9dab8SLorenzo Bianconi CHAN6G(225, 7075), 143edf9dab8SLorenzo Bianconi CHAN6G(229, 7095), 144edf9dab8SLorenzo Bianconi CHAN6G(233, 7115), 145edf9dab8SLorenzo Bianconi }; 146edf9dab8SLorenzo Bianconi 14717f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 14817f1de56SFelix Fietkau { .throughput = 0 * 1024, .blink_time = 334 }, 14917f1de56SFelix Fietkau { .throughput = 1 * 1024, .blink_time = 260 }, 15017f1de56SFelix Fietkau { .throughput = 5 * 1024, .blink_time = 220 }, 15117f1de56SFelix Fietkau { .throughput = 10 * 1024, .blink_time = 190 }, 15217f1de56SFelix Fietkau { .throughput = 20 * 1024, .blink_time = 170 }, 15317f1de56SFelix Fietkau { .throughput = 50 * 1024, .blink_time = 150 }, 15417f1de56SFelix Fietkau { .throughput = 70 * 1024, .blink_time = 130 }, 15517f1de56SFelix Fietkau { .throughput = 100 * 1024, .blink_time = 110 }, 15617f1de56SFelix Fietkau { .throughput = 200 * 1024, .blink_time = 80 }, 15717f1de56SFelix Fietkau { .throughput = 300 * 1024, .blink_time = 50 }, 15817f1de56SFelix Fietkau }; 15917f1de56SFelix Fietkau 16054b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = { 16154b8fdebSLorenzo Bianconi CCK_RATE(0, 10), 16254b8fdebSLorenzo Bianconi CCK_RATE(1, 20), 16354b8fdebSLorenzo Bianconi CCK_RATE(2, 55), 16454b8fdebSLorenzo Bianconi CCK_RATE(3, 110), 16554b8fdebSLorenzo Bianconi OFDM_RATE(11, 60), 16654b8fdebSLorenzo Bianconi OFDM_RATE(15, 90), 16754b8fdebSLorenzo Bianconi OFDM_RATE(10, 120), 16854b8fdebSLorenzo Bianconi OFDM_RATE(14, 180), 16954b8fdebSLorenzo Bianconi OFDM_RATE(9, 240), 17054b8fdebSLorenzo Bianconi OFDM_RATE(13, 360), 17154b8fdebSLorenzo Bianconi OFDM_RATE(8, 480), 17254b8fdebSLorenzo Bianconi OFDM_RATE(12, 540), 17354b8fdebSLorenzo Bianconi }; 17454b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates); 17554b8fdebSLorenzo Bianconi 176502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { 177502604f5SYN Chen { .start_freq = 2402, .end_freq = 2494, }, 178502604f5SYN Chen { .start_freq = 5150, .end_freq = 5350, }, 179502604f5SYN Chen { .start_freq = 5350, .end_freq = 5470, }, 180502604f5SYN Chen { .start_freq = 5470, .end_freq = 5725, }, 181502604f5SYN Chen { .start_freq = 5725, .end_freq = 5950, }, 182162d5c14SDeren Wu { .start_freq = 5945, .end_freq = 6165, }, 183162d5c14SDeren Wu { .start_freq = 6165, .end_freq = 6405, }, 184162d5c14SDeren Wu { .start_freq = 6405, .end_freq = 6525, }, 185162d5c14SDeren Wu { .start_freq = 6525, .end_freq = 6705, }, 186162d5c14SDeren Wu { .start_freq = 6705, .end_freq = 6865, }, 187162d5c14SDeren Wu { .start_freq = 6865, .end_freq = 7125, }, 188502604f5SYN Chen }; 189502604f5SYN Chen 19097f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = { 191502604f5SYN Chen .type = NL80211_SAR_TYPE_POWER, 192502604f5SYN Chen .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), 193502604f5SYN Chen .freq_ranges = &mt76_sar_freq_ranges[0], 194502604f5SYN Chen }; 195502604f5SYN Chen 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; 200*14cdeaf9SRyder Lee struct device_node *np = dev->dev->of_node; 20117f1de56SFelix Fietkau 2023abd46ddSLorenzo Bianconi if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) 20317f1de56SFelix Fietkau return 0; 20417f1de56SFelix Fietkau 205*14cdeaf9SRyder Lee np = of_get_child_by_name(np, "led"); 206*14cdeaf9SRyder Lee if (np) { 207*14cdeaf9SRyder Lee if (!of_device_is_available(np)) { 208*14cdeaf9SRyder Lee of_node_put(np); 209*14cdeaf9SRyder Lee dev_info(dev->dev, 210*14cdeaf9SRyder Lee "led registration was explicitly disabled by dts\n"); 211*14cdeaf9SRyder Lee return 0; 212*14cdeaf9SRyder Lee } 213*14cdeaf9SRyder Lee 214*14cdeaf9SRyder Lee if (phy == &dev->phy) { 215*14cdeaf9SRyder Lee int led_pin; 216*14cdeaf9SRyder Lee 217*14cdeaf9SRyder Lee if (!of_property_read_u32(np, "led-sources", &led_pin)) 218*14cdeaf9SRyder Lee phy->leds.pin = led_pin; 219*14cdeaf9SRyder Lee 220*14cdeaf9SRyder Lee phy->leds.al = 221*14cdeaf9SRyder Lee of_property_read_bool(np, "led-active-low"); 222*14cdeaf9SRyder Lee } 223*14cdeaf9SRyder Lee 224*14cdeaf9SRyder Lee of_node_put(np); 225*14cdeaf9SRyder Lee } 226*14cdeaf9SRyder Lee 2273abd46ddSLorenzo Bianconi snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s", 2283abd46ddSLorenzo Bianconi wiphy_name(hw->wiphy)); 22917f1de56SFelix Fietkau 2303abd46ddSLorenzo Bianconi phy->leds.cdev.name = phy->leds.name; 2313abd46ddSLorenzo Bianconi phy->leds.cdev.default_trigger = 23217f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 23317f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 23417f1de56SFelix Fietkau mt76_tpt_blink, 23517f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 23617f1de56SFelix Fietkau 237*14cdeaf9SRyder Lee dev_info(dev->dev, 238*14cdeaf9SRyder Lee "registering led '%s'\n", phy->leds.name); 23936f7e2b2SFelix Fietkau 2403abd46ddSLorenzo Bianconi return led_classdev_register(dev->dev, &phy->leds.cdev); 2413abd46ddSLorenzo Bianconi } 2423abd46ddSLorenzo Bianconi 2433abd46ddSLorenzo Bianconi static void mt76_led_cleanup(struct mt76_phy *phy) 24436f7e2b2SFelix Fietkau { 2453abd46ddSLorenzo Bianconi if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set) 24636f7e2b2SFelix Fietkau return; 24736f7e2b2SFelix Fietkau 2483abd46ddSLorenzo Bianconi led_classdev_unregister(&phy->leds.cdev); 24917f1de56SFelix Fietkau } 25017f1de56SFelix Fietkau 251bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy, 252551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 253551e1ef4SLorenzo Bianconi bool vht) 254551e1ef4SLorenzo Bianconi { 255551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 256bb3e3fecSRyder Lee int i, nstream = hweight8(phy->antenna_mask); 257551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 258551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 259551e1ef4SLorenzo Bianconi 260551e1ef4SLorenzo Bianconi if (nstream > 1) 261551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 262551e1ef4SLorenzo Bianconi else 263551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 264551e1ef4SLorenzo Bianconi 265551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 266551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 267551e1ef4SLorenzo Bianconi 268551e1ef4SLorenzo Bianconi if (!vht) 269551e1ef4SLorenzo Bianconi return; 270551e1ef4SLorenzo Bianconi 271551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 272551e1ef4SLorenzo Bianconi if (nstream > 1) 273551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 274551e1ef4SLorenzo Bianconi else 275551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 276abba3453SDeren Wu vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 277abba3453SDeren Wu IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; 278551e1ef4SLorenzo Bianconi 279551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 280551e1ef4SLorenzo Bianconi if (i < nstream) 281551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 282551e1ef4SLorenzo Bianconi else 283551e1ef4SLorenzo Bianconi mcs_map |= 284551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 285551e1ef4SLorenzo Bianconi } 286551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 287551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 288781b80f4SFelix Fietkau if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW)) 289d9fcfc14SDeren Wu vht_cap->vht_mcs.tx_highest |= 290d9fcfc14SDeren Wu cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); 291551e1ef4SLorenzo Bianconi } 292551e1ef4SLorenzo Bianconi 293bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 2945ebdc3e0SLorenzo Bianconi { 29548dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) 296bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 29748dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) 298bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 299edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) 300edf9dab8SLorenzo Bianconi mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); 3015ebdc3e0SLorenzo Bianconi } 3025ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 3035ebdc3e0SLorenzo Bianconi 30417f1de56SFelix Fietkau static int 30577af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, 30617f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 307edf9dab8SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates, 308edf9dab8SLorenzo Bianconi bool ht, bool vht) 30917f1de56SFelix Fietkau { 31017f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 31117f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 31277af762eSLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap; 31377af762eSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 31417f1de56SFelix Fietkau void *chanlist; 31517f1de56SFelix Fietkau int size; 31617f1de56SFelix Fietkau 31717f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 31817f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 31917f1de56SFelix Fietkau if (!chanlist) 32017f1de56SFelix Fietkau return -ENOMEM; 32117f1de56SFelix Fietkau 322a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 32317f1de56SFelix Fietkau GFP_KERNEL); 32417f1de56SFelix Fietkau if (!msband->chan) 32517f1de56SFelix Fietkau return -ENOMEM; 32617f1de56SFelix Fietkau 32717f1de56SFelix Fietkau sband->channels = chanlist; 32817f1de56SFelix Fietkau sband->n_channels = n_chan; 32917f1de56SFelix Fietkau sband->bitrates = rates; 33017f1de56SFelix Fietkau sband->n_bitrates = n_rates; 33117f1de56SFelix Fietkau 332edf9dab8SLorenzo Bianconi if (!ht) 333edf9dab8SLorenzo Bianconi return 0; 334edf9dab8SLorenzo Bianconi 33517f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 33617f1de56SFelix Fietkau ht_cap->ht_supported = true; 33717f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 33817f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 33917f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 34017f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 34117f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 34217f1de56SFelix Fietkau 34317f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 34417f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 34517f1de56SFelix Fietkau 34677af762eSLorenzo Bianconi mt76_init_stream_cap(phy, sband, vht); 347551e1ef4SLorenzo Bianconi 34817f1de56SFelix Fietkau if (!vht) 34917f1de56SFelix Fietkau return 0; 35017f1de56SFelix Fietkau 35117f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 35217f1de56SFelix Fietkau vht_cap->vht_supported = true; 35317f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 35417f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 35549149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 35649149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 35717f1de56SFelix Fietkau 35817f1de56SFelix Fietkau return 0; 35917f1de56SFelix Fietkau } 36017f1de56SFelix Fietkau 36117f1de56SFelix Fietkau static int 36277af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, 36317f1de56SFelix Fietkau int n_rates) 36417f1de56SFelix Fietkau { 36577af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 36617f1de56SFelix Fietkau 36777af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, 36877af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_2ghz), rates, 369edf9dab8SLorenzo Bianconi n_rates, true, false); 37017f1de56SFelix Fietkau } 37117f1de56SFelix Fietkau 37217f1de56SFelix Fietkau static int 37377af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, 37417f1de56SFelix Fietkau int n_rates, bool vht) 37517f1de56SFelix Fietkau { 37677af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 37717f1de56SFelix Fietkau 37877af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, 37977af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_5ghz), rates, 380edf9dab8SLorenzo Bianconi n_rates, true, vht); 381edf9dab8SLorenzo Bianconi } 382edf9dab8SLorenzo Bianconi 383edf9dab8SLorenzo Bianconi static int 384edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, 385edf9dab8SLorenzo Bianconi int n_rates) 386edf9dab8SLorenzo Bianconi { 387edf9dab8SLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; 388edf9dab8SLorenzo Bianconi 389edf9dab8SLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, 390edf9dab8SLorenzo Bianconi ARRAY_SIZE(mt76_channels_6ghz), rates, 391edf9dab8SLorenzo Bianconi n_rates, false, false); 39217f1de56SFelix Fietkau } 39317f1de56SFelix Fietkau 39417f1de56SFelix Fietkau static void 395c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 396c89d3625SFelix Fietkau enum nl80211_band band) 39717f1de56SFelix Fietkau { 398c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 39917f1de56SFelix Fietkau bool found = false; 40017f1de56SFelix Fietkau int i; 40117f1de56SFelix Fietkau 40217f1de56SFelix Fietkau if (!sband) 40317f1de56SFelix Fietkau return; 40417f1de56SFelix Fietkau 40517f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 40617f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 40717f1de56SFelix Fietkau continue; 40817f1de56SFelix Fietkau 40917f1de56SFelix Fietkau found = true; 41017f1de56SFelix Fietkau break; 41117f1de56SFelix Fietkau } 41217f1de56SFelix Fietkau 413c89d3625SFelix Fietkau if (found) { 414c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0]; 415c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0]; 41617f1de56SFelix Fietkau return; 417c89d3625SFelix Fietkau } 41817f1de56SFelix Fietkau 41917f1de56SFelix Fietkau sband->n_channels = 0; 420c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL; 42117f1de56SFelix Fietkau } 42217f1de56SFelix Fietkau 423d43de9cfSLorenzo Bianconi static int 42498df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) 425c89d3625SFelix Fietkau { 42698df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 427c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 428c89d3625SFelix Fietkau 4290335c034SFelix Fietkau INIT_LIST_HEAD(&phy->tx_list); 4300335c034SFelix Fietkau spin_lock_init(&phy->tx_lock); 4310335c034SFelix Fietkau 432c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 43398df2baeSLorenzo Bianconi SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); 434c89d3625SFelix Fietkau 435c278a64aSRyder Lee wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 436c278a64aSRyder Lee NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; 437dd89a013SLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 438b807b368SLorenzo Bianconi WIPHY_FLAG_SUPPORTS_TDLS | 439b807b368SLorenzo Bianconi WIPHY_FLAG_AP_UAPSD; 440c89d3625SFelix Fietkau 441c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 442c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 443d9c54264SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 444c89d3625SFelix Fietkau 4450a57d636SBo Jiao wiphy->available_antennas_tx = phy->antenna_mask; 4460a57d636SBo Jiao wiphy->available_antennas_rx = phy->antenna_mask; 447c89d3625SFelix Fietkau 448d43de9cfSLorenzo Bianconi wiphy->sar_capa = &mt76_sar_capa; 449d43de9cfSLorenzo Bianconi phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, 450d43de9cfSLorenzo Bianconi sizeof(struct mt76_freq_range_power), 451d43de9cfSLorenzo Bianconi GFP_KERNEL); 452d43de9cfSLorenzo Bianconi if (!phy->frp) 453d43de9cfSLorenzo Bianconi return -ENOMEM; 454d43de9cfSLorenzo Bianconi 455c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 456b807b368SLorenzo Bianconi hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 457c9619dfaSShayne Chen 458c9619dfaSShayne Chen if (!hw->max_tx_fragments) 459c89d3625SFelix Fietkau hw->max_tx_fragments = 16; 460c89d3625SFelix Fietkau 461c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 462c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 463c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 464c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 465c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 466c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 467ed89b893SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 4685b0fb852SBen Greear 469c2fcc83bSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD) && 470c2fcc83bSFelix Fietkau hw->max_tx_fragments > 1) { 471c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 472c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 4735b0fb852SBen Greear } 4745b0fb852SBen Greear 475c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 476c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 477c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 478d43de9cfSLorenzo Bianconi 479d43de9cfSLorenzo Bianconi return 0; 480c89d3625SFelix Fietkau } 481c89d3625SFelix Fietkau 482c89d3625SFelix Fietkau struct mt76_phy * 483c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 484dc44c45cSLorenzo Bianconi const struct ieee80211_ops *ops, u8 band_idx) 485c89d3625SFelix Fietkau { 486c89d3625SFelix Fietkau struct ieee80211_hw *hw; 487db78a791SLorenzo Bianconi unsigned int phy_size; 488c89d3625SFelix Fietkau struct mt76_phy *phy; 489c89d3625SFelix Fietkau 490c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8); 491db78a791SLorenzo Bianconi hw = ieee80211_alloc_hw(size + phy_size, ops); 492c89d3625SFelix Fietkau if (!hw) 493c89d3625SFelix Fietkau return NULL; 494c89d3625SFelix Fietkau 495c89d3625SFelix Fietkau phy = hw->priv; 496c89d3625SFelix Fietkau phy->dev = dev; 497c89d3625SFelix Fietkau phy->hw = hw; 498db78a791SLorenzo Bianconi phy->priv = hw->priv + phy_size; 499dc44c45cSLorenzo Bianconi phy->band_idx = band_idx; 500c89d3625SFelix Fietkau 5018af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 5028af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 5038af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 5048af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 5058af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 5068af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 5078af414e8SLorenzo Bianconi #endif 5088af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 5098af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 5108af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 5118af414e8SLorenzo Bianconi 512c89d3625SFelix Fietkau return phy; 513c89d3625SFelix Fietkau } 514c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy); 515c89d3625SFelix Fietkau 516db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht, 517db78a791SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates) 518c89d3625SFelix Fietkau { 519c89d3625SFelix Fietkau int ret; 520c89d3625SFelix Fietkau 521d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, phy->hw); 522d43de9cfSLorenzo Bianconi if (ret) 523d43de9cfSLorenzo Bianconi return ret; 524db78a791SLorenzo Bianconi 525db78a791SLorenzo Bianconi if (phy->cap.has_2ghz) { 526db78a791SLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 527db78a791SLorenzo Bianconi if (ret) 528db78a791SLorenzo Bianconi return ret; 529db78a791SLorenzo Bianconi } 530db78a791SLorenzo Bianconi 531db78a791SLorenzo Bianconi if (phy->cap.has_5ghz) { 532db78a791SLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 533db78a791SLorenzo Bianconi if (ret) 534db78a791SLorenzo Bianconi return ret; 535db78a791SLorenzo Bianconi } 536db78a791SLorenzo Bianconi 537edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 538edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 539edf9dab8SLorenzo Bianconi if (ret) 540edf9dab8SLorenzo Bianconi return ret; 541edf9dab8SLorenzo Bianconi } 542edf9dab8SLorenzo Bianconi 5439e81c2c7SLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS)) { 5449e81c2c7SLorenzo Bianconi ret = mt76_led_init(phy); 5459e81c2c7SLorenzo Bianconi if (ret) 5469e81c2c7SLorenzo Bianconi return ret; 5479e81c2c7SLorenzo Bianconi } 5489e81c2c7SLorenzo Bianconi 549db78a791SLorenzo Bianconi wiphy_read_of_freq_limits(phy->hw->wiphy); 550db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 551db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 552edf9dab8SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); 553db78a791SLorenzo Bianconi 554c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw); 555c89d3625SFelix Fietkau if (ret) 556c89d3625SFelix Fietkau return ret; 557c89d3625SFelix Fietkau 55841130c32SLorenzo Bianconi set_bit(MT76_STATE_REGISTERED, &phy->state); 559dc44c45cSLorenzo Bianconi phy->dev->phys[phy->band_idx] = phy; 560db78a791SLorenzo Bianconi 561c89d3625SFelix Fietkau return 0; 562c89d3625SFelix Fietkau } 563c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy); 564c89d3625SFelix Fietkau 565db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy) 566c89d3625SFelix Fietkau { 567c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev; 568c89d3625SFelix Fietkau 56941130c32SLorenzo Bianconi if (!test_bit(MT76_STATE_REGISTERED, &phy->state)) 57041130c32SLorenzo Bianconi return; 57141130c32SLorenzo Bianconi 5729e81c2c7SLorenzo Bianconi if (IS_ENABLED(CONFIG_MT76_LEDS)) 5739e81c2c7SLorenzo Bianconi mt76_led_cleanup(phy); 574c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 575c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw); 576dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = NULL; 577c89d3625SFelix Fietkau } 578c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy); 579c89d3625SFelix Fietkau 5802f5c3c77SLorenzo Bianconi int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q) 5812f5c3c77SLorenzo Bianconi { 5822f5c3c77SLorenzo Bianconi struct page_pool_params pp_params = { 5832f5c3c77SLorenzo Bianconi .order = 0, 58409d96ee5SYunsheng Lin .flags = 0, 5852f5c3c77SLorenzo Bianconi .nid = NUMA_NO_NODE, 5862f5c3c77SLorenzo Bianconi .dev = dev->dma_dev, 5872f5c3c77SLorenzo Bianconi }; 5882f5c3c77SLorenzo Bianconi int idx = q - dev->q_rx; 5892f5c3c77SLorenzo Bianconi 5902f5c3c77SLorenzo Bianconi switch (idx) { 5912f5c3c77SLorenzo Bianconi case MT_RXQ_MAIN: 5922f5c3c77SLorenzo Bianconi case MT_RXQ_BAND1: 5932f5c3c77SLorenzo Bianconi case MT_RXQ_BAND2: 5942f5c3c77SLorenzo Bianconi pp_params.pool_size = 256; 5952f5c3c77SLorenzo Bianconi break; 5962f5c3c77SLorenzo Bianconi default: 5972f5c3c77SLorenzo Bianconi pp_params.pool_size = 16; 5982f5c3c77SLorenzo Bianconi break; 5992f5c3c77SLorenzo Bianconi } 6002f5c3c77SLorenzo Bianconi 6012f5c3c77SLorenzo Bianconi if (mt76_is_mmio(dev)) { 6022f5c3c77SLorenzo Bianconi /* rely on page_pool for DMA mapping */ 6032f5c3c77SLorenzo Bianconi pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; 6042f5c3c77SLorenzo Bianconi pp_params.dma_dir = DMA_FROM_DEVICE; 6052f5c3c77SLorenzo Bianconi pp_params.max_len = PAGE_SIZE; 6062f5c3c77SLorenzo Bianconi pp_params.offset = 0; 6072f5c3c77SLorenzo Bianconi } 6082f5c3c77SLorenzo Bianconi 6092f5c3c77SLorenzo Bianconi q->page_pool = page_pool_create(&pp_params); 6102f5c3c77SLorenzo Bianconi if (IS_ERR(q->page_pool)) { 6112f5c3c77SLorenzo Bianconi int err = PTR_ERR(q->page_pool); 6122f5c3c77SLorenzo Bianconi 6132f5c3c77SLorenzo Bianconi q->page_pool = NULL; 6142f5c3c77SLorenzo Bianconi return err; 6152f5c3c77SLorenzo Bianconi } 6162f5c3c77SLorenzo Bianconi 6172f5c3c77SLorenzo Bianconi return 0; 6182f5c3c77SLorenzo Bianconi } 6192f5c3c77SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_create_page_pool); 6202f5c3c77SLorenzo Bianconi 621a85b590cSFelix Fietkau struct mt76_dev * 622c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 623c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 624c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 625a85b590cSFelix Fietkau { 626a85b590cSFelix Fietkau struct ieee80211_hw *hw; 627ac24dd35SFelix Fietkau struct mt76_phy *phy; 628a85b590cSFelix Fietkau struct mt76_dev *dev; 629e5443256SFelix Fietkau int i; 630a85b590cSFelix Fietkau 631a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 632a85b590cSFelix Fietkau if (!hw) 633a85b590cSFelix Fietkau return NULL; 634a85b590cSFelix Fietkau 635a85b590cSFelix Fietkau dev = hw->priv; 636a85b590cSFelix Fietkau dev->hw = hw; 637c0f7b25aSLorenzo Bianconi dev->dev = pdev; 638c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 639d1ddc536SFelix Fietkau dev->dma_dev = pdev; 640c0f7b25aSLorenzo Bianconi 641ac24dd35SFelix Fietkau phy = &dev->phy; 642ac24dd35SFelix Fietkau phy->dev = dev; 643ac24dd35SFelix Fietkau phy->hw = hw; 644dc44c45cSLorenzo Bianconi phy->band_idx = MT_BAND0; 645dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = phy; 646ac24dd35SFelix Fietkau 647a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 648a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 649a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 650c34f1005SLorenzo Bianconi spin_lock_init(&dev->status_lock); 6512666beceSSujuan Chen spin_lock_init(&dev->wed_lock); 652108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 65326e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 654a85b590cSFelix Fietkau 65509872957SLorenzo Bianconi skb_queue_head_init(&dev->mcu.res_q); 65609872957SLorenzo Bianconi init_waitqueue_head(&dev->mcu.wait); 65709872957SLorenzo Bianconi mutex_init(&dev->mcu.mutex); 658781eef5bSFelix Fietkau dev->tx_worker.fn = mt76_tx_worker; 65909872957SLorenzo Bianconi 6608af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 6618af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 6628af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 6638af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 6648af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 6658af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 6668af414e8SLorenzo Bianconi #endif 6678af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 6688af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 6698af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 6708af414e8SLorenzo Bianconi 67151252cc5SLorenzo Bianconi spin_lock_init(&dev->token_lock); 67251252cc5SLorenzo Bianconi idr_init(&dev->token); 67351252cc5SLorenzo Bianconi 6742666beceSSujuan Chen spin_lock_init(&dev->rx_token_lock); 6752666beceSSujuan Chen idr_init(&dev->rx_token); 6762666beceSSujuan Chen 677bd1e3e7bSLorenzo Bianconi INIT_LIST_HEAD(&dev->wcid_list); 678fbba711cSLorenzo Bianconi INIT_LIST_HEAD(&dev->sta_poll_list); 679fbba711cSLorenzo Bianconi spin_lock_init(&dev->sta_poll_lock); 680bd1e3e7bSLorenzo Bianconi 681e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 6822666beceSSujuan Chen INIT_LIST_HEAD(&dev->rxwi_cache); 68361b5156bSFelix Fietkau dev->token_size = dev->drv->token_size; 684e5443256SFelix Fietkau 685e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 686e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 687e5443256SFelix Fietkau 688a86f1d01SLorenzo Bianconi dev->wq = alloc_ordered_workqueue("mt76", 0); 689a86f1d01SLorenzo Bianconi if (!dev->wq) { 690a86f1d01SLorenzo Bianconi ieee80211_free_hw(hw); 691a86f1d01SLorenzo Bianconi return NULL; 692a86f1d01SLorenzo Bianconi } 693a86f1d01SLorenzo Bianconi 694a85b590cSFelix Fietkau return dev; 695a85b590cSFelix Fietkau } 696a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 697a85b590cSFelix Fietkau 69817f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 69917f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 70017f1de56SFelix Fietkau { 70117f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 702c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy; 70317f1de56SFelix Fietkau int ret; 70417f1de56SFelix Fietkau 70517f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 7060335c034SFelix Fietkau mt76_wcid_init(&dev->global_wcid); 707d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, hw); 708d43de9cfSLorenzo Bianconi if (ret) 709d43de9cfSLorenzo Bianconi return ret; 71017f1de56SFelix Fietkau 71148dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) { 71277af762eSLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 71317f1de56SFelix Fietkau if (ret) 71417f1de56SFelix Fietkau return ret; 71517f1de56SFelix Fietkau } 71617f1de56SFelix Fietkau 71748dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) { 71877af762eSLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 71917f1de56SFelix Fietkau if (ret) 72017f1de56SFelix Fietkau return ret; 72117f1de56SFelix Fietkau } 72217f1de56SFelix Fietkau 723edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 724edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 725edf9dab8SLorenzo Bianconi if (ret) 726edf9dab8SLorenzo Bianconi return ret; 727edf9dab8SLorenzo Bianconi } 728edf9dab8SLorenzo Bianconi 729c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy); 730c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 731c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 732edf9dab8SLorenzo Bianconi mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); 73317f1de56SFelix Fietkau 734b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 7353abd46ddSLorenzo Bianconi ret = mt76_led_init(phy); 73617f1de56SFelix Fietkau if (ret) 73717f1de56SFelix Fietkau return ret; 738b374e868SArnd Bergmann } 73917f1de56SFelix Fietkau 740781eef5bSFelix Fietkau ret = ieee80211_register_hw(hw); 741781eef5bSFelix Fietkau if (ret) 742781eef5bSFelix Fietkau return ret; 743781eef5bSFelix Fietkau 744781eef5bSFelix Fietkau WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 74541130c32SLorenzo Bianconi set_bit(MT76_STATE_REGISTERED, &phy->state); 746781eef5bSFelix Fietkau sched_set_fifo_low(dev->tx_worker.task); 747781eef5bSFelix Fietkau 748781eef5bSFelix Fietkau return 0; 74917f1de56SFelix Fietkau } 75017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 75117f1de56SFelix Fietkau 75217f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 75317f1de56SFelix Fietkau { 75417f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 75517f1de56SFelix Fietkau 75641130c32SLorenzo Bianconi if (!test_bit(MT76_STATE_REGISTERED, &dev->phy.state)) 75741130c32SLorenzo Bianconi return; 75841130c32SLorenzo Bianconi 759d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 7603abd46ddSLorenzo Bianconi mt76_led_cleanup(&dev->phy); 761c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 7620335c034SFelix Fietkau mt76_wcid_cleanup(dev, &dev->global_wcid); 76317f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 76417f1de56SFelix Fietkau } 76517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 76617f1de56SFelix Fietkau 767def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 768def34a2fSLorenzo Bianconi { 769781eef5bSFelix Fietkau mt76_worker_teardown(&dev->tx_worker); 770a86f1d01SLorenzo Bianconi if (dev->wq) { 771a86f1d01SLorenzo Bianconi destroy_workqueue(dev->wq); 772a86f1d01SLorenzo Bianconi dev->wq = NULL; 773a86f1d01SLorenzo Bianconi } 774def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 775def34a2fSLorenzo Bianconi } 776def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 777def34a2fSLorenzo Bianconi 778cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) 779cc4b3c13SLorenzo Bianconi { 780cc4b3c13SLorenzo Bianconi struct sk_buff *skb = phy->rx_amsdu[q].head; 7812c2bdd23SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 782cc4b3c13SLorenzo Bianconi struct mt76_dev *dev = phy->dev; 783cc4b3c13SLorenzo Bianconi 784cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = NULL; 785cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = NULL; 7862c2bdd23SFelix Fietkau 7872c2bdd23SFelix Fietkau /* 7882c2bdd23SFelix Fietkau * Validate if the amsdu has a proper first subframe. 7892c2bdd23SFelix Fietkau * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU 7902c2bdd23SFelix Fietkau * flag of the QoS header gets flipped. In such cases, the first 7912c2bdd23SFelix Fietkau * subframe has a LLC/SNAP header in the location of the destination 7922c2bdd23SFelix Fietkau * address. 7932c2bdd23SFelix Fietkau */ 7942c2bdd23SFelix Fietkau if (skb_shinfo(skb)->frag_list) { 7952c2bdd23SFelix Fietkau int offset = 0; 7962c2bdd23SFelix Fietkau 7972c2bdd23SFelix Fietkau if (!(status->flag & RX_FLAG_8023)) { 7982c2bdd23SFelix Fietkau offset = ieee80211_get_hdrlen_from_skb(skb); 7992c2bdd23SFelix Fietkau 8002c2bdd23SFelix Fietkau if ((status->flag & 8012c2bdd23SFelix Fietkau (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == 8022c2bdd23SFelix Fietkau RX_FLAG_DECRYPTED) 8032c2bdd23SFelix Fietkau offset += 8; 8042c2bdd23SFelix Fietkau } 8052c2bdd23SFelix Fietkau 8062c2bdd23SFelix Fietkau if (ether_addr_equal(skb->data + offset, rfc1042_header)) { 8072c2bdd23SFelix Fietkau dev_kfree_skb(skb); 8082c2bdd23SFelix Fietkau return; 8092c2bdd23SFelix Fietkau } 8102c2bdd23SFelix Fietkau } 811cc4b3c13SLorenzo Bianconi __skb_queue_tail(&dev->rx_skb[q], skb); 812cc4b3c13SLorenzo Bianconi } 813cc4b3c13SLorenzo Bianconi 814cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, 815cc4b3c13SLorenzo Bianconi struct sk_buff *skb) 816cc4b3c13SLorenzo Bianconi { 817cc4b3c13SLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 818cc4b3c13SLorenzo Bianconi 819cc4b3c13SLorenzo Bianconi if (phy->rx_amsdu[q].head && 820cc4b3c13SLorenzo Bianconi (!status->amsdu || status->first_amsdu || 821cc4b3c13SLorenzo Bianconi status->seqno != phy->rx_amsdu[q].seqno)) 822cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 823cc4b3c13SLorenzo Bianconi 824cc4b3c13SLorenzo Bianconi if (!phy->rx_amsdu[q].head) { 825cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; 826cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].seqno = status->seqno; 827cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = skb; 828cc4b3c13SLorenzo Bianconi } else { 829cc4b3c13SLorenzo Bianconi *phy->rx_amsdu[q].tail = skb; 830cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb->next; 831cc4b3c13SLorenzo Bianconi } 832cc4b3c13SLorenzo Bianconi 833cc4b3c13SLorenzo Bianconi if (!status->amsdu || status->last_amsdu) 834cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 835cc4b3c13SLorenzo Bianconi } 836cc4b3c13SLorenzo Bianconi 83717f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 83817f1de56SFelix Fietkau { 839011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 840128c9b7dSLorenzo Bianconi struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); 841011849e0SFelix Fietkau 842011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 84317f1de56SFelix Fietkau dev_kfree_skb(skb); 84417f1de56SFelix Fietkau return; 84517f1de56SFelix Fietkau } 84617f1de56SFelix Fietkau 847f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE 848c918c74dSShayne Chen if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { 849c918c74dSShayne Chen phy->test.rx_stats.packets[q]++; 850f0efa862SFelix Fietkau if (status->flag & RX_FLAG_FAILED_FCS_CRC) 851c918c74dSShayne Chen phy->test.rx_stats.fcs_error[q]++; 852f0efa862SFelix Fietkau } 853f0efa862SFelix Fietkau #endif 854cc4b3c13SLorenzo Bianconi 855cc4b3c13SLorenzo Bianconi mt76_rx_release_burst(phy, q, skb); 85617f1de56SFelix Fietkau } 85717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 85817f1de56SFelix Fietkau 8595a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy) 86026e40d4cSFelix Fietkau { 861af005f26SLorenzo Bianconi struct mt76_queue *q; 86291990519SLorenzo Bianconi int i; 8635a95ca41SFelix Fietkau 8645a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) { 86591990519SLorenzo Bianconi q = phy->q_tx[i]; 866af005f26SLorenzo Bianconi if (q && q->queued) 86726e40d4cSFelix Fietkau return true; 86826e40d4cSFelix Fietkau } 86926e40d4cSFelix Fietkau 87026e40d4cSFelix Fietkau return false; 87126e40d4cSFelix Fietkau } 87239d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 87326e40d4cSFelix Fietkau 8740fd0eb54SFelix Fietkau static struct mt76_channel_state * 87596747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 8760fd0eb54SFelix Fietkau { 8770fd0eb54SFelix Fietkau struct mt76_sband *msband; 8780fd0eb54SFelix Fietkau int idx; 8790fd0eb54SFelix Fietkau 8800fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 88196747a51SFelix Fietkau msband = &phy->sband_2g; 882edf9dab8SLorenzo Bianconi else if (c->band == NL80211_BAND_6GHZ) 883edf9dab8SLorenzo Bianconi msband = &phy->sband_6g; 8840fd0eb54SFelix Fietkau else 88596747a51SFelix Fietkau msband = &phy->sband_5g; 8860fd0eb54SFelix Fietkau 8870fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 8880fd0eb54SFelix Fietkau return &msband->chan[idx]; 8890fd0eb54SFelix Fietkau } 8900fd0eb54SFelix Fietkau 89104414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 89296747a51SFelix Fietkau { 89396747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state; 89496747a51SFelix Fietkau 89596747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time, 89696747a51SFelix Fietkau phy->survey_time)); 89796747a51SFelix Fietkau phy->survey_time = time; 89896747a51SFelix Fietkau } 89904414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 90096747a51SFelix Fietkau 901c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy) 9025ce09c1aSFelix Fietkau { 903c560b137SRyder Lee struct mt76_dev *dev = phy->dev; 904aec65e48SFelix Fietkau ktime_t cur_time; 905aec65e48SFelix Fietkau 9065ce09c1aSFelix Fietkau if (dev->drv->update_survey) 907c560b137SRyder Lee dev->drv->update_survey(phy); 9085ce09c1aSFelix Fietkau 909aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 910c560b137SRyder Lee mt76_update_survey_active_time(phy, cur_time); 911aec65e48SFelix Fietkau 9125ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 913c560b137SRyder Lee struct mt76_channel_state *state = phy->chan_state; 91496747a51SFelix Fietkau 915237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 9165ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 9175ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 918237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 9195ce09c1aSFelix Fietkau } 9205ce09c1aSFelix Fietkau } 9215ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 9225ce09c1aSFelix Fietkau 92396747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy) 92417f1de56SFelix Fietkau { 92596747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 92696747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 92717f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 92817f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 92926e40d4cSFelix Fietkau int timeout = HZ / 5; 93017f1de56SFelix Fietkau 9315a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 932c560b137SRyder Lee mt76_update_survey(phy); 93317f1de56SFelix Fietkau 9343f306448SFelix Fietkau if (phy->chandef.chan->center_freq != chandef->chan->center_freq || 9353f306448SFelix Fietkau phy->chandef.width != chandef->width) 9363f306448SFelix Fietkau phy->dfs_state = MT_DFS_STATE_UNKNOWN; 9373f306448SFelix Fietkau 93896747a51SFelix Fietkau phy->chandef = *chandef; 93996747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan); 94017f1de56SFelix Fietkau 94117f1de56SFelix Fietkau if (!offchannel) 94296747a51SFelix Fietkau phy->main_chan = chandef->chan; 94317f1de56SFelix Fietkau 94496747a51SFelix Fietkau if (chandef->chan != phy->main_chan) 94596747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 94617f1de56SFelix Fietkau } 94717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 94817f1de56SFelix Fietkau 94917f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 95017f1de56SFelix Fietkau struct survey_info *survey) 95117f1de56SFelix Fietkau { 95296747a51SFelix Fietkau struct mt76_phy *phy = hw->priv; 95396747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 95417f1de56SFelix Fietkau struct mt76_sband *sband; 95517f1de56SFelix Fietkau struct ieee80211_channel *chan; 95617f1de56SFelix Fietkau struct mt76_channel_state *state; 95717f1de56SFelix Fietkau int ret = 0; 95817f1de56SFelix Fietkau 959237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 96017f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 961c560b137SRyder Lee mt76_update_survey(phy); 96217f1de56SFelix Fietkau 963edf9dab8SLorenzo Bianconi if (idx >= phy->sband_2g.sband.n_channels + 964edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels) { 965edf9dab8SLorenzo Bianconi idx -= (phy->sband_2g.sband.n_channels + 966edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels); 967edf9dab8SLorenzo Bianconi sband = &phy->sband_6g; 968edf9dab8SLorenzo Bianconi } else if (idx >= phy->sband_2g.sband.n_channels) { 969edf9dab8SLorenzo Bianconi idx -= phy->sband_2g.sband.n_channels; 97096747a51SFelix Fietkau sband = &phy->sband_5g; 971edf9dab8SLorenzo Bianconi } else { 972edf9dab8SLorenzo Bianconi sband = &phy->sband_2g; 97317f1de56SFelix Fietkau } 97417f1de56SFelix Fietkau 975237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 976237312c5SLorenzo Bianconi ret = -ENOENT; 977237312c5SLorenzo Bianconi goto out; 978237312c5SLorenzo Bianconi } 97917f1de56SFelix Fietkau 98017f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 98196747a51SFelix Fietkau state = mt76_channel_state(phy, chan); 98217f1de56SFelix Fietkau 98317f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 98417f1de56SFelix Fietkau survey->channel = chan; 98517f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 986ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 987e5051965SFelix Fietkau if (state->noise) 988e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM; 989e5051965SFelix Fietkau 99096747a51SFelix Fietkau if (chan == phy->main_chan) { 99117f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 99217f1de56SFelix Fietkau 9935ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 9945ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 9955ce09c1aSFelix Fietkau } 9965ce09c1aSFelix Fietkau 99717f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 9986bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 999237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 1000e5051965SFelix Fietkau survey->noise = state->noise; 1001237312c5SLorenzo Bianconi 1002237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 1003237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 1004ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 100517f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 100617f1de56SFelix Fietkau 1007237312c5SLorenzo Bianconi out: 1008237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 1009237312c5SLorenzo Bianconi 101017f1de56SFelix Fietkau return ret; 101117f1de56SFelix Fietkau } 101217f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 101317f1de56SFelix Fietkau 101430ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 101530ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 101630ce7f44SFelix Fietkau { 101730ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 101830ce7f44SFelix Fietkau int i; 101930ce7f44SFelix Fietkau 102030ce7f44SFelix Fietkau wcid->rx_check_pn = false; 102130ce7f44SFelix Fietkau 102230ce7f44SFelix Fietkau if (!key) 102330ce7f44SFelix Fietkau return; 102430ce7f44SFelix Fietkau 102501cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 102601cfc1b4SLorenzo Bianconi return; 102730ce7f44SFelix Fietkau 102801cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 1029a1b0bbd4SXing Song 1030a1b0bbd4SXing Song /* data frame */ 103130ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 103230ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 103330ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 103430ce7f44SFelix Fietkau } 1035a1b0bbd4SXing Song 1036a1b0bbd4SXing Song /* robust management frame */ 1037a1b0bbd4SXing Song ieee80211_get_key_rx_seq(key, -1, &seq); 1038a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 1039a1b0bbd4SXing Song 104030ce7f44SFelix Fietkau } 104130ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 104230ce7f44SFelix Fietkau 1043a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal) 10444550fb9eSFelix Fietkau { 10454550fb9eSFelix Fietkau int signal = -128; 10464550fb9eSFelix Fietkau u8 chains; 10474550fb9eSFelix Fietkau 1048a71b648eSRyder Lee for (chains = chain_mask; chains; chains >>= 1, chain_signal++) { 10494550fb9eSFelix Fietkau int cur, diff; 10504550fb9eSFelix Fietkau 10516450b133SDeren Wu cur = *chain_signal; 10526450b133SDeren Wu if (!(chains & BIT(0)) || 10536450b133SDeren Wu cur > 0) 10544550fb9eSFelix Fietkau continue; 10554550fb9eSFelix Fietkau 10564550fb9eSFelix Fietkau if (cur > signal) 10574550fb9eSFelix Fietkau swap(cur, signal); 10584550fb9eSFelix Fietkau 10594550fb9eSFelix Fietkau diff = signal - cur; 10604550fb9eSFelix Fietkau if (diff == 0) 10614550fb9eSFelix Fietkau signal += 3; 10624550fb9eSFelix Fietkau else if (diff <= 2) 10634550fb9eSFelix Fietkau signal += 2; 10644550fb9eSFelix Fietkau else if (diff <= 6) 10654550fb9eSFelix Fietkau signal += 1; 10664550fb9eSFelix Fietkau } 10674550fb9eSFelix Fietkau 10684550fb9eSFelix Fietkau return signal; 10694550fb9eSFelix Fietkau } 1070a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal); 10714550fb9eSFelix Fietkau 1072bfc394ddSFelix Fietkau static void 1073bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 1074bfc394ddSFelix Fietkau struct ieee80211_hw **hw, 1075bfc394ddSFelix Fietkau struct ieee80211_sta **sta) 10764e34249eSFelix Fietkau { 10774e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 1078abe3f3daSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 10794e34249eSFelix Fietkau struct mt76_rx_status mstat; 10804e34249eSFelix Fietkau 10814e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 10824e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 10834e34249eSFelix Fietkau 10844e34249eSFelix Fietkau status->flag = mstat.flag; 10854e34249eSFelix Fietkau status->freq = mstat.freq; 10864e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 10874e34249eSFelix Fietkau status->encoding = mstat.encoding; 10884e34249eSFelix Fietkau status->bw = mstat.bw; 1089021af945SShayne Chen if (status->encoding == RX_ENC_EHT) { 1090021af945SShayne Chen status->eht.ru = mstat.eht.ru; 1091021af945SShayne Chen status->eht.gi = mstat.eht.gi; 1092021af945SShayne Chen } else { 1093af4a2f2fSRyder Lee status->he_ru = mstat.he_ru; 1094af4a2f2fSRyder Lee status->he_gi = mstat.he_gi; 1095af4a2f2fSRyder Lee status->he_dcm = mstat.he_dcm; 1096021af945SShayne Chen } 10974e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 10984e34249eSFelix Fietkau status->nss = mstat.nss; 10994e34249eSFelix Fietkau status->band = mstat.band; 11004e34249eSFelix Fietkau status->signal = mstat.signal; 11014e34249eSFelix Fietkau status->chains = mstat.chains; 1102d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 11030fda6d7bSRyder Lee status->device_timestamp = mstat.timestamp; 11040fda6d7bSRyder Lee status->mactime = mstat.timestamp; 1105a71b648eSRyder Lee status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal); 11064550fb9eSFelix Fietkau if (status->signal <= -128) 11074550fb9eSFelix Fietkau status->flag |= RX_FLAG_NO_SIGNAL_VAL; 11084e34249eSFelix Fietkau 1109abe3f3daSRyder Lee if (ieee80211_is_beacon(hdr->frame_control) || 1110abe3f3daSRyder Lee ieee80211_is_probe_resp(hdr->frame_control)) 1111abe3f3daSRyder Lee status->boottime_ns = ktime_get_boottime_ns(); 1112abe3f3daSRyder Lee 11134e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 111413381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 111513381dcdSRyder Lee sizeof(mstat.chain_signal)); 111613381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 111713381dcdSRyder Lee sizeof(mstat.chain_signal)); 11189c68a57bSFelix Fietkau 1119bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid); 1120128c9b7dSLorenzo Bianconi *hw = mt76_phy_hw(dev, mstat.phy_idx); 11214e34249eSFelix Fietkau } 11224e34249eSFelix Fietkau 11233c1032e1SFelix Fietkau static void 112430ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 112530ce7f44SFelix Fietkau { 112630ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 112730ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 112830ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 1129a1b0bbd4SXing Song int security_idx; 113030ce7f44SFelix Fietkau int ret; 113130ce7f44SFelix Fietkau 113230ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 11333c1032e1SFelix Fietkau return; 113430ce7f44SFelix Fietkau 11351858e4fcSMeiChia Chiu if (status->flag & RX_FLAG_ONLY_MONITOR) 11363c1032e1SFelix Fietkau return; 11371858e4fcSMeiChia Chiu 113830ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 11393c1032e1SFelix Fietkau return; 114030ce7f44SFelix Fietkau 11417360cdecSFelix Fietkau security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 11427360cdecSFelix Fietkau if (status->flag & RX_FLAG_8023) 11437360cdecSFelix Fietkau goto skip_hdr_check; 11447360cdecSFelix Fietkau 1145a1b0bbd4SXing Song hdr = mt76_skb_get_hdr(skb); 114630ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 114730ce7f44SFelix Fietkau /* 114830ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 114930ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 115030ce7f44SFelix Fietkau */ 115130ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 115230ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 11533c1032e1SFelix Fietkau return; 115430ce7f44SFelix Fietkau } 115530ce7f44SFelix Fietkau 1156a1b0bbd4SXing Song /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): 1157a1b0bbd4SXing Song * 1158a1b0bbd4SXing Song * the recipient shall maintain a single replay counter for received 1159a1b0bbd4SXing Song * individually addressed robust Management frames that are received 1160a1b0bbd4SXing Song * with the To DS subfield equal to 0, [...] 1161a1b0bbd4SXing Song */ 1162a1b0bbd4SXing Song if (ieee80211_is_mgmt(hdr->frame_control) && 1163a1b0bbd4SXing Song !ieee80211_has_tods(hdr->frame_control)) 1164a1b0bbd4SXing Song security_idx = IEEE80211_NUM_TIDS; 1165a1b0bbd4SXing Song 11667360cdecSFelix Fietkau skip_hdr_check: 116730ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 1168a1b0bbd4SXing Song ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], 116930ce7f44SFelix Fietkau sizeof(status->iv)); 11703c1032e1SFelix Fietkau if (ret <= 0) { 11713c1032e1SFelix Fietkau status->flag |= RX_FLAG_ONLY_MONITOR; 11723c1032e1SFelix Fietkau return; 11733c1032e1SFelix Fietkau } 117430ce7f44SFelix Fietkau 1175a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); 117630ce7f44SFelix Fietkau 117730ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 117830ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 117930ce7f44SFelix Fietkau } 118030ce7f44SFelix Fietkau 1181d71ef286SFelix Fietkau static void 11825ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 11835ce09c1aSFelix Fietkau int len) 11845ce09c1aSFelix Fietkau { 11855ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 118685b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = { 118785b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags, 118885b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx, 118985b7a5d0SLorenzo Bianconi .encoding = status->encoding, 119085b7a5d0SLorenzo Bianconi .band = status->band, 119185b7a5d0SLorenzo Bianconi .nss = status->nss, 119285b7a5d0SLorenzo Bianconi .bw = status->bw, 119385b7a5d0SLorenzo Bianconi }; 11945ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 11955ce09c1aSFelix Fietkau u32 airtime; 1196e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 11975ce09c1aSFelix Fietkau 119885b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 1199237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 12005ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 1201237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 12025ce09c1aSFelix Fietkau 12035ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 12045ce09c1aSFelix Fietkau return; 12055ce09c1aSFelix Fietkau 12065ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1207e195dad1SFelix Fietkau ieee80211_sta_register_airtime(sta, tidno, 0, airtime); 12085ce09c1aSFelix Fietkau } 12095ce09c1aSFelix Fietkau 12105ce09c1aSFelix Fietkau static void 12115ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 12125ce09c1aSFelix Fietkau { 12135ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 12145ce09c1aSFelix Fietkau int wcid_idx; 12155ce09c1aSFelix Fietkau 12165ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 12175ce09c1aSFelix Fietkau return; 12185ce09c1aSFelix Fietkau 12195ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 1220bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 12215ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 12225ce09c1aSFelix Fietkau else 12235ce09c1aSFelix Fietkau wcid = NULL; 12245ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 12255ce09c1aSFelix Fietkau 12265ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 12275ce09c1aSFelix Fietkau 12285ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 12295ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 12305ce09c1aSFelix Fietkau } 12315ce09c1aSFelix Fietkau 12325ce09c1aSFelix Fietkau static void 12335ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 12345ce09c1aSFelix Fietkau { 12355ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 12365ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 12375ce09c1aSFelix Fietkau 12385ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 12395ce09c1aSFelix Fietkau return; 12405ce09c1aSFelix Fietkau 12415ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 1242e195dad1SFelix Fietkau struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1243e195dad1SFelix Fietkau 1244e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1245e195dad1SFelix Fietkau return; 1246e195dad1SFelix Fietkau 124798df2baeSLorenzo Bianconi if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) 12485ce09c1aSFelix Fietkau return; 12495ce09c1aSFelix Fietkau 12505ce09c1aSFelix Fietkau wcid = NULL; 12515ce09c1aSFelix Fietkau } 12525ce09c1aSFelix Fietkau 12535ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 12545ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 12555ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 12565ce09c1aSFelix Fietkau 12575ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 12585ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 12595ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 12605ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 12615ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 12625ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 12635ce09c1aSFelix Fietkau } 12645ce09c1aSFelix Fietkau 12655ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 12665ce09c1aSFelix Fietkau return; 12675ce09c1aSFelix Fietkau } 12685ce09c1aSFelix Fietkau 12695ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 12705ce09c1aSFelix Fietkau } 12715ce09c1aSFelix Fietkau 12725ce09c1aSFelix Fietkau static void 1273ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 1274d71ef286SFelix Fietkau { 1275d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 127677ae1d5eSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1277d71ef286SFelix Fietkau struct ieee80211_sta *sta; 1278bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 1279d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 1280e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 1281d71ef286SFelix Fietkau bool ps; 1282d71ef286SFelix Fietkau 1283128c9b7dSLorenzo Bianconi hw = mt76_phy_hw(dev, status->phy_idx); 1284e195dad1SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && 1285e195dad1SFelix Fietkau !(status->flag & RX_FLAG_8023)) { 1286bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 128736d91096SFelix Fietkau if (sta) 128836d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 128936d91096SFelix Fietkau } 129036d91096SFelix Fietkau 12915ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 12925ce09c1aSFelix Fietkau 1293d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 1294d71ef286SFelix Fietkau return; 1295d71ef286SFelix Fietkau 1296d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1297d71ef286SFelix Fietkau 129802e5a769SFelix Fietkau if (status->signal <= 0) 129902e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 130002e5a769SFelix Fietkau 1301ef13edc0SFelix Fietkau wcid->inactive_count = 0; 1302ef13edc0SFelix Fietkau 1303e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1304e195dad1SFelix Fietkau return; 1305e195dad1SFelix Fietkau 1306d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 1307d71ef286SFelix Fietkau return; 1308d71ef286SFelix Fietkau 1309d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 1310d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 1311d71ef286SFelix Fietkau return; 1312d71ef286SFelix Fietkau } 1313d71ef286SFelix Fietkau 1314d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 1315d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 1316d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 1317d71ef286SFelix Fietkau return; 1318d71ef286SFelix Fietkau 1319d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 1320d71ef286SFelix Fietkau 1321d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 1322d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 1323e195dad1SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, tidno); 1324d71ef286SFelix Fietkau 1325d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 1326d71ef286SFelix Fietkau return; 1327d71ef286SFelix Fietkau 132811b2a25fSFelix Fietkau if (ps) 1329d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 1330d71ef286SFelix Fietkau 1331f28c3139SLorenzo Bianconi if (dev->drv->sta_ps) 1332d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 1333608f7c47SFelix Fietkau 1334608f7c47SFelix Fietkau if (!ps) 1335608f7c47SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 1336608f7c47SFelix Fietkau 13379f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 1338d71ef286SFelix Fietkau } 1339d71ef286SFelix Fietkau 13409d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 134181e850efSLorenzo Bianconi struct napi_struct *napi) 134217f1de56SFelix Fietkau { 13439c68a57bSFelix Fietkau struct ieee80211_sta *sta; 1344bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 13453298b1f8SFelix Fietkau struct sk_buff *skb, *tmp; 13463298b1f8SFelix Fietkau LIST_HEAD(list); 13479d9d738bSFelix Fietkau 1348c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 13499d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 1350cc4b3c13SLorenzo Bianconi struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 1351cc4b3c13SLorenzo Bianconi 13523c1032e1SFelix Fietkau mt76_check_ccmp_pn(skb); 1353cc4b3c13SLorenzo Bianconi skb_shinfo(skb)->frag_list = NULL; 1354bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta); 13553298b1f8SFelix Fietkau ieee80211_rx_list(hw, sta, skb, &list); 1356cc4b3c13SLorenzo Bianconi 1357cc4b3c13SLorenzo Bianconi /* subsequent amsdu frames */ 1358cc4b3c13SLorenzo Bianconi while (nskb) { 1359cc4b3c13SLorenzo Bianconi skb = nskb; 1360cc4b3c13SLorenzo Bianconi nskb = nskb->next; 1361cc4b3c13SLorenzo Bianconi skb->next = NULL; 1362cc4b3c13SLorenzo Bianconi 1363cc4b3c13SLorenzo Bianconi mt76_rx_convert(dev, skb, &hw, &sta); 1364cc4b3c13SLorenzo Bianconi ieee80211_rx_list(hw, sta, skb, &list); 1365cc4b3c13SLorenzo Bianconi } 13669d9d738bSFelix Fietkau } 1367c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 13683298b1f8SFelix Fietkau 13693298b1f8SFelix Fietkau if (!napi) { 13703298b1f8SFelix Fietkau netif_receive_skb_list(&list); 13713298b1f8SFelix Fietkau return; 13723298b1f8SFelix Fietkau } 13733298b1f8SFelix Fietkau 13743298b1f8SFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) { 13753298b1f8SFelix Fietkau skb_list_del_init(skb); 13763298b1f8SFelix Fietkau napi_gro_receive(napi, skb); 13773298b1f8SFelix Fietkau } 13789d9d738bSFelix Fietkau } 13799d9d738bSFelix Fietkau 138081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 138181e850efSLorenzo Bianconi struct napi_struct *napi) 13829d9d738bSFelix Fietkau { 1383aee5b8cfSFelix Fietkau struct sk_buff_head frames; 138417f1de56SFelix Fietkau struct sk_buff *skb; 138517f1de56SFelix Fietkau 1386aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 1387aee5b8cfSFelix Fietkau 1388d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 1389ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 13904f831d18SLorenzo Bianconi if (mtk_wed_device_active(&dev->mmio.wed)) 13914f831d18SLorenzo Bianconi __skb_queue_tail(&frames, skb); 13924f831d18SLorenzo Bianconi else 1393aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 1394d71ef286SFelix Fietkau } 1395aee5b8cfSFelix Fietkau 139681e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 13974e34249eSFelix Fietkau } 139881e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 1399723b90dcSFelix Fietkau 1400e28487eaSFelix Fietkau static int 1401a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, 1402a1a99d7bSLorenzo Bianconi struct ieee80211_sta *sta) 1403e28487eaSFelix Fietkau { 1404e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 1405a1a99d7bSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 1406e28487eaSFelix Fietkau int ret; 1407e28487eaSFelix Fietkau int i; 1408e28487eaSFelix Fietkau 1409e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 1410e28487eaSFelix Fietkau 1411e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 1412e28487eaSFelix Fietkau if (ret) 1413e28487eaSFelix Fietkau goto out; 1414e28487eaSFelix Fietkau 1415e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 1416e28487eaSFelix Fietkau struct mt76_txq *mtxq; 1417e28487eaSFelix Fietkau 1418e28487eaSFelix Fietkau if (!sta->txq[i]) 1419e28487eaSFelix Fietkau continue; 1420e28487eaSFelix Fietkau 1421e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 142251fb1278SFelix Fietkau mtxq->wcid = wcid->idx; 1423e28487eaSFelix Fietkau } 1424e28487eaSFelix Fietkau 1425ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 1426a1a99d7bSLorenzo Bianconi if (phy->band_idx == MT_BAND1) 1427426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 1428a1a99d7bSLorenzo Bianconi wcid->phy_idx = phy->band_idx; 1429e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 1430e28487eaSFelix Fietkau 14310335c034SFelix Fietkau mt76_wcid_init(wcid); 1432e28487eaSFelix Fietkau out: 1433e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 1434e28487eaSFelix Fietkau 1435e28487eaSFelix Fietkau return ret; 1436e28487eaSFelix Fietkau } 1437e28487eaSFelix Fietkau 143813f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 1439723b90dcSFelix Fietkau struct ieee80211_sta *sta) 1440723b90dcSFelix Fietkau { 1441723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 144213f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 1443723b90dcSFelix Fietkau 144458bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 144558bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 144658bab0d4SFelix Fietkau 1447e28487eaSFelix Fietkau if (dev->drv->sta_remove) 1448e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 1449e28487eaSFelix Fietkau 14500335c034SFelix Fietkau mt76_wcid_cleanup(dev, wcid); 1451bd1e3e7bSLorenzo Bianconi 1452426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx); 1453426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 145413f61dfcSLorenzo Bianconi } 145513f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 1456e28487eaSFelix Fietkau 145713f61dfcSLorenzo Bianconi static void 145813f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 145913f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 146013f61dfcSLorenzo Bianconi { 146113f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 146213f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 1463723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 1464723b90dcSFelix Fietkau } 1465e28487eaSFelix Fietkau 1466e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1467e28487eaSFelix Fietkau struct ieee80211_sta *sta, 1468e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 1469e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 1470e28487eaSFelix Fietkau { 1471426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv; 1472426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev; 1473e28487eaSFelix Fietkau 1474e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 1475e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 1476a1a99d7bSLorenzo Bianconi return mt76_sta_add(phy, vif, sta); 1477e28487eaSFelix Fietkau 14789c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 14799c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 14809c193de5SFelix Fietkau dev->drv->sta_assoc) 14819c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 14829c193de5SFelix Fietkau 1483e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 1484e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 1485e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 1486e28487eaSFelix Fietkau 1487e28487eaSFelix Fietkau return 0; 1488e28487eaSFelix Fietkau } 1489e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 14909313faacSFelix Fietkau 149143ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 149243ba1922SFelix Fietkau struct ieee80211_sta *sta) 149343ba1922SFelix Fietkau { 149443ba1922SFelix Fietkau struct mt76_phy *phy = hw->priv; 149543ba1922SFelix Fietkau struct mt76_dev *dev = phy->dev; 149643ba1922SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 149743ba1922SFelix Fietkau 149843ba1922SFelix Fietkau mutex_lock(&dev->mutex); 1499fcfe1b5eSFelix Fietkau spin_lock_bh(&dev->status_lock); 150043ba1922SFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 1501fcfe1b5eSFelix Fietkau spin_unlock_bh(&dev->status_lock); 150243ba1922SFelix Fietkau mutex_unlock(&dev->mutex); 150343ba1922SFelix Fietkau } 150443ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 150543ba1922SFelix Fietkau 15060335c034SFelix Fietkau void mt76_wcid_init(struct mt76_wcid *wcid) 15070335c034SFelix Fietkau { 15080335c034SFelix Fietkau INIT_LIST_HEAD(&wcid->tx_list); 15090335c034SFelix Fietkau skb_queue_head_init(&wcid->tx_pending); 15100335c034SFelix Fietkau 15110335c034SFelix Fietkau INIT_LIST_HEAD(&wcid->list); 15120335c034SFelix Fietkau idr_init(&wcid->pktid); 15130335c034SFelix Fietkau } 15140335c034SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_init); 15150335c034SFelix Fietkau 15160335c034SFelix Fietkau void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) 15170335c034SFelix Fietkau { 15180335c034SFelix Fietkau struct mt76_phy *phy = dev->phys[wcid->phy_idx]; 15190335c034SFelix Fietkau struct ieee80211_hw *hw; 15200335c034SFelix Fietkau struct sk_buff_head list; 15210335c034SFelix Fietkau struct sk_buff *skb; 15220335c034SFelix Fietkau 15230335c034SFelix Fietkau mt76_tx_status_lock(dev, &list); 15240335c034SFelix Fietkau mt76_tx_status_skb_get(dev, wcid, -1, &list); 15250335c034SFelix Fietkau mt76_tx_status_unlock(dev, &list); 15260335c034SFelix Fietkau 15270335c034SFelix Fietkau idr_destroy(&wcid->pktid); 15280335c034SFelix Fietkau 15290335c034SFelix Fietkau spin_lock_bh(&phy->tx_lock); 15300335c034SFelix Fietkau 15310335c034SFelix Fietkau if (!list_empty(&wcid->tx_list)) 15320335c034SFelix Fietkau list_del_init(&wcid->tx_list); 15330335c034SFelix Fietkau 15340335c034SFelix Fietkau spin_lock(&wcid->tx_pending.lock); 15350335c034SFelix Fietkau skb_queue_splice_tail_init(&wcid->tx_pending, &list); 15360335c034SFelix Fietkau spin_unlock(&wcid->tx_pending.lock); 15370335c034SFelix Fietkau 15380335c034SFelix Fietkau spin_unlock_bh(&phy->tx_lock); 15390335c034SFelix Fietkau 15400335c034SFelix Fietkau while ((skb = __skb_dequeue(&list)) != NULL) { 15410335c034SFelix Fietkau hw = mt76_tx_status_get_hw(dev, skb); 15420335c034SFelix Fietkau ieee80211_free_txskb(hw, skb); 15430335c034SFelix Fietkau } 15440335c034SFelix Fietkau } 15450335c034SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_wcid_cleanup); 15460335c034SFelix Fietkau 15479313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 15489313faacSFelix Fietkau int *dbm) 15499313faacSFelix Fietkau { 1550beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1551beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask); 155207cda406SFelix Fietkau int delta = mt76_tx_power_nss_delta(n_chains); 15539313faacSFelix Fietkau 155407cda406SFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 15559313faacSFelix Fietkau 15569313faacSFelix Fietkau return 0; 15579313faacSFelix Fietkau } 15589313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 1559e7173858SFelix Fietkau 1560b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw, 1561b3cb885eSLorenzo Bianconi const struct cfg80211_sar_specs *sar) 1562b3cb885eSLorenzo Bianconi { 1563b3cb885eSLorenzo Bianconi struct mt76_phy *phy = hw->priv; 1564b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; 1565b3cb885eSLorenzo Bianconi int i; 1566b3cb885eSLorenzo Bianconi 1567b3cb885eSLorenzo Bianconi if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) 1568b3cb885eSLorenzo Bianconi return -EINVAL; 1569b3cb885eSLorenzo Bianconi 1570b3cb885eSLorenzo Bianconi for (i = 0; i < sar->num_sub_specs; i++) { 1571b3cb885eSLorenzo Bianconi u32 index = sar->sub_specs[i].freq_range_index; 1572b3cb885eSLorenzo Bianconi /* SAR specifies power limitaton in 0.25dbm */ 1573b3cb885eSLorenzo Bianconi s32 power = sar->sub_specs[i].power >> 1; 1574b3cb885eSLorenzo Bianconi 1575b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1576b3cb885eSLorenzo Bianconi power = 127; 1577b3cb885eSLorenzo Bianconi 1578b3cb885eSLorenzo Bianconi phy->frp[index].range = &capa->freq_ranges[index]; 1579b3cb885eSLorenzo Bianconi phy->frp[index].power = power; 1580b3cb885eSLorenzo Bianconi } 1581b3cb885eSLorenzo Bianconi 1582b3cb885eSLorenzo Bianconi return 0; 1583b3cb885eSLorenzo Bianconi } 1584b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power); 1585b3cb885eSLorenzo Bianconi 1586b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy, 1587b3cb885eSLorenzo Bianconi struct ieee80211_channel *chan, 1588b3cb885eSLorenzo Bianconi int power) 1589b3cb885eSLorenzo Bianconi { 1590b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; 1591b3cb885eSLorenzo Bianconi int freq, i; 1592b3cb885eSLorenzo Bianconi 1593b3cb885eSLorenzo Bianconi if (!capa || !phy->frp) 1594b3cb885eSLorenzo Bianconi return power; 1595b3cb885eSLorenzo Bianconi 1596b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1597b3cb885eSLorenzo Bianconi power = 127; 1598b3cb885eSLorenzo Bianconi 1599b3cb885eSLorenzo Bianconi freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); 1600b3cb885eSLorenzo Bianconi for (i = 0 ; i < capa->num_freq_ranges; i++) { 1601b3cb885eSLorenzo Bianconi if (phy->frp[i].range && 1602b3cb885eSLorenzo Bianconi freq >= phy->frp[i].range->start_freq && 1603b3cb885eSLorenzo Bianconi freq < phy->frp[i].range->end_freq) { 1604b3cb885eSLorenzo Bianconi power = min_t(int, phy->frp[i].power, power); 1605b3cb885eSLorenzo Bianconi break; 1606b3cb885eSLorenzo Bianconi } 1607b3cb885eSLorenzo Bianconi } 1608b3cb885eSLorenzo Bianconi 1609b3cb885eSLorenzo Bianconi return power; 1610b3cb885eSLorenzo Bianconi } 1611b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power); 1612b3cb885eSLorenzo Bianconi 1613e7173858SFelix Fietkau static void 1614e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 1615e7173858SFelix Fietkau { 1616d0a9123eSJohannes Berg if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 1617e7173858SFelix Fietkau ieee80211_csa_finish(vif); 1618e7173858SFelix Fietkau } 1619e7173858SFelix Fietkau 1620e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 1621e7173858SFelix Fietkau { 1622e7173858SFelix Fietkau if (!dev->csa_complete) 1623e7173858SFelix Fietkau return; 1624e7173858SFelix Fietkau 1625e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1626e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1627e7173858SFelix Fietkau __mt76_csa_finish, dev); 1628e7173858SFelix Fietkau 1629e7173858SFelix Fietkau dev->csa_complete = 0; 1630e7173858SFelix Fietkau } 1631e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 1632e7173858SFelix Fietkau 1633e7173858SFelix Fietkau static void 1634e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 1635e7173858SFelix Fietkau { 1636e7173858SFelix Fietkau struct mt76_dev *dev = priv; 1637e7173858SFelix Fietkau 1638d0a9123eSJohannes Berg if (!vif->bss_conf.csa_active) 1639e7173858SFelix Fietkau return; 1640e7173858SFelix Fietkau 16418552a434SJohn Crispin dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 1642e7173858SFelix Fietkau } 1643e7173858SFelix Fietkau 1644e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 1645e7173858SFelix Fietkau { 1646e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1647e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1648e7173858SFelix Fietkau __mt76_csa_check, dev); 1649e7173858SFelix Fietkau } 1650e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 165187d53103SStanislaw Gruszka 165287d53103SStanislaw Gruszka int 165387d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 165487d53103SStanislaw Gruszka { 165587d53103SStanislaw Gruszka return 0; 165687d53103SStanislaw Gruszka } 165787d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 1658eadfd98fSLorenzo Bianconi 1659eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 1660eadfd98fSLorenzo Bianconi { 1661eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 1662eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 1663eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 1664eadfd98fSLorenzo Bianconi 1665eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 1666eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 1667eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 1668eadfd98fSLorenzo Bianconi 1669eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 1670eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 1671eadfd98fSLorenzo Bianconi hdr[2] = 0; 1672eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 1673eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 1674eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 1675eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 1676eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1677eadfd98fSLorenzo Bianconi 1678eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1679eadfd98fSLorenzo Bianconi } 1680eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1681d2679d65SLorenzo Bianconi 1682d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1683d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1684d2679d65SLorenzo Bianconi int idx, bool cck) 1685d2679d65SLorenzo Bianconi { 1686d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1687d2679d65SLorenzo Bianconi 1688d2679d65SLorenzo Bianconi if (cck) { 1689edf9dab8SLorenzo Bianconi if (sband != &dev->phy.sband_2g.sband) 1690d2679d65SLorenzo Bianconi return 0; 1691d2679d65SLorenzo Bianconi 1692d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 169396747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) { 1694d2679d65SLorenzo Bianconi offset = 4; 1695d2679d65SLorenzo Bianconi } 1696d2679d65SLorenzo Bianconi 1697d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1698d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1699d2679d65SLorenzo Bianconi return i; 1700d2679d65SLorenzo Bianconi } 1701d2679d65SLorenzo Bianconi 1702d2679d65SLorenzo Bianconi return 0; 1703d2679d65SLorenzo Bianconi } 1704d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 17058b8ab5c2SLorenzo Bianconi 17068b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 17078b8ab5c2SLorenzo Bianconi const u8 *mac) 17088b8ab5c2SLorenzo Bianconi { 1709011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 17108b8ab5c2SLorenzo Bianconi 1711011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state); 17128b8ab5c2SLorenzo Bianconi } 17138b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 17148b8ab5c2SLorenzo Bianconi 17158b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 17168b8ab5c2SLorenzo Bianconi { 1717011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 17188b8ab5c2SLorenzo Bianconi 1719011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state); 17208b8ab5c2SLorenzo Bianconi } 17218b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1722e49c76d4SLorenzo Bianconi 1723e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1724e49c76d4SLorenzo Bianconi { 1725beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1726beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev; 1727e49c76d4SLorenzo Bianconi 1728e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1729beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask; 1730beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask; 1731e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1732e49c76d4SLorenzo Bianconi 1733e49c76d4SLorenzo Bianconi return 0; 1734e49c76d4SLorenzo Bianconi } 1735e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1736b671da33SLorenzo Bianconi 1737b1cb42adSLorenzo Bianconi struct mt76_queue * 1738b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, 1739f68d6762SFelix Fietkau int ring_base, u32 flags) 1740b671da33SLorenzo Bianconi { 1741b671da33SLorenzo Bianconi struct mt76_queue *hwq; 1742b671da33SLorenzo Bianconi int err; 1743b671da33SLorenzo Bianconi 1744b671da33SLorenzo Bianconi hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); 1745b671da33SLorenzo Bianconi if (!hwq) 1746b1cb42adSLorenzo Bianconi return ERR_PTR(-ENOMEM); 1747b671da33SLorenzo Bianconi 1748f68d6762SFelix Fietkau hwq->flags = flags; 1749f68d6762SFelix Fietkau 1750b671da33SLorenzo Bianconi err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); 1751b671da33SLorenzo Bianconi if (err < 0) 1752b1cb42adSLorenzo Bianconi return ERR_PTR(err); 1753b671da33SLorenzo Bianconi 1754b1cb42adSLorenzo Bianconi return hwq; 1755b671da33SLorenzo Bianconi } 1756b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue); 1757e4867225SSean Wang 175832b1000dSSean Wang u16 mt76_calculate_default_rate(struct mt76_phy *phy, 175932b1000dSSean Wang struct ieee80211_vif *vif, int rateidx) 1760e4867225SSean Wang { 176132b1000dSSean Wang struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 176232b1000dSSean Wang struct cfg80211_chan_def *chandef = mvif->ctx ? 176332b1000dSSean Wang &mvif->ctx->def : 176432b1000dSSean Wang &phy->chandef; 176533920b2bSRyder Lee int offset = 0; 1766e4867225SSean Wang 176732b1000dSSean Wang if (chandef->chan->band != NL80211_BAND_2GHZ) 1768e4867225SSean Wang offset = 4; 1769e4867225SSean Wang 177033920b2bSRyder Lee /* pick the lowest rate for hidden nodes */ 177133920b2bSRyder Lee if (rateidx < 0) 177233920b2bSRyder Lee rateidx = 0; 177333920b2bSRyder Lee 1774d4f3d1c4SLorenzo Bianconi rateidx += offset; 1775d4f3d1c4SLorenzo Bianconi if (rateidx >= ARRAY_SIZE(mt76_rates)) 1776d4f3d1c4SLorenzo Bianconi rateidx = offset; 1777e4867225SSean Wang 1778d4f3d1c4SLorenzo Bianconi return mt76_rates[rateidx].hw_value; 1779e4867225SSean Wang } 178033920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); 178154ae98ffSLorenzo Bianconi 178254ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, 1783731425f3SShayne Chen struct mt76_sta_stats *stats, bool eht) 178454ae98ffSLorenzo Bianconi { 178554ae98ffSLorenzo Bianconi int i, ei = wi->initial_stat_idx; 178654ae98ffSLorenzo Bianconi u64 *data = wi->data; 178754ae98ffSLorenzo Bianconi 178854ae98ffSLorenzo Bianconi wi->sta_count++; 178954ae98ffSLorenzo Bianconi 179054ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; 179154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; 179254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; 179354ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; 179454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; 179554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; 179654ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; 179754ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; 179854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; 1799731425f3SShayne Chen if (eht) { 1800731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU]; 1801731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG]; 1802731425f3SShayne Chen data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU]; 1803731425f3SShayne Chen } 180454ae98ffSLorenzo Bianconi 1805731425f3SShayne Chen for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++) 180654ae98ffSLorenzo Bianconi data[ei++] += stats->tx_bw[i]; 180754ae98ffSLorenzo Bianconi 1808731425f3SShayne Chen for (i = 0; i < (eht ? 14 : 12); i++) 180954ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mcs[i]; 181054ae98ffSLorenzo Bianconi 1811749c2c2bSRyder Lee for (i = 0; i < 4; i++) 1812749c2c2bSRyder Lee data[ei++] += stats->tx_nss[i]; 1813749c2c2bSRyder Lee 181454ae98ffSLorenzo Bianconi wi->worker_stat_count = ei - wi->initial_stat_idx; 181554ae98ffSLorenzo Bianconi } 181654ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker); 18173f306448SFelix Fietkau 1818192ad406SLorenzo Bianconi void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index) 1819192ad406SLorenzo Bianconi { 1820192ad406SLorenzo Bianconi #ifdef CONFIG_PAGE_POOL_STATS 1821192ad406SLorenzo Bianconi struct page_pool_stats stats = {}; 1822192ad406SLorenzo Bianconi int i; 1823192ad406SLorenzo Bianconi 1824192ad406SLorenzo Bianconi mt76_for_each_q_rx(dev, i) 1825192ad406SLorenzo Bianconi page_pool_get_stats(dev->q_rx[i].page_pool, &stats); 1826192ad406SLorenzo Bianconi 1827192ad406SLorenzo Bianconi page_pool_ethtool_stats_get(data, &stats); 1828192ad406SLorenzo Bianconi *index += page_pool_ethtool_stats_get_count(); 1829192ad406SLorenzo Bianconi #endif 1830192ad406SLorenzo Bianconi } 1831192ad406SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats); 1832192ad406SLorenzo Bianconi 18333f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) 18343f306448SFelix Fietkau { 18353f306448SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 18363f306448SFelix Fietkau struct mt76_dev *dev = phy->dev; 18373f306448SFelix Fietkau 18383f306448SFelix Fietkau if (dev->region == NL80211_DFS_UNSET || 18393f306448SFelix Fietkau test_bit(MT76_SCANNING, &phy->state)) 18403f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 18413f306448SFelix Fietkau 18423f306448SFelix Fietkau if (!hw->conf.radar_enabled) { 18433f306448SFelix Fietkau if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && 18443f306448SFelix Fietkau (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) 18453f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 18463f306448SFelix Fietkau 18473f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 18483f306448SFelix Fietkau } 18493f306448SFelix Fietkau 185000a883e6SFelix Fietkau if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) 18513f306448SFelix Fietkau return MT_DFS_STATE_CAC; 18523f306448SFelix Fietkau 18533f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 18543f306448SFelix Fietkau } 18553f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); 1856