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, }, 181502604f5SYN Chen }; 182502604f5SYN Chen 18397f8e1aeSLorenzo Bianconi static const struct cfg80211_sar_capa mt76_sar_capa = { 184502604f5SYN Chen .type = NL80211_SAR_TYPE_POWER, 185502604f5SYN Chen .num_freq_ranges = ARRAY_SIZE(mt76_sar_freq_ranges), 186502604f5SYN Chen .freq_ranges = &mt76_sar_freq_ranges[0], 187502604f5SYN Chen }; 188502604f5SYN Chen 18917f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev) 19017f1de56SFelix Fietkau { 19117f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node; 19217f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 19317f1de56SFelix Fietkau int led_pin; 19417f1de56SFelix Fietkau 19517f1de56SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 19617f1de56SFelix Fietkau return 0; 19717f1de56SFelix Fietkau 19817f1de56SFelix Fietkau snprintf(dev->led_name, sizeof(dev->led_name), 19917f1de56SFelix Fietkau "mt76-%s", wiphy_name(hw->wiphy)); 20017f1de56SFelix Fietkau 20117f1de56SFelix Fietkau dev->led_cdev.name = dev->led_name; 20217f1de56SFelix Fietkau dev->led_cdev.default_trigger = 20317f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 20417f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 20517f1de56SFelix Fietkau mt76_tpt_blink, 20617f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 20717f1de56SFelix Fietkau 20817f1de56SFelix Fietkau np = of_get_child_by_name(np, "led"); 20917f1de56SFelix Fietkau if (np) { 21017f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin)) 21117f1de56SFelix Fietkau dev->led_pin = led_pin; 21217f1de56SFelix Fietkau dev->led_al = of_property_read_bool(np, "led-active-low"); 21317f1de56SFelix Fietkau } 21417f1de56SFelix Fietkau 21536f7e2b2SFelix Fietkau return led_classdev_register(dev->dev, &dev->led_cdev); 21636f7e2b2SFelix Fietkau } 21736f7e2b2SFelix Fietkau 21836f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev) 21936f7e2b2SFelix Fietkau { 22036f7e2b2SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 22136f7e2b2SFelix Fietkau return; 22236f7e2b2SFelix Fietkau 22336f7e2b2SFelix Fietkau led_classdev_unregister(&dev->led_cdev); 22417f1de56SFelix Fietkau } 22517f1de56SFelix Fietkau 226bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy, 227551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 228551e1ef4SLorenzo Bianconi bool vht) 229551e1ef4SLorenzo Bianconi { 230551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 231bb3e3fecSRyder Lee int i, nstream = hweight8(phy->antenna_mask); 232551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 233551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 234551e1ef4SLorenzo Bianconi 235551e1ef4SLorenzo Bianconi if (nstream > 1) 236551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 237551e1ef4SLorenzo Bianconi else 238551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 239551e1ef4SLorenzo Bianconi 240551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 241551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 242551e1ef4SLorenzo Bianconi 243551e1ef4SLorenzo Bianconi if (!vht) 244551e1ef4SLorenzo Bianconi return; 245551e1ef4SLorenzo Bianconi 246551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 247551e1ef4SLorenzo Bianconi if (nstream > 1) 248551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 249551e1ef4SLorenzo Bianconi else 250551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 251abba3453SDeren Wu vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 252abba3453SDeren Wu IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; 253551e1ef4SLorenzo Bianconi 254551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 255551e1ef4SLorenzo Bianconi if (i < nstream) 256551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 257551e1ef4SLorenzo Bianconi else 258551e1ef4SLorenzo Bianconi mcs_map |= 259551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 260551e1ef4SLorenzo Bianconi } 261551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 262551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 263551e1ef4SLorenzo Bianconi } 264551e1ef4SLorenzo Bianconi 265bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 2665ebdc3e0SLorenzo Bianconi { 26748dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) 268bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 26948dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) 270bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 271edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) 272edf9dab8SLorenzo Bianconi mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); 2735ebdc3e0SLorenzo Bianconi } 2745ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 2755ebdc3e0SLorenzo Bianconi 27617f1de56SFelix Fietkau static int 27777af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, 27817f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 279edf9dab8SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates, 280edf9dab8SLorenzo Bianconi bool ht, bool vht) 28117f1de56SFelix Fietkau { 28217f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 28317f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 28477af762eSLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap; 28577af762eSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 28617f1de56SFelix Fietkau void *chanlist; 28717f1de56SFelix Fietkau int size; 28817f1de56SFelix Fietkau 28917f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 29017f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 29117f1de56SFelix Fietkau if (!chanlist) 29217f1de56SFelix Fietkau return -ENOMEM; 29317f1de56SFelix Fietkau 294a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 29517f1de56SFelix Fietkau GFP_KERNEL); 29617f1de56SFelix Fietkau if (!msband->chan) 29717f1de56SFelix Fietkau return -ENOMEM; 29817f1de56SFelix Fietkau 29917f1de56SFelix Fietkau sband->channels = chanlist; 30017f1de56SFelix Fietkau sband->n_channels = n_chan; 30117f1de56SFelix Fietkau sband->bitrates = rates; 30217f1de56SFelix Fietkau sband->n_bitrates = n_rates; 30317f1de56SFelix Fietkau 304edf9dab8SLorenzo Bianconi if (!ht) 305edf9dab8SLorenzo Bianconi return 0; 306edf9dab8SLorenzo Bianconi 30717f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 30817f1de56SFelix Fietkau ht_cap->ht_supported = true; 30917f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 31017f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 31117f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 31217f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 31317f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 31417f1de56SFelix Fietkau 31517f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 31617f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 31717f1de56SFelix Fietkau 31877af762eSLorenzo Bianconi mt76_init_stream_cap(phy, sband, vht); 319551e1ef4SLorenzo Bianconi 32017f1de56SFelix Fietkau if (!vht) 32117f1de56SFelix Fietkau return 0; 32217f1de56SFelix Fietkau 32317f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 32417f1de56SFelix Fietkau vht_cap->vht_supported = true; 32517f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 32617f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 32749149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 32849149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 32917f1de56SFelix Fietkau 33017f1de56SFelix Fietkau return 0; 33117f1de56SFelix Fietkau } 33217f1de56SFelix Fietkau 33317f1de56SFelix Fietkau static int 33477af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, 33517f1de56SFelix Fietkau int n_rates) 33617f1de56SFelix Fietkau { 33777af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 33817f1de56SFelix Fietkau 33977af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, 34077af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_2ghz), rates, 341edf9dab8SLorenzo Bianconi n_rates, true, false); 34217f1de56SFelix Fietkau } 34317f1de56SFelix Fietkau 34417f1de56SFelix Fietkau static int 34577af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, 34617f1de56SFelix Fietkau int n_rates, bool vht) 34717f1de56SFelix Fietkau { 34877af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 34917f1de56SFelix Fietkau 35077af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, 35177af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_5ghz), rates, 352edf9dab8SLorenzo Bianconi n_rates, true, vht); 353edf9dab8SLorenzo Bianconi } 354edf9dab8SLorenzo Bianconi 355edf9dab8SLorenzo Bianconi static int 356edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, 357edf9dab8SLorenzo Bianconi int n_rates) 358edf9dab8SLorenzo Bianconi { 359edf9dab8SLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; 360edf9dab8SLorenzo Bianconi 361edf9dab8SLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, 362edf9dab8SLorenzo Bianconi ARRAY_SIZE(mt76_channels_6ghz), rates, 363edf9dab8SLorenzo Bianconi n_rates, false, false); 36417f1de56SFelix Fietkau } 36517f1de56SFelix Fietkau 36617f1de56SFelix Fietkau static void 367c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 368c89d3625SFelix Fietkau enum nl80211_band band) 36917f1de56SFelix Fietkau { 370c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 37117f1de56SFelix Fietkau bool found = false; 37217f1de56SFelix Fietkau int i; 37317f1de56SFelix Fietkau 37417f1de56SFelix Fietkau if (!sband) 37517f1de56SFelix Fietkau return; 37617f1de56SFelix Fietkau 37717f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 37817f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 37917f1de56SFelix Fietkau continue; 38017f1de56SFelix Fietkau 38117f1de56SFelix Fietkau found = true; 38217f1de56SFelix Fietkau break; 38317f1de56SFelix Fietkau } 38417f1de56SFelix Fietkau 385c89d3625SFelix Fietkau if (found) { 386c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0]; 387c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0]; 38817f1de56SFelix Fietkau return; 389c89d3625SFelix Fietkau } 39017f1de56SFelix Fietkau 39117f1de56SFelix Fietkau sband->n_channels = 0; 392c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL; 39317f1de56SFelix Fietkau } 39417f1de56SFelix Fietkau 395d43de9cfSLorenzo Bianconi static int 39698df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) 397c89d3625SFelix Fietkau { 39898df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 399c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 400c89d3625SFelix Fietkau 401c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 40298df2baeSLorenzo Bianconi SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); 403c89d3625SFelix Fietkau 404c89d3625SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 405dd89a013SLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 406b807b368SLorenzo Bianconi WIPHY_FLAG_SUPPORTS_TDLS | 407b807b368SLorenzo Bianconi WIPHY_FLAG_AP_UAPSD; 408c89d3625SFelix Fietkau 409c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 410c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 411d9c54264SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 412c89d3625SFelix Fietkau 4130a57d636SBo Jiao wiphy->available_antennas_tx = phy->antenna_mask; 4140a57d636SBo Jiao wiphy->available_antennas_rx = phy->antenna_mask; 415c89d3625SFelix Fietkau 416d43de9cfSLorenzo Bianconi wiphy->sar_capa = &mt76_sar_capa; 417d43de9cfSLorenzo Bianconi phy->frp = devm_kcalloc(dev->dev, wiphy->sar_capa->num_freq_ranges, 418d43de9cfSLorenzo Bianconi sizeof(struct mt76_freq_range_power), 419d43de9cfSLorenzo Bianconi GFP_KERNEL); 420d43de9cfSLorenzo Bianconi if (!phy->frp) 421d43de9cfSLorenzo Bianconi return -ENOMEM; 422d43de9cfSLorenzo Bianconi 423c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 424b807b368SLorenzo Bianconi hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 425c9619dfaSShayne Chen 426c9619dfaSShayne Chen if (!hw->max_tx_fragments) 427c89d3625SFelix Fietkau hw->max_tx_fragments = 16; 428c89d3625SFelix Fietkau 429c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 430c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 431c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 432c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 433c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 434c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 435ed89b893SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 436c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 437c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 438c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 439c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 440c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 441d43de9cfSLorenzo Bianconi 442d43de9cfSLorenzo Bianconi return 0; 443c89d3625SFelix Fietkau } 444c89d3625SFelix Fietkau 445c89d3625SFelix Fietkau struct mt76_phy * 446c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 447c89d3625SFelix Fietkau const struct ieee80211_ops *ops) 448c89d3625SFelix Fietkau { 449c89d3625SFelix Fietkau struct ieee80211_hw *hw; 450db78a791SLorenzo Bianconi unsigned int phy_size; 451c89d3625SFelix Fietkau struct mt76_phy *phy; 452c89d3625SFelix Fietkau 453c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8); 454db78a791SLorenzo Bianconi hw = ieee80211_alloc_hw(size + phy_size, ops); 455c89d3625SFelix Fietkau if (!hw) 456c89d3625SFelix Fietkau return NULL; 457c89d3625SFelix Fietkau 458c89d3625SFelix Fietkau phy = hw->priv; 459c89d3625SFelix Fietkau phy->dev = dev; 460c89d3625SFelix Fietkau phy->hw = hw; 461db78a791SLorenzo Bianconi phy->priv = hw->priv + phy_size; 462c89d3625SFelix Fietkau 4638af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 4648af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 4658af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 4668af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 4678af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 4688af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 4698af414e8SLorenzo Bianconi #endif 4708af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 4718af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 4728af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 4738af414e8SLorenzo Bianconi 474c89d3625SFelix Fietkau return phy; 475c89d3625SFelix Fietkau } 476c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy); 477c89d3625SFelix Fietkau 478db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht, 479db78a791SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates) 480c89d3625SFelix Fietkau { 481c89d3625SFelix Fietkau int ret; 482c89d3625SFelix Fietkau 483d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, phy->hw); 484d43de9cfSLorenzo Bianconi if (ret) 485d43de9cfSLorenzo Bianconi return ret; 486db78a791SLorenzo Bianconi 487db78a791SLorenzo Bianconi if (phy->cap.has_2ghz) { 488db78a791SLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 489db78a791SLorenzo Bianconi if (ret) 490db78a791SLorenzo Bianconi return ret; 491db78a791SLorenzo Bianconi } 492db78a791SLorenzo Bianconi 493db78a791SLorenzo Bianconi if (phy->cap.has_5ghz) { 494db78a791SLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 495db78a791SLorenzo Bianconi if (ret) 496db78a791SLorenzo Bianconi return ret; 497db78a791SLorenzo Bianconi } 498db78a791SLorenzo Bianconi 499edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 500edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 501edf9dab8SLorenzo Bianconi if (ret) 502edf9dab8SLorenzo Bianconi return ret; 503edf9dab8SLorenzo Bianconi } 504edf9dab8SLorenzo Bianconi 505db78a791SLorenzo Bianconi wiphy_read_of_freq_limits(phy->hw->wiphy); 506db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 507db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 508edf9dab8SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); 509db78a791SLorenzo Bianconi 510c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw); 511c89d3625SFelix Fietkau if (ret) 512c89d3625SFelix Fietkau return ret; 513c89d3625SFelix Fietkau 514c89d3625SFelix Fietkau phy->dev->phy2 = phy; 515db78a791SLorenzo Bianconi 516c89d3625SFelix Fietkau return 0; 517c89d3625SFelix Fietkau } 518c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy); 519c89d3625SFelix Fietkau 520db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy) 521c89d3625SFelix Fietkau { 522c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev; 523c89d3625SFelix Fietkau 524c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 525c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw); 52694b6df08SFelix Fietkau dev->phy2 = NULL; 527c89d3625SFelix Fietkau } 528c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy); 529c89d3625SFelix Fietkau 530a85b590cSFelix Fietkau struct mt76_dev * 531c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 532c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 533c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 534a85b590cSFelix Fietkau { 535a85b590cSFelix Fietkau struct ieee80211_hw *hw; 536ac24dd35SFelix Fietkau struct mt76_phy *phy; 537a85b590cSFelix Fietkau struct mt76_dev *dev; 538e5443256SFelix Fietkau int i; 539a85b590cSFelix Fietkau 540a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 541a85b590cSFelix Fietkau if (!hw) 542a85b590cSFelix Fietkau return NULL; 543a85b590cSFelix Fietkau 544a85b590cSFelix Fietkau dev = hw->priv; 545a85b590cSFelix Fietkau dev->hw = hw; 546c0f7b25aSLorenzo Bianconi dev->dev = pdev; 547c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 548c0f7b25aSLorenzo Bianconi 549ac24dd35SFelix Fietkau phy = &dev->phy; 550ac24dd35SFelix Fietkau phy->dev = dev; 551ac24dd35SFelix Fietkau phy->hw = hw; 552ac24dd35SFelix Fietkau 553a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 554a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 555a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 556c34f1005SLorenzo Bianconi spin_lock_init(&dev->status_lock); 557108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 55826e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 559a85b590cSFelix Fietkau 56009872957SLorenzo Bianconi skb_queue_head_init(&dev->mcu.res_q); 56109872957SLorenzo Bianconi init_waitqueue_head(&dev->mcu.wait); 56209872957SLorenzo Bianconi mutex_init(&dev->mcu.mutex); 563781eef5bSFelix Fietkau dev->tx_worker.fn = mt76_tx_worker; 56409872957SLorenzo Bianconi 5658af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 5668af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 5678af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 5688af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 5698af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 5708af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 5718af414e8SLorenzo Bianconi #endif 5728af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 5738af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 5748af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 5758af414e8SLorenzo Bianconi 57651252cc5SLorenzo Bianconi spin_lock_init(&dev->token_lock); 57751252cc5SLorenzo Bianconi idr_init(&dev->token); 57851252cc5SLorenzo Bianconi 579bd1e3e7bSLorenzo Bianconi INIT_LIST_HEAD(&dev->wcid_list); 580bd1e3e7bSLorenzo Bianconi 581e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 582e5443256SFelix Fietkau 583e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 584e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 585e5443256SFelix Fietkau 586a86f1d01SLorenzo Bianconi dev->wq = alloc_ordered_workqueue("mt76", 0); 587a86f1d01SLorenzo Bianconi if (!dev->wq) { 588a86f1d01SLorenzo Bianconi ieee80211_free_hw(hw); 589a86f1d01SLorenzo Bianconi return NULL; 590a86f1d01SLorenzo Bianconi } 591a86f1d01SLorenzo Bianconi 592a85b590cSFelix Fietkau return dev; 593a85b590cSFelix Fietkau } 594a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 595a85b590cSFelix Fietkau 59617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 59717f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 59817f1de56SFelix Fietkau { 59917f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 600c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy; 60117f1de56SFelix Fietkau int ret; 60217f1de56SFelix Fietkau 60317f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 604d43de9cfSLorenzo Bianconi ret = mt76_phy_init(phy, hw); 605d43de9cfSLorenzo Bianconi if (ret) 606d43de9cfSLorenzo Bianconi return ret; 60717f1de56SFelix Fietkau 60848dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) { 60977af762eSLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 61017f1de56SFelix Fietkau if (ret) 61117f1de56SFelix Fietkau return ret; 61217f1de56SFelix Fietkau } 61317f1de56SFelix Fietkau 61448dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) { 61577af762eSLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 61617f1de56SFelix Fietkau if (ret) 61717f1de56SFelix Fietkau return ret; 61817f1de56SFelix Fietkau } 61917f1de56SFelix Fietkau 620edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 621edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 622edf9dab8SLorenzo Bianconi if (ret) 623edf9dab8SLorenzo Bianconi return ret; 624edf9dab8SLorenzo Bianconi } 625edf9dab8SLorenzo Bianconi 626c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy); 627c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 628c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 629edf9dab8SLorenzo Bianconi mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); 63017f1de56SFelix Fietkau 631b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 63217f1de56SFelix Fietkau ret = mt76_led_init(dev); 63317f1de56SFelix Fietkau if (ret) 63417f1de56SFelix Fietkau return ret; 635b374e868SArnd Bergmann } 63617f1de56SFelix Fietkau 637781eef5bSFelix Fietkau ret = ieee80211_register_hw(hw); 638781eef5bSFelix Fietkau if (ret) 639781eef5bSFelix Fietkau return ret; 640781eef5bSFelix Fietkau 641781eef5bSFelix Fietkau WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 642781eef5bSFelix Fietkau sched_set_fifo_low(dev->tx_worker.task); 643781eef5bSFelix Fietkau 644781eef5bSFelix Fietkau return 0; 64517f1de56SFelix Fietkau } 64617f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 64717f1de56SFelix Fietkau 64817f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 64917f1de56SFelix Fietkau { 65017f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 65117f1de56SFelix Fietkau 652d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 65336f7e2b2SFelix Fietkau mt76_led_cleanup(dev); 654c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 65517f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 65617f1de56SFelix Fietkau } 65717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 65817f1de56SFelix Fietkau 659def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 660def34a2fSLorenzo Bianconi { 661781eef5bSFelix Fietkau mt76_worker_teardown(&dev->tx_worker); 662a86f1d01SLorenzo Bianconi if (dev->wq) { 663a86f1d01SLorenzo Bianconi destroy_workqueue(dev->wq); 664a86f1d01SLorenzo Bianconi dev->wq = NULL; 665a86f1d01SLorenzo Bianconi } 666def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 667def34a2fSLorenzo Bianconi } 668def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 669def34a2fSLorenzo Bianconi 670cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) 671cc4b3c13SLorenzo Bianconi { 672cc4b3c13SLorenzo Bianconi struct sk_buff *skb = phy->rx_amsdu[q].head; 6732c2bdd23SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 674cc4b3c13SLorenzo Bianconi struct mt76_dev *dev = phy->dev; 675cc4b3c13SLorenzo Bianconi 676cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = NULL; 677cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = NULL; 6782c2bdd23SFelix Fietkau 6792c2bdd23SFelix Fietkau /* 6802c2bdd23SFelix Fietkau * Validate if the amsdu has a proper first subframe. 6812c2bdd23SFelix Fietkau * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU 6822c2bdd23SFelix Fietkau * flag of the QoS header gets flipped. In such cases, the first 6832c2bdd23SFelix Fietkau * subframe has a LLC/SNAP header in the location of the destination 6842c2bdd23SFelix Fietkau * address. 6852c2bdd23SFelix Fietkau */ 6862c2bdd23SFelix Fietkau if (skb_shinfo(skb)->frag_list) { 6872c2bdd23SFelix Fietkau int offset = 0; 6882c2bdd23SFelix Fietkau 6892c2bdd23SFelix Fietkau if (!(status->flag & RX_FLAG_8023)) { 6902c2bdd23SFelix Fietkau offset = ieee80211_get_hdrlen_from_skb(skb); 6912c2bdd23SFelix Fietkau 6922c2bdd23SFelix Fietkau if ((status->flag & 6932c2bdd23SFelix Fietkau (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == 6942c2bdd23SFelix Fietkau RX_FLAG_DECRYPTED) 6952c2bdd23SFelix Fietkau offset += 8; 6962c2bdd23SFelix Fietkau } 6972c2bdd23SFelix Fietkau 6982c2bdd23SFelix Fietkau if (ether_addr_equal(skb->data + offset, rfc1042_header)) { 6992c2bdd23SFelix Fietkau dev_kfree_skb(skb); 7002c2bdd23SFelix Fietkau return; 7012c2bdd23SFelix Fietkau } 7022c2bdd23SFelix Fietkau } 703cc4b3c13SLorenzo Bianconi __skb_queue_tail(&dev->rx_skb[q], skb); 704cc4b3c13SLorenzo Bianconi } 705cc4b3c13SLorenzo Bianconi 706cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, 707cc4b3c13SLorenzo Bianconi struct sk_buff *skb) 708cc4b3c13SLorenzo Bianconi { 709cc4b3c13SLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 710cc4b3c13SLorenzo Bianconi 711cc4b3c13SLorenzo Bianconi if (phy->rx_amsdu[q].head && 712cc4b3c13SLorenzo Bianconi (!status->amsdu || status->first_amsdu || 713cc4b3c13SLorenzo Bianconi status->seqno != phy->rx_amsdu[q].seqno)) 714cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 715cc4b3c13SLorenzo Bianconi 716cc4b3c13SLorenzo Bianconi if (!phy->rx_amsdu[q].head) { 717cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; 718cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].seqno = status->seqno; 719cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = skb; 720cc4b3c13SLorenzo Bianconi } else { 721cc4b3c13SLorenzo Bianconi *phy->rx_amsdu[q].tail = skb; 722cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb->next; 723cc4b3c13SLorenzo Bianconi } 724cc4b3c13SLorenzo Bianconi 725cc4b3c13SLorenzo Bianconi if (!status->amsdu || status->last_amsdu) 726cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 727cc4b3c13SLorenzo Bianconi } 728cc4b3c13SLorenzo Bianconi 72917f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 73017f1de56SFelix Fietkau { 731011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 732011849e0SFelix Fietkau struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy); 733011849e0SFelix Fietkau 734011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 73517f1de56SFelix Fietkau dev_kfree_skb(skb); 73617f1de56SFelix Fietkau return; 73717f1de56SFelix Fietkau } 73817f1de56SFelix Fietkau 739f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE 740c918c74dSShayne Chen if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { 741c918c74dSShayne Chen phy->test.rx_stats.packets[q]++; 742f0efa862SFelix Fietkau if (status->flag & RX_FLAG_FAILED_FCS_CRC) 743c918c74dSShayne Chen phy->test.rx_stats.fcs_error[q]++; 744f0efa862SFelix Fietkau } 745f0efa862SFelix Fietkau #endif 746cc4b3c13SLorenzo Bianconi 747cc4b3c13SLorenzo Bianconi mt76_rx_release_burst(phy, q, skb); 74817f1de56SFelix Fietkau } 74917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 75017f1de56SFelix Fietkau 7515a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy) 75226e40d4cSFelix Fietkau { 753af005f26SLorenzo Bianconi struct mt76_queue *q; 75491990519SLorenzo Bianconi int i; 7555a95ca41SFelix Fietkau 7565a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) { 75791990519SLorenzo Bianconi q = phy->q_tx[i]; 758af005f26SLorenzo Bianconi if (q && q->queued) 75926e40d4cSFelix Fietkau return true; 76026e40d4cSFelix Fietkau } 76126e40d4cSFelix Fietkau 76226e40d4cSFelix Fietkau return false; 76326e40d4cSFelix Fietkau } 76439d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 76526e40d4cSFelix Fietkau 7660fd0eb54SFelix Fietkau static struct mt76_channel_state * 76796747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 7680fd0eb54SFelix Fietkau { 7690fd0eb54SFelix Fietkau struct mt76_sband *msband; 7700fd0eb54SFelix Fietkau int idx; 7710fd0eb54SFelix Fietkau 7720fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 77396747a51SFelix Fietkau msband = &phy->sband_2g; 774edf9dab8SLorenzo Bianconi else if (c->band == NL80211_BAND_6GHZ) 775edf9dab8SLorenzo Bianconi msband = &phy->sband_6g; 7760fd0eb54SFelix Fietkau else 77796747a51SFelix Fietkau msband = &phy->sband_5g; 7780fd0eb54SFelix Fietkau 7790fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 7800fd0eb54SFelix Fietkau return &msband->chan[idx]; 7810fd0eb54SFelix Fietkau } 7820fd0eb54SFelix Fietkau 78304414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 78496747a51SFelix Fietkau { 78596747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state; 78696747a51SFelix Fietkau 78796747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time, 78896747a51SFelix Fietkau phy->survey_time)); 78996747a51SFelix Fietkau phy->survey_time = time; 79096747a51SFelix Fietkau } 79104414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 79296747a51SFelix Fietkau 793c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy) 7945ce09c1aSFelix Fietkau { 795c560b137SRyder Lee struct mt76_dev *dev = phy->dev; 796aec65e48SFelix Fietkau ktime_t cur_time; 797aec65e48SFelix Fietkau 7985ce09c1aSFelix Fietkau if (dev->drv->update_survey) 799c560b137SRyder Lee dev->drv->update_survey(phy); 8005ce09c1aSFelix Fietkau 801aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 802c560b137SRyder Lee mt76_update_survey_active_time(phy, cur_time); 803aec65e48SFelix Fietkau 8045ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 805c560b137SRyder Lee struct mt76_channel_state *state = phy->chan_state; 80696747a51SFelix Fietkau 807237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 8085ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 8095ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 810237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 8115ce09c1aSFelix Fietkau } 8125ce09c1aSFelix Fietkau } 8135ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 8145ce09c1aSFelix Fietkau 81596747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy) 81617f1de56SFelix Fietkau { 81796747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 81896747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 81917f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 82017f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 82126e40d4cSFelix Fietkau int timeout = HZ / 5; 82217f1de56SFelix Fietkau 8235a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 824c560b137SRyder Lee mt76_update_survey(phy); 82517f1de56SFelix Fietkau 8263f306448SFelix Fietkau if (phy->chandef.chan->center_freq != chandef->chan->center_freq || 8273f306448SFelix Fietkau phy->chandef.width != chandef->width) 8283f306448SFelix Fietkau phy->dfs_state = MT_DFS_STATE_UNKNOWN; 8293f306448SFelix Fietkau 83096747a51SFelix Fietkau phy->chandef = *chandef; 83196747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan); 83217f1de56SFelix Fietkau 83317f1de56SFelix Fietkau if (!offchannel) 83496747a51SFelix Fietkau phy->main_chan = chandef->chan; 83517f1de56SFelix Fietkau 83696747a51SFelix Fietkau if (chandef->chan != phy->main_chan) 83796747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 83817f1de56SFelix Fietkau } 83917f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 84017f1de56SFelix Fietkau 84117f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 84217f1de56SFelix Fietkau struct survey_info *survey) 84317f1de56SFelix Fietkau { 84496747a51SFelix Fietkau struct mt76_phy *phy = hw->priv; 84596747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 84617f1de56SFelix Fietkau struct mt76_sband *sband; 84717f1de56SFelix Fietkau struct ieee80211_channel *chan; 84817f1de56SFelix Fietkau struct mt76_channel_state *state; 84917f1de56SFelix Fietkau int ret = 0; 85017f1de56SFelix Fietkau 851237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 85217f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 853c560b137SRyder Lee mt76_update_survey(phy); 85417f1de56SFelix Fietkau 855edf9dab8SLorenzo Bianconi if (idx >= phy->sband_2g.sband.n_channels + 856edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels) { 857edf9dab8SLorenzo Bianconi idx -= (phy->sband_2g.sband.n_channels + 858edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels); 859edf9dab8SLorenzo Bianconi sband = &phy->sband_6g; 860edf9dab8SLorenzo Bianconi } else if (idx >= phy->sband_2g.sband.n_channels) { 861edf9dab8SLorenzo Bianconi idx -= phy->sband_2g.sband.n_channels; 86296747a51SFelix Fietkau sband = &phy->sband_5g; 863edf9dab8SLorenzo Bianconi } else { 864edf9dab8SLorenzo Bianconi sband = &phy->sband_2g; 86517f1de56SFelix Fietkau } 86617f1de56SFelix Fietkau 867237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 868237312c5SLorenzo Bianconi ret = -ENOENT; 869237312c5SLorenzo Bianconi goto out; 870237312c5SLorenzo Bianconi } 87117f1de56SFelix Fietkau 87217f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 87396747a51SFelix Fietkau state = mt76_channel_state(phy, chan); 87417f1de56SFelix Fietkau 87517f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 87617f1de56SFelix Fietkau survey->channel = chan; 87717f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 878ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 879e5051965SFelix Fietkau if (state->noise) 880e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM; 881e5051965SFelix Fietkau 88296747a51SFelix Fietkau if (chan == phy->main_chan) { 88317f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 88417f1de56SFelix Fietkau 8855ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 8865ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 8875ce09c1aSFelix Fietkau } 8885ce09c1aSFelix Fietkau 88917f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 8906bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 891237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 892e5051965SFelix Fietkau survey->noise = state->noise; 893237312c5SLorenzo Bianconi 894237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 895237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 896ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 89717f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 89817f1de56SFelix Fietkau 899237312c5SLorenzo Bianconi out: 900237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 901237312c5SLorenzo Bianconi 90217f1de56SFelix Fietkau return ret; 90317f1de56SFelix Fietkau } 90417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 90517f1de56SFelix Fietkau 90630ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 90730ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 90830ce7f44SFelix Fietkau { 90930ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 91030ce7f44SFelix Fietkau int i; 91130ce7f44SFelix Fietkau 91230ce7f44SFelix Fietkau wcid->rx_check_pn = false; 91330ce7f44SFelix Fietkau 91430ce7f44SFelix Fietkau if (!key) 91530ce7f44SFelix Fietkau return; 91630ce7f44SFelix Fietkau 91701cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 91801cfc1b4SLorenzo Bianconi return; 91930ce7f44SFelix Fietkau 92001cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 921a1b0bbd4SXing Song 922a1b0bbd4SXing Song /* data frame */ 92330ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 92430ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 92530ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 92630ce7f44SFelix Fietkau } 927a1b0bbd4SXing Song 928a1b0bbd4SXing Song /* robust management frame */ 929a1b0bbd4SXing Song ieee80211_get_key_rx_seq(key, -1, &seq); 930a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 931a1b0bbd4SXing Song 93230ce7f44SFelix Fietkau } 93330ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 93430ce7f44SFelix Fietkau 9354550fb9eSFelix Fietkau static int 9364550fb9eSFelix Fietkau mt76_rx_signal(struct mt76_rx_status *status) 9374550fb9eSFelix Fietkau { 9384550fb9eSFelix Fietkau s8 *chain_signal = status->chain_signal; 9394550fb9eSFelix Fietkau int signal = -128; 9404550fb9eSFelix Fietkau u8 chains; 9414550fb9eSFelix Fietkau 9424550fb9eSFelix Fietkau for (chains = status->chains; chains; chains >>= 1, chain_signal++) { 9434550fb9eSFelix Fietkau int cur, diff; 9444550fb9eSFelix Fietkau 9456450b133SDeren Wu cur = *chain_signal; 9466450b133SDeren Wu if (!(chains & BIT(0)) || 9476450b133SDeren Wu cur > 0) 9484550fb9eSFelix Fietkau continue; 9494550fb9eSFelix Fietkau 9504550fb9eSFelix Fietkau if (cur > signal) 9514550fb9eSFelix Fietkau swap(cur, signal); 9524550fb9eSFelix Fietkau 9534550fb9eSFelix Fietkau diff = signal - cur; 9544550fb9eSFelix Fietkau if (diff == 0) 9554550fb9eSFelix Fietkau signal += 3; 9564550fb9eSFelix Fietkau else if (diff <= 2) 9574550fb9eSFelix Fietkau signal += 2; 9584550fb9eSFelix Fietkau else if (diff <= 6) 9594550fb9eSFelix Fietkau signal += 1; 9604550fb9eSFelix Fietkau } 9614550fb9eSFelix Fietkau 9624550fb9eSFelix Fietkau return signal; 9634550fb9eSFelix Fietkau } 9644550fb9eSFelix Fietkau 965bfc394ddSFelix Fietkau static void 966bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 967bfc394ddSFelix Fietkau struct ieee80211_hw **hw, 968bfc394ddSFelix Fietkau struct ieee80211_sta **sta) 9694e34249eSFelix Fietkau { 9704e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 971abe3f3daSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 9724e34249eSFelix Fietkau struct mt76_rx_status mstat; 9734e34249eSFelix Fietkau 9744e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 9754e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 9764e34249eSFelix Fietkau 9774e34249eSFelix Fietkau status->flag = mstat.flag; 9784e34249eSFelix Fietkau status->freq = mstat.freq; 9794e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 9804e34249eSFelix Fietkau status->encoding = mstat.encoding; 9814e34249eSFelix Fietkau status->bw = mstat.bw; 982af4a2f2fSRyder Lee status->he_ru = mstat.he_ru; 983af4a2f2fSRyder Lee status->he_gi = mstat.he_gi; 984af4a2f2fSRyder Lee status->he_dcm = mstat.he_dcm; 9854e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 9864e34249eSFelix Fietkau status->nss = mstat.nss; 9874e34249eSFelix Fietkau status->band = mstat.band; 9884e34249eSFelix Fietkau status->signal = mstat.signal; 9894e34249eSFelix Fietkau status->chains = mstat.chains; 990d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 9910fda6d7bSRyder Lee status->device_timestamp = mstat.timestamp; 9920fda6d7bSRyder Lee status->mactime = mstat.timestamp; 9934550fb9eSFelix Fietkau status->signal = mt76_rx_signal(&mstat); 9944550fb9eSFelix Fietkau if (status->signal <= -128) 9954550fb9eSFelix Fietkau status->flag |= RX_FLAG_NO_SIGNAL_VAL; 9964e34249eSFelix Fietkau 997abe3f3daSRyder Lee if (ieee80211_is_beacon(hdr->frame_control) || 998abe3f3daSRyder Lee ieee80211_is_probe_resp(hdr->frame_control)) 999abe3f3daSRyder Lee status->boottime_ns = ktime_get_boottime_ns(); 1000abe3f3daSRyder Lee 10014e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 100213381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 100313381dcdSRyder Lee sizeof(mstat.chain_signal)); 100413381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 100513381dcdSRyder Lee sizeof(mstat.chain_signal)); 10069c68a57bSFelix Fietkau 1007bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid); 1008bfc394ddSFelix Fietkau *hw = mt76_phy_hw(dev, mstat.ext_phy); 10094e34249eSFelix Fietkau } 10104e34249eSFelix Fietkau 101130ce7f44SFelix Fietkau static int 101230ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 101330ce7f44SFelix Fietkau { 101430ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 101530ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 101630ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 1017a1b0bbd4SXing Song int security_idx; 101830ce7f44SFelix Fietkau int ret; 101930ce7f44SFelix Fietkau 102030ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 102130ce7f44SFelix Fietkau return 0; 102230ce7f44SFelix Fietkau 102330ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 102430ce7f44SFelix Fietkau return 0; 102530ce7f44SFelix Fietkau 10267360cdecSFelix Fietkau security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 10277360cdecSFelix Fietkau if (status->flag & RX_FLAG_8023) 10287360cdecSFelix Fietkau goto skip_hdr_check; 10297360cdecSFelix Fietkau 1030a1b0bbd4SXing Song hdr = mt76_skb_get_hdr(skb); 103130ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 103230ce7f44SFelix Fietkau /* 103330ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 103430ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 103530ce7f44SFelix Fietkau */ 103630ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 103730ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 103830ce7f44SFelix Fietkau return 0; 103930ce7f44SFelix Fietkau } 104030ce7f44SFelix Fietkau 1041a1b0bbd4SXing Song /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): 1042a1b0bbd4SXing Song * 1043a1b0bbd4SXing Song * the recipient shall maintain a single replay counter for received 1044a1b0bbd4SXing Song * individually addressed robust Management frames that are received 1045a1b0bbd4SXing Song * with the To DS subfield equal to 0, [...] 1046a1b0bbd4SXing Song */ 1047a1b0bbd4SXing Song if (ieee80211_is_mgmt(hdr->frame_control) && 1048a1b0bbd4SXing Song !ieee80211_has_tods(hdr->frame_control)) 1049a1b0bbd4SXing Song security_idx = IEEE80211_NUM_TIDS; 1050a1b0bbd4SXing Song 10517360cdecSFelix Fietkau skip_hdr_check: 105230ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 1053a1b0bbd4SXing Song ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], 105430ce7f44SFelix Fietkau sizeof(status->iv)); 105530ce7f44SFelix Fietkau if (ret <= 0) 105630ce7f44SFelix Fietkau return -EINVAL; /* replay */ 105730ce7f44SFelix Fietkau 1058a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); 105930ce7f44SFelix Fietkau 106030ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 106130ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 106230ce7f44SFelix Fietkau 106330ce7f44SFelix Fietkau return 0; 106430ce7f44SFelix Fietkau } 106530ce7f44SFelix Fietkau 1066d71ef286SFelix Fietkau static void 10675ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 10685ce09c1aSFelix Fietkau int len) 10695ce09c1aSFelix Fietkau { 10705ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 107185b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = { 107285b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags, 107385b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx, 107485b7a5d0SLorenzo Bianconi .encoding = status->encoding, 107585b7a5d0SLorenzo Bianconi .band = status->band, 107685b7a5d0SLorenzo Bianconi .nss = status->nss, 107785b7a5d0SLorenzo Bianconi .bw = status->bw, 107885b7a5d0SLorenzo Bianconi }; 10795ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 10805ce09c1aSFelix Fietkau u32 airtime; 1081e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 10825ce09c1aSFelix Fietkau 108385b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 1084237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 10855ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 1086237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 10875ce09c1aSFelix Fietkau 10885ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 10895ce09c1aSFelix Fietkau return; 10905ce09c1aSFelix Fietkau 10915ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1092e195dad1SFelix Fietkau ieee80211_sta_register_airtime(sta, tidno, 0, airtime); 10935ce09c1aSFelix Fietkau } 10945ce09c1aSFelix Fietkau 10955ce09c1aSFelix Fietkau static void 10965ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 10975ce09c1aSFelix Fietkau { 10985ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 10995ce09c1aSFelix Fietkau int wcid_idx; 11005ce09c1aSFelix Fietkau 11015ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 11025ce09c1aSFelix Fietkau return; 11035ce09c1aSFelix Fietkau 11045ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 1105bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 11065ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 11075ce09c1aSFelix Fietkau else 11085ce09c1aSFelix Fietkau wcid = NULL; 11095ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 11105ce09c1aSFelix Fietkau 11115ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 11125ce09c1aSFelix Fietkau 11135ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 11145ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 11155ce09c1aSFelix Fietkau } 11165ce09c1aSFelix Fietkau 11175ce09c1aSFelix Fietkau static void 11185ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 11195ce09c1aSFelix Fietkau { 11205ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 11215ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 11225ce09c1aSFelix Fietkau 11235ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 11245ce09c1aSFelix Fietkau return; 11255ce09c1aSFelix Fietkau 11265ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 1127e195dad1SFelix Fietkau struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1128e195dad1SFelix Fietkau 1129e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1130e195dad1SFelix Fietkau return; 1131e195dad1SFelix Fietkau 113298df2baeSLorenzo Bianconi if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) 11335ce09c1aSFelix Fietkau return; 11345ce09c1aSFelix Fietkau 11355ce09c1aSFelix Fietkau wcid = NULL; 11365ce09c1aSFelix Fietkau } 11375ce09c1aSFelix Fietkau 11385ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 11395ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 11405ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 11415ce09c1aSFelix Fietkau 11425ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 11435ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 11445ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 11455ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 11465ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 11475ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 11485ce09c1aSFelix Fietkau } 11495ce09c1aSFelix Fietkau 11505ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 11515ce09c1aSFelix Fietkau return; 11525ce09c1aSFelix Fietkau } 11535ce09c1aSFelix Fietkau 11545ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 11555ce09c1aSFelix Fietkau } 11565ce09c1aSFelix Fietkau 11575ce09c1aSFelix Fietkau static void 1158ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 1159d71ef286SFelix Fietkau { 1160d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 116177ae1d5eSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1162d71ef286SFelix Fietkau struct ieee80211_sta *sta; 1163bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 1164d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 1165e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 1166d71ef286SFelix Fietkau bool ps; 1167d71ef286SFelix Fietkau 1168bfc394ddSFelix Fietkau hw = mt76_phy_hw(dev, status->ext_phy); 1169e195dad1SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && 1170e195dad1SFelix Fietkau !(status->flag & RX_FLAG_8023)) { 1171bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 117236d91096SFelix Fietkau if (sta) 117336d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 117436d91096SFelix Fietkau } 117536d91096SFelix Fietkau 11765ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 11775ce09c1aSFelix Fietkau 1178d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 1179d71ef286SFelix Fietkau return; 1180d71ef286SFelix Fietkau 1181d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1182d71ef286SFelix Fietkau 118302e5a769SFelix Fietkau if (status->signal <= 0) 118402e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 118502e5a769SFelix Fietkau 1186ef13edc0SFelix Fietkau wcid->inactive_count = 0; 1187ef13edc0SFelix Fietkau 1188e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1189e195dad1SFelix Fietkau return; 1190e195dad1SFelix Fietkau 1191d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 1192d71ef286SFelix Fietkau return; 1193d71ef286SFelix Fietkau 1194d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 1195d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 1196d71ef286SFelix Fietkau return; 1197d71ef286SFelix Fietkau } 1198d71ef286SFelix Fietkau 1199d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 1200d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 1201d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 1202d71ef286SFelix Fietkau return; 1203d71ef286SFelix Fietkau 1204d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 1205d71ef286SFelix Fietkau 1206d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 1207d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 1208e195dad1SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, tidno); 1209d71ef286SFelix Fietkau 1210d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 1211d71ef286SFelix Fietkau return; 1212d71ef286SFelix Fietkau 121311b2a25fSFelix Fietkau if (ps) 1214d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 1215d71ef286SFelix Fietkau 1216d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 1217608f7c47SFelix Fietkau 1218608f7c47SFelix Fietkau if (!ps) 1219608f7c47SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 1220608f7c47SFelix Fietkau 12219f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 1222d71ef286SFelix Fietkau } 1223d71ef286SFelix Fietkau 12249d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 122581e850efSLorenzo Bianconi struct napi_struct *napi) 122617f1de56SFelix Fietkau { 12279c68a57bSFelix Fietkau struct ieee80211_sta *sta; 1228bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 12293298b1f8SFelix Fietkau struct sk_buff *skb, *tmp; 12303298b1f8SFelix Fietkau LIST_HEAD(list); 12319d9d738bSFelix Fietkau 1232c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 12339d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 1234cc4b3c13SLorenzo Bianconi struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 1235cc4b3c13SLorenzo Bianconi 123630ce7f44SFelix Fietkau if (mt76_check_ccmp_pn(skb)) { 123730ce7f44SFelix Fietkau dev_kfree_skb(skb); 123830ce7f44SFelix Fietkau continue; 123930ce7f44SFelix Fietkau } 124030ce7f44SFelix Fietkau 1241cc4b3c13SLorenzo Bianconi skb_shinfo(skb)->frag_list = NULL; 1242bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta); 12433298b1f8SFelix Fietkau ieee80211_rx_list(hw, sta, skb, &list); 1244cc4b3c13SLorenzo Bianconi 1245cc4b3c13SLorenzo Bianconi /* subsequent amsdu frames */ 1246cc4b3c13SLorenzo Bianconi while (nskb) { 1247cc4b3c13SLorenzo Bianconi skb = nskb; 1248cc4b3c13SLorenzo Bianconi nskb = nskb->next; 1249cc4b3c13SLorenzo Bianconi skb->next = NULL; 1250cc4b3c13SLorenzo Bianconi 1251cc4b3c13SLorenzo Bianconi mt76_rx_convert(dev, skb, &hw, &sta); 1252cc4b3c13SLorenzo Bianconi ieee80211_rx_list(hw, sta, skb, &list); 1253cc4b3c13SLorenzo Bianconi } 12549d9d738bSFelix Fietkau } 1255c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 12563298b1f8SFelix Fietkau 12573298b1f8SFelix Fietkau if (!napi) { 12583298b1f8SFelix Fietkau netif_receive_skb_list(&list); 12593298b1f8SFelix Fietkau return; 12603298b1f8SFelix Fietkau } 12613298b1f8SFelix Fietkau 12623298b1f8SFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) { 12633298b1f8SFelix Fietkau skb_list_del_init(skb); 12643298b1f8SFelix Fietkau napi_gro_receive(napi, skb); 12653298b1f8SFelix Fietkau } 12669d9d738bSFelix Fietkau } 12679d9d738bSFelix Fietkau 126881e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 126981e850efSLorenzo Bianconi struct napi_struct *napi) 12709d9d738bSFelix Fietkau { 1271aee5b8cfSFelix Fietkau struct sk_buff_head frames; 127217f1de56SFelix Fietkau struct sk_buff *skb; 127317f1de56SFelix Fietkau 1274aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 1275aee5b8cfSFelix Fietkau 1276d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 1277ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 1278aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 1279d71ef286SFelix Fietkau } 1280aee5b8cfSFelix Fietkau 128181e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 12824e34249eSFelix Fietkau } 128381e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 1284723b90dcSFelix Fietkau 1285e28487eaSFelix Fietkau static int 1286e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 1287426e8e41SFelix Fietkau struct ieee80211_sta *sta, bool ext_phy) 1288e28487eaSFelix Fietkau { 1289e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 1290e28487eaSFelix Fietkau int ret; 1291e28487eaSFelix Fietkau int i; 1292e28487eaSFelix Fietkau 1293e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 1294e28487eaSFelix Fietkau 1295e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 1296e28487eaSFelix Fietkau if (ret) 1297e28487eaSFelix Fietkau goto out; 1298e28487eaSFelix Fietkau 1299e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 1300e28487eaSFelix Fietkau struct mt76_txq *mtxq; 1301e28487eaSFelix Fietkau 1302e28487eaSFelix Fietkau if (!sta->txq[i]) 1303e28487eaSFelix Fietkau continue; 1304e28487eaSFelix Fietkau 1305e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 130651fb1278SFelix Fietkau mtxq->wcid = wcid->idx; 1307e28487eaSFelix Fietkau } 1308e28487eaSFelix Fietkau 1309ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 1310426e8e41SFelix Fietkau if (ext_phy) 1311426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 1312c7d2d631SFelix Fietkau wcid->ext_phy = ext_phy; 1313e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 1314e28487eaSFelix Fietkau 1315bd1e3e7bSLorenzo Bianconi mt76_packet_id_init(wcid); 1316e28487eaSFelix Fietkau out: 1317e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 1318e28487eaSFelix Fietkau 1319e28487eaSFelix Fietkau return ret; 1320e28487eaSFelix Fietkau } 1321e28487eaSFelix Fietkau 132213f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 1323723b90dcSFelix Fietkau struct ieee80211_sta *sta) 1324723b90dcSFelix Fietkau { 1325723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 132613f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 1327723b90dcSFelix Fietkau 132858bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 132958bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 133058bab0d4SFelix Fietkau 1331e28487eaSFelix Fietkau if (dev->drv->sta_remove) 1332e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 1333e28487eaSFelix Fietkau 1334bd1e3e7bSLorenzo Bianconi mt76_packet_id_flush(dev, wcid); 1335bd1e3e7bSLorenzo Bianconi 1336426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx); 1337426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 133813f61dfcSLorenzo Bianconi } 133913f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 1340e28487eaSFelix Fietkau 134113f61dfcSLorenzo Bianconi static void 134213f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 134313f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 134413f61dfcSLorenzo Bianconi { 134513f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 134613f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 1347723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 1348723b90dcSFelix Fietkau } 1349e28487eaSFelix Fietkau 1350e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1351e28487eaSFelix Fietkau struct ieee80211_sta *sta, 1352e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 1353e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 1354e28487eaSFelix Fietkau { 1355426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv; 1356426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev; 1357426e8e41SFelix Fietkau bool ext_phy = phy != &dev->phy; 1358e28487eaSFelix Fietkau 1359e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 1360e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 1361426e8e41SFelix Fietkau return mt76_sta_add(dev, vif, sta, ext_phy); 1362e28487eaSFelix Fietkau 13639c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 13649c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 13659c193de5SFelix Fietkau dev->drv->sta_assoc) 13669c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 13679c193de5SFelix Fietkau 1368e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 1369e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 1370e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 1371e28487eaSFelix Fietkau 1372e28487eaSFelix Fietkau return 0; 1373e28487eaSFelix Fietkau } 1374e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 13759313faacSFelix Fietkau 137643ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 137743ba1922SFelix Fietkau struct ieee80211_sta *sta) 137843ba1922SFelix Fietkau { 137943ba1922SFelix Fietkau struct mt76_phy *phy = hw->priv; 138043ba1922SFelix Fietkau struct mt76_dev *dev = phy->dev; 138143ba1922SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 138243ba1922SFelix Fietkau 138343ba1922SFelix Fietkau mutex_lock(&dev->mutex); 1384*fcfe1b5eSFelix Fietkau spin_lock_bh(&dev->status_lock); 138543ba1922SFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 1386*fcfe1b5eSFelix Fietkau spin_unlock_bh(&dev->status_lock); 138743ba1922SFelix Fietkau mutex_unlock(&dev->mutex); 138843ba1922SFelix Fietkau } 138943ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 139043ba1922SFelix Fietkau 13919313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 13929313faacSFelix Fietkau int *dbm) 13939313faacSFelix Fietkau { 1394beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1395beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask); 139607cda406SFelix Fietkau int delta = mt76_tx_power_nss_delta(n_chains); 13979313faacSFelix Fietkau 139807cda406SFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 13999313faacSFelix Fietkau 14009313faacSFelix Fietkau return 0; 14019313faacSFelix Fietkau } 14029313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 1403e7173858SFelix Fietkau 1404b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw, 1405b3cb885eSLorenzo Bianconi const struct cfg80211_sar_specs *sar) 1406b3cb885eSLorenzo Bianconi { 1407b3cb885eSLorenzo Bianconi struct mt76_phy *phy = hw->priv; 1408b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; 1409b3cb885eSLorenzo Bianconi int i; 1410b3cb885eSLorenzo Bianconi 1411b3cb885eSLorenzo Bianconi if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) 1412b3cb885eSLorenzo Bianconi return -EINVAL; 1413b3cb885eSLorenzo Bianconi 1414b3cb885eSLorenzo Bianconi for (i = 0; i < sar->num_sub_specs; i++) { 1415b3cb885eSLorenzo Bianconi u32 index = sar->sub_specs[i].freq_range_index; 1416b3cb885eSLorenzo Bianconi /* SAR specifies power limitaton in 0.25dbm */ 1417b3cb885eSLorenzo Bianconi s32 power = sar->sub_specs[i].power >> 1; 1418b3cb885eSLorenzo Bianconi 1419b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1420b3cb885eSLorenzo Bianconi power = 127; 1421b3cb885eSLorenzo Bianconi 1422b3cb885eSLorenzo Bianconi phy->frp[index].range = &capa->freq_ranges[index]; 1423b3cb885eSLorenzo Bianconi phy->frp[index].power = power; 1424b3cb885eSLorenzo Bianconi } 1425b3cb885eSLorenzo Bianconi 1426b3cb885eSLorenzo Bianconi return 0; 1427b3cb885eSLorenzo Bianconi } 1428b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power); 1429b3cb885eSLorenzo Bianconi 1430b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy, 1431b3cb885eSLorenzo Bianconi struct ieee80211_channel *chan, 1432b3cb885eSLorenzo Bianconi int power) 1433b3cb885eSLorenzo Bianconi { 1434b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; 1435b3cb885eSLorenzo Bianconi int freq, i; 1436b3cb885eSLorenzo Bianconi 1437b3cb885eSLorenzo Bianconi if (!capa || !phy->frp) 1438b3cb885eSLorenzo Bianconi return power; 1439b3cb885eSLorenzo Bianconi 1440b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1441b3cb885eSLorenzo Bianconi power = 127; 1442b3cb885eSLorenzo Bianconi 1443b3cb885eSLorenzo Bianconi freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); 1444b3cb885eSLorenzo Bianconi for (i = 0 ; i < capa->num_freq_ranges; i++) { 1445b3cb885eSLorenzo Bianconi if (phy->frp[i].range && 1446b3cb885eSLorenzo Bianconi freq >= phy->frp[i].range->start_freq && 1447b3cb885eSLorenzo Bianconi freq < phy->frp[i].range->end_freq) { 1448b3cb885eSLorenzo Bianconi power = min_t(int, phy->frp[i].power, power); 1449b3cb885eSLorenzo Bianconi break; 1450b3cb885eSLorenzo Bianconi } 1451b3cb885eSLorenzo Bianconi } 1452b3cb885eSLorenzo Bianconi 1453b3cb885eSLorenzo Bianconi return power; 1454b3cb885eSLorenzo Bianconi } 1455b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power); 1456b3cb885eSLorenzo Bianconi 1457e7173858SFelix Fietkau static void 1458e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 1459e7173858SFelix Fietkau { 14608552a434SJohn Crispin if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 1461e7173858SFelix Fietkau ieee80211_csa_finish(vif); 1462e7173858SFelix Fietkau } 1463e7173858SFelix Fietkau 1464e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 1465e7173858SFelix Fietkau { 1466e7173858SFelix Fietkau if (!dev->csa_complete) 1467e7173858SFelix Fietkau return; 1468e7173858SFelix Fietkau 1469e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1470e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1471e7173858SFelix Fietkau __mt76_csa_finish, dev); 1472e7173858SFelix Fietkau 1473e7173858SFelix Fietkau dev->csa_complete = 0; 1474e7173858SFelix Fietkau } 1475e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 1476e7173858SFelix Fietkau 1477e7173858SFelix Fietkau static void 1478e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 1479e7173858SFelix Fietkau { 1480e7173858SFelix Fietkau struct mt76_dev *dev = priv; 1481e7173858SFelix Fietkau 1482e7173858SFelix Fietkau if (!vif->csa_active) 1483e7173858SFelix Fietkau return; 1484e7173858SFelix Fietkau 14858552a434SJohn Crispin dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 1486e7173858SFelix Fietkau } 1487e7173858SFelix Fietkau 1488e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 1489e7173858SFelix Fietkau { 1490e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1491e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1492e7173858SFelix Fietkau __mt76_csa_check, dev); 1493e7173858SFelix Fietkau } 1494e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 149587d53103SStanislaw Gruszka 149687d53103SStanislaw Gruszka int 149787d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 149887d53103SStanislaw Gruszka { 149987d53103SStanislaw Gruszka return 0; 150087d53103SStanislaw Gruszka } 150187d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 1502eadfd98fSLorenzo Bianconi 1503eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 1504eadfd98fSLorenzo Bianconi { 1505eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 1506eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 1507eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 1508eadfd98fSLorenzo Bianconi 1509eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 1510eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 1511eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 1512eadfd98fSLorenzo Bianconi 1513eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 1514eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 1515eadfd98fSLorenzo Bianconi hdr[2] = 0; 1516eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 1517eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 1518eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 1519eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 1520eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1521eadfd98fSLorenzo Bianconi 1522eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1523eadfd98fSLorenzo Bianconi } 1524eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1525d2679d65SLorenzo Bianconi 1526d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1527d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1528d2679d65SLorenzo Bianconi int idx, bool cck) 1529d2679d65SLorenzo Bianconi { 1530d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1531d2679d65SLorenzo Bianconi 1532d2679d65SLorenzo Bianconi if (cck) { 1533edf9dab8SLorenzo Bianconi if (sband != &dev->phy.sband_2g.sband) 1534d2679d65SLorenzo Bianconi return 0; 1535d2679d65SLorenzo Bianconi 1536d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 153796747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) { 1538d2679d65SLorenzo Bianconi offset = 4; 1539d2679d65SLorenzo Bianconi } 1540d2679d65SLorenzo Bianconi 1541d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1542d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1543d2679d65SLorenzo Bianconi return i; 1544d2679d65SLorenzo Bianconi } 1545d2679d65SLorenzo Bianconi 1546d2679d65SLorenzo Bianconi return 0; 1547d2679d65SLorenzo Bianconi } 1548d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 15498b8ab5c2SLorenzo Bianconi 15508b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 15518b8ab5c2SLorenzo Bianconi const u8 *mac) 15528b8ab5c2SLorenzo Bianconi { 1553011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 15548b8ab5c2SLorenzo Bianconi 1555011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state); 15568b8ab5c2SLorenzo Bianconi } 15578b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 15588b8ab5c2SLorenzo Bianconi 15598b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 15608b8ab5c2SLorenzo Bianconi { 1561011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 15628b8ab5c2SLorenzo Bianconi 1563011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state); 15648b8ab5c2SLorenzo Bianconi } 15658b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1566e49c76d4SLorenzo Bianconi 1567e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1568e49c76d4SLorenzo Bianconi { 1569beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1570beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev; 1571e49c76d4SLorenzo Bianconi 1572e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1573beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask; 1574beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask; 1575e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1576e49c76d4SLorenzo Bianconi 1577e49c76d4SLorenzo Bianconi return 0; 1578e49c76d4SLorenzo Bianconi } 1579e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1580b671da33SLorenzo Bianconi 1581b1cb42adSLorenzo Bianconi struct mt76_queue * 1582b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, 1583b1cb42adSLorenzo Bianconi int ring_base) 1584b671da33SLorenzo Bianconi { 1585b671da33SLorenzo Bianconi struct mt76_queue *hwq; 1586b671da33SLorenzo Bianconi int err; 1587b671da33SLorenzo Bianconi 1588b671da33SLorenzo Bianconi hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); 1589b671da33SLorenzo Bianconi if (!hwq) 1590b1cb42adSLorenzo Bianconi return ERR_PTR(-ENOMEM); 1591b671da33SLorenzo Bianconi 1592b671da33SLorenzo Bianconi err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); 1593b671da33SLorenzo Bianconi if (err < 0) 1594b1cb42adSLorenzo Bianconi return ERR_PTR(err); 1595b671da33SLorenzo Bianconi 1596b1cb42adSLorenzo Bianconi return hwq; 1597b671da33SLorenzo Bianconi } 1598b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue); 1599e4867225SSean Wang 160033920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) 1601e4867225SSean Wang { 160233920b2bSRyder Lee int offset = 0; 1603e4867225SSean Wang 1604edf9dab8SLorenzo Bianconi if (phy->chandef.chan->band != NL80211_BAND_2GHZ) 1605e4867225SSean Wang offset = 4; 1606e4867225SSean Wang 160733920b2bSRyder Lee /* pick the lowest rate for hidden nodes */ 160833920b2bSRyder Lee if (rateidx < 0) 160933920b2bSRyder Lee rateidx = 0; 161033920b2bSRyder Lee 1611d4f3d1c4SLorenzo Bianconi rateidx += offset; 1612d4f3d1c4SLorenzo Bianconi if (rateidx >= ARRAY_SIZE(mt76_rates)) 1613d4f3d1c4SLorenzo Bianconi rateidx = offset; 1614e4867225SSean Wang 1615d4f3d1c4SLorenzo Bianconi return mt76_rates[rateidx].hw_value; 1616e4867225SSean Wang } 161733920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); 161854ae98ffSLorenzo Bianconi 161954ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, 162054ae98ffSLorenzo Bianconi struct mt76_sta_stats *stats) 162154ae98ffSLorenzo Bianconi { 162254ae98ffSLorenzo Bianconi int i, ei = wi->initial_stat_idx; 162354ae98ffSLorenzo Bianconi u64 *data = wi->data; 162454ae98ffSLorenzo Bianconi 162554ae98ffSLorenzo Bianconi wi->sta_count++; 162654ae98ffSLorenzo Bianconi 162754ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; 162854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; 162954ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; 163054ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; 163154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; 163254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; 163354ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; 163454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; 163554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; 163654ae98ffSLorenzo Bianconi 163754ae98ffSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++) 163854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_bw[i]; 163954ae98ffSLorenzo Bianconi 164054ae98ffSLorenzo Bianconi for (i = 0; i < 12; i++) 164154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mcs[i]; 164254ae98ffSLorenzo Bianconi 164354ae98ffSLorenzo Bianconi wi->worker_stat_count = ei - wi->initial_stat_idx; 164454ae98ffSLorenzo Bianconi } 164554ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker); 16463f306448SFelix Fietkau 16473f306448SFelix Fietkau enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) 16483f306448SFelix Fietkau { 16493f306448SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 16503f306448SFelix Fietkau struct mt76_dev *dev = phy->dev; 16513f306448SFelix Fietkau 16523f306448SFelix Fietkau if (dev->region == NL80211_DFS_UNSET || 16533f306448SFelix Fietkau test_bit(MT76_SCANNING, &phy->state)) 16543f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 16553f306448SFelix Fietkau 16563f306448SFelix Fietkau if (!hw->conf.radar_enabled) { 16573f306448SFelix Fietkau if ((hw->conf.flags & IEEE80211_CONF_MONITOR) && 16583f306448SFelix Fietkau (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR)) 16593f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 16603f306448SFelix Fietkau 16613f306448SFelix Fietkau return MT_DFS_STATE_DISABLED; 16623f306448SFelix Fietkau } 16633f306448SFelix Fietkau 166400a883e6SFelix Fietkau if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->chandef, NL80211_IFTYPE_AP)) 16653f306448SFelix Fietkau return MT_DFS_STATE_CAC; 16663f306448SFelix Fietkau 16673f306448SFelix Fietkau return MT_DFS_STATE_ACTIVE; 16683f306448SFelix Fietkau } 16693f306448SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); 1670