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 183502604f5SYN Chen 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 EXPORT_SYMBOL_GPL(mt76_sar_capa); 189502604f5SYN Chen 19017f1de56SFelix Fietkau static int mt76_led_init(struct mt76_dev *dev) 19117f1de56SFelix Fietkau { 19217f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node; 19317f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 19417f1de56SFelix Fietkau int led_pin; 19517f1de56SFelix Fietkau 19617f1de56SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 19717f1de56SFelix Fietkau return 0; 19817f1de56SFelix Fietkau 19917f1de56SFelix Fietkau snprintf(dev->led_name, sizeof(dev->led_name), 20017f1de56SFelix Fietkau "mt76-%s", wiphy_name(hw->wiphy)); 20117f1de56SFelix Fietkau 20217f1de56SFelix Fietkau dev->led_cdev.name = dev->led_name; 20317f1de56SFelix Fietkau dev->led_cdev.default_trigger = 20417f1de56SFelix Fietkau ieee80211_create_tpt_led_trigger(hw, 20517f1de56SFelix Fietkau IEEE80211_TPT_LEDTRIG_FL_RADIO, 20617f1de56SFelix Fietkau mt76_tpt_blink, 20717f1de56SFelix Fietkau ARRAY_SIZE(mt76_tpt_blink)); 20817f1de56SFelix Fietkau 20917f1de56SFelix Fietkau np = of_get_child_by_name(np, "led"); 21017f1de56SFelix Fietkau if (np) { 21117f1de56SFelix Fietkau if (!of_property_read_u32(np, "led-sources", &led_pin)) 21217f1de56SFelix Fietkau dev->led_pin = led_pin; 21317f1de56SFelix Fietkau dev->led_al = of_property_read_bool(np, "led-active-low"); 21417f1de56SFelix Fietkau } 21517f1de56SFelix Fietkau 21636f7e2b2SFelix Fietkau return led_classdev_register(dev->dev, &dev->led_cdev); 21736f7e2b2SFelix Fietkau } 21836f7e2b2SFelix Fietkau 21936f7e2b2SFelix Fietkau static void mt76_led_cleanup(struct mt76_dev *dev) 22036f7e2b2SFelix Fietkau { 22136f7e2b2SFelix Fietkau if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 22236f7e2b2SFelix Fietkau return; 22336f7e2b2SFelix Fietkau 22436f7e2b2SFelix Fietkau led_classdev_unregister(&dev->led_cdev); 22517f1de56SFelix Fietkau } 22617f1de56SFelix Fietkau 227bb3e3fecSRyder Lee static void mt76_init_stream_cap(struct mt76_phy *phy, 228551e1ef4SLorenzo Bianconi struct ieee80211_supported_band *sband, 229551e1ef4SLorenzo Bianconi bool vht) 230551e1ef4SLorenzo Bianconi { 231551e1ef4SLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 232bb3e3fecSRyder Lee int i, nstream = hweight8(phy->antenna_mask); 233551e1ef4SLorenzo Bianconi struct ieee80211_sta_vht_cap *vht_cap; 234551e1ef4SLorenzo Bianconi u16 mcs_map = 0; 235551e1ef4SLorenzo Bianconi 236551e1ef4SLorenzo Bianconi if (nstream > 1) 237551e1ef4SLorenzo Bianconi ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 238551e1ef4SLorenzo Bianconi else 239551e1ef4SLorenzo Bianconi ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 240551e1ef4SLorenzo Bianconi 241551e1ef4SLorenzo Bianconi for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 242551e1ef4SLorenzo Bianconi ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 243551e1ef4SLorenzo Bianconi 244551e1ef4SLorenzo Bianconi if (!vht) 245551e1ef4SLorenzo Bianconi return; 246551e1ef4SLorenzo Bianconi 247551e1ef4SLorenzo Bianconi vht_cap = &sband->vht_cap; 248551e1ef4SLorenzo Bianconi if (nstream > 1) 249551e1ef4SLorenzo Bianconi vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 250551e1ef4SLorenzo Bianconi else 251551e1ef4SLorenzo Bianconi vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 252551e1ef4SLorenzo Bianconi 253551e1ef4SLorenzo Bianconi for (i = 0; i < 8; i++) { 254551e1ef4SLorenzo Bianconi if (i < nstream) 255551e1ef4SLorenzo Bianconi mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 256551e1ef4SLorenzo Bianconi else 257551e1ef4SLorenzo Bianconi mcs_map |= 258551e1ef4SLorenzo Bianconi (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 259551e1ef4SLorenzo Bianconi } 260551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 261551e1ef4SLorenzo Bianconi vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 262551e1ef4SLorenzo Bianconi } 263551e1ef4SLorenzo Bianconi 264bb3e3fecSRyder Lee void mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 2655ebdc3e0SLorenzo Bianconi { 26648dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) 267bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 26848dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) 269bb3e3fecSRyder Lee mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 270edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) 271edf9dab8SLorenzo Bianconi mt76_init_stream_cap(phy, &phy->sband_6g.sband, vht); 2725ebdc3e0SLorenzo Bianconi } 2735ebdc3e0SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_set_stream_caps); 2745ebdc3e0SLorenzo Bianconi 27517f1de56SFelix Fietkau static int 27677af762eSLorenzo Bianconi mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband, 27717f1de56SFelix Fietkau const struct ieee80211_channel *chan, int n_chan, 278edf9dab8SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates, 279edf9dab8SLorenzo Bianconi bool ht, bool vht) 28017f1de56SFelix Fietkau { 28117f1de56SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 28217f1de56SFelix Fietkau struct ieee80211_sta_vht_cap *vht_cap; 28377af762eSLorenzo Bianconi struct ieee80211_sta_ht_cap *ht_cap; 28477af762eSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 28517f1de56SFelix Fietkau void *chanlist; 28617f1de56SFelix Fietkau int size; 28717f1de56SFelix Fietkau 28817f1de56SFelix Fietkau size = n_chan * sizeof(*chan); 28917f1de56SFelix Fietkau chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 29017f1de56SFelix Fietkau if (!chanlist) 29117f1de56SFelix Fietkau return -ENOMEM; 29217f1de56SFelix Fietkau 293a86854d0SKees Cook msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 29417f1de56SFelix Fietkau GFP_KERNEL); 29517f1de56SFelix Fietkau if (!msband->chan) 29617f1de56SFelix Fietkau return -ENOMEM; 29717f1de56SFelix Fietkau 29817f1de56SFelix Fietkau sband->channels = chanlist; 29917f1de56SFelix Fietkau sband->n_channels = n_chan; 30017f1de56SFelix Fietkau sband->bitrates = rates; 30117f1de56SFelix Fietkau sband->n_bitrates = n_rates; 30217f1de56SFelix Fietkau 303edf9dab8SLorenzo Bianconi if (!ht) 304edf9dab8SLorenzo Bianconi return 0; 305edf9dab8SLorenzo Bianconi 30617f1de56SFelix Fietkau ht_cap = &sband->ht_cap; 30717f1de56SFelix Fietkau ht_cap->ht_supported = true; 30817f1de56SFelix Fietkau ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 30917f1de56SFelix Fietkau IEEE80211_HT_CAP_GRN_FLD | 31017f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_20 | 31117f1de56SFelix Fietkau IEEE80211_HT_CAP_SGI_40 | 31217f1de56SFelix Fietkau (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 31317f1de56SFelix Fietkau 31417f1de56SFelix Fietkau ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 31517f1de56SFelix Fietkau ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 31617f1de56SFelix Fietkau 31777af762eSLorenzo Bianconi mt76_init_stream_cap(phy, sband, vht); 318551e1ef4SLorenzo Bianconi 31917f1de56SFelix Fietkau if (!vht) 32017f1de56SFelix Fietkau return 0; 32117f1de56SFelix Fietkau 32217f1de56SFelix Fietkau vht_cap = &sband->vht_cap; 32317f1de56SFelix Fietkau vht_cap->vht_supported = true; 32417f1de56SFelix Fietkau vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 32517f1de56SFelix Fietkau IEEE80211_VHT_CAP_RXSTBC_1 | 32649149d3fSFelix Fietkau IEEE80211_VHT_CAP_SHORT_GI_80 | 327f1103fa6SRyder Lee IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | 328f1103fa6SRyder Lee IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 32949149d3fSFelix Fietkau (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 33017f1de56SFelix Fietkau 33117f1de56SFelix Fietkau return 0; 33217f1de56SFelix Fietkau } 33317f1de56SFelix Fietkau 33417f1de56SFelix Fietkau static int 33577af762eSLorenzo Bianconi mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates, 33617f1de56SFelix Fietkau int n_rates) 33717f1de56SFelix Fietkau { 33877af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 33917f1de56SFelix Fietkau 34077af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz, 34177af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_2ghz), rates, 342edf9dab8SLorenzo Bianconi n_rates, true, false); 34317f1de56SFelix Fietkau } 34417f1de56SFelix Fietkau 34517f1de56SFelix Fietkau static int 34677af762eSLorenzo Bianconi mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates, 34717f1de56SFelix Fietkau int n_rates, bool vht) 34817f1de56SFelix Fietkau { 34977af762eSLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 35017f1de56SFelix Fietkau 35177af762eSLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz, 35277af762eSLorenzo Bianconi ARRAY_SIZE(mt76_channels_5ghz), rates, 353edf9dab8SLorenzo Bianconi n_rates, true, vht); 354edf9dab8SLorenzo Bianconi } 355edf9dab8SLorenzo Bianconi 356edf9dab8SLorenzo Bianconi static int 357edf9dab8SLorenzo Bianconi mt76_init_sband_6g(struct mt76_phy *phy, struct ieee80211_rate *rates, 358edf9dab8SLorenzo Bianconi int n_rates) 359edf9dab8SLorenzo Bianconi { 360edf9dab8SLorenzo Bianconi phy->hw->wiphy->bands[NL80211_BAND_6GHZ] = &phy->sband_6g.sband; 361edf9dab8SLorenzo Bianconi 362edf9dab8SLorenzo Bianconi return mt76_init_sband(phy, &phy->sband_6g, mt76_channels_6ghz, 363edf9dab8SLorenzo Bianconi ARRAY_SIZE(mt76_channels_6ghz), rates, 364edf9dab8SLorenzo Bianconi n_rates, false, false); 36517f1de56SFelix Fietkau } 36617f1de56SFelix Fietkau 36717f1de56SFelix Fietkau static void 368c89d3625SFelix Fietkau mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 369c89d3625SFelix Fietkau enum nl80211_band band) 37017f1de56SFelix Fietkau { 371c89d3625SFelix Fietkau struct ieee80211_supported_band *sband = &msband->sband; 37217f1de56SFelix Fietkau bool found = false; 37317f1de56SFelix Fietkau int i; 37417f1de56SFelix Fietkau 37517f1de56SFelix Fietkau if (!sband) 37617f1de56SFelix Fietkau return; 37717f1de56SFelix Fietkau 37817f1de56SFelix Fietkau for (i = 0; i < sband->n_channels; i++) { 37917f1de56SFelix Fietkau if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 38017f1de56SFelix Fietkau continue; 38117f1de56SFelix Fietkau 38217f1de56SFelix Fietkau found = true; 38317f1de56SFelix Fietkau break; 38417f1de56SFelix Fietkau } 38517f1de56SFelix Fietkau 386c89d3625SFelix Fietkau if (found) { 387c89d3625SFelix Fietkau phy->chandef.chan = &sband->channels[0]; 388c89d3625SFelix Fietkau phy->chan_state = &msband->chan[0]; 38917f1de56SFelix Fietkau return; 390c89d3625SFelix Fietkau } 39117f1de56SFelix Fietkau 39217f1de56SFelix Fietkau sband->n_channels = 0; 393c89d3625SFelix Fietkau phy->hw->wiphy->bands[band] = NULL; 39417f1de56SFelix Fietkau } 39517f1de56SFelix Fietkau 396c89d3625SFelix Fietkau static void 39798df2baeSLorenzo Bianconi mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) 398c89d3625SFelix Fietkau { 39998df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev; 400c89d3625SFelix Fietkau struct wiphy *wiphy = hw->wiphy; 401c89d3625SFelix Fietkau 402c89d3625SFelix Fietkau SET_IEEE80211_DEV(hw, dev->dev); 40398df2baeSLorenzo Bianconi SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); 404c89d3625SFelix Fietkau 405c89d3625SFelix Fietkau wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 406dd89a013SLorenzo Bianconi wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 407b807b368SLorenzo Bianconi WIPHY_FLAG_SUPPORTS_TDLS | 408b807b368SLorenzo Bianconi WIPHY_FLAG_AP_UAPSD; 409c89d3625SFelix Fietkau 410c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 411c89d3625SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 412d9c54264SFelix Fietkau wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 413c89d3625SFelix Fietkau 4140a57d636SBo Jiao wiphy->available_antennas_tx = phy->antenna_mask; 4150a57d636SBo Jiao wiphy->available_antennas_rx = phy->antenna_mask; 416c89d3625SFelix Fietkau 417c89d3625SFelix Fietkau hw->txq_data_size = sizeof(struct mt76_txq); 418b807b368SLorenzo Bianconi hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 419c9619dfaSShayne Chen 420c9619dfaSShayne Chen if (!hw->max_tx_fragments) 421c89d3625SFelix Fietkau hw->max_tx_fragments = 16; 422c89d3625SFelix Fietkau 423c89d3625SFelix Fietkau ieee80211_hw_set(hw, SIGNAL_DBM); 424c89d3625SFelix Fietkau ieee80211_hw_set(hw, AMPDU_AGGREGATION); 425c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 426c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 427c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 428c89d3625SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 429ed89b893SFelix Fietkau ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 430c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_AMSDU); 431c89d3625SFelix Fietkau ieee80211_hw_set(hw, TX_FRAG_LIST); 432c89d3625SFelix Fietkau ieee80211_hw_set(hw, MFP_CAPABLE); 433c89d3625SFelix Fietkau ieee80211_hw_set(hw, AP_LINK_PS); 434c89d3625SFelix Fietkau ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 435c89d3625SFelix Fietkau } 436c89d3625SFelix Fietkau 437c89d3625SFelix Fietkau struct mt76_phy * 438c89d3625SFelix Fietkau mt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 439c89d3625SFelix Fietkau const struct ieee80211_ops *ops) 440c89d3625SFelix Fietkau { 441c89d3625SFelix Fietkau struct ieee80211_hw *hw; 442db78a791SLorenzo Bianconi unsigned int phy_size; 443c89d3625SFelix Fietkau struct mt76_phy *phy; 444c89d3625SFelix Fietkau 445c89d3625SFelix Fietkau phy_size = ALIGN(sizeof(*phy), 8); 446db78a791SLorenzo Bianconi hw = ieee80211_alloc_hw(size + phy_size, ops); 447c89d3625SFelix Fietkau if (!hw) 448c89d3625SFelix Fietkau return NULL; 449c89d3625SFelix Fietkau 450c89d3625SFelix Fietkau phy = hw->priv; 451c89d3625SFelix Fietkau phy->dev = dev; 452c89d3625SFelix Fietkau phy->hw = hw; 453db78a791SLorenzo Bianconi phy->priv = hw->priv + phy_size; 454c89d3625SFelix Fietkau 4558af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 4568af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 4578af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 4588af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 4598af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 4608af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 4618af414e8SLorenzo Bianconi #endif 4628af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 4638af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 4648af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 4658af414e8SLorenzo Bianconi 466c89d3625SFelix Fietkau return phy; 467c89d3625SFelix Fietkau } 468c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_phy); 469c89d3625SFelix Fietkau 470db78a791SLorenzo Bianconi int mt76_register_phy(struct mt76_phy *phy, bool vht, 471db78a791SLorenzo Bianconi struct ieee80211_rate *rates, int n_rates) 472c89d3625SFelix Fietkau { 473c89d3625SFelix Fietkau int ret; 474c89d3625SFelix Fietkau 47598df2baeSLorenzo Bianconi mt76_phy_init(phy, phy->hw); 476db78a791SLorenzo Bianconi 477db78a791SLorenzo Bianconi if (phy->cap.has_2ghz) { 478db78a791SLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 479db78a791SLorenzo Bianconi if (ret) 480db78a791SLorenzo Bianconi return ret; 481db78a791SLorenzo Bianconi } 482db78a791SLorenzo Bianconi 483db78a791SLorenzo Bianconi if (phy->cap.has_5ghz) { 484db78a791SLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 485db78a791SLorenzo Bianconi if (ret) 486db78a791SLorenzo Bianconi return ret; 487db78a791SLorenzo Bianconi } 488db78a791SLorenzo Bianconi 489edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 490edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 491edf9dab8SLorenzo Bianconi if (ret) 492edf9dab8SLorenzo Bianconi return ret; 493edf9dab8SLorenzo Bianconi } 494edf9dab8SLorenzo Bianconi 495db78a791SLorenzo Bianconi wiphy_read_of_freq_limits(phy->hw->wiphy); 496db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 497db78a791SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 498edf9dab8SLorenzo Bianconi mt76_check_sband(phy, &phy->sband_6g, NL80211_BAND_6GHZ); 499db78a791SLorenzo Bianconi 500c89d3625SFelix Fietkau ret = ieee80211_register_hw(phy->hw); 501c89d3625SFelix Fietkau if (ret) 502c89d3625SFelix Fietkau return ret; 503c89d3625SFelix Fietkau 504c89d3625SFelix Fietkau phy->dev->phy2 = phy; 505db78a791SLorenzo Bianconi 506c89d3625SFelix Fietkau return 0; 507c89d3625SFelix Fietkau } 508c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_phy); 509c89d3625SFelix Fietkau 510db78a791SLorenzo Bianconi void mt76_unregister_phy(struct mt76_phy *phy) 511c89d3625SFelix Fietkau { 512c89d3625SFelix Fietkau struct mt76_dev *dev = phy->dev; 513c89d3625SFelix Fietkau 514c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 515c89d3625SFelix Fietkau ieee80211_unregister_hw(phy->hw); 51694b6df08SFelix Fietkau dev->phy2 = NULL; 517c89d3625SFelix Fietkau } 518c89d3625SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_phy); 519c89d3625SFelix Fietkau 520a85b590cSFelix Fietkau struct mt76_dev * 521c0f7b25aSLorenzo Bianconi mt76_alloc_device(struct device *pdev, unsigned int size, 522c0f7b25aSLorenzo Bianconi const struct ieee80211_ops *ops, 523c0f7b25aSLorenzo Bianconi const struct mt76_driver_ops *drv_ops) 524a85b590cSFelix Fietkau { 525a85b590cSFelix Fietkau struct ieee80211_hw *hw; 526ac24dd35SFelix Fietkau struct mt76_phy *phy; 527a85b590cSFelix Fietkau struct mt76_dev *dev; 528e5443256SFelix Fietkau int i; 529a85b590cSFelix Fietkau 530a85b590cSFelix Fietkau hw = ieee80211_alloc_hw(size, ops); 531a85b590cSFelix Fietkau if (!hw) 532a85b590cSFelix Fietkau return NULL; 533a85b590cSFelix Fietkau 534a85b590cSFelix Fietkau dev = hw->priv; 535a85b590cSFelix Fietkau dev->hw = hw; 536c0f7b25aSLorenzo Bianconi dev->dev = pdev; 537c0f7b25aSLorenzo Bianconi dev->drv = drv_ops; 538c0f7b25aSLorenzo Bianconi 539ac24dd35SFelix Fietkau phy = &dev->phy; 540ac24dd35SFelix Fietkau phy->dev = dev; 541ac24dd35SFelix Fietkau phy->hw = hw; 542ac24dd35SFelix Fietkau 543a85b590cSFelix Fietkau spin_lock_init(&dev->rx_lock); 544a85b590cSFelix Fietkau spin_lock_init(&dev->lock); 545a85b590cSFelix Fietkau spin_lock_init(&dev->cc_lock); 546c34f1005SLorenzo Bianconi spin_lock_init(&dev->status_lock); 547108a4861SStanislaw Gruszka mutex_init(&dev->mutex); 54826e40d4cSFelix Fietkau init_waitqueue_head(&dev->tx_wait); 549a85b590cSFelix Fietkau 55009872957SLorenzo Bianconi skb_queue_head_init(&dev->mcu.res_q); 55109872957SLorenzo Bianconi init_waitqueue_head(&dev->mcu.wait); 55209872957SLorenzo Bianconi mutex_init(&dev->mcu.mutex); 553781eef5bSFelix Fietkau dev->tx_worker.fn = mt76_tx_worker; 55409872957SLorenzo Bianconi 5558af414e8SLorenzo Bianconi hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 5568af414e8SLorenzo Bianconi hw->wiphy->interface_modes = 5578af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_STATION) | 5588af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_AP) | 5598af414e8SLorenzo Bianconi #ifdef CONFIG_MAC80211_MESH 5608af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_MESH_POINT) | 5618af414e8SLorenzo Bianconi #endif 5628af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_CLIENT) | 5638af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_P2P_GO) | 5648af414e8SLorenzo Bianconi BIT(NL80211_IFTYPE_ADHOC); 5658af414e8SLorenzo Bianconi 56651252cc5SLorenzo Bianconi spin_lock_init(&dev->token_lock); 56751252cc5SLorenzo Bianconi idr_init(&dev->token); 56851252cc5SLorenzo Bianconi 569bd1e3e7bSLorenzo Bianconi INIT_LIST_HEAD(&dev->wcid_list); 570bd1e3e7bSLorenzo Bianconi 571e5443256SFelix Fietkau INIT_LIST_HEAD(&dev->txwi_cache); 572e5443256SFelix Fietkau 573e5443256SFelix Fietkau for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 574e5443256SFelix Fietkau skb_queue_head_init(&dev->rx_skb[i]); 575e5443256SFelix Fietkau 576a86f1d01SLorenzo Bianconi dev->wq = alloc_ordered_workqueue("mt76", 0); 577a86f1d01SLorenzo Bianconi if (!dev->wq) { 578a86f1d01SLorenzo Bianconi ieee80211_free_hw(hw); 579a86f1d01SLorenzo Bianconi return NULL; 580a86f1d01SLorenzo Bianconi } 581a86f1d01SLorenzo Bianconi 582a85b590cSFelix Fietkau return dev; 583a85b590cSFelix Fietkau } 584a85b590cSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_alloc_device); 585a85b590cSFelix Fietkau 58617f1de56SFelix Fietkau int mt76_register_device(struct mt76_dev *dev, bool vht, 58717f1de56SFelix Fietkau struct ieee80211_rate *rates, int n_rates) 58817f1de56SFelix Fietkau { 58917f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 590c89d3625SFelix Fietkau struct mt76_phy *phy = &dev->phy; 59117f1de56SFelix Fietkau int ret; 59217f1de56SFelix Fietkau 59317f1de56SFelix Fietkau dev_set_drvdata(dev->dev, dev); 59498df2baeSLorenzo Bianconi mt76_phy_init(phy, hw); 59517f1de56SFelix Fietkau 59648dbce5cSLorenzo Bianconi if (phy->cap.has_2ghz) { 59777af762eSLorenzo Bianconi ret = mt76_init_sband_2g(phy, rates, n_rates); 59817f1de56SFelix Fietkau if (ret) 59917f1de56SFelix Fietkau return ret; 60017f1de56SFelix Fietkau } 60117f1de56SFelix Fietkau 60248dbce5cSLorenzo Bianconi if (phy->cap.has_5ghz) { 60377af762eSLorenzo Bianconi ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht); 60417f1de56SFelix Fietkau if (ret) 60517f1de56SFelix Fietkau return ret; 60617f1de56SFelix Fietkau } 60717f1de56SFelix Fietkau 608edf9dab8SLorenzo Bianconi if (phy->cap.has_6ghz) { 609edf9dab8SLorenzo Bianconi ret = mt76_init_sband_6g(phy, rates + 4, n_rates - 4); 610edf9dab8SLorenzo Bianconi if (ret) 611edf9dab8SLorenzo Bianconi return ret; 612edf9dab8SLorenzo Bianconi } 613edf9dab8SLorenzo Bianconi 614c89d3625SFelix Fietkau wiphy_read_of_freq_limits(hw->wiphy); 615c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 616c89d3625SFelix Fietkau mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 617edf9dab8SLorenzo Bianconi mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); 61817f1de56SFelix Fietkau 619b374e868SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) { 62017f1de56SFelix Fietkau ret = mt76_led_init(dev); 62117f1de56SFelix Fietkau if (ret) 62217f1de56SFelix Fietkau return ret; 623b374e868SArnd Bergmann } 62417f1de56SFelix Fietkau 625781eef5bSFelix Fietkau ret = ieee80211_register_hw(hw); 626781eef5bSFelix Fietkau if (ret) 627781eef5bSFelix Fietkau return ret; 628781eef5bSFelix Fietkau 629781eef5bSFelix Fietkau WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 630781eef5bSFelix Fietkau sched_set_fifo_low(dev->tx_worker.task); 631781eef5bSFelix Fietkau 632781eef5bSFelix Fietkau return 0; 63317f1de56SFelix Fietkau } 63417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_register_device); 63517f1de56SFelix Fietkau 63617f1de56SFelix Fietkau void mt76_unregister_device(struct mt76_dev *dev) 63717f1de56SFelix Fietkau { 63817f1de56SFelix Fietkau struct ieee80211_hw *hw = dev->hw; 63917f1de56SFelix Fietkau 640d68f4e43SArnd Bergmann if (IS_ENABLED(CONFIG_MT76_LEDS)) 64136f7e2b2SFelix Fietkau mt76_led_cleanup(dev); 642c02f86eeSLorenzo Bianconi mt76_tx_status_check(dev, true); 64317f1de56SFelix Fietkau ieee80211_unregister_hw(hw); 64417f1de56SFelix Fietkau } 64517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_unregister_device); 64617f1de56SFelix Fietkau 647def34a2fSLorenzo Bianconi void mt76_free_device(struct mt76_dev *dev) 648def34a2fSLorenzo Bianconi { 649781eef5bSFelix Fietkau mt76_worker_teardown(&dev->tx_worker); 650a86f1d01SLorenzo Bianconi if (dev->wq) { 651a86f1d01SLorenzo Bianconi destroy_workqueue(dev->wq); 652a86f1d01SLorenzo Bianconi dev->wq = NULL; 653a86f1d01SLorenzo Bianconi } 654def34a2fSLorenzo Bianconi ieee80211_free_hw(dev->hw); 655def34a2fSLorenzo Bianconi } 656def34a2fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_free_device); 657def34a2fSLorenzo Bianconi 658cc4b3c13SLorenzo Bianconi static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) 659cc4b3c13SLorenzo Bianconi { 660cc4b3c13SLorenzo Bianconi struct sk_buff *skb = phy->rx_amsdu[q].head; 6612c2bdd23SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 662cc4b3c13SLorenzo Bianconi struct mt76_dev *dev = phy->dev; 663cc4b3c13SLorenzo Bianconi 664cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = NULL; 665cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = NULL; 6662c2bdd23SFelix Fietkau 6672c2bdd23SFelix Fietkau /* 6682c2bdd23SFelix Fietkau * Validate if the amsdu has a proper first subframe. 6692c2bdd23SFelix Fietkau * A single MSDU can be parsed as A-MSDU when the unauthenticated A-MSDU 6702c2bdd23SFelix Fietkau * flag of the QoS header gets flipped. In such cases, the first 6712c2bdd23SFelix Fietkau * subframe has a LLC/SNAP header in the location of the destination 6722c2bdd23SFelix Fietkau * address. 6732c2bdd23SFelix Fietkau */ 6742c2bdd23SFelix Fietkau if (skb_shinfo(skb)->frag_list) { 6752c2bdd23SFelix Fietkau int offset = 0; 6762c2bdd23SFelix Fietkau 6772c2bdd23SFelix Fietkau if (!(status->flag & RX_FLAG_8023)) { 6782c2bdd23SFelix Fietkau offset = ieee80211_get_hdrlen_from_skb(skb); 6792c2bdd23SFelix Fietkau 6802c2bdd23SFelix Fietkau if ((status->flag & 6812c2bdd23SFelix Fietkau (RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED)) == 6822c2bdd23SFelix Fietkau RX_FLAG_DECRYPTED) 6832c2bdd23SFelix Fietkau offset += 8; 6842c2bdd23SFelix Fietkau } 6852c2bdd23SFelix Fietkau 6862c2bdd23SFelix Fietkau if (ether_addr_equal(skb->data + offset, rfc1042_header)) { 6872c2bdd23SFelix Fietkau dev_kfree_skb(skb); 6882c2bdd23SFelix Fietkau return; 6892c2bdd23SFelix Fietkau } 6902c2bdd23SFelix Fietkau } 691cc4b3c13SLorenzo Bianconi __skb_queue_tail(&dev->rx_skb[q], skb); 692cc4b3c13SLorenzo Bianconi } 693cc4b3c13SLorenzo Bianconi 694cc4b3c13SLorenzo Bianconi static void mt76_rx_release_burst(struct mt76_phy *phy, enum mt76_rxq_id q, 695cc4b3c13SLorenzo Bianconi struct sk_buff *skb) 696cc4b3c13SLorenzo Bianconi { 697cc4b3c13SLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 698cc4b3c13SLorenzo Bianconi 699cc4b3c13SLorenzo Bianconi if (phy->rx_amsdu[q].head && 700cc4b3c13SLorenzo Bianconi (!status->amsdu || status->first_amsdu || 701cc4b3c13SLorenzo Bianconi status->seqno != phy->rx_amsdu[q].seqno)) 702cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 703cc4b3c13SLorenzo Bianconi 704cc4b3c13SLorenzo Bianconi if (!phy->rx_amsdu[q].head) { 705cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb_shinfo(skb)->frag_list; 706cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].seqno = status->seqno; 707cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].head = skb; 708cc4b3c13SLorenzo Bianconi } else { 709cc4b3c13SLorenzo Bianconi *phy->rx_amsdu[q].tail = skb; 710cc4b3c13SLorenzo Bianconi phy->rx_amsdu[q].tail = &skb->next; 711cc4b3c13SLorenzo Bianconi } 712cc4b3c13SLorenzo Bianconi 713cc4b3c13SLorenzo Bianconi if (!status->amsdu || status->last_amsdu) 714cc4b3c13SLorenzo Bianconi mt76_rx_release_amsdu(phy, q); 715cc4b3c13SLorenzo Bianconi } 716cc4b3c13SLorenzo Bianconi 71717f1de56SFelix Fietkau void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 71817f1de56SFelix Fietkau { 719011849e0SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 720011849e0SFelix Fietkau struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy); 721011849e0SFelix Fietkau 722011849e0SFelix Fietkau if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 72317f1de56SFelix Fietkau dev_kfree_skb(skb); 72417f1de56SFelix Fietkau return; 72517f1de56SFelix Fietkau } 72617f1de56SFelix Fietkau 727f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE 728c918c74dSShayne Chen if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { 729c918c74dSShayne Chen phy->test.rx_stats.packets[q]++; 730f0efa862SFelix Fietkau if (status->flag & RX_FLAG_FAILED_FCS_CRC) 731c918c74dSShayne Chen phy->test.rx_stats.fcs_error[q]++; 732f0efa862SFelix Fietkau } 733f0efa862SFelix Fietkau #endif 734cc4b3c13SLorenzo Bianconi 735cc4b3c13SLorenzo Bianconi mt76_rx_release_burst(phy, q, skb); 73617f1de56SFelix Fietkau } 73717f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_rx); 73817f1de56SFelix Fietkau 7395a95ca41SFelix Fietkau bool mt76_has_tx_pending(struct mt76_phy *phy) 74026e40d4cSFelix Fietkau { 741af005f26SLorenzo Bianconi struct mt76_queue *q; 74291990519SLorenzo Bianconi int i; 7435a95ca41SFelix Fietkau 7445a95ca41SFelix Fietkau for (i = 0; i < __MT_TXQ_MAX; i++) { 74591990519SLorenzo Bianconi q = phy->q_tx[i]; 746af005f26SLorenzo Bianconi if (q && q->queued) 74726e40d4cSFelix Fietkau return true; 74826e40d4cSFelix Fietkau } 74926e40d4cSFelix Fietkau 75026e40d4cSFelix Fietkau return false; 75126e40d4cSFelix Fietkau } 75239d501d9SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_has_tx_pending); 75326e40d4cSFelix Fietkau 7540fd0eb54SFelix Fietkau static struct mt76_channel_state * 75596747a51SFelix Fietkau mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 7560fd0eb54SFelix Fietkau { 7570fd0eb54SFelix Fietkau struct mt76_sband *msband; 7580fd0eb54SFelix Fietkau int idx; 7590fd0eb54SFelix Fietkau 7600fd0eb54SFelix Fietkau if (c->band == NL80211_BAND_2GHZ) 76196747a51SFelix Fietkau msband = &phy->sband_2g; 762edf9dab8SLorenzo Bianconi else if (c->band == NL80211_BAND_6GHZ) 763edf9dab8SLorenzo Bianconi msband = &phy->sband_6g; 7640fd0eb54SFelix Fietkau else 76596747a51SFelix Fietkau msband = &phy->sband_5g; 7660fd0eb54SFelix Fietkau 7670fd0eb54SFelix Fietkau idx = c - &msband->sband.channels[0]; 7680fd0eb54SFelix Fietkau return &msband->chan[idx]; 7690fd0eb54SFelix Fietkau } 7700fd0eb54SFelix Fietkau 77104414240SLorenzo Bianconi void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 77296747a51SFelix Fietkau { 77396747a51SFelix Fietkau struct mt76_channel_state *state = phy->chan_state; 77496747a51SFelix Fietkau 77596747a51SFelix Fietkau state->cc_active += ktime_to_us(ktime_sub(time, 77696747a51SFelix Fietkau phy->survey_time)); 77796747a51SFelix Fietkau phy->survey_time = time; 77896747a51SFelix Fietkau } 77904414240SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 78096747a51SFelix Fietkau 781c560b137SRyder Lee void mt76_update_survey(struct mt76_phy *phy) 7825ce09c1aSFelix Fietkau { 783c560b137SRyder Lee struct mt76_dev *dev = phy->dev; 784aec65e48SFelix Fietkau ktime_t cur_time; 785aec65e48SFelix Fietkau 7865ce09c1aSFelix Fietkau if (dev->drv->update_survey) 787c560b137SRyder Lee dev->drv->update_survey(phy); 7885ce09c1aSFelix Fietkau 789aec65e48SFelix Fietkau cur_time = ktime_get_boottime(); 790c560b137SRyder Lee mt76_update_survey_active_time(phy, cur_time); 791aec65e48SFelix Fietkau 7925ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 793c560b137SRyder Lee struct mt76_channel_state *state = phy->chan_state; 79496747a51SFelix Fietkau 795237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 7965ce09c1aSFelix Fietkau state->cc_bss_rx += dev->cur_cc_bss_rx; 7975ce09c1aSFelix Fietkau dev->cur_cc_bss_rx = 0; 798237312c5SLorenzo Bianconi spin_unlock_bh(&dev->cc_lock); 7995ce09c1aSFelix Fietkau } 8005ce09c1aSFelix Fietkau } 8015ce09c1aSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_update_survey); 8025ce09c1aSFelix Fietkau 80396747a51SFelix Fietkau void mt76_set_channel(struct mt76_phy *phy) 80417f1de56SFelix Fietkau { 80596747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 80696747a51SFelix Fietkau struct ieee80211_hw *hw = phy->hw; 80717f1de56SFelix Fietkau struct cfg80211_chan_def *chandef = &hw->conf.chandef; 80817f1de56SFelix Fietkau bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 80926e40d4cSFelix Fietkau int timeout = HZ / 5; 81017f1de56SFelix Fietkau 8115a95ca41SFelix Fietkau wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 812c560b137SRyder Lee mt76_update_survey(phy); 81317f1de56SFelix Fietkau 81496747a51SFelix Fietkau phy->chandef = *chandef; 81596747a51SFelix Fietkau phy->chan_state = mt76_channel_state(phy, chandef->chan); 81617f1de56SFelix Fietkau 81717f1de56SFelix Fietkau if (!offchannel) 81896747a51SFelix Fietkau phy->main_chan = chandef->chan; 81917f1de56SFelix Fietkau 82096747a51SFelix Fietkau if (chandef->chan != phy->main_chan) 82196747a51SFelix Fietkau memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 82217f1de56SFelix Fietkau } 82317f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_set_channel); 82417f1de56SFelix Fietkau 82517f1de56SFelix Fietkau int mt76_get_survey(struct ieee80211_hw *hw, int idx, 82617f1de56SFelix Fietkau struct survey_info *survey) 82717f1de56SFelix Fietkau { 82896747a51SFelix Fietkau struct mt76_phy *phy = hw->priv; 82996747a51SFelix Fietkau struct mt76_dev *dev = phy->dev; 83017f1de56SFelix Fietkau struct mt76_sband *sband; 83117f1de56SFelix Fietkau struct ieee80211_channel *chan; 83217f1de56SFelix Fietkau struct mt76_channel_state *state; 83317f1de56SFelix Fietkau int ret = 0; 83417f1de56SFelix Fietkau 835237312c5SLorenzo Bianconi mutex_lock(&dev->mutex); 83617f1de56SFelix Fietkau if (idx == 0 && dev->drv->update_survey) 837c560b137SRyder Lee mt76_update_survey(phy); 83817f1de56SFelix Fietkau 839edf9dab8SLorenzo Bianconi if (idx >= phy->sband_2g.sband.n_channels + 840edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels) { 841edf9dab8SLorenzo Bianconi idx -= (phy->sband_2g.sband.n_channels + 842edf9dab8SLorenzo Bianconi phy->sband_5g.sband.n_channels); 843edf9dab8SLorenzo Bianconi sband = &phy->sband_6g; 844edf9dab8SLorenzo Bianconi } else if (idx >= phy->sband_2g.sband.n_channels) { 845edf9dab8SLorenzo Bianconi idx -= phy->sband_2g.sband.n_channels; 84696747a51SFelix Fietkau sband = &phy->sband_5g; 847edf9dab8SLorenzo Bianconi } else { 848edf9dab8SLorenzo Bianconi sband = &phy->sband_2g; 84917f1de56SFelix Fietkau } 85017f1de56SFelix Fietkau 851237312c5SLorenzo Bianconi if (idx >= sband->sband.n_channels) { 852237312c5SLorenzo Bianconi ret = -ENOENT; 853237312c5SLorenzo Bianconi goto out; 854237312c5SLorenzo Bianconi } 85517f1de56SFelix Fietkau 85617f1de56SFelix Fietkau chan = &sband->sband.channels[idx]; 85796747a51SFelix Fietkau state = mt76_channel_state(phy, chan); 85817f1de56SFelix Fietkau 85917f1de56SFelix Fietkau memset(survey, 0, sizeof(*survey)); 86017f1de56SFelix Fietkau survey->channel = chan; 86117f1de56SFelix Fietkau survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 862ea565833SFelix Fietkau survey->filled |= dev->drv->survey_flags; 863e5051965SFelix Fietkau if (state->noise) 864e5051965SFelix Fietkau survey->filled |= SURVEY_INFO_NOISE_DBM; 865e5051965SFelix Fietkau 86696747a51SFelix Fietkau if (chan == phy->main_chan) { 86717f1de56SFelix Fietkau survey->filled |= SURVEY_INFO_IN_USE; 86817f1de56SFelix Fietkau 8695ce09c1aSFelix Fietkau if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 8705ce09c1aSFelix Fietkau survey->filled |= SURVEY_INFO_TIME_BSS_RX; 8715ce09c1aSFelix Fietkau } 8725ce09c1aSFelix Fietkau 87317f1de56SFelix Fietkau survey->time_busy = div_u64(state->cc_busy, 1000); 8746bfa6e38SLorenzo Bianconi survey->time_rx = div_u64(state->cc_rx, 1000); 875237312c5SLorenzo Bianconi survey->time = div_u64(state->cc_active, 1000); 876e5051965SFelix Fietkau survey->noise = state->noise; 877237312c5SLorenzo Bianconi 878237312c5SLorenzo Bianconi spin_lock_bh(&dev->cc_lock); 879237312c5SLorenzo Bianconi survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 880ea565833SFelix Fietkau survey->time_tx = div_u64(state->cc_tx, 1000); 88117f1de56SFelix Fietkau spin_unlock_bh(&dev->cc_lock); 88217f1de56SFelix Fietkau 883237312c5SLorenzo Bianconi out: 884237312c5SLorenzo Bianconi mutex_unlock(&dev->mutex); 885237312c5SLorenzo Bianconi 88617f1de56SFelix Fietkau return ret; 88717f1de56SFelix Fietkau } 88817f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_survey); 88917f1de56SFelix Fietkau 89030ce7f44SFelix Fietkau void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 89130ce7f44SFelix Fietkau struct ieee80211_key_conf *key) 89230ce7f44SFelix Fietkau { 89330ce7f44SFelix Fietkau struct ieee80211_key_seq seq; 89430ce7f44SFelix Fietkau int i; 89530ce7f44SFelix Fietkau 89630ce7f44SFelix Fietkau wcid->rx_check_pn = false; 89730ce7f44SFelix Fietkau 89830ce7f44SFelix Fietkau if (!key) 89930ce7f44SFelix Fietkau return; 90030ce7f44SFelix Fietkau 90101cfc1b4SLorenzo Bianconi if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 90201cfc1b4SLorenzo Bianconi return; 90330ce7f44SFelix Fietkau 90401cfc1b4SLorenzo Bianconi wcid->rx_check_pn = true; 905a1b0bbd4SXing Song 906a1b0bbd4SXing Song /* data frame */ 90730ce7f44SFelix Fietkau for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 90830ce7f44SFelix Fietkau ieee80211_get_key_rx_seq(key, i, &seq); 90930ce7f44SFelix Fietkau memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 91030ce7f44SFelix Fietkau } 911a1b0bbd4SXing Song 912a1b0bbd4SXing Song /* robust management frame */ 913a1b0bbd4SXing Song ieee80211_get_key_rx_seq(key, -1, &seq); 914a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 915a1b0bbd4SXing Song 91630ce7f44SFelix Fietkau } 91730ce7f44SFelix Fietkau EXPORT_SYMBOL(mt76_wcid_key_setup); 91830ce7f44SFelix Fietkau 919bfc394ddSFelix Fietkau static void 920bfc394ddSFelix Fietkau mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 921bfc394ddSFelix Fietkau struct ieee80211_hw **hw, 922bfc394ddSFelix Fietkau struct ieee80211_sta **sta) 9234e34249eSFelix Fietkau { 9244e34249eSFelix Fietkau struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 925abe3f3daSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 9264e34249eSFelix Fietkau struct mt76_rx_status mstat; 9274e34249eSFelix Fietkau 9284e34249eSFelix Fietkau mstat = *((struct mt76_rx_status *)skb->cb); 9294e34249eSFelix Fietkau memset(status, 0, sizeof(*status)); 9304e34249eSFelix Fietkau 9314e34249eSFelix Fietkau status->flag = mstat.flag; 9324e34249eSFelix Fietkau status->freq = mstat.freq; 9334e34249eSFelix Fietkau status->enc_flags = mstat.enc_flags; 9344e34249eSFelix Fietkau status->encoding = mstat.encoding; 9354e34249eSFelix Fietkau status->bw = mstat.bw; 936af4a2f2fSRyder Lee status->he_ru = mstat.he_ru; 937af4a2f2fSRyder Lee status->he_gi = mstat.he_gi; 938af4a2f2fSRyder Lee status->he_dcm = mstat.he_dcm; 9394e34249eSFelix Fietkau status->rate_idx = mstat.rate_idx; 9404e34249eSFelix Fietkau status->nss = mstat.nss; 9414e34249eSFelix Fietkau status->band = mstat.band; 9424e34249eSFelix Fietkau status->signal = mstat.signal; 9434e34249eSFelix Fietkau status->chains = mstat.chains; 944d515fdcaSFelix Fietkau status->ampdu_reference = mstat.ampdu_ref; 9450fda6d7bSRyder Lee status->device_timestamp = mstat.timestamp; 9460fda6d7bSRyder Lee status->mactime = mstat.timestamp; 9474e34249eSFelix Fietkau 948abe3f3daSRyder Lee if (ieee80211_is_beacon(hdr->frame_control) || 949abe3f3daSRyder Lee ieee80211_is_probe_resp(hdr->frame_control)) 950abe3f3daSRyder Lee status->boottime_ns = ktime_get_boottime_ns(); 951abe3f3daSRyder Lee 9524e34249eSFelix Fietkau BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 95313381dcdSRyder Lee BUILD_BUG_ON(sizeof(status->chain_signal) != 95413381dcdSRyder Lee sizeof(mstat.chain_signal)); 95513381dcdSRyder Lee memcpy(status->chain_signal, mstat.chain_signal, 95613381dcdSRyder Lee sizeof(mstat.chain_signal)); 9579c68a57bSFelix Fietkau 958bfc394ddSFelix Fietkau *sta = wcid_to_sta(mstat.wcid); 959bfc394ddSFelix Fietkau *hw = mt76_phy_hw(dev, mstat.ext_phy); 9604e34249eSFelix Fietkau } 9614e34249eSFelix Fietkau 96230ce7f44SFelix Fietkau static int 96330ce7f44SFelix Fietkau mt76_check_ccmp_pn(struct sk_buff *skb) 96430ce7f44SFelix Fietkau { 96530ce7f44SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 96630ce7f44SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 96730ce7f44SFelix Fietkau struct ieee80211_hdr *hdr; 968a1b0bbd4SXing Song int security_idx; 96930ce7f44SFelix Fietkau int ret; 97030ce7f44SFelix Fietkau 97130ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_DECRYPTED)) 97230ce7f44SFelix Fietkau return 0; 97330ce7f44SFelix Fietkau 97430ce7f44SFelix Fietkau if (!wcid || !wcid->rx_check_pn) 97530ce7f44SFelix Fietkau return 0; 97630ce7f44SFelix Fietkau 9777360cdecSFelix Fietkau security_idx = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 9787360cdecSFelix Fietkau if (status->flag & RX_FLAG_8023) 9797360cdecSFelix Fietkau goto skip_hdr_check; 9807360cdecSFelix Fietkau 981a1b0bbd4SXing Song hdr = mt76_skb_get_hdr(skb); 98230ce7f44SFelix Fietkau if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 98330ce7f44SFelix Fietkau /* 98430ce7f44SFelix Fietkau * Validate the first fragment both here and in mac80211 98530ce7f44SFelix Fietkau * All further fragments will be validated by mac80211 only. 98630ce7f44SFelix Fietkau */ 98730ce7f44SFelix Fietkau if (ieee80211_is_frag(hdr) && 98830ce7f44SFelix Fietkau !ieee80211_is_first_frag(hdr->frame_control)) 98930ce7f44SFelix Fietkau return 0; 99030ce7f44SFelix Fietkau } 99130ce7f44SFelix Fietkau 992a1b0bbd4SXing Song /* IEEE 802.11-2020, 12.5.3.4.4 "PN and replay detection" c): 993a1b0bbd4SXing Song * 994a1b0bbd4SXing Song * the recipient shall maintain a single replay counter for received 995a1b0bbd4SXing Song * individually addressed robust Management frames that are received 996a1b0bbd4SXing Song * with the To DS subfield equal to 0, [...] 997a1b0bbd4SXing Song */ 998a1b0bbd4SXing Song if (ieee80211_is_mgmt(hdr->frame_control) && 999a1b0bbd4SXing Song !ieee80211_has_tods(hdr->frame_control)) 1000a1b0bbd4SXing Song security_idx = IEEE80211_NUM_TIDS; 1001a1b0bbd4SXing Song 10027360cdecSFelix Fietkau skip_hdr_check: 100330ce7f44SFelix Fietkau BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 1004a1b0bbd4SXing Song ret = memcmp(status->iv, wcid->rx_key_pn[security_idx], 100530ce7f44SFelix Fietkau sizeof(status->iv)); 100630ce7f44SFelix Fietkau if (ret <= 0) 100730ce7f44SFelix Fietkau return -EINVAL; /* replay */ 100830ce7f44SFelix Fietkau 1009a1b0bbd4SXing Song memcpy(wcid->rx_key_pn[security_idx], status->iv, sizeof(status->iv)); 101030ce7f44SFelix Fietkau 101130ce7f44SFelix Fietkau if (status->flag & RX_FLAG_IV_STRIPPED) 101230ce7f44SFelix Fietkau status->flag |= RX_FLAG_PN_VALIDATED; 101330ce7f44SFelix Fietkau 101430ce7f44SFelix Fietkau return 0; 101530ce7f44SFelix Fietkau } 101630ce7f44SFelix Fietkau 1017d71ef286SFelix Fietkau static void 10185ce09c1aSFelix Fietkau mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 10195ce09c1aSFelix Fietkau int len) 10205ce09c1aSFelix Fietkau { 10215ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 102285b7a5d0SLorenzo Bianconi struct ieee80211_rx_status info = { 102385b7a5d0SLorenzo Bianconi .enc_flags = status->enc_flags, 102485b7a5d0SLorenzo Bianconi .rate_idx = status->rate_idx, 102585b7a5d0SLorenzo Bianconi .encoding = status->encoding, 102685b7a5d0SLorenzo Bianconi .band = status->band, 102785b7a5d0SLorenzo Bianconi .nss = status->nss, 102885b7a5d0SLorenzo Bianconi .bw = status->bw, 102985b7a5d0SLorenzo Bianconi }; 10305ce09c1aSFelix Fietkau struct ieee80211_sta *sta; 10315ce09c1aSFelix Fietkau u32 airtime; 1032e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 10335ce09c1aSFelix Fietkau 103485b7a5d0SLorenzo Bianconi airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 1035237312c5SLorenzo Bianconi spin_lock(&dev->cc_lock); 10365ce09c1aSFelix Fietkau dev->cur_cc_bss_rx += airtime; 1037237312c5SLorenzo Bianconi spin_unlock(&dev->cc_lock); 10385ce09c1aSFelix Fietkau 10395ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) 10405ce09c1aSFelix Fietkau return; 10415ce09c1aSFelix Fietkau 10425ce09c1aSFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1043e195dad1SFelix Fietkau ieee80211_sta_register_airtime(sta, tidno, 0, airtime); 10445ce09c1aSFelix Fietkau } 10455ce09c1aSFelix Fietkau 10465ce09c1aSFelix Fietkau static void 10475ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(struct mt76_dev *dev) 10485ce09c1aSFelix Fietkau { 10495ce09c1aSFelix Fietkau struct mt76_wcid *wcid; 10505ce09c1aSFelix Fietkau int wcid_idx; 10515ce09c1aSFelix Fietkau 10525ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len) 10535ce09c1aSFelix Fietkau return; 10545ce09c1aSFelix Fietkau 10555ce09c1aSFelix Fietkau wcid_idx = dev->rx_ampdu_status.wcid_idx; 1056bf5238b2SFelix Fietkau if (wcid_idx < ARRAY_SIZE(dev->wcid)) 10575ce09c1aSFelix Fietkau wcid = rcu_dereference(dev->wcid[wcid_idx]); 10585ce09c1aSFelix Fietkau else 10595ce09c1aSFelix Fietkau wcid = NULL; 10605ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid = wcid; 10615ce09c1aSFelix Fietkau 10625ce09c1aSFelix Fietkau mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 10635ce09c1aSFelix Fietkau 10645ce09c1aSFelix Fietkau dev->rx_ampdu_len = 0; 10655ce09c1aSFelix Fietkau dev->rx_ampdu_ref = 0; 10665ce09c1aSFelix Fietkau } 10675ce09c1aSFelix Fietkau 10685ce09c1aSFelix Fietkau static void 10695ce09c1aSFelix Fietkau mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 10705ce09c1aSFelix Fietkau { 10715ce09c1aSFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 10725ce09c1aSFelix Fietkau struct mt76_wcid *wcid = status->wcid; 10735ce09c1aSFelix Fietkau 10745ce09c1aSFelix Fietkau if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 10755ce09c1aSFelix Fietkau return; 10765ce09c1aSFelix Fietkau 10775ce09c1aSFelix Fietkau if (!wcid || !wcid->sta) { 1078e195dad1SFelix Fietkau struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1079e195dad1SFelix Fietkau 1080e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1081e195dad1SFelix Fietkau return; 1082e195dad1SFelix Fietkau 108398df2baeSLorenzo Bianconi if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr)) 10845ce09c1aSFelix Fietkau return; 10855ce09c1aSFelix Fietkau 10865ce09c1aSFelix Fietkau wcid = NULL; 10875ce09c1aSFelix Fietkau } 10885ce09c1aSFelix Fietkau 10895ce09c1aSFelix Fietkau if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 10905ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) 10915ce09c1aSFelix Fietkau mt76_airtime_flush_ampdu(dev); 10925ce09c1aSFelix Fietkau 10935ce09c1aSFelix Fietkau if (status->flag & RX_FLAG_AMPDU_DETAILS) { 10945ce09c1aSFelix Fietkau if (!dev->rx_ampdu_len || 10955ce09c1aSFelix Fietkau status->ampdu_ref != dev->rx_ampdu_ref) { 10965ce09c1aSFelix Fietkau dev->rx_ampdu_status = *status; 10975ce09c1aSFelix Fietkau dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 10985ce09c1aSFelix Fietkau dev->rx_ampdu_ref = status->ampdu_ref; 10995ce09c1aSFelix Fietkau } 11005ce09c1aSFelix Fietkau 11015ce09c1aSFelix Fietkau dev->rx_ampdu_len += skb->len; 11025ce09c1aSFelix Fietkau return; 11035ce09c1aSFelix Fietkau } 11045ce09c1aSFelix Fietkau 11055ce09c1aSFelix Fietkau mt76_airtime_report(dev, status, skb->len); 11065ce09c1aSFelix Fietkau } 11075ce09c1aSFelix Fietkau 11085ce09c1aSFelix Fietkau static void 1109ef13edc0SFelix Fietkau mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 1110d71ef286SFelix Fietkau { 1111d71ef286SFelix Fietkau struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 111277ae1d5eSRyder Lee struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 1113d71ef286SFelix Fietkau struct ieee80211_sta *sta; 1114bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 1115d71ef286SFelix Fietkau struct mt76_wcid *wcid = status->wcid; 1116e195dad1SFelix Fietkau u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; 1117d71ef286SFelix Fietkau bool ps; 1118d71ef286SFelix Fietkau 1119bfc394ddSFelix Fietkau hw = mt76_phy_hw(dev, status->ext_phy); 1120e195dad1SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control) && !wcid && 1121e195dad1SFelix Fietkau !(status->flag & RX_FLAG_8023)) { 1122bfc394ddSFelix Fietkau sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 112336d91096SFelix Fietkau if (sta) 112436d91096SFelix Fietkau wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 112536d91096SFelix Fietkau } 112636d91096SFelix Fietkau 11275ce09c1aSFelix Fietkau mt76_airtime_check(dev, skb); 11285ce09c1aSFelix Fietkau 1129d71ef286SFelix Fietkau if (!wcid || !wcid->sta) 1130d71ef286SFelix Fietkau return; 1131d71ef286SFelix Fietkau 1132d71ef286SFelix Fietkau sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 1133d71ef286SFelix Fietkau 113402e5a769SFelix Fietkau if (status->signal <= 0) 113502e5a769SFelix Fietkau ewma_signal_add(&wcid->rssi, -status->signal); 113602e5a769SFelix Fietkau 1137ef13edc0SFelix Fietkau wcid->inactive_count = 0; 1138ef13edc0SFelix Fietkau 1139e195dad1SFelix Fietkau if (status->flag & RX_FLAG_8023) 1140e195dad1SFelix Fietkau return; 1141e195dad1SFelix Fietkau 1142d71ef286SFelix Fietkau if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 1143d71ef286SFelix Fietkau return; 1144d71ef286SFelix Fietkau 1145d71ef286SFelix Fietkau if (ieee80211_is_pspoll(hdr->frame_control)) { 1146d71ef286SFelix Fietkau ieee80211_sta_pspoll(sta); 1147d71ef286SFelix Fietkau return; 1148d71ef286SFelix Fietkau } 1149d71ef286SFelix Fietkau 1150d71ef286SFelix Fietkau if (ieee80211_has_morefrags(hdr->frame_control) || 1151d71ef286SFelix Fietkau !(ieee80211_is_mgmt(hdr->frame_control) || 1152d71ef286SFelix Fietkau ieee80211_is_data(hdr->frame_control))) 1153d71ef286SFelix Fietkau return; 1154d71ef286SFelix Fietkau 1155d71ef286SFelix Fietkau ps = ieee80211_has_pm(hdr->frame_control); 1156d71ef286SFelix Fietkau 1157d71ef286SFelix Fietkau if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 1158d71ef286SFelix Fietkau ieee80211_is_qos_nullfunc(hdr->frame_control))) 1159e195dad1SFelix Fietkau ieee80211_sta_uapsd_trigger(sta, tidno); 1160d71ef286SFelix Fietkau 1161d71ef286SFelix Fietkau if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 1162d71ef286SFelix Fietkau return; 1163d71ef286SFelix Fietkau 116411b2a25fSFelix Fietkau if (ps) 1165d71ef286SFelix Fietkau set_bit(MT_WCID_FLAG_PS, &wcid->flags); 116611b2a25fSFelix Fietkau else 1167d71ef286SFelix Fietkau clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 1168d71ef286SFelix Fietkau 1169d71ef286SFelix Fietkau dev->drv->sta_ps(dev, sta, ps); 11709f67c277SFelix Fietkau ieee80211_sta_ps_transition(sta, ps); 1171d71ef286SFelix Fietkau } 1172d71ef286SFelix Fietkau 11739d9d738bSFelix Fietkau void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 117481e850efSLorenzo Bianconi struct napi_struct *napi) 117517f1de56SFelix Fietkau { 11769c68a57bSFelix Fietkau struct ieee80211_sta *sta; 1177bfc394ddSFelix Fietkau struct ieee80211_hw *hw; 11783298b1f8SFelix Fietkau struct sk_buff *skb, *tmp; 11793298b1f8SFelix Fietkau LIST_HEAD(list); 11809d9d738bSFelix Fietkau 1181c3d7c82aSFelix Fietkau spin_lock(&dev->rx_lock); 11829d9d738bSFelix Fietkau while ((skb = __skb_dequeue(frames)) != NULL) { 1183cc4b3c13SLorenzo Bianconi struct sk_buff *nskb = skb_shinfo(skb)->frag_list; 1184cc4b3c13SLorenzo Bianconi 118530ce7f44SFelix Fietkau if (mt76_check_ccmp_pn(skb)) { 118630ce7f44SFelix Fietkau dev_kfree_skb(skb); 118730ce7f44SFelix Fietkau continue; 118830ce7f44SFelix Fietkau } 118930ce7f44SFelix Fietkau 1190cc4b3c13SLorenzo Bianconi skb_shinfo(skb)->frag_list = NULL; 1191bfc394ddSFelix Fietkau mt76_rx_convert(dev, skb, &hw, &sta); 11923298b1f8SFelix Fietkau ieee80211_rx_list(hw, sta, skb, &list); 1193cc4b3c13SLorenzo Bianconi 1194cc4b3c13SLorenzo Bianconi /* subsequent amsdu frames */ 1195cc4b3c13SLorenzo Bianconi while (nskb) { 1196cc4b3c13SLorenzo Bianconi skb = nskb; 1197cc4b3c13SLorenzo Bianconi nskb = nskb->next; 1198cc4b3c13SLorenzo Bianconi skb->next = NULL; 1199cc4b3c13SLorenzo Bianconi 1200cc4b3c13SLorenzo Bianconi mt76_rx_convert(dev, skb, &hw, &sta); 1201cc4b3c13SLorenzo Bianconi ieee80211_rx_list(hw, sta, skb, &list); 1202cc4b3c13SLorenzo Bianconi } 12039d9d738bSFelix Fietkau } 1204c3d7c82aSFelix Fietkau spin_unlock(&dev->rx_lock); 12053298b1f8SFelix Fietkau 12063298b1f8SFelix Fietkau if (!napi) { 12073298b1f8SFelix Fietkau netif_receive_skb_list(&list); 12083298b1f8SFelix Fietkau return; 12093298b1f8SFelix Fietkau } 12103298b1f8SFelix Fietkau 12113298b1f8SFelix Fietkau list_for_each_entry_safe(skb, tmp, &list, list) { 12123298b1f8SFelix Fietkau skb_list_del_init(skb); 12133298b1f8SFelix Fietkau napi_gro_receive(napi, skb); 12143298b1f8SFelix Fietkau } 12159d9d738bSFelix Fietkau } 12169d9d738bSFelix Fietkau 121781e850efSLorenzo Bianconi void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 121881e850efSLorenzo Bianconi struct napi_struct *napi) 12199d9d738bSFelix Fietkau { 1220aee5b8cfSFelix Fietkau struct sk_buff_head frames; 122117f1de56SFelix Fietkau struct sk_buff *skb; 122217f1de56SFelix Fietkau 1223aee5b8cfSFelix Fietkau __skb_queue_head_init(&frames); 1224aee5b8cfSFelix Fietkau 1225d71ef286SFelix Fietkau while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 1226ef13edc0SFelix Fietkau mt76_check_sta(dev, skb); 1227aee5b8cfSFelix Fietkau mt76_rx_aggr_reorder(skb, &frames); 1228d71ef286SFelix Fietkau } 1229aee5b8cfSFelix Fietkau 123081e850efSLorenzo Bianconi mt76_rx_complete(dev, &frames, napi); 12314e34249eSFelix Fietkau } 123281e850efSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 1233723b90dcSFelix Fietkau 1234e28487eaSFelix Fietkau static int 1235e28487eaSFelix Fietkau mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 1236426e8e41SFelix Fietkau struct ieee80211_sta *sta, bool ext_phy) 1237e28487eaSFelix Fietkau { 1238e28487eaSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 1239e28487eaSFelix Fietkau int ret; 1240e28487eaSFelix Fietkau int i; 1241e28487eaSFelix Fietkau 1242e28487eaSFelix Fietkau mutex_lock(&dev->mutex); 1243e28487eaSFelix Fietkau 1244e28487eaSFelix Fietkau ret = dev->drv->sta_add(dev, vif, sta); 1245e28487eaSFelix Fietkau if (ret) 1246e28487eaSFelix Fietkau goto out; 1247e28487eaSFelix Fietkau 1248e28487eaSFelix Fietkau for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 1249e28487eaSFelix Fietkau struct mt76_txq *mtxq; 1250e28487eaSFelix Fietkau 1251e28487eaSFelix Fietkau if (!sta->txq[i]) 1252e28487eaSFelix Fietkau continue; 1253e28487eaSFelix Fietkau 1254e28487eaSFelix Fietkau mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 1255e28487eaSFelix Fietkau mtxq->wcid = wcid; 1256e28487eaSFelix Fietkau } 1257e28487eaSFelix Fietkau 1258ef13edc0SFelix Fietkau ewma_signal_init(&wcid->rssi); 1259426e8e41SFelix Fietkau if (ext_phy) 1260426e8e41SFelix Fietkau mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 1261c7d2d631SFelix Fietkau wcid->ext_phy = ext_phy; 1262e28487eaSFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 1263e28487eaSFelix Fietkau 1264bd1e3e7bSLorenzo Bianconi mt76_packet_id_init(wcid); 1265e28487eaSFelix Fietkau out: 1266e28487eaSFelix Fietkau mutex_unlock(&dev->mutex); 1267e28487eaSFelix Fietkau 1268e28487eaSFelix Fietkau return ret; 1269e28487eaSFelix Fietkau } 1270e28487eaSFelix Fietkau 127113f61dfcSLorenzo Bianconi void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 1272723b90dcSFelix Fietkau struct ieee80211_sta *sta) 1273723b90dcSFelix Fietkau { 1274723b90dcSFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 127513f61dfcSLorenzo Bianconi int i, idx = wcid->idx; 1276723b90dcSFelix Fietkau 127758bab0d4SFelix Fietkau for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 127858bab0d4SFelix Fietkau mt76_rx_aggr_stop(dev, wcid, i); 127958bab0d4SFelix Fietkau 1280e28487eaSFelix Fietkau if (dev->drv->sta_remove) 1281e28487eaSFelix Fietkau dev->drv->sta_remove(dev, vif, sta); 1282e28487eaSFelix Fietkau 1283bd1e3e7bSLorenzo Bianconi mt76_packet_id_flush(dev, wcid); 1284bd1e3e7bSLorenzo Bianconi 1285426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_mask, idx); 1286426e8e41SFelix Fietkau mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 128713f61dfcSLorenzo Bianconi } 128813f61dfcSLorenzo Bianconi EXPORT_SYMBOL_GPL(__mt76_sta_remove); 1289e28487eaSFelix Fietkau 129013f61dfcSLorenzo Bianconi static void 129113f61dfcSLorenzo Bianconi mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 129213f61dfcSLorenzo Bianconi struct ieee80211_sta *sta) 129313f61dfcSLorenzo Bianconi { 129413f61dfcSLorenzo Bianconi mutex_lock(&dev->mutex); 129513f61dfcSLorenzo Bianconi __mt76_sta_remove(dev, vif, sta); 1296723b90dcSFelix Fietkau mutex_unlock(&dev->mutex); 1297723b90dcSFelix Fietkau } 1298e28487eaSFelix Fietkau 1299e28487eaSFelix Fietkau int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1300e28487eaSFelix Fietkau struct ieee80211_sta *sta, 1301e28487eaSFelix Fietkau enum ieee80211_sta_state old_state, 1302e28487eaSFelix Fietkau enum ieee80211_sta_state new_state) 1303e28487eaSFelix Fietkau { 1304426e8e41SFelix Fietkau struct mt76_phy *phy = hw->priv; 1305426e8e41SFelix Fietkau struct mt76_dev *dev = phy->dev; 1306426e8e41SFelix Fietkau bool ext_phy = phy != &dev->phy; 1307e28487eaSFelix Fietkau 1308e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NOTEXIST && 1309e28487eaSFelix Fietkau new_state == IEEE80211_STA_NONE) 1310426e8e41SFelix Fietkau return mt76_sta_add(dev, vif, sta, ext_phy); 1311e28487eaSFelix Fietkau 13129c193de5SFelix Fietkau if (old_state == IEEE80211_STA_AUTH && 13139c193de5SFelix Fietkau new_state == IEEE80211_STA_ASSOC && 13149c193de5SFelix Fietkau dev->drv->sta_assoc) 13159c193de5SFelix Fietkau dev->drv->sta_assoc(dev, vif, sta); 13169c193de5SFelix Fietkau 1317e28487eaSFelix Fietkau if (old_state == IEEE80211_STA_NONE && 1318e28487eaSFelix Fietkau new_state == IEEE80211_STA_NOTEXIST) 1319e28487eaSFelix Fietkau mt76_sta_remove(dev, vif, sta); 1320e28487eaSFelix Fietkau 1321e28487eaSFelix Fietkau return 0; 1322e28487eaSFelix Fietkau } 1323e28487eaSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_state); 13249313faacSFelix Fietkau 132543ba1922SFelix Fietkau void mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 132643ba1922SFelix Fietkau struct ieee80211_sta *sta) 132743ba1922SFelix Fietkau { 132843ba1922SFelix Fietkau struct mt76_phy *phy = hw->priv; 132943ba1922SFelix Fietkau struct mt76_dev *dev = phy->dev; 133043ba1922SFelix Fietkau struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 133143ba1922SFelix Fietkau 133243ba1922SFelix Fietkau mutex_lock(&dev->mutex); 133343ba1922SFelix Fietkau rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 133443ba1922SFelix Fietkau mutex_unlock(&dev->mutex); 133543ba1922SFelix Fietkau } 133643ba1922SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 133743ba1922SFelix Fietkau 13389313faacSFelix Fietkau int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 13399313faacSFelix Fietkau int *dbm) 13409313faacSFelix Fietkau { 1341beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1342beaaeb6bSFelix Fietkau int n_chains = hweight8(phy->antenna_mask); 134307cda406SFelix Fietkau int delta = mt76_tx_power_nss_delta(n_chains); 13449313faacSFelix Fietkau 134507cda406SFelix Fietkau *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 13469313faacSFelix Fietkau 13479313faacSFelix Fietkau return 0; 13489313faacSFelix Fietkau } 13499313faacSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_txpower); 1350e7173858SFelix Fietkau 1351*b3cb885eSLorenzo Bianconi int mt76_init_sar_power(struct ieee80211_hw *hw, 1352*b3cb885eSLorenzo Bianconi const struct cfg80211_sar_specs *sar) 1353*b3cb885eSLorenzo Bianconi { 1354*b3cb885eSLorenzo Bianconi struct mt76_phy *phy = hw->priv; 1355*b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = hw->wiphy->sar_capa; 1356*b3cb885eSLorenzo Bianconi int i; 1357*b3cb885eSLorenzo Bianconi 1358*b3cb885eSLorenzo Bianconi if (sar->type != NL80211_SAR_TYPE_POWER || !sar->num_sub_specs) 1359*b3cb885eSLorenzo Bianconi return -EINVAL; 1360*b3cb885eSLorenzo Bianconi 1361*b3cb885eSLorenzo Bianconi for (i = 0; i < sar->num_sub_specs; i++) { 1362*b3cb885eSLorenzo Bianconi u32 index = sar->sub_specs[i].freq_range_index; 1363*b3cb885eSLorenzo Bianconi /* SAR specifies power limitaton in 0.25dbm */ 1364*b3cb885eSLorenzo Bianconi s32 power = sar->sub_specs[i].power >> 1; 1365*b3cb885eSLorenzo Bianconi 1366*b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1367*b3cb885eSLorenzo Bianconi power = 127; 1368*b3cb885eSLorenzo Bianconi 1369*b3cb885eSLorenzo Bianconi phy->frp[index].range = &capa->freq_ranges[index]; 1370*b3cb885eSLorenzo Bianconi phy->frp[index].power = power; 1371*b3cb885eSLorenzo Bianconi } 1372*b3cb885eSLorenzo Bianconi 1373*b3cb885eSLorenzo Bianconi return 0; 1374*b3cb885eSLorenzo Bianconi } 1375*b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_sar_power); 1376*b3cb885eSLorenzo Bianconi 1377*b3cb885eSLorenzo Bianconi int mt76_get_sar_power(struct mt76_phy *phy, 1378*b3cb885eSLorenzo Bianconi struct ieee80211_channel *chan, 1379*b3cb885eSLorenzo Bianconi int power) 1380*b3cb885eSLorenzo Bianconi { 1381*b3cb885eSLorenzo Bianconi const struct cfg80211_sar_capa *capa = phy->hw->wiphy->sar_capa; 1382*b3cb885eSLorenzo Bianconi int freq, i; 1383*b3cb885eSLorenzo Bianconi 1384*b3cb885eSLorenzo Bianconi if (!capa || !phy->frp) 1385*b3cb885eSLorenzo Bianconi return power; 1386*b3cb885eSLorenzo Bianconi 1387*b3cb885eSLorenzo Bianconi if (power > 127 || power < -127) 1388*b3cb885eSLorenzo Bianconi power = 127; 1389*b3cb885eSLorenzo Bianconi 1390*b3cb885eSLorenzo Bianconi freq = ieee80211_channel_to_frequency(chan->hw_value, chan->band); 1391*b3cb885eSLorenzo Bianconi for (i = 0 ; i < capa->num_freq_ranges; i++) { 1392*b3cb885eSLorenzo Bianconi if (phy->frp[i].range && 1393*b3cb885eSLorenzo Bianconi freq >= phy->frp[i].range->start_freq && 1394*b3cb885eSLorenzo Bianconi freq < phy->frp[i].range->end_freq) { 1395*b3cb885eSLorenzo Bianconi power = min_t(int, phy->frp[i].power, power); 1396*b3cb885eSLorenzo Bianconi break; 1397*b3cb885eSLorenzo Bianconi } 1398*b3cb885eSLorenzo Bianconi } 1399*b3cb885eSLorenzo Bianconi 1400*b3cb885eSLorenzo Bianconi return power; 1401*b3cb885eSLorenzo Bianconi } 1402*b3cb885eSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_sar_power); 1403*b3cb885eSLorenzo Bianconi 1404e7173858SFelix Fietkau static void 1405e7173858SFelix Fietkau __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 1406e7173858SFelix Fietkau { 14078552a434SJohn Crispin if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 1408e7173858SFelix Fietkau ieee80211_csa_finish(vif); 1409e7173858SFelix Fietkau } 1410e7173858SFelix Fietkau 1411e7173858SFelix Fietkau void mt76_csa_finish(struct mt76_dev *dev) 1412e7173858SFelix Fietkau { 1413e7173858SFelix Fietkau if (!dev->csa_complete) 1414e7173858SFelix Fietkau return; 1415e7173858SFelix Fietkau 1416e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1417e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1418e7173858SFelix Fietkau __mt76_csa_finish, dev); 1419e7173858SFelix Fietkau 1420e7173858SFelix Fietkau dev->csa_complete = 0; 1421e7173858SFelix Fietkau } 1422e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_finish); 1423e7173858SFelix Fietkau 1424e7173858SFelix Fietkau static void 1425e7173858SFelix Fietkau __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 1426e7173858SFelix Fietkau { 1427e7173858SFelix Fietkau struct mt76_dev *dev = priv; 1428e7173858SFelix Fietkau 1429e7173858SFelix Fietkau if (!vif->csa_active) 1430e7173858SFelix Fietkau return; 1431e7173858SFelix Fietkau 14328552a434SJohn Crispin dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 1433e7173858SFelix Fietkau } 1434e7173858SFelix Fietkau 1435e7173858SFelix Fietkau void mt76_csa_check(struct mt76_dev *dev) 1436e7173858SFelix Fietkau { 1437e7173858SFelix Fietkau ieee80211_iterate_active_interfaces_atomic(dev->hw, 1438e7173858SFelix Fietkau IEEE80211_IFACE_ITER_RESUME_ALL, 1439e7173858SFelix Fietkau __mt76_csa_check, dev); 1440e7173858SFelix Fietkau } 1441e7173858SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_csa_check); 144287d53103SStanislaw Gruszka 144387d53103SStanislaw Gruszka int 144487d53103SStanislaw Gruszka mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 144587d53103SStanislaw Gruszka { 144687d53103SStanislaw Gruszka return 0; 144787d53103SStanislaw Gruszka } 144887d53103SStanislaw Gruszka EXPORT_SYMBOL_GPL(mt76_set_tim); 1449eadfd98fSLorenzo Bianconi 1450eadfd98fSLorenzo Bianconi void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 1451eadfd98fSLorenzo Bianconi { 1452eadfd98fSLorenzo Bianconi struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 1453eadfd98fSLorenzo Bianconi int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 1454eadfd98fSLorenzo Bianconi u8 *hdr, *pn = status->iv; 1455eadfd98fSLorenzo Bianconi 1456eadfd98fSLorenzo Bianconi __skb_push(skb, 8); 1457eadfd98fSLorenzo Bianconi memmove(skb->data, skb->data + 8, hdr_len); 1458eadfd98fSLorenzo Bianconi hdr = skb->data + hdr_len; 1459eadfd98fSLorenzo Bianconi 1460eadfd98fSLorenzo Bianconi hdr[0] = pn[5]; 1461eadfd98fSLorenzo Bianconi hdr[1] = pn[4]; 1462eadfd98fSLorenzo Bianconi hdr[2] = 0; 1463eadfd98fSLorenzo Bianconi hdr[3] = 0x20 | (key_id << 6); 1464eadfd98fSLorenzo Bianconi hdr[4] = pn[3]; 1465eadfd98fSLorenzo Bianconi hdr[5] = pn[2]; 1466eadfd98fSLorenzo Bianconi hdr[6] = pn[1]; 1467eadfd98fSLorenzo Bianconi hdr[7] = pn[0]; 1468eadfd98fSLorenzo Bianconi 1469eadfd98fSLorenzo Bianconi status->flag &= ~RX_FLAG_IV_STRIPPED; 1470eadfd98fSLorenzo Bianconi } 1471eadfd98fSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 1472d2679d65SLorenzo Bianconi 1473d2679d65SLorenzo Bianconi int mt76_get_rate(struct mt76_dev *dev, 1474d2679d65SLorenzo Bianconi struct ieee80211_supported_band *sband, 1475d2679d65SLorenzo Bianconi int idx, bool cck) 1476d2679d65SLorenzo Bianconi { 1477d2679d65SLorenzo Bianconi int i, offset = 0, len = sband->n_bitrates; 1478d2679d65SLorenzo Bianconi 1479d2679d65SLorenzo Bianconi if (cck) { 1480edf9dab8SLorenzo Bianconi if (sband != &dev->phy.sband_2g.sband) 1481d2679d65SLorenzo Bianconi return 0; 1482d2679d65SLorenzo Bianconi 1483d2679d65SLorenzo Bianconi idx &= ~BIT(2); /* short preamble */ 148496747a51SFelix Fietkau } else if (sband == &dev->phy.sband_2g.sband) { 1485d2679d65SLorenzo Bianconi offset = 4; 1486d2679d65SLorenzo Bianconi } 1487d2679d65SLorenzo Bianconi 1488d2679d65SLorenzo Bianconi for (i = offset; i < len; i++) { 1489d2679d65SLorenzo Bianconi if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 1490d2679d65SLorenzo Bianconi return i; 1491d2679d65SLorenzo Bianconi } 1492d2679d65SLorenzo Bianconi 1493d2679d65SLorenzo Bianconi return 0; 1494d2679d65SLorenzo Bianconi } 1495d2679d65SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_rate); 14968b8ab5c2SLorenzo Bianconi 14978b8ab5c2SLorenzo Bianconi void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 14988b8ab5c2SLorenzo Bianconi const u8 *mac) 14998b8ab5c2SLorenzo Bianconi { 1500011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 15018b8ab5c2SLorenzo Bianconi 1502011849e0SFelix Fietkau set_bit(MT76_SCANNING, &phy->state); 15038b8ab5c2SLorenzo Bianconi } 15048b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan); 15058b8ab5c2SLorenzo Bianconi 15068b8ab5c2SLorenzo Bianconi void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 15078b8ab5c2SLorenzo Bianconi { 1508011849e0SFelix Fietkau struct mt76_phy *phy = hw->priv; 15098b8ab5c2SLorenzo Bianconi 1510011849e0SFelix Fietkau clear_bit(MT76_SCANNING, &phy->state); 15118b8ab5c2SLorenzo Bianconi } 15128b8ab5c2SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 1513e49c76d4SLorenzo Bianconi 1514e49c76d4SLorenzo Bianconi int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 1515e49c76d4SLorenzo Bianconi { 1516beaaeb6bSFelix Fietkau struct mt76_phy *phy = hw->priv; 1517beaaeb6bSFelix Fietkau struct mt76_dev *dev = phy->dev; 1518e49c76d4SLorenzo Bianconi 1519e49c76d4SLorenzo Bianconi mutex_lock(&dev->mutex); 1520beaaeb6bSFelix Fietkau *tx_ant = phy->antenna_mask; 1521beaaeb6bSFelix Fietkau *rx_ant = phy->antenna_mask; 1522e49c76d4SLorenzo Bianconi mutex_unlock(&dev->mutex); 1523e49c76d4SLorenzo Bianconi 1524e49c76d4SLorenzo Bianconi return 0; 1525e49c76d4SLorenzo Bianconi } 1526e49c76d4SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_get_antenna); 1527b671da33SLorenzo Bianconi 1528b1cb42adSLorenzo Bianconi struct mt76_queue * 1529b1cb42adSLorenzo Bianconi mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, 1530b1cb42adSLorenzo Bianconi int ring_base) 1531b671da33SLorenzo Bianconi { 1532b671da33SLorenzo Bianconi struct mt76_queue *hwq; 1533b671da33SLorenzo Bianconi int err; 1534b671da33SLorenzo Bianconi 1535b671da33SLorenzo Bianconi hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL); 1536b671da33SLorenzo Bianconi if (!hwq) 1537b1cb42adSLorenzo Bianconi return ERR_PTR(-ENOMEM); 1538b671da33SLorenzo Bianconi 1539b671da33SLorenzo Bianconi err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); 1540b671da33SLorenzo Bianconi if (err < 0) 1541b1cb42adSLorenzo Bianconi return ERR_PTR(err); 1542b671da33SLorenzo Bianconi 1543b1cb42adSLorenzo Bianconi return hwq; 1544b671da33SLorenzo Bianconi } 1545b1cb42adSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_init_queue); 1546e4867225SSean Wang 154733920b2bSRyder Lee u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx) 1548e4867225SSean Wang { 154933920b2bSRyder Lee int offset = 0; 1550e4867225SSean Wang 1551edf9dab8SLorenzo Bianconi if (phy->chandef.chan->band != NL80211_BAND_2GHZ) 1552e4867225SSean Wang offset = 4; 1553e4867225SSean Wang 155433920b2bSRyder Lee /* pick the lowest rate for hidden nodes */ 155533920b2bSRyder Lee if (rateidx < 0) 155633920b2bSRyder Lee rateidx = 0; 155733920b2bSRyder Lee 1558d4f3d1c4SLorenzo Bianconi rateidx += offset; 1559d4f3d1c4SLorenzo Bianconi if (rateidx >= ARRAY_SIZE(mt76_rates)) 1560d4f3d1c4SLorenzo Bianconi rateidx = offset; 1561e4867225SSean Wang 1562d4f3d1c4SLorenzo Bianconi return mt76_rates[rateidx].hw_value; 1563e4867225SSean Wang } 156433920b2bSRyder Lee EXPORT_SYMBOL_GPL(mt76_calculate_default_rate); 156554ae98ffSLorenzo Bianconi 156654ae98ffSLorenzo Bianconi void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi, 156754ae98ffSLorenzo Bianconi struct mt76_sta_stats *stats) 156854ae98ffSLorenzo Bianconi { 156954ae98ffSLorenzo Bianconi int i, ei = wi->initial_stat_idx; 157054ae98ffSLorenzo Bianconi u64 *data = wi->data; 157154ae98ffSLorenzo Bianconi 157254ae98ffSLorenzo Bianconi wi->sta_count++; 157354ae98ffSLorenzo Bianconi 157454ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_CCK]; 157554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_OFDM]; 157654ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT]; 157754ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HT_GF]; 157854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_VHT]; 157954ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_SU]; 158054ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU]; 158154ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB]; 158254ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU]; 158354ae98ffSLorenzo Bianconi 158454ae98ffSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++) 158554ae98ffSLorenzo Bianconi data[ei++] += stats->tx_bw[i]; 158654ae98ffSLorenzo Bianconi 158754ae98ffSLorenzo Bianconi for (i = 0; i < 12; i++) 158854ae98ffSLorenzo Bianconi data[ei++] += stats->tx_mcs[i]; 158954ae98ffSLorenzo Bianconi 159054ae98ffSLorenzo Bianconi wi->worker_stat_count = ei - wi->initial_stat_idx; 159154ae98ffSLorenzo Bianconi } 159254ae98ffSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76_ethtool_worker); 1593