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), 7817f1de56SFelix Fietkau }; 7917f1de56SFelix Fietkau 80edf9dab8SLorenzo Bianconi static const struct ieee80211_channel mt76_channels_6ghz[] = { 81edf9dab8SLorenzo Bianconi /* UNII-5 */ 82edf9dab8SLorenzo Bianconi CHAN6G(1, 5955), 83edf9dab8SLorenzo Bianconi CHAN6G(5, 5975), 84edf9dab8SLorenzo Bianconi CHAN6G(9, 5995), 85edf9dab8SLorenzo Bianconi CHAN6G(13, 6015), 86edf9dab8SLorenzo Bianconi CHAN6G(17, 6035), 87edf9dab8SLorenzo Bianconi CHAN6G(21, 6055), 88edf9dab8SLorenzo Bianconi CHAN6G(25, 6075), 89edf9dab8SLorenzo Bianconi CHAN6G(29, 6095), 90edf9dab8SLorenzo Bianconi CHAN6G(33, 6115), 91edf9dab8SLorenzo Bianconi CHAN6G(37, 6135), 92edf9dab8SLorenzo Bianconi CHAN6G(41, 6155), 93edf9dab8SLorenzo Bianconi CHAN6G(45, 6175), 94edf9dab8SLorenzo Bianconi CHAN6G(49, 6195), 95edf9dab8SLorenzo Bianconi CHAN6G(53, 6215), 96edf9dab8SLorenzo Bianconi CHAN6G(57, 6235), 97edf9dab8SLorenzo Bianconi CHAN6G(61, 6255), 98edf9dab8SLorenzo Bianconi CHAN6G(65, 6275), 99edf9dab8SLorenzo Bianconi CHAN6G(69, 6295), 100edf9dab8SLorenzo Bianconi CHAN6G(73, 6315), 101edf9dab8SLorenzo Bianconi CHAN6G(77, 6335), 102edf9dab8SLorenzo Bianconi CHAN6G(81, 6355), 103edf9dab8SLorenzo Bianconi CHAN6G(85, 6375), 104edf9dab8SLorenzo Bianconi CHAN6G(89, 6395), 105edf9dab8SLorenzo Bianconi CHAN6G(93, 6415), 106edf9dab8SLorenzo Bianconi /* UNII-6 */ 107edf9dab8SLorenzo Bianconi CHAN6G(97, 6435), 108edf9dab8SLorenzo Bianconi CHAN6G(101, 6455), 109edf9dab8SLorenzo Bianconi CHAN6G(105, 6475), 110edf9dab8SLorenzo Bianconi CHAN6G(109, 6495), 111edf9dab8SLorenzo Bianconi CHAN6G(113, 6515), 112edf9dab8SLorenzo Bianconi CHAN6G(117, 6535), 113edf9dab8SLorenzo Bianconi /* UNII-7 */ 114edf9dab8SLorenzo Bianconi CHAN6G(121, 6555), 115edf9dab8SLorenzo Bianconi CHAN6G(125, 6575), 116edf9dab8SLorenzo Bianconi CHAN6G(129, 6595), 117edf9dab8SLorenzo Bianconi CHAN6G(133, 6615), 118edf9dab8SLorenzo Bianconi CHAN6G(137, 6635), 119edf9dab8SLorenzo Bianconi CHAN6G(141, 6655), 120edf9dab8SLorenzo Bianconi CHAN6G(145, 6675), 121edf9dab8SLorenzo Bianconi CHAN6G(149, 6695), 122edf9dab8SLorenzo Bianconi CHAN6G(153, 6715), 123edf9dab8SLorenzo Bianconi CHAN6G(157, 6735), 124edf9dab8SLorenzo Bianconi CHAN6G(161, 6755), 125edf9dab8SLorenzo Bianconi CHAN6G(165, 6775), 126edf9dab8SLorenzo Bianconi CHAN6G(169, 6795), 127edf9dab8SLorenzo Bianconi CHAN6G(173, 6815), 128edf9dab8SLorenzo Bianconi CHAN6G(177, 6835), 129edf9dab8SLorenzo Bianconi CHAN6G(181, 6855), 130edf9dab8SLorenzo Bianconi CHAN6G(185, 6875), 131edf9dab8SLorenzo Bianconi /* UNII-8 */ 132edf9dab8SLorenzo Bianconi CHAN6G(189, 6895), 133edf9dab8SLorenzo Bianconi CHAN6G(193, 6915), 134edf9dab8SLorenzo Bianconi CHAN6G(197, 6935), 135edf9dab8SLorenzo Bianconi CHAN6G(201, 6955), 136edf9dab8SLorenzo Bianconi CHAN6G(205, 6975), 137edf9dab8SLorenzo Bianconi CHAN6G(209, 6995), 138edf9dab8SLorenzo Bianconi CHAN6G(213, 7015), 139edf9dab8SLorenzo Bianconi CHAN6G(217, 7035), 140edf9dab8SLorenzo Bianconi CHAN6G(221, 7055), 141edf9dab8SLorenzo Bianconi CHAN6G(225, 7075), 142edf9dab8SLorenzo Bianconi CHAN6G(229, 7095), 143edf9dab8SLorenzo Bianconi CHAN6G(233, 7115), 144edf9dab8SLorenzo Bianconi }; 145edf9dab8SLorenzo Bianconi 14617f1de56SFelix Fietkau static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 14717f1de56SFelix Fietkau { .throughput = 0 * 1024, .blink_time = 334 }, 14817f1de56SFelix Fietkau { .throughput = 1 * 1024, .blink_time = 260 }, 14917f1de56SFelix Fietkau { .throughput = 5 * 1024, .blink_time = 220 }, 15017f1de56SFelix Fietkau { .throughput = 10 * 1024, .blink_time = 190 }, 15117f1de56SFelix Fietkau { .throughput = 20 * 1024, .blink_time = 170 }, 15217f1de56SFelix Fietkau { .throughput = 50 * 1024, .blink_time = 150 }, 15317f1de56SFelix Fietkau { .throughput = 70 * 1024, .blink_time = 130 }, 15417f1de56SFelix Fietkau { .throughput = 100 * 1024, .blink_time = 110 }, 15517f1de56SFelix Fietkau { .throughput = 200 * 1024, .blink_time = 80 }, 15617f1de56SFelix Fietkau { .throughput = 300 * 1024, .blink_time = 50 }, 15717f1de56SFelix Fietkau }; 15817f1de56SFelix Fietkau 15954b8fdebSLorenzo Bianconi struct ieee80211_rate mt76_rates[] = { 16054b8fdebSLorenzo Bianconi CCK_RATE(0, 10), 16154b8fdebSLorenzo Bianconi CCK_RATE(1, 20), 16254b8fdebSLorenzo Bianconi CCK_RATE(2, 55), 16354b8fdebSLorenzo Bianconi CCK_RATE(3, 110), 16454b8fdebSLorenzo Bianconi OFDM_RATE(11, 60), 16554b8fdebSLorenzo Bianconi OFDM_RATE(15, 90), 16654b8fdebSLorenzo Bianconi OFDM_RATE(10, 120), 16754b8fdebSLorenzo Bianconi OFDM_RATE(14, 180), 16854b8fdebSLorenzo Bianconi OFDM_RATE(9, 240), 16954b8fdebSLorenzo Bianconi OFDM_RATE(13, 360), 17054b8fdebSLorenzo Bianconi OFDM_RATE(8, 480), 17154b8fdebSLorenzo Bianconi OFDM_RATE(12, 540), 17254b8fdebSLorenzo Bianconi }; 17354b8fdebSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rates); 17454b8fdebSLorenzo Bianconi 175502604f5SYN Chen static const struct cfg80211_sar_freq_ranges mt76_sar_freq_ranges[] = { 176502604f5SYN Chen { .start_freq = 2402, .end_freq = 2494, }, 177502604f5SYN Chen { .start_freq = 5150, .end_freq = 5350, }, 178502604f5SYN Chen { .start_freq = 5350, .end_freq = 5470, }, 179502604f5SYN Chen { .start_freq = 5470, .end_freq = 5725, }, 180502604f5SYN Chen { .start_freq = 5725, .end_freq = 5950, }, 181162d5c14SDeren Wu { .start_freq = 5945, .end_freq = 6165, }, 182162d5c14SDeren Wu { .start_freq = 6165, .end_freq = 6405, }, 183162d5c14SDeren Wu { .start_freq = 6405, .end_freq = 6525, }, 184162d5c14SDeren Wu { .start_freq = 6525, .end_freq = 6705, }, 185162d5c14SDeren Wu { .start_freq = 6705, .end_freq = 6865, }, 186162d5c14SDeren Wu { .start_freq = 6865, .end_freq = 7125, }, 187502604f5SYN Chen }; 188502604f5SYN Chen 18997f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = { 190502604f5SYN Chen .type = NL80211_SAR_TYPE_POWER, 191502604f5SYN Chen .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), 192502604f5SYN Chen .freq_ranges = &mt76_sar_freq_ranges[0], 193502604f5SYN Chen }; 194502604f5SYN Chen 19517f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev) 19617f1de56SFelix Fietkau { 19717f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node; 19817f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 19917f1de56SFelix Fietkau int led_pin; 20017f1de56SFelix Fietkau 20117f1de56SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 20217f1de56SFelix Fietkau return 0; 20317f1de56SFelix Fietkau 20417f1de56SFelix Fietkau snprintf(dev->led_name, sizeof(dev->led_name), 20517f1de56SFelix Fietkau "mt76-%s", wiphy_name(hw->wiphy)); 20617f1de56SFelix Fietkau 20717f1de56SFelix Fietkau dev->led_cdev.name = dev->led_name; 20817f1de56SFelix Fietkau dev->led_cdev.default_trigger = 20917f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 21017f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 21117f1de56SFelix Fietkau mt76_tpt_blink, 21217f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 21317f1de56SFelix Fietkau 21417f1de56SFelix Fietkau np = of_get_child_by_name(np, "led"); 21517f1de56SFelix Fietkau if (np) { 21617f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin)) 21717f1de56SFelix Fietkau dev->led_pin = led_pin; 21817f1de56SFelix Fietkau dev->led_al = of_property_read_bool(np, "led-active-low"); 2190a14c1d0SLiang He of_node_put(np); 22017f1de56SFelix Fietkau } 22117f1de56SFelix Fietkau 22236f7e2b2SFelix Fietkau return led_classdev_register(dev->dev, &dev->led_cdev); 22336f7e2b2SFelix Fietkau } 22436f7e2b2SFelix Fietkau 22536f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev) 22636f7e2b2SFelix Fietkau { 22736f7e2b2SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 22836f7e2b2SFelix Fietkau return; 22936f7e2b2SFelix Fietkau 23036f7e2b2SFelix Fietkau led_classdev_unregister(&dev->led_cdev); 23117f1de56SFelix Fietkau } 23217f1de56SFelix Fietkau 233bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy, 234551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 235551e1ef4SLorenzo Bianconi bool vht) 236551e1ef4SLorenzo Bianconi { 237551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 238bb3e3fecSRyder Lee int i, nstream = hweight8(phy->antenna_mask); 239551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 240551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 241551e1ef4SLorenzo Bianconi 242551e1ef4SLorenzo Bianconi if (nstream > 1) 243551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 244551e1ef4SLorenzo Bianconi else 245551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 246551e1ef4SLorenzo Bianconi 247551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 248551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 249551e1ef4SLorenzo Bianconi 250551e1ef4SLorenzo Bianconi if (!vht) 251551e1ef4SLorenzo Bianconi return; 252551e1ef4SLorenzo Bianconi 253551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 254551e1ef4SLorenzo Bianconi if (nstream > 1) 255551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 256551e1ef4SLorenzo Bianconi else 257551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 258abba3453SDeren Wu vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 259abba3453SDeren Wu IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; 260551e1ef4SLorenzo Bianconi 261551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 262551e1ef4SLorenzo Bianconi if (i < nstream) 263551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 264551e1ef4SLorenzo Bianconi else 265551e1ef4SLorenzo Bianconi mcs_map |= 266551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 267551e1ef4SLorenzo Bianconi } 268551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 269551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 270781b80f4SFelix Fietkau if (ieee80211_hw_check(phy->hw, SUPPORTS_VHT_EXT_NSS_BW)) 271d9fcfc14SDeren Wu vht_cap->vht_mcs.tx_highest |= 272d9fcfc14SDeren Wu cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); 273551e1ef4SLorenzo Bianconi } 274551e1ef4SLorenzo Bianconi 275bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 2765ebdc3e0SLorenzo Bianconi { 27748dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) 278bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 27948dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) 280bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 281edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) 282edf9dab8SLorenzo Bianconi mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); 2835ebdc3e0SLorenzo Bianconi } 2845ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 2855ebdc3e0SLorenzo Bianconi 28617f1de56SFelix Fietkau static int 28777af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, 28817f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 289edf9dab8SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates, 290edf9dab8SLorenzo Bianconi bool ht, bool vht) 29117f1de56SFelix Fietkau { 29217f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 29317f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 29477af762eSLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap; 29577af762eSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 29617f1de56SFelix Fietkau void *chanlist; 29717f1de56SFelix Fietkau int size; 29817f1de56SFelix Fietkau 29917f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 30017f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 30117f1de56SFelix Fietkau if (!chanlist) 30217f1de56SFelix Fietkau return -ENOMEM; 30317f1de56SFelix Fietkau 304a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 30517f1de56SFelix Fietkau GFP_KERNEL); 30617f1de56SFelix Fietkau if (!msband->chan) 30717f1de56SFelix Fietkau return -ENOMEM; 30817f1de56SFelix Fietkau 30917f1de56SFelix Fietkau sband->channels = chanlist; 31017f1de56SFelix Fietkau sband->n_channels = n_chan; 31117f1de56SFelix Fietkau sband->bitrates = rates; 31217f1de56SFelix Fietkau sband->n_bitrates = n_rates; 31317f1de56SFelix Fietkau 314edf9dab8SLorenzo Bianconi if (!ht) 315edf9dab8SLorenzo Bianconi return 0; 316edf9dab8SLorenzo Bianconi 31717f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 31817f1de56SFelix Fietkau ht_cap->ht_supported = true; 31917f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 32017f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 32117f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 32217f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 32317f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 32417f1de56SFelix Fietkau 32517f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 32617f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 32717f1de56SFelix Fietkau 32877af762eSLorenzo Bianconi mt76_init_stream_cap(phy, sband, vht); 329551e1ef4SLorenzo Bianconi 33017f1de56SFelix Fietkau if (!vht) 33117f1de56SFelix Fietkau return 0; 33217f1de56SFelix Fietkau 33317f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 33417f1de56SFelix Fietkau vht_cap->vht_supported = true; 33517f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 33617f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 33749149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 33849149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 33917f1de56SFelix Fietkau 34017f1de56SFelix Fietkau return 0; 34117f1de56SFelix Fietkau } 34217f1de56SFelix Fietkau 34317f1de56SFelix Fietkau static int 34477af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, 34517f1de56SFelix Fietkau int n_rates) 34617f1de56SFelix Fietkau { 34777af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 34817f1de56SFelix Fietkau 34977af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, 35077af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_2ghz), rates, 351edf9dab8SLorenzo Bianconi n_rates, true, false); 35217f1de56SFelix Fietkau } 35317f1de56SFelix Fietkau 35417f1de56SFelix Fietkau static int 35577af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, 35617f1de56SFelix Fietkau int n_rates, bool vht) 35717f1de56SFelix Fietkau { 35877af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 35917f1de56SFelix Fietkau 36077af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, 36177af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_5ghz), rates, 362edf9dab8SLorenzo Bianconi n_rates, true, vht); 363edf9dab8SLorenzo Bianconi } 364edf9dab8SLorenzo Bianconi 365edf9dab8SLorenzo Bianconi static int 366edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, 367edf9dab8SLorenzo Bianconi int n_rates) 368edf9dab8SLorenzo Bianconi { 369edf9dab8SLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; 370edf9dab8SLorenzo Bianconi 371edf9dab8SLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, 372edf9dab8SLorenzo Bianconi ARRAY_SIZE(mt76_channels_6ghz), rates, 373edf9dab8SLorenzo Bianconi n_rates, false, false); 37417f1de56SFelix Fietkau } 37517f1de56SFelix Fietkau 37617f1de56SFelix Fietkau static void 377c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 378c89d3625SFelix Fietkau enum nl80211_band band) 37917f1de56SFelix Fietkau { 380c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 38117f1de56SFelix Fietkau bool found = false; 38217f1de56SFelix Fietkau int i; 38317f1de56SFelix Fietkau 38417f1de56SFelix Fietkau if (!sband) 38517f1de56SFelix Fietkau return; 38617f1de56SFelix Fietkau 38717f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 38817f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 38917f1de56SFelix Fietkau continue; 39017f1de56SFelix Fietkau 39117f1de56SFelix Fietkau found = true; 39217f1de56SFelix Fietkau break; 39317f1de56SFelix Fietkau } 39417f1de56SFelix Fietkau 395c89d3625SFelix Fietkau if (found) { 396c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0]; 397c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0]; 39817f1de56SFelix Fietkau return; 399c89d3625SFelix Fietkau } 40017f1de56SFelix Fietkau 40117f1de56SFelix Fietkau sband->n_channels = 0; 402c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL; 40317f1de56SFelix Fietkau } 40417f1de56SFelix Fietkau 405d43de9cfSLorenzo Bianconi static int 40698df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) 407c89d3625SFelix Fietkau { 40898df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 409c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 410c89d3625SFelix Fietkau 411c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 41298df2baeSLorenzo Bianconi SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); 413c89d3625SFelix Fietkau 414c89d3625SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 415dd89a013SLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 416b807b368SLorenzo Bianconi WIPHY_FLAG_SUPPORTS_TDLS | 417b807b368SLorenzo Bianconi WIPHY_FLAG_AP_UAPSD; 418c89d3625SFelix Fietkau 419c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 420c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 421d9c54264SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 422c89d3625SFelix Fietkau 4230a57d636SBo Jiao wiphy->available_antennas_tx = phy->antenna_mask; 4240a57d636SBo Jiao wiphy->available_antennas_rx = phy->antenna_mask; 425c89d3625SFelix Fietkau 426d43de9cfSLorenzo Bianconi wiphy->sar_capa = &mt76_sar_capa; 427d43de9cfSLorenzo Bianconi phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, 428d43de9cfSLorenzo Bianconi sizeof(struct mt76_freq_range_power), 429d43de9cfSLorenzo Bianconi GFP_KERNEL); 430d43de9cfSLorenzo Bianconi if (!phy->frp) 431d43de9cfSLorenzo Bianconi return -ENOMEM; 432d43de9cfSLorenzo Bianconi 433c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 434b807b368SLorenzo Bianconi hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 435c9619dfaSShayne Chen 436c9619dfaSShayne Chen if (!hw->max_tx_fragments) 437c89d3625SFelix Fietkau hw->max_tx_fragments = 16; 438c89d3625SFelix Fietkau 439c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 440c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 441c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 442c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 443c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 444c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 445ed89b893SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 4465b0fb852SBen Greear 4475b0fb852SBen Greear if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) { 448c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 449c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 4505b0fb852SBen Greear } 4515b0fb852SBen Greear 452c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 453c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 454c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 455d43de9cfSLorenzo Bianconi 456d43de9cfSLorenzo Bianconi return 0; 457c89d3625SFelix Fietkau } 458c89d3625SFelix Fietkau 459c89d3625SFelix Fietkau struct mt76_phy * 460c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 461dc44c45cSLorenzo Bianconi const struct ieee80211_ops *ops, u8 band_idx) 462c89d3625SFelix Fietkau { 463c89d3625SFelix Fietkau struct ieee80211_hw *hw; 464db78a791SLorenzo Bianconi unsigned int phy_size; 465c89d3625SFelix Fietkau struct mt76_phy *phy; 466c89d3625SFelix Fietkau 467c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8); 468db78a791SLorenzo Bianconi hw = ieee80211_alloc_hw(size + phy_size, ops); 469c89d3625SFelix Fietkau if (!hw) 470c89d3625SFelix Fietkau return NULL; 471c89d3625SFelix Fietkau 472c89d3625SFelix Fietkau phy = hw->priv; 473c89d3625SFelix Fietkau phy->dev = dev; 474c89d3625SFelix Fietkau phy->hw = hw; 475db78a791SLorenzo Bianconi phy->priv = hw->priv + phy_size; 476dc44c45cSLorenzo Bianconi phy->band_idx = band_idx; 477c89d3625SFelix Fietkau 4788af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 4798af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 4808af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 4818af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 4828af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 4838af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 4848af414e8SLorenzo Bianconi #endif 4858af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 4868af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 4878af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 4888af414e8SLorenzo Bianconi 489c89d3625SFelix Fietkau return phy; 490c89d3625SFelix Fietkau } 491c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy); 492c89d3625SFelix Fietkau 493db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht, 494db78a791SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates) 495c89d3625SFelix Fietkau { 496c89d3625SFelix Fietkau int ret; 497c89d3625SFelix Fietkau 498d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, phy->hw); 499d43de9cfSLorenzo Bianconi if (ret) 500d43de9cfSLorenzo Bianconi return ret; 501db78a791SLorenzo Bianconi 502db78a791SLorenzo Bianconi if (phy->cap.has_2ghz) { 503db78a791SLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 504db78a791SLorenzo Bianconi if (ret) 505db78a791SLorenzo Bianconi return ret; 506db78a791SLorenzo Bianconi } 507db78a791SLorenzo Bianconi 508db78a791SLorenzo Bianconi if (phy->cap.has_5ghz) { 509db78a791SLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 510db78a791SLorenzo Bianconi if (ret) 511db78a791SLorenzo Bianconi return ret; 512db78a791SLorenzo Bianconi } 513db78a791SLorenzo Bianconi 514edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 515edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 516edf9dab8SLorenzo Bianconi if (ret) 517edf9dab8SLorenzo Bianconi return ret; 518edf9dab8SLorenzo Bianconi } 519edf9dab8SLorenzo Bianconi 520db78a791SLorenzo Bianconi wiphy_read_of_freq_limits(phy->hw->wiphy); 521db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 522db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 523edf9dab8SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); 524db78a791SLorenzo Bianconi 525c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw); 526c89d3625SFelix Fietkau if (ret) 527c89d3625SFelix Fietkau return ret; 528c89d3625SFelix Fietkau 529dc44c45cSLorenzo Bianconi phy->dev->phys[phy->band_idx] = phy; 530db78a791SLorenzo Bianconi 531c89d3625SFelix Fietkau return 0; 532c89d3625SFelix Fietkau } 533c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy); 534c89d3625SFelix Fietkau 535db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy) 536c89d3625SFelix Fietkau { 537c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev; 538c89d3625SFelix Fietkau 539c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 540c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw); 541dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = NULL; 542c89d3625SFelix Fietkau } 543c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy); 544c89d3625SFelix Fietkau 545a85b590cSFelix Fietkau struct mt76_dev * 546c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 547c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 548c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 549a85b590cSFelix Fietkau { 550a85b590cSFelix Fietkau struct ieee80211_hw *hw; 551ac24dd35SFelix Fietkau struct mt76_phy *phy; 552a85b590cSFelix Fietkau struct mt76_dev *dev; 553e5443256SFelix Fietkau int i; 554a85b590cSFelix Fietkau 555a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 556a85b590cSFelix Fietkau if (!hw) 557a85b590cSFelix Fietkau return NULL; 558a85b590cSFelix Fietkau 559a85b590cSFelix Fietkau dev = hw->priv; 560a85b590cSFelix Fietkau dev->hw = hw; 561c0f7b25aSLorenzo Bianconi dev->dev = pdev; 562c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 563d1ddc536SFelix Fietkau dev->dma_dev = pdev; 564c0f7b25aSLorenzo Bianconi 565ac24dd35SFelix Fietkau phy = &dev->phy; 566ac24dd35SFelix Fietkau phy->dev = dev; 567ac24dd35SFelix Fietkau phy->hw = hw; 568dc44c45cSLorenzo Bianconi phy->band_idx = MT_BAND0; 569dc44c45cSLorenzo Bianconi dev->phys[phy->band_idx] = phy; 570ac24dd35SFelix Fietkau 571a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 572a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 573a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 574c34f1005SLorenzo Bianconi spin_lock_init(&dev->status_lock); 575*2666beceSSujuan Chen spin_lock_init(&dev->wed_lock); 576108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 57726e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 578a85b590cSFelix Fietkau 57909872957SLorenzo Bianconi skb_queue_head_init(&dev->mcu.res_q); 58009872957SLorenzo Bianconi init_waitqueue_head(&dev->mcu.wait); 58109872957SLorenzo Bianconi mutex_init(&dev->mcu.mutex); 582781eef5bSFelix Fietkau dev->tx_worker.fn = mt76_tx_worker; 58309872957SLorenzo Bianconi 5848af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 5858af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 5868af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 5878af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 5888af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 5898af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 5908af414e8SLorenzo Bianconi #endif 5918af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 5928af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 5938af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 5948af414e8SLorenzo Bianconi 59551252cc5SLorenzo Bianconi spin_lock_init(&dev->token_lock); 59651252cc5SLorenzo Bianconi idr_init(&dev->token); 59751252cc5SLorenzo Bianconi 598*2666beceSSujuan Chen spin_lock_init(&dev->rx_token_lock); 599*2666beceSSujuan Chen idr_init(&dev->rx_token); 600*2666beceSSujuan Chen 601bd1e3e7bSLorenzo Bianconi INIT_LIST_HEAD(&dev->wcid_list); 602bd1e3e7bSLorenzo Bianconi 603e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 604*2666beceSSujuan Chen INIT_LIST_HEAD(&dev->rxwi_cache); 60561b5156bSFelix Fietkau dev->token_size = dev->drv->token_size; 606e5443256SFelix Fietkau 607e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 608e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 609e5443256SFelix Fietkau 610a86f1d01SLorenzo Bianconi dev->wq = alloc_ordered_workqueue("mt76", 0); 611a86f1d01SLorenzo Bianconi if (!dev->wq) { 612a86f1d01SLorenzo Bianconi ieee80211_free_hw(hw); 613a86f1d01SLorenzo Bianconi return NULL; 614a86f1d01SLorenzo Bianconi } 615a86f1d01SLorenzo Bianconi 616a85b590cSFelix Fietkau return dev; 617a85b590cSFelix Fietkau } 618a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 619a85b590cSFelix Fietkau 62017f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 62117f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 62217f1de56SFelix Fietkau { 62317f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 624c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy; 62517f1de56SFelix Fietkau int ret; 62617f1de56SFelix Fietkau 62717f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 628d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, hw); 629d43de9cfSLorenzo Bianconi if (ret) 630d43de9cfSLorenzo Bianconi return ret; 63117f1de56SFelix Fietkau 63248dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) { 63377af762eSLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 63417f1de56SFelix Fietkau if (ret) 63517f1de56SFelix Fietkau return ret; 63617f1de56SFelix Fietkau } 63717f1de56SFelix Fietkau 63848dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) { 63977af762eSLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 64017f1de56SFelix Fietkau if (ret) 64117f1de56SFelix Fietkau return ret; 64217f1de56SFelix Fietkau } 64317f1de56SFelix Fietkau 644edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 645edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 646edf9dab8SLorenzo Bianconi if (ret) 647edf9dab8SLorenzo Bianconi return ret; 648edf9dab8SLorenzo Bianconi } 649edf9dab8SLorenzo Bianconi 650c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy); 651c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 652c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 653edf9dab8SLorenzo Bianconi mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); 65417f1de56SFelix Fietkau 655b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 65617f1de56SFelix Fietkau ret = mt76_led_init(dev); 65717f1de56SFelix Fietkau if (ret) 65817f1de56SFelix Fietkau return ret; 659b374e868SArnd Bergmann } 66017f1de56SFelix Fietkau 661781eef5bSFelix Fietkau ret = ieee80211_register_hw(hw); 662781eef5bSFelix Fietkau if (ret) 663781eef5bSFelix Fietkau return ret; 664781eef5bSFelix Fietkau 665781eef5bSFelix Fietkau WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 666781eef5bSFelix Fietkau sched_set_fifo_low(dev->tx_worker.task); 667781eef5bSFelix Fietkau 668781eef5bSFelix Fietkau return 0; 66917f1de56SFelix Fietkau } 67017f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 67117f1de56SFelix Fietkau 67217f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 67317f1de56SFelix Fietkau { 67417f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 67517f1de56SFelix Fietkau 676d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 67736f7e2b2SFelix Fietkau mt76_led_cleanup(dev); 678c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 67917f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 68017f1de56SFelix Fietkau } 68117f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 68217f1de56SFelix Fietkau 683def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 684def34a2fSLorenzo Bianconi { 685781eef5bSFelix Fietkau mt76_worker_teardown(&dev->tx_worker); 686a86f1d01SLorenzo Bianconi if (dev->wq) { 687a86f1d01SLorenzo Bianconi destroy_workqueue(dev->wq); 688a86f1d01SLorenzo Bianconi dev->wq = NULL; 689a86f1d01SLorenzo Bianconi } 690def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 691def34a2fSLorenzo Bianconi } 692def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 693def34a2fSLorenzo Bianconi 694cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) 695cc4b3c13SLorenzo Bianconi { 696cc4b3c13SLorenzo Bianconi struct sk_buff *skb = phy->rx_amsdu[q].head; 6972c2bdd23SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 698cc4b3c13SLorenzo Bianconi struct mt76_dev *dev = phy->dev; 699cc4b3c13SLorenzo Bianconi 700cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = NULL; 701cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = NULL; 7022c2bdd23SFelix Fietkau 7032c2bdd23SFelix Fietkau /* 7042c2bdd23SFelix Fietkau * Validate if the amsdu has a proper first subframe. 7052c2bdd23SFelix Fietkau * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU 7062c2bdd23SFelix Fietkau * flag of the QoS header gets flipped. In such cases, the first 7072c2bdd23SFelix Fietkau * subframe has a LLC/SNAP header in the location of the destination 7082c2bdd23SFelix Fietkau * address. 7092c2bdd23SFelix Fietkau */ 7102c2bdd23SFelix Fietkau if (skb_shinfo(skb)->frag_list) { 7112c2bdd23SFelix Fietkau int offset = 0; 7122c2bdd23SFelix Fietkau 7132c2bdd23SFelix Fietkau if (!(status->flag & RX_FLAG_8023)) { 7142c2bdd23SFelix Fietkau offset = ieee80211_get_hdrlen_from_skb(skb); 7152c2bdd23SFelix Fietkau 7162c2bdd23SFelix Fietkau if ((status->flag & 7172c2bdd23SFelix Fietkau (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == 7182c2bdd23SFelix Fietkau RX_FLAG_DECRYPTED) 7192c2bdd23SFelix Fietkau offset += 8; 7202c2bdd23SFelix Fietkau } 7212c2bdd23SFelix Fietkau 7222c2bdd23SFelix Fietkau if (ether_addr_equal(skb->data + offset, rfc1042_header)) { 7232c2bdd23SFelix Fietkau dev_kfree_skb(skb); 7242c2bdd23SFelix Fietkau return; 7252c2bdd23SFelix Fietkau } 7262c2bdd23SFelix Fietkau } 727cc4b3c13SLorenzo Bianconi __skb_queue_tail(&dev->rx_skb[q], skb); 728cc4b3c13SLorenzo Bianconi } 729cc4b3c13SLorenzo Bianconi 730cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, 731cc4b3c13SLorenzo Bianconi struct sk_buff *skb) 732cc4b3c13SLorenzo Bianconi { 733cc4b3c13SLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 734cc4b3c13SLorenzo Bianconi 735cc4b3c13SLorenzo Bianconi if (phy->rx_amsdu[q].head && 736cc4b3c13SLorenzo Bianconi (!status->amsdu || status->first_amsdu || 737cc4b3c13SLorenzo Bianconi status->seqno != phy->rx_amsdu[q].seqno)) 738cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 739cc4b3c13SLorenzo Bianconi 740cc4b3c13SLorenzo Bianconi if (!phy->rx_amsdu[q].head) { 741cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; 742cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].seqno = status->seqno; 743cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = skb; 744cc4b3c13SLorenzo Bianconi } else { 745cc4b3c13SLorenzo Bianconi *phy->rx_amsdu[q].tail = skb; 746cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb->next; 747cc4b3c13SLorenzo Bianconi } 748cc4b3c13SLorenzo Bianconi 749cc4b3c13SLorenzo Bianconi if (!status->amsdu || status->last_amsdu) 750cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 751cc4b3c13SLorenzo Bianconi } 752cc4b3c13SLorenzo Bianconi 75317f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 75417f1de56SFelix Fietkau { 755011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 756128c9b7dSLorenzo Bianconi struct mt76_phy *phy = mt76_dev_phy(dev, status->phy_idx); 757011849e0SFelix Fietkau 758011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 75917f1de56SFelix Fietkau dev_kfree_skb(skb); 76017f1de56SFelix Fietkau return; 76117f1de56SFelix Fietkau } 76217f1de56SFelix Fietkau 763f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE 764c918c74dSShayne Chen if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { 765c918c74dSShayne Chen phy->test.rx_stats.packets[q]++; 766f0efa862SFelix Fietkau if (status->flag & RX_FLAG_FAILED_FCS_CRC) 767c918c74dSShayne Chen phy->test.rx_stats.fcs_error[q]++; 768f0efa862SFelix Fietkau } 769f0efa862SFelix Fietkau #endif 770cc4b3c13SLorenzo Bianconi 771cc4b3c13SLorenzo Bianconi mt76_rx_release_burst(phy, q, skb); 77217f1de56SFelix Fietkau } 77317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 77417f1de56SFelix Fietkau 7755a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy) 77626e40d4cSFelix Fietkau { 777af005f26SLorenzo Bianconi struct mt76_queue *q; 77891990519SLorenzo Bianconi int i; 7795a95ca41SFelix Fietkau 7805a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) { 78191990519SLorenzo Bianconi q = phy->q_tx[i]; 782af005f26SLorenzo Bianconi if (q && q->queued) 78326e40d4cSFelix Fietkau return true; 78426e40d4cSFelix Fietkau } 78526e40d4cSFelix Fietkau 78626e40d4cSFelix Fietkau return false; 78726e40d4cSFelix Fietkau } 78839d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 78926e40d4cSFelix Fietkau 7900fd0eb54SFelix Fietkau static struct mt76_channel_state * 79196747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 7920fd0eb54SFelix Fietkau { 7930fd0eb54SFelix Fietkau struct mt76_sband *msband; 7940fd0eb54SFelix Fietkau int idx; 7950fd0eb54SFelix Fietkau 7960fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 79796747a51SFelix Fietkau msband = &phy->sband_2g; 798edf9dab8SLorenzo Bianconi else if (c->band == NL80211_BAND_6GHZ) 799edf9dab8SLorenzo Bianconi msband = &phy->sband_6g; 8000fd0eb54SFelix Fietkau else 80196747a51SFelix Fietkau msband = &phy->sband_5g; 8020fd0eb54SFelix Fietkau 8030fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 8040fd0eb54SFelix Fietkau return &msband->chan[idx]; 8050fd0eb54SFelix Fietkau } 8060fd0eb54SFelix Fietkau 80704414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 80896747a51SFelix Fietkau { 80996747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state; 81096747a51SFelix Fietkau 81196747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time, 81296747a51SFelix Fietkau phy->survey_time)); 81396747a51SFelix Fietkau phy->survey_time = time; 81496747a51SFelix Fietkau } 81504414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 81696747a51SFelix Fietkau 817c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy) 8185ce09c1aSFelix Fietkau { 819c560b137SRyder Lee struct mt76_dev *dev = phy->dev; 820aec65e48SFelix Fietkau ktime_t cur_time; 821aec65e48SFelix Fietkau 8225ce09c1aSFelix Fietkau if (dev->drv->update_survey) 823c560b137SRyder Lee dev->drv->update_survey(phy); 8245ce09c1aSFelix Fietkau 825aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 826c560b137SRyder Lee mt76_update_survey_active_time(phy, cur_time); 827aec65e48SFelix Fietkau 8285ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 829c560b137SRyder Lee struct mt76_channel_state *state = phy->chan_state; 83096747a51SFelix Fietkau 831237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 8325ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 8335ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 834237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 8355ce09c1aSFelix Fietkau } 8365ce09c1aSFelix Fietkau } 8375ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 8385ce09c1aSFelix Fietkau 83996747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy) 84017f1de56SFelix Fietkau { 84196747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 84296747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 84317f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 84417f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 84526e40d4cSFelix Fietkau int timeout = HZ / 5; 84617f1de56SFelix Fietkau 8475a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 848c560b137SRyder Lee mt76_update_survey(phy); 84917f1de56SFelix Fietkau 8503f306448SFelix Fietkau if (phy->chandef.chan->center_freq != chandef->chan->center_freq || 8513f306448SFelix Fietkau phy->chandef.width != chandef->width) 8523f306448SFelix Fietkau phy->dfs_state = MT_DFS_STATE_UNKNOWN; 8533f306448SFelix Fietkau 85496747a51SFelix Fietkau phy->chandef = *chandef; 85596747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan); 85617f1de56SFelix Fietkau 85717f1de56SFelix Fietkau if (!offchannel) 85896747a51SFelix Fietkau phy->main_chan = chandef->chan; 85917f1de56SFelix Fietkau 86096747a51SFelix Fietkau if (chandef->chan != phy->main_chan) 86196747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 86217f1de56SFelix Fietkau } 86317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 86417f1de56SFelix Fietkau 86517f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 86617f1de56SFelix Fietkau struct survey_info *survey) 86717f1de56SFelix Fietkau { 86896747a51SFelix Fietkau struct mt76_phy *phy = hw->priv; 86996747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 87017f1de56SFelix Fietkau struct mt76_sband *sband; 87117f1de56SFelix Fietkau struct ieee80211_channel *chan; 87217f1de56SFelix Fietkau struct mt76_channel_state *state; 87317f1de56SFelix Fietkau int ret = 0; 87417f1de56SFelix Fietkau 875237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 87617f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 877c560b137SRyder Lee mt76_update_survey(phy); 87817f1de56SFelix Fietkau 879edf9dab8SLorenzo Bianconi if (idx >= phy->sband_2g.sband.n_channels + 880edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels) { 881edf9dab8SLorenzo Bianconi idx -= (phy->sband_2g.sband.n_channels + 882edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels); 883edf9dab8SLorenzo Bianconi sband = &phy->sband_6g; 884edf9dab8SLorenzo Bianconi } else if (idx >= phy->sband_2g.sband.n_channels) { 885edf9dab8SLorenzo Bianconi idx -= phy->sband_2g.sband.n_channels; 88696747a51SFelix Fietkau sband = &phy->sband_5g; 887edf9dab8SLorenzo Bianconi } else { 888edf9dab8SLorenzo Bianconi sband = &phy->sband_2g; 88917f1de56SFelix Fietkau } 89017f1de56SFelix Fietkau 891237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 892237312c5SLorenzo Bianconi ret = -ENOENT; 893237312c5SLorenzo Bianconi goto out; 894237312c5SLorenzo Bianconi } 89517f1de56SFelix Fietkau 89617f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 89796747a51SFelix Fietkau state = mt76_channel_state(phy, chan); 89817f1de56SFelix Fietkau 89917f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 90017f1de56SFelix Fietkau survey->channel = chan; 90117f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 902ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 903e5051965SFelix Fietkau if (state->noise) 904e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM; 905e5051965SFelix Fietkau 90696747a51SFelix Fietkau if (chan == phy->main_chan) { 90717f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 90817f1de56SFelix Fietkau 9095ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 9105ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 9115ce09c1aSFelix Fietkau } 9125ce09c1aSFelix Fietkau 91317f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 9146bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 915237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 916e5051965SFelix Fietkau survey->noise = state->noise; 917237312c5SLorenzo Bianconi 918237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 919237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 920ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 92117f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 92217f1de56SFelix Fietkau 923237312c5SLorenzo Bianconi out: 924237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 925237312c5SLorenzo Bianconi 92617f1de56SFelix Fietkau return ret; 92717f1de56SFelix Fietkau } 92817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 92917f1de56SFelix Fietkau 93030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 93130ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 93230ce7f44SFelix Fietkau { 93330ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 93430ce7f44SFelix Fietkau int i; 93530ce7f44SFelix Fietkau 93630ce7f44SFelix Fietkau wcid->rx_check_pn = false; 93730ce7f44SFelix Fietkau 93830ce7f44SFelix Fietkau if (!key) 93930ce7f44SFelix Fietkau return; 94030ce7f44SFelix Fietkau 94101cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 94201cfc1b4SLorenzo Bianconi return; 94330ce7f44SFelix Fietkau 94401cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 945a1b0bbd4SXing Song 946a1b0bbd4SXing Song /* data frame */ 94730ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 94830ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 94930ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 95030ce7f44SFelix Fietkau } 951a1b0bbd4SXing Song 952a1b0bbd4SXing Song /* robust management frame */ 953a1b0bbd4SXing Song ieee80211_get_key_rx_seq(key, -1, &seq); 954a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 955a1b0bbd4SXing Song 95630ce7f44SFelix Fietkau } 95730ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 95830ce7f44SFelix Fietkau 959a71b648eSRyder Lee int mt76_rx_signal(u8 chain_mask, s8 *chain_signal) 9604550fb9eSFelix Fietkau { 9614550fb9eSFelix Fietkau int signal = -128; 9624550fb9eSFelix Fietkau u8 chains; 9634550fb9eSFelix Fietkau 964a71b648eSRyder Lee for (chains = chain_mask; chains; chains >>= 1, chain_signal++) { 9654550fb9eSFelix Fietkau int cur, diff; 9664550fb9eSFelix Fietkau 9676450b133SDeren Wu cur = *chain_signal; 9686450b133SDeren Wu if (!(chains & BIT(0)) || 9696450b133SDeren Wu cur > 0) 9704550fb9eSFelix Fietkau continue; 9714550fb9eSFelix Fietkau 9724550fb9eSFelix Fietkau if (cur > signal) 9734550fb9eSFelix Fietkau swap(cur, signal); 9744550fb9eSFelix Fietkau 9754550fb9eSFelix Fietkau diff = signal - cur; 9764550fb9eSFelix Fietkau if (diff == 0) 9774550fb9eSFelix Fietkau signal += 3; 9784550fb9eSFelix Fietkau else if (diff <= 2) 9794550fb9eSFelix Fietkau signal += 2; 9804550fb9eSFelix Fietkau else if (diff <= 6) 9814550fb9eSFelix Fietkau signal += 1; 9824550fb9eSFelix Fietkau } 9834550fb9eSFelix Fietkau 9844550fb9eSFelix Fietkau return signal; 9854550fb9eSFelix Fietkau } 986a71b648eSRyder Lee EXPORT_SYMBOL(mt76_rx_signal); 9874550fb9eSFelix Fietkau 988bfc394ddSFelix Fietkau static void 989bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 990bfc394ddSFelix Fietkau struct ieee80211_hw **hw, 991bfc394ddSFelix Fietkau struct ieee80211_sta **sta) 9924e34249eSFelix Fietkau { 9934e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 994abe3f3daSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 9954e34249eSFelix Fietkau struct mt76_rx_status mstat; 9964e34249eSFelix Fietkau 9974e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 9984e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 9994e34249eSFelix Fietkau 10004e34249eSFelix Fietkau status->flag = mstat.flag; 10014e34249eSFelix Fietkau status->freq = mstat.freq; 10024e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 10034e34249eSFelix Fietkau status->encoding = mstat.encoding; 10044e34249eSFelix Fietkau status->bw = mstat.bw; 1005af4a2f2fSRyder Lee status->he_ru = mstat.he_ru; 1006af4a2f2fSRyder Lee status->he_gi = mstat.he_gi; 1007af4a2f2fSRyder Lee status->he_dcm = mstat.he_dcm; 10084e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 10094e34249eSFelix Fietkau status->nss = mstat.nss; 10104e34249eSFelix Fietkau status->band = mstat.band; 10114e34249eSFelix Fietkau status->signal = mstat.signal; 10124e34249eSFelix Fietkau status->chains = mstat.chains; 1013d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 10140fda6d7bSRyder Lee status->device_timestamp = mstat.timestamp; 10150fda6d7bSRyder Lee status->mactime = mstat.timestamp; 1016a71b648eSRyder Lee status->signal = mt76_rx_signal(mstat.chains, mstat.chain_signal); 10174550fb9eSFelix Fietkau if (status->signal <= -128) 10184550fb9eSFelix Fietkau status->flag |= RX_FLAG_NO_SIGNAL_VAL; 10194e34249eSFelix Fietkau 1020abe3f3daSRyder Lee if (ieee80211_is_beacon(hdr->frame_control) || 1021abe3f3daSRyder Lee ieee80211_is_probe_resp(hdr->frame_control)) 1022abe3f3daSRyder Lee status->boottime_ns = ktime_get_boottime_ns(); 1023abe3f3daSRyder Lee 10244e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 102513381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 102613381dcdSRyder Lee sizeof(mstat.chain_signal)); 102713381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 102813381dcdSRyder Lee sizeof(mstat.chain_signal)); 10299c68a57bSFelix Fietkau 1030bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid); 1031128c9b7dSLorenzo Bianconi *hw = mt76_phy_hw(dev, mstat.phy_idx); 10324e34249eSFelix Fietkau } 10334e34249eSFelix Fietkau 10343c1032e1SFelix Fietkau static void 103530ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 103630ce7f44SFelix Fietkau { 103730ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 103830ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 103930ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 1040a1b0bbd4SXing Song int security_idx; 104130ce7f44SFelix Fietkau int ret; 104230ce7f44SFelix Fietkau 104330ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 10443c1032e1SFelix Fietkau return; 104530ce7f44SFelix Fietkau 10461858e4fcSMeiChia Chiu if (status->flag & RX_FLAG_ONLY_MONITOR) 10473c1032e1SFelix Fietkau return; 10481858e4fcSMeiChia Chiu 104930ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 10503c1032e1SFelix Fietkau return; 105130ce7f44SFelix Fietkau 10527360cdecSFelix Fietkau security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 10537360cdecSFelix Fietkau if (status->flag & RX_FLAG_8023) 10547360cdecSFelix Fietkau goto skip_hdr_check; 10557360cdecSFelix Fietkau 1056a1b0bbd4SXing Song hdr = mt76_skb_get_hdr(skb); 105730ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 105830ce7f44SFelix Fietkau /* 105930ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 106030ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 106130ce7f44SFelix Fietkau */ 106230ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 106330ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 10643c1032e1SFelix Fietkau return; 106530ce7f44SFelix Fietkau } 106630ce7f44SFelix Fietkau 1067a1b0bbd4SXing Song /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): 1068a1b0bbd4SXing Song * 1069a1b0bbd4SXing Song * the recipient shall maintain a single replay counter for received 1070a1b0bbd4SXing Song * individually addressed robust Management frames that are received 1071a1b0bbd4SXing Song * with the To DS subfield equal to 0, [...] 1072a1b0bbd4SXing Song */ 1073a1b0bbd4SXing Song if (ieee80211_is_mgmt(hdr->frame_control) && 1074a1b0bbd4SXing Song !ieee80211_has_tods(hdr->frame_control)) 1075a1b0bbd4SXing Song security_idx = IEEE80211_NUM_TIDS; 1076a1b0bbd4SXing Song 10777360cdecSFelix Fietkau skip_hdr_check: 107830ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 1079a1b0bbd4SXing Song ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], 108030ce7f44SFelix Fietkau sizeof(status->iv)); 10813c1032e1SFelix Fietkau if (ret <= 0) { 10823c1032e1SFelix Fietkau status->flag |= RX_FLAG_ONLY_MONITOR; 10833c1032e1SFelix Fietkau return; 10843c1032e1SFelix Fietkau } 108530ce7f44SFelix Fietkau 1086a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); 108730ce7f44SFelix Fietkau 108830ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 108930ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 109030ce7f44SFelix Fietkau } 109130ce7f44SFelix Fietkau 1092d71ef286SFelix Fietkau static void 10935ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 10945ce09c1aSFelix Fietkau int len) 10955ce09c1aSFelix Fietkau { 10965ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 109785b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = { 109885b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags, 109985b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx, 110085b7a5d0SLorenzo Bianconi .encoding = status->encoding, 110185b7a5d0SLorenzo Bianconi .band = status->band, 110285b7a5d0SLorenzo Bianconi .nss = status->nss, 110385b7a5d0SLorenzo Bianconi .bw = status->bw, 110485b7a5d0SLorenzo Bianconi }; 11055ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 11065ce09c1aSFelix Fietkau u32 airtime; 1107e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 11085ce09c1aSFelix Fietkau 110985b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 1110237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 11115ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 1112237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 11135ce09c1aSFelix Fietkau 11145ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 11155ce09c1aSFelix Fietkau return; 11165ce09c1aSFelix Fietkau 11175ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1118e195dad1SFelix Fietkau ieee80211_sta_register_airtime(sta, tidno, 0, airtime); 11195ce09c1aSFelix Fietkau } 11205ce09c1aSFelix Fietkau 11215ce09c1aSFelix Fietkau static void 11225ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 11235ce09c1aSFelix Fietkau { 11245ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 11255ce09c1aSFelix Fietkau int wcid_idx; 11265ce09c1aSFelix Fietkau 11275ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 11285ce09c1aSFelix Fietkau return; 11295ce09c1aSFelix Fietkau 11305ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 1131bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 11325ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 11335ce09c1aSFelix Fietkau else 11345ce09c1aSFelix Fietkau wcid = NULL; 11355ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 11365ce09c1aSFelix Fietkau 11375ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 11385ce09c1aSFelix Fietkau 11395ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 11405ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 11415ce09c1aSFelix Fietkau } 11425ce09c1aSFelix Fietkau 11435ce09c1aSFelix Fietkau static void 11445ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 11455ce09c1aSFelix Fietkau { 11465ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 11475ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 11485ce09c1aSFelix Fietkau 11495ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 11505ce09c1aSFelix Fietkau return; 11515ce09c1aSFelix Fietkau 11525ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 1153e195dad1SFelix Fietkau struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1154e195dad1SFelix Fietkau 1155e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1156e195dad1SFelix Fietkau return; 1157e195dad1SFelix Fietkau 115898df2baeSLorenzo Bianconi if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) 11595ce09c1aSFelix Fietkau return; 11605ce09c1aSFelix Fietkau 11615ce09c1aSFelix Fietkau wcid = NULL; 11625ce09c1aSFelix Fietkau } 11635ce09c1aSFelix Fietkau 11645ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 11655ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 11665ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 11675ce09c1aSFelix Fietkau 11685ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 11695ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 11705ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 11715ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 11725ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 11735ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 11745ce09c1aSFelix Fietkau } 11755ce09c1aSFelix Fietkau 11765ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 11775ce09c1aSFelix Fietkau return; 11785ce09c1aSFelix Fietkau } 11795ce09c1aSFelix Fietkau 11805ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 11815ce09c1aSFelix Fietkau } 11825ce09c1aSFelix Fietkau 11835ce09c1aSFelix Fietkau static void 1184ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 1185d71ef286SFelix Fietkau { 1186d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 118777ae1d5eSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1188d71ef286SFelix Fietkau struct ieee80211_sta *sta; 1189bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 1190d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 1191e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 1192d71ef286SFelix Fietkau bool ps; 1193d71ef286SFelix Fietkau 1194128c9b7dSLorenzo Bianconi hw = mt76_phy_hw(dev, status->phy_idx); 1195e195dad1SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && 1196e195dad1SFelix Fietkau !(status->flag & RX_FLAG_8023)) { 1197bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 119836d91096SFelix Fietkau if (sta) 119936d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 120036d91096SFelix Fietkau } 120136d91096SFelix Fietkau 12025ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 12035ce09c1aSFelix Fietkau 1204d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 1205d71ef286SFelix Fietkau return; 1206d71ef286SFelix Fietkau 1207d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1208d71ef286SFelix Fietkau 120902e5a769SFelix Fietkau if (status->signal <= 0) 121002e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 121102e5a769SFelix Fietkau 1212ef13edc0SFelix Fietkau wcid->inactive_count = 0; 1213ef13edc0SFelix Fietkau 1214e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1215e195dad1SFelix Fietkau return; 1216e195dad1SFelix Fietkau 1217d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 1218d71ef286SFelix Fietkau return; 1219d71ef286SFelix Fietkau 1220d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 1221d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 1222d71ef286SFelix Fietkau return; 1223d71ef286SFelix Fietkau } 1224d71ef286SFelix Fietkau 1225d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 1226d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 1227d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 1228d71ef286SFelix Fietkau return; 1229d71ef286SFelix Fietkau 1230d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 1231d71ef286SFelix Fietkau 1232d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 1233d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 1234e195dad1SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, tidno); 1235d71ef286SFelix Fietkau 1236d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 1237d71ef286SFelix Fietkau return; 1238d71ef286SFelix Fietkau 123911b2a25fSFelix Fietkau if (ps) 1240d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 1241d71ef286SFelix Fietkau 1242d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 1243608f7c47SFelix Fietkau 1244608f7c47SFelix Fietkau if (!ps) 1245608f7c47SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 1246608f7c47SFelix Fietkau 12479f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 1248d71ef286SFelix Fietkau } 1249d71ef286SFelix Fietkau 12509d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 125181e850efSLorenzo Bianconi struct napi_struct *napi) 125217f1de56SFelix Fietkau { 12539c68a57bSFelix Fietkau struct ieee80211_sta *sta; 1254bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 12553298b1f8SFelix Fietkau struct sk_buff *skb, *tmp; 12563298b1f8SFelix Fietkau LIST_HEAD(list); 12579d9d738bSFelix Fietkau 1258c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 12599d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 1260cc4b3c13SLorenzo Bianconi struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 1261cc4b3c13SLorenzo Bianconi 12623c1032e1SFelix Fietkau mt76_check_ccmp_pn(skb); 1263cc4b3c13SLorenzo Bianconi skb_shinfo(skb)->frag_list = NULL; 1264bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta); 12653298b1f8SFelix Fietkau ieee80211_rx_list(hw, sta, skb, &list); 1266cc4b3c13SLorenzo Bianconi 1267cc4b3c13SLorenzo Bianconi /* subsequent amsdu frames */ 1268cc4b3c13SLorenzo Bianconi while (nskb) { 1269cc4b3c13SLorenzo Bianconi skb = nskb; 1270cc4b3c13SLorenzo Bianconi nskb = nskb->next; 1271cc4b3c13SLorenzo Bianconi skb->next = NULL; 1272cc4b3c13SLorenzo Bianconi 1273cc4b3c13SLorenzo Bianconi mt76_rx_convert(dev, skb, &hw, &sta); 1274cc4b3c13SLorenzo Bianconi ieee80211_rx_list(hw, sta, skb, &list); 1275cc4b3c13SLorenzo Bianconi } 12769d9d738bSFelix Fietkau } 1277c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 12783298b1f8SFelix Fietkau 12793298b1f8SFelix Fietkau if (!napi) { 12803298b1f8SFelix Fietkau netif_receive_skb_list(&list); 12813298b1f8SFelix Fietkau return; 12823298b1f8SFelix Fietkau } 12833298b1f8SFelix Fietkau 12843298b1f8SFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) { 12853298b1f8SFelix Fietkau skb_list_del_init(skb); 12863298b1f8SFelix Fietkau napi_gro_receive(napi, skb); 12873298b1f8SFelix Fietkau } 12889d9d738bSFelix Fietkau } 12899d9d738bSFelix Fietkau 129081e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 129181e850efSLorenzo Bianconi struct napi_struct *napi) 12929d9d738bSFelix Fietkau { 1293aee5b8cfSFelix Fietkau struct sk_buff_head frames; 129417f1de56SFelix Fietkau struct sk_buff *skb; 129517f1de56SFelix Fietkau 1296aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 1297aee5b8cfSFelix Fietkau 1298d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 1299ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 1300aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 1301d71ef286SFelix Fietkau } 1302aee5b8cfSFelix Fietkau 130381e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 13044e34249eSFelix Fietkau } 130581e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 1306723b90dcSFelix Fietkau 1307e28487eaSFelix Fietkau static int 1308a1a99d7bSLorenzo Bianconi mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif, 1309a1a99d7bSLorenzo Bianconi struct ieee80211_sta *sta) 1310e28487eaSFelix Fietkau { 1311e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 1312a1a99d7bSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 1313e28487eaSFelix Fietkau int ret; 1314e28487eaSFelix Fietkau int i; 1315e28487eaSFelix Fietkau 1316e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 1317e28487eaSFelix Fietkau 1318e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 1319e28487eaSFelix Fietkau if (ret) 1320e28487eaSFelix Fietkau goto out; 1321e28487eaSFelix Fietkau 1322e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 1323e28487eaSFelix Fietkau struct mt76_txq *mtxq; 1324e28487eaSFelix Fietkau 1325e28487eaSFelix Fietkau if (!sta->txq[i]) 1326e28487eaSFelix Fietkau continue; 1327e28487eaSFelix Fietkau 1328e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 132951fb1278SFelix Fietkau mtxq->wcid = wcid->idx; 1330e28487eaSFelix Fietkau } 1331e28487eaSFelix Fietkau 1332ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 1333a1a99d7bSLorenzo Bianconi if (phy->band_idx == MT_BAND1) 1334426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 1335a1a99d7bSLorenzo Bianconi wcid->phy_idx = phy->band_idx; 1336e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 1337e28487eaSFelix Fietkau 1338bd1e3e7bSLorenzo Bianconi mt76_packet_id_init(wcid); 1339e28487eaSFelix Fietkau out: 1340e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 1341e28487eaSFelix Fietkau 1342e28487eaSFelix Fietkau return ret; 1343e28487eaSFelix Fietkau } 1344e28487eaSFelix Fietkau 134513f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 1346723b90dcSFelix Fietkau struct ieee80211_sta *sta) 1347723b90dcSFelix Fietkau { 1348723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 134913f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 1350723b90dcSFelix Fietkau 135158bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 135258bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 135358bab0d4SFelix Fietkau 1354e28487eaSFelix Fietkau if (dev->drv->sta_remove) 1355e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 1356e28487eaSFelix Fietkau 1357bd1e3e7bSLorenzo Bianconi mt76_packet_id_flush(dev, wcid); 1358bd1e3e7bSLorenzo Bianconi 1359426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx); 1360426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 136113f61dfcSLorenzo Bianconi } 136213f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 1363e28487eaSFelix Fietkau 136413f61dfcSLorenzo Bianconi static void 136513f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 136613f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 136713f61dfcSLorenzo Bianconi { 136813f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 136913f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 1370723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 1371723b90dcSFelix Fietkau } 1372e28487eaSFelix Fietkau 1373e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1374e28487eaSFelix Fietkau struct ieee80211_sta *sta, 1375e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 1376e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 1377e28487eaSFelix Fietkau { 1378426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv; 1379426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev; 1380e28487eaSFelix Fietkau 1381e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 1382e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 1383a1a99d7bSLorenzo Bianconi return mt76_sta_add(phy, vif, sta); 1384e28487eaSFelix Fietkau 13859c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 13869c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 13879c193de5SFelix Fietkau dev->drv->sta_assoc) 13889c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 13899c193de5SFelix Fietkau 1390e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 1391e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 1392e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 1393e28487eaSFelix Fietkau 1394e28487eaSFelix Fietkau return 0; 1395e28487eaSFelix Fietkau } 1396e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 13979313faacSFelix Fietkau 139843ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 139943ba1922SFelix Fietkau struct ieee80211_sta *sta) 140043ba1922SFelix Fietkau { 140143ba1922SFelix Fietkau struct mt76_phy *phy = hw->priv; 140243ba1922SFelix Fietkau struct mt76_dev *dev = phy->dev; 140343ba1922SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 140443ba1922SFelix Fietkau 140543ba1922SFelix Fietkau mutex_lock(&dev->mutex); 1406fcfe1b5eSFelix Fietkau spin_lock_bh(&dev->status_lock); 140743ba1922SFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 1408fcfe1b5eSFelix Fietkau spin_unlock_bh(&dev->status_lock); 140943ba1922SFelix Fietkau mutex_unlock(&dev->mutex); 141043ba1922SFelix Fietkau } 141143ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 141243ba1922SFelix Fietkau 14139313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 14149313faacSFelix Fietkau int *dbm) 14159313faacSFelix Fietkau { 1416beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1417beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask); 141807cda406SFelix Fietkau int delta = mt76_tx_power_nss_delta(n_chains); 14199313faacSFelix Fietkau 142007cda406SFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 14219313faacSFelix Fietkau 14229313faacSFelix Fietkau return 0; 14239313faacSFelix Fietkau } 14249313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 1425e7173858SFelix Fietkau 1426b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw, 1427b3cb885eSLorenzo Bianconi const struct cfg80211_sar_specs *sar) 1428b3cb885eSLorenzo Bianconi { 1429b3cb885eSLorenzo Bianconi struct mt76_phy *phy = hw->priv; 1430b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; 1431b3cb885eSLorenzo Bianconi int i; 1432b3cb885eSLorenzo Bianconi 1433b3cb885eSLorenzo Bianconi if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) 1434b3cb885eSLorenzo Bianconi return -EINVAL; 1435b3cb885eSLorenzo Bianconi 1436b3cb885eSLorenzo Bianconi for (i = 0; i < sar->num_sub_specs; i++) { 1437b3cb885eSLorenzo Bianconi u32 index = sar->sub_specs[i].freq_range_index; 1438b3cb885eSLorenzo Bianconi /* SAR specifies power limitaton in 0.25dbm */ 1439b3cb885eSLorenzo Bianconi s32 power = sar->sub_specs[i].power >> 1; 1440b3cb885eSLorenzo Bianconi 1441b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1442b3cb885eSLorenzo Bianconi power = 127; 1443b3cb885eSLorenzo Bianconi 1444b3cb885eSLorenzo Bianconi phy->frp[index].range = &capa->freq_ranges[index]; 1445b3cb885eSLorenzo Bianconi phy->frp[index].power = power; 1446b3cb885eSLorenzo Bianconi } 1447b3cb885eSLorenzo Bianconi 1448b3cb885eSLorenzo Bianconi return 0; 1449b3cb885eSLorenzo Bianconi } 1450b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power); 1451b3cb885eSLorenzo Bianconi 1452b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy, 1453b3cb885eSLorenzo Bianconi struct ieee80211_channel *chan, 1454b3cb885eSLorenzo Bianconi int power) 1455b3cb885eSLorenzo Bianconi { 1456b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; 1457b3cb885eSLorenzo Bianconi int freq, i; 1458b3cb885eSLorenzo Bianconi 1459b3cb885eSLorenzo Bianconi if (!capa || !phy->frp) 1460b3cb885eSLorenzo Bianconi return power; 1461b3cb885eSLorenzo Bianconi 1462b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1463b3cb885eSLorenzo Bianconi power = 127; 1464b3cb885eSLorenzo Bianconi 1465b3cb885eSLorenzo Bianconi freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); 1466b3cb885eSLorenzo Bianconi for (i = 0 ; i < capa->num_freq_ranges; i++) { 1467b3cb885eSLorenzo Bianconi if (phy->frp[i].range && 1468b3cb885eSLorenzo Bianconi freq >= phy->frp[i].range->start_freq && 1469b3cb885eSLorenzo Bianconi freq < phy->frp[i].range->end_freq) { 1470b3cb885eSLorenzo Bianconi power = min_t(int, phy->frp[i].power, power); 1471b3cb885eSLorenzo Bianconi break; 1472b3cb885eSLorenzo Bianconi } 1473b3cb885eSLorenzo Bianconi } 1474b3cb885eSLorenzo Bianconi 1475b3cb885eSLorenzo Bianconi return power; 1476b3cb885eSLorenzo Bianconi } 1477b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power); 1478b3cb885eSLorenzo Bianconi 1479e7173858SFelix Fietkau static void 1480e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 1481e7173858SFelix Fietkau { 1482d0a9123eSJohannes Berg if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 1483e7173858SFelix Fietkau ieee80211_csa_finish(vif); 1484e7173858SFelix Fietkau } 1485e7173858SFelix Fietkau 1486e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 1487e7173858SFelix Fietkau { 1488e7173858SFelix Fietkau if (!dev->csa_complete) 1489e7173858SFelix Fietkau return; 1490e7173858SFelix Fietkau 1491e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1492e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1493e7173858SFelix Fietkau __mt76_csa_finish, dev); 1494e7173858SFelix Fietkau 1495e7173858SFelix Fietkau dev->csa_complete = 0; 1496e7173858SFelix Fietkau } 1497e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 1498e7173858SFelix Fietkau 1499e7173858SFelix Fietkau static void 1500e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 1501e7173858SFelix Fietkau { 1502e7173858SFelix Fietkau struct mt76_dev *dev = priv; 1503e7173858SFelix Fietkau 1504d0a9123eSJohannes Berg if (!vif->bss_conf.csa_active) 1505e7173858SFelix Fietkau return; 1506e7173858SFelix Fietkau 15078552a434SJohn Crispin dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 1508e7173858SFelix Fietkau } 1509e7173858SFelix Fietkau 1510e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 1511e7173858SFelix Fietkau { 1512e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1513e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1514e7173858SFelix Fietkau __mt76_csa_check, dev); 1515e7173858SFelix Fietkau } 1516e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 151787d53103SStanislaw Gruszka 151887d53103SStanislaw Gruszka int 151987d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 152087d53103SStanislaw Gruszka { 152187d53103SStanislaw Gruszka return 0; 152287d53103SStanislaw Gruszka } 152387d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 1524eadfd98fSLorenzo Bianconi 1525eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 1526eadfd98fSLorenzo Bianconi { 1527eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 1528eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 1529eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 1530eadfd98fSLorenzo Bianconi 1531eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 1532eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 1533eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 1534eadfd98fSLorenzo Bianconi 1535eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 1536eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 1537eadfd98fSLorenzo Bianconi hdr[2] = 0; 1538eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 1539eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 1540eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 1541eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 1542eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1543eadfd98fSLorenzo Bianconi 1544eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1545eadfd98fSLorenzo Bianconi } 1546eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1547d2679d65SLorenzo Bianconi 1548d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1549d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1550d2679d65SLorenzo Bianconi int idx, bool cck) 1551d2679d65SLorenzo Bianconi { 1552d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1553d2679d65SLorenzo Bianconi 1554d2679d65SLorenzo Bianconi if (cck) { 1555edf9dab8SLorenzo Bianconi if (sband != &dev->phy.sband_2g.sband) 1556d2679d65SLorenzo Bianconi return 0; 1557d2679d65SLorenzo Bianconi 1558d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 155996747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) { 1560d2679d65SLorenzo Bianconi offset = 4; 1561d2679d65SLorenzo Bianconi } 1562d2679d65SLorenzo Bianconi 1563d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1564d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1565d2679d65SLorenzo Bianconi return i; 1566d2679d65SLorenzo Bianconi } 1567d2679d65SLorenzo Bianconi 1568d2679d65SLorenzo Bianconi return 0; 1569d2679d65SLorenzo Bianconi } 1570d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 15718b8ab5c2SLorenzo Bianconi 15728b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 15738b8ab5c2SLorenzo Bianconi const u8 *mac) 15748b8ab5c2SLorenzo Bianconi { 1575011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 15768b8ab5c2SLorenzo Bianconi 1577011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state); 15788b8ab5c2SLorenzo Bianconi } 15798b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 15808b8ab5c2SLorenzo Bianconi 15818b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 15828b8ab5c2SLorenzo Bianconi { 1583011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 15848b8ab5c2SLorenzo Bianconi 1585011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state); 15868b8ab5c2SLorenzo Bianconi } 15878b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1588e49c76d4SLorenzo Bianconi 1589e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1590e49c76d4SLorenzo Bianconi { 1591beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1592beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev; 1593e49c76d4SLorenzo Bianconi 1594e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1595beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask; 1596beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask; 1597e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1598e49c76d4SLorenzo Bianconi 1599e49c76d4SLorenzo Bianconi return 0; 1600e49c76d4SLorenzo Bianconi } 1601e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1602b671da33SLorenzo Bianconi 1603b1cb42adSLorenzo Bianconi struct mt76_queue * 1604b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, 1605f68d6762SFelix Fietkau int ring_base, u32 flags) 1606b671da33SLorenzo Bianconi { 1607b671da33SLorenzo Bianconi struct mt76_queue *hwq; 1608b671da33SLorenzo Bianconi int err; 1609b671da33SLorenzo Bianconi 1610b671da33SLorenzo Bianconi hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); 1611b671da33SLorenzo Bianconi if (!hwq) 1612b1cb42adSLorenzo Bianconi return ERR_PTR(-ENOMEM); 1613b671da33SLorenzo Bianconi 1614f68d6762SFelix Fietkau hwq->flags = flags; 1615f68d6762SFelix Fietkau 1616b671da33SLorenzo Bianconi err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); 1617b671da33SLorenzo Bianconi if (err < 0) 1618b1cb42adSLorenzo Bianconi return ERR_PTR(err); 1619b671da33SLorenzo Bianconi 1620b1cb42adSLorenzo Bianconi return hwq; 1621b671da33SLorenzo Bianconi } 1622b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue); 1623e4867225SSean Wang 162433920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) 1625e4867225SSean Wang { 162633920b2bSRyder Lee int offset = 0; 1627e4867225SSean Wang 1628edf9dab8SLorenzo Bianconi if (phy->chandef.chan->band != NL80211_BAND_2GHZ) 1629e4867225SSean Wang offset = 4; 1630e4867225SSean Wang 163133920b2bSRyder Lee /* pick the lowest rate for hidden nodes */ 163233920b2bSRyder Lee if (rateidx < 0) 163333920b2bSRyder Lee rateidx = 0; 163433920b2bSRyder Lee 1635d4f3d1c4SLorenzo Bianconi rateidx += offset; 1636d4f3d1c4SLorenzo Bianconi if (rateidx >= ARRAY_SIZE(mt76_rates)) 1637d4f3d1c4SLorenzo Bianconi rateidx = offset; 1638e4867225SSean Wang 1639d4f3d1c4SLorenzo Bianconi return mt76_rates[rateidx].hw_value; 1640e4867225SSean Wang } 164133920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); 164254ae98ffSLorenzo Bianconi 164354ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, 164454ae98ffSLorenzo Bianconi struct mt76_sta_stats *stats) 164554ae98ffSLorenzo Bianconi { 164654ae98ffSLorenzo Bianconi int i, ei = wi->initial_stat_idx; 164754ae98ffSLorenzo Bianconi u64 *data = wi->data; 164854ae98ffSLorenzo Bianconi 164954ae98ffSLorenzo Bianconi wi->sta_count++; 165054ae98ffSLorenzo Bianconi 165154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; 165254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; 165354ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; 165454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; 165554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; 165654ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; 165754ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; 165854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; 165954ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; 166054ae98ffSLorenzo Bianconi 166154ae98ffSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++) 166254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_bw[i]; 166354ae98ffSLorenzo Bianconi 166454ae98ffSLorenzo Bianconi for (i = 0; i < 12; i++) 166554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mcs[i]; 166654ae98ffSLorenzo Bianconi 166754ae98ffSLorenzo Bianconi wi->worker_stat_count = ei - wi->initial_stat_idx; 166854ae98ffSLorenzo Bianconi } 166954ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker); 16703f306448SFelix Fietkau 16713f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) 16723f306448SFelix Fietkau { 16733f306448SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 16743f306448SFelix Fietkau struct mt76_dev *dev = phy->dev; 16753f306448SFelix Fietkau 16763f306448SFelix Fietkau if (dev->region == NL80211_DFS_UNSET || 16773f306448SFelix Fietkau test_bit(MT76_SCANNING, &phy->state)) 16783f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 16793f306448SFelix Fietkau 16803f306448SFelix Fietkau if (!hw->conf.radar_enabled) { 16813f306448SFelix Fietkau if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && 16823f306448SFelix Fietkau (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) 16833f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 16843f306448SFelix Fietkau 16853f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 16863f306448SFelix Fietkau } 16873f306448SFelix Fietkau 168800a883e6SFelix Fietkau if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) 16893f306448SFelix Fietkau return MT_DFS_STATE_CAC; 16903f306448SFelix Fietkau 16913f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 16923f306448SFelix Fietkau } 16933f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); 1694