18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/sched.h> 68c2ecf20Sopenharmony_ci#include <linux/of.h> 78c2ecf20Sopenharmony_ci#include "mt76.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define CHAN2G(_idx, _freq) { \ 108c2ecf20Sopenharmony_ci .band = NL80211_BAND_2GHZ, \ 118c2ecf20Sopenharmony_ci .center_freq = (_freq), \ 128c2ecf20Sopenharmony_ci .hw_value = (_idx), \ 138c2ecf20Sopenharmony_ci .max_power = 30, \ 148c2ecf20Sopenharmony_ci} 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define CHAN5G(_idx, _freq) { \ 178c2ecf20Sopenharmony_ci .band = NL80211_BAND_5GHZ, \ 188c2ecf20Sopenharmony_ci .center_freq = (_freq), \ 198c2ecf20Sopenharmony_ci .hw_value = (_idx), \ 208c2ecf20Sopenharmony_ci .max_power = 30, \ 218c2ecf20Sopenharmony_ci} 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic const struct ieee80211_channel mt76_channels_2ghz[] = { 248c2ecf20Sopenharmony_ci CHAN2G(1, 2412), 258c2ecf20Sopenharmony_ci CHAN2G(2, 2417), 268c2ecf20Sopenharmony_ci CHAN2G(3, 2422), 278c2ecf20Sopenharmony_ci CHAN2G(4, 2427), 288c2ecf20Sopenharmony_ci CHAN2G(5, 2432), 298c2ecf20Sopenharmony_ci CHAN2G(6, 2437), 308c2ecf20Sopenharmony_ci CHAN2G(7, 2442), 318c2ecf20Sopenharmony_ci CHAN2G(8, 2447), 328c2ecf20Sopenharmony_ci CHAN2G(9, 2452), 338c2ecf20Sopenharmony_ci CHAN2G(10, 2457), 348c2ecf20Sopenharmony_ci CHAN2G(11, 2462), 358c2ecf20Sopenharmony_ci CHAN2G(12, 2467), 368c2ecf20Sopenharmony_ci CHAN2G(13, 2472), 378c2ecf20Sopenharmony_ci CHAN2G(14, 2484), 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic const struct ieee80211_channel mt76_channels_5ghz[] = { 418c2ecf20Sopenharmony_ci CHAN5G(36, 5180), 428c2ecf20Sopenharmony_ci CHAN5G(40, 5200), 438c2ecf20Sopenharmony_ci CHAN5G(44, 5220), 448c2ecf20Sopenharmony_ci CHAN5G(48, 5240), 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci CHAN5G(52, 5260), 478c2ecf20Sopenharmony_ci CHAN5G(56, 5280), 488c2ecf20Sopenharmony_ci CHAN5G(60, 5300), 498c2ecf20Sopenharmony_ci CHAN5G(64, 5320), 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci CHAN5G(100, 5500), 528c2ecf20Sopenharmony_ci CHAN5G(104, 5520), 538c2ecf20Sopenharmony_ci CHAN5G(108, 5540), 548c2ecf20Sopenharmony_ci CHAN5G(112, 5560), 558c2ecf20Sopenharmony_ci CHAN5G(116, 5580), 568c2ecf20Sopenharmony_ci CHAN5G(120, 5600), 578c2ecf20Sopenharmony_ci CHAN5G(124, 5620), 588c2ecf20Sopenharmony_ci CHAN5G(128, 5640), 598c2ecf20Sopenharmony_ci CHAN5G(132, 5660), 608c2ecf20Sopenharmony_ci CHAN5G(136, 5680), 618c2ecf20Sopenharmony_ci CHAN5G(140, 5700), 628c2ecf20Sopenharmony_ci CHAN5G(144, 5720), 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci CHAN5G(149, 5745), 658c2ecf20Sopenharmony_ci CHAN5G(153, 5765), 668c2ecf20Sopenharmony_ci CHAN5G(157, 5785), 678c2ecf20Sopenharmony_ci CHAN5G(161, 5805), 688c2ecf20Sopenharmony_ci CHAN5G(165, 5825), 698c2ecf20Sopenharmony_ci CHAN5G(169, 5845), 708c2ecf20Sopenharmony_ci CHAN5G(173, 5865), 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct ieee80211_tpt_blink mt76_tpt_blink[] = { 748c2ecf20Sopenharmony_ci { .throughput = 0 * 1024, .blink_time = 334 }, 758c2ecf20Sopenharmony_ci { .throughput = 1 * 1024, .blink_time = 260 }, 768c2ecf20Sopenharmony_ci { .throughput = 5 * 1024, .blink_time = 220 }, 778c2ecf20Sopenharmony_ci { .throughput = 10 * 1024, .blink_time = 190 }, 788c2ecf20Sopenharmony_ci { .throughput = 20 * 1024, .blink_time = 170 }, 798c2ecf20Sopenharmony_ci { .throughput = 50 * 1024, .blink_time = 150 }, 808c2ecf20Sopenharmony_ci { .throughput = 70 * 1024, .blink_time = 130 }, 818c2ecf20Sopenharmony_ci { .throughput = 100 * 1024, .blink_time = 110 }, 828c2ecf20Sopenharmony_ci { .throughput = 200 * 1024, .blink_time = 80 }, 838c2ecf20Sopenharmony_ci { .throughput = 300 * 1024, .blink_time = 50 }, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int mt76_led_init(struct mt76_dev *dev) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct device_node *np = dev->dev->of_node; 898c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = dev->hw; 908c2ecf20Sopenharmony_ci int led_pin; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci snprintf(dev->led_name, sizeof(dev->led_name), 968c2ecf20Sopenharmony_ci "mt76-%s", wiphy_name(hw->wiphy)); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dev->led_cdev.name = dev->led_name; 998c2ecf20Sopenharmony_ci dev->led_cdev.default_trigger = 1008c2ecf20Sopenharmony_ci ieee80211_create_tpt_led_trigger(hw, 1018c2ecf20Sopenharmony_ci IEEE80211_TPT_LEDTRIG_FL_RADIO, 1028c2ecf20Sopenharmony_ci mt76_tpt_blink, 1038c2ecf20Sopenharmony_ci ARRAY_SIZE(mt76_tpt_blink)); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci np = of_get_child_by_name(np, "led"); 1068c2ecf20Sopenharmony_ci if (np) { 1078c2ecf20Sopenharmony_ci if (!of_property_read_u32(np, "led-sources", &led_pin)) 1088c2ecf20Sopenharmony_ci dev->led_pin = led_pin; 1098c2ecf20Sopenharmony_ci dev->led_al = of_property_read_bool(np, "led-active-low"); 1108c2ecf20Sopenharmony_ci of_node_put(np); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return led_classdev_register(dev->dev, &dev->led_cdev); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void mt76_led_cleanup(struct mt76_dev *dev) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) 1198c2ecf20Sopenharmony_ci return; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci led_classdev_unregister(&dev->led_cdev); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void mt76_init_stream_cap(struct mt76_phy *phy, 1258c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband, 1268c2ecf20Sopenharmony_ci bool vht) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; 1298c2ecf20Sopenharmony_ci int i, nstream = hweight8(phy->antenna_mask); 1308c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *vht_cap; 1318c2ecf20Sopenharmony_ci u16 mcs_map = 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (nstream > 1) 1348c2ecf20Sopenharmony_ci ht_cap->cap |= IEEE80211_HT_CAP_TX_STBC; 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci ht_cap->cap &= ~IEEE80211_HT_CAP_TX_STBC; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) 1398c2ecf20Sopenharmony_ci ht_cap->mcs.rx_mask[i] = i < nstream ? 0xff : 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (!vht) 1428c2ecf20Sopenharmony_ci return; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci vht_cap = &sband->vht_cap; 1458c2ecf20Sopenharmony_ci if (nstream > 1) 1468c2ecf20Sopenharmony_ci vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; 1478c2ecf20Sopenharmony_ci else 1488c2ecf20Sopenharmony_ci vht_cap->cap &= ~IEEE80211_VHT_CAP_TXSTBC; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 1518c2ecf20Sopenharmony_ci if (i < nstream) 1528c2ecf20Sopenharmony_ci mcs_map |= (IEEE80211_VHT_MCS_SUPPORT_0_9 << (i * 2)); 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci mcs_map |= 1558c2ecf20Sopenharmony_ci (IEEE80211_VHT_MCS_NOT_SUPPORTED << (i * 2)); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map); 1588c2ecf20Sopenharmony_ci vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_civoid mt76_set_stream_caps(struct mt76_phy *phy, bool vht) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci if (phy->cap.has_2ghz) 1648c2ecf20Sopenharmony_ci mt76_init_stream_cap(phy, &phy->sband_2g.sband, false); 1658c2ecf20Sopenharmony_ci if (phy->cap.has_5ghz) 1668c2ecf20Sopenharmony_ci mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_set_stream_caps); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int 1718c2ecf20Sopenharmony_cimt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, 1728c2ecf20Sopenharmony_ci const struct ieee80211_channel *chan, int n_chan, 1738c2ecf20Sopenharmony_ci struct ieee80211_rate *rates, int n_rates, bool vht) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = &msband->sband; 1768c2ecf20Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap; 1778c2ecf20Sopenharmony_ci struct ieee80211_sta_vht_cap *vht_cap; 1788c2ecf20Sopenharmony_ci void *chanlist; 1798c2ecf20Sopenharmony_ci int size; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci size = n_chan * sizeof(*chan); 1828c2ecf20Sopenharmony_ci chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 1838c2ecf20Sopenharmony_ci if (!chanlist) 1848c2ecf20Sopenharmony_ci return -ENOMEM; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci msband->chan = devm_kcalloc(dev->dev, n_chan, sizeof(*msband->chan), 1878c2ecf20Sopenharmony_ci GFP_KERNEL); 1888c2ecf20Sopenharmony_ci if (!msband->chan) 1898c2ecf20Sopenharmony_ci return -ENOMEM; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci sband->channels = chanlist; 1928c2ecf20Sopenharmony_ci sband->n_channels = n_chan; 1938c2ecf20Sopenharmony_ci sband->bitrates = rates; 1948c2ecf20Sopenharmony_ci sband->n_bitrates = n_rates; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci ht_cap = &sband->ht_cap; 1978c2ecf20Sopenharmony_ci ht_cap->ht_supported = true; 1988c2ecf20Sopenharmony_ci ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 1998c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_GRN_FLD | 2008c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 2018c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_40 | 2028c2ecf20Sopenharmony_ci (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 2058c2ecf20Sopenharmony_ci ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci mt76_init_stream_cap(&dev->phy, sband, vht); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (!vht) 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci vht_cap = &sband->vht_cap; 2138c2ecf20Sopenharmony_ci vht_cap->vht_supported = true; 2148c2ecf20Sopenharmony_ci vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC | 2158c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_RXSTBC_1 | 2168c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_SHORT_GI_80 | 2178c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN | 2188c2ecf20Sopenharmony_ci IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN | 2198c2ecf20Sopenharmony_ci (3 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int 2258c2ecf20Sopenharmony_cimt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, 2268c2ecf20Sopenharmony_ci int n_rates) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return mt76_init_sband(dev, &dev->phy.sband_2g, 2318c2ecf20Sopenharmony_ci mt76_channels_2ghz, 2328c2ecf20Sopenharmony_ci ARRAY_SIZE(mt76_channels_2ghz), 2338c2ecf20Sopenharmony_ci rates, n_rates, false); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int 2378c2ecf20Sopenharmony_cimt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, 2388c2ecf20Sopenharmony_ci int n_rates, bool vht) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return mt76_init_sband(dev, &dev->phy.sband_5g, 2438c2ecf20Sopenharmony_ci mt76_channels_5ghz, 2448c2ecf20Sopenharmony_ci ARRAY_SIZE(mt76_channels_5ghz), 2458c2ecf20Sopenharmony_ci rates, n_rates, vht); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void 2498c2ecf20Sopenharmony_cimt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband, 2508c2ecf20Sopenharmony_ci enum nl80211_band band) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband = &msband->sband; 2538c2ecf20Sopenharmony_ci bool found = false; 2548c2ecf20Sopenharmony_ci int i; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!sband) 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 2608c2ecf20Sopenharmony_ci if (sband->channels[i].flags & IEEE80211_CHAN_DISABLED) 2618c2ecf20Sopenharmony_ci continue; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci found = true; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (found) { 2688c2ecf20Sopenharmony_ci phy->chandef.chan = &sband->channels[0]; 2698c2ecf20Sopenharmony_ci phy->chan_state = &msband->chan[0]; 2708c2ecf20Sopenharmony_ci return; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci sband->n_channels = 0; 2748c2ecf20Sopenharmony_ci phy->hw->wiphy->bands[band] = NULL; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic void 2788c2ecf20Sopenharmony_cimt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct wiphy *wiphy = hw->wiphy; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(hw, dev->dev); 2838c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 2868c2ecf20Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | 2878c2ecf20Sopenharmony_ci WIPHY_FLAG_SUPPORTS_TDLS | 2888c2ecf20Sopenharmony_ci WIPHY_FLAG_AP_UAPSD; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 2918c2ecf20Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 2928c2ecf20Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci wiphy->available_antennas_tx = dev->phy.antenna_mask; 2958c2ecf20Sopenharmony_ci wiphy->available_antennas_rx = dev->phy.antenna_mask; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci hw->txq_data_size = sizeof(struct mt76_txq); 2988c2ecf20Sopenharmony_ci hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!hw->max_tx_fragments) 3018c2ecf20Sopenharmony_ci hw->max_tx_fragments = 16; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 3048c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 3058c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 3068c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 3078c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 3088c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); 3098c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) { 3128c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, TX_AMSDU); 3138c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, TX_FRAG_LIST); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 3178c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, AP_LINK_PS); 3188c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 3198c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 3228c2ecf20Sopenharmony_ci wiphy->interface_modes = 3238c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_STATION) | 3248c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 3258c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 3268c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 3278c2ecf20Sopenharmony_ci#endif 3288c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 3298c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | 3308c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistruct mt76_phy * 3348c2ecf20Sopenharmony_cimt76_alloc_phy(struct mt76_dev *dev, unsigned int size, 3358c2ecf20Sopenharmony_ci const struct ieee80211_ops *ops) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 3388c2ecf20Sopenharmony_ci struct mt76_phy *phy; 3398c2ecf20Sopenharmony_ci unsigned int phy_size, chan_size; 3408c2ecf20Sopenharmony_ci unsigned int size_2g, size_5g; 3418c2ecf20Sopenharmony_ci void *priv; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci phy_size = ALIGN(sizeof(*phy), 8); 3448c2ecf20Sopenharmony_ci chan_size = sizeof(dev->phy.sband_2g.chan[0]); 3458c2ecf20Sopenharmony_ci size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8); 3468c2ecf20Sopenharmony_ci size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci size += phy_size + size_2g + size_5g; 3498c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(size, ops); 3508c2ecf20Sopenharmony_ci if (!hw) 3518c2ecf20Sopenharmony_ci return NULL; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci phy = hw->priv; 3548c2ecf20Sopenharmony_ci phy->dev = dev; 3558c2ecf20Sopenharmony_ci phy->hw = hw; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci mt76_phy_init(dev, hw); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci priv = hw->priv + phy_size; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci phy->sband_2g = dev->phy.sband_2g; 3628c2ecf20Sopenharmony_ci phy->sband_2g.chan = priv; 3638c2ecf20Sopenharmony_ci priv += size_2g; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci phy->sband_5g = dev->phy.sband_5g; 3668c2ecf20Sopenharmony_ci phy->sband_5g.chan = priv; 3678c2ecf20Sopenharmony_ci priv += size_5g; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci phy->priv = priv; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband; 3728c2ecf20Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ); 3758c2ecf20Sopenharmony_ci mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return phy; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_alloc_phy); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ciint 3828c2ecf20Sopenharmony_cimt76_register_phy(struct mt76_phy *phy) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = ieee80211_register_hw(phy->hw); 3878c2ecf20Sopenharmony_ci if (ret) 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci phy->dev->phy2 = phy; 3918c2ecf20Sopenharmony_ci return 0; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_register_phy); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_civoid 3968c2ecf20Sopenharmony_cimt76_unregister_phy(struct mt76_phy *phy) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci dev->phy2 = NULL; 4018c2ecf20Sopenharmony_ci mt76_tx_status_check(dev, NULL, true); 4028c2ecf20Sopenharmony_ci ieee80211_unregister_hw(phy->hw); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_unregister_phy); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistruct mt76_dev * 4078c2ecf20Sopenharmony_cimt76_alloc_device(struct device *pdev, unsigned int size, 4088c2ecf20Sopenharmony_ci const struct ieee80211_ops *ops, 4098c2ecf20Sopenharmony_ci const struct mt76_driver_ops *drv_ops) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 4128c2ecf20Sopenharmony_ci struct mt76_phy *phy; 4138c2ecf20Sopenharmony_ci struct mt76_dev *dev; 4148c2ecf20Sopenharmony_ci int i; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(size, ops); 4178c2ecf20Sopenharmony_ci if (!hw) 4188c2ecf20Sopenharmony_ci return NULL; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci dev = hw->priv; 4218c2ecf20Sopenharmony_ci dev->hw = hw; 4228c2ecf20Sopenharmony_ci dev->dev = pdev; 4238c2ecf20Sopenharmony_ci dev->drv = drv_ops; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci phy = &dev->phy; 4268c2ecf20Sopenharmony_ci phy->dev = dev; 4278c2ecf20Sopenharmony_ci phy->hw = hw; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci spin_lock_init(&dev->rx_lock); 4308c2ecf20Sopenharmony_ci spin_lock_init(&dev->lock); 4318c2ecf20Sopenharmony_ci spin_lock_init(&dev->cc_lock); 4328c2ecf20Sopenharmony_ci mutex_init(&dev->mutex); 4338c2ecf20Sopenharmony_ci init_waitqueue_head(&dev->tx_wait); 4348c2ecf20Sopenharmony_ci skb_queue_head_init(&dev->status_list); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci skb_queue_head_init(&dev->mcu.res_q); 4378c2ecf20Sopenharmony_ci init_waitqueue_head(&dev->mcu.wait); 4388c2ecf20Sopenharmony_ci mutex_init(&dev->mcu.mutex); 4398c2ecf20Sopenharmony_ci dev->tx_worker.fn = mt76_tx_worker; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dev->txwi_cache); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) 4448c2ecf20Sopenharmony_ci skb_queue_head_init(&dev->rx_skb[i]); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci dev->wq = alloc_ordered_workqueue("mt76", 0); 4478c2ecf20Sopenharmony_ci if (!dev->wq) { 4488c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 4498c2ecf20Sopenharmony_ci return NULL; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return dev; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_alloc_device); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciint mt76_register_device(struct mt76_dev *dev, bool vht, 4578c2ecf20Sopenharmony_ci struct ieee80211_rate *rates, int n_rates) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = dev->hw; 4608c2ecf20Sopenharmony_ci struct mt76_phy *phy = &dev->phy; 4618c2ecf20Sopenharmony_ci int ret; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci dev_set_drvdata(dev->dev, dev); 4648c2ecf20Sopenharmony_ci mt76_phy_init(dev, hw); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (phy->cap.has_2ghz) { 4678c2ecf20Sopenharmony_ci ret = mt76_init_sband_2g(dev, rates, n_rates); 4688c2ecf20Sopenharmony_ci if (ret) 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (phy->cap.has_5ghz) { 4738c2ecf20Sopenharmony_ci ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht); 4748c2ecf20Sopenharmony_ci if (ret) 4758c2ecf20Sopenharmony_ci return ret; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci wiphy_read_of_freq_limits(hw->wiphy); 4798c2ecf20Sopenharmony_ci mt76_check_sband(&dev->phy, &phy->sband_2g, NL80211_BAND_2GHZ); 4808c2ecf20Sopenharmony_ci mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MT76_LEDS)) { 4838c2ecf20Sopenharmony_ci ret = mt76_led_init(dev); 4848c2ecf20Sopenharmony_ci if (ret) 4858c2ecf20Sopenharmony_ci return ret; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = ieee80211_register_hw(hw); 4898c2ecf20Sopenharmony_ci if (ret) 4908c2ecf20Sopenharmony_ci return ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx")); 4938c2ecf20Sopenharmony_ci sched_set_fifo_low(dev->tx_worker.task); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return 0; 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_register_device); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_civoid mt76_unregister_device(struct mt76_dev *dev) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = dev->hw; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_MT76_LEDS)) 5048c2ecf20Sopenharmony_ci mt76_led_cleanup(dev); 5058c2ecf20Sopenharmony_ci mt76_tx_status_check(dev, NULL, true); 5068c2ecf20Sopenharmony_ci ieee80211_unregister_hw(hw); 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_unregister_device); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_civoid mt76_free_device(struct mt76_dev *dev) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci mt76_worker_teardown(&dev->tx_worker); 5138c2ecf20Sopenharmony_ci if (dev->wq) { 5148c2ecf20Sopenharmony_ci destroy_workqueue(dev->wq); 5158c2ecf20Sopenharmony_ci dev->wq = NULL; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci ieee80211_free_hw(dev->hw); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_free_device); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_civoid mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 5248c2ecf20Sopenharmony_ci struct mt76_phy *phy = mt76_dev_phy(dev, status->ext_phy); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &phy->state)) { 5278c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 5288c2ecf20Sopenharmony_ci return; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 5328c2ecf20Sopenharmony_ci if (dev->test.state == MT76_TM_STATE_RX_FRAMES) { 5338c2ecf20Sopenharmony_ci dev->test.rx_stats.packets[q]++; 5348c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_FAILED_FCS_CRC) 5358c2ecf20Sopenharmony_ci dev->test.rx_stats.fcs_error[q]++; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci#endif 5388c2ecf20Sopenharmony_ci __skb_queue_tail(&dev->rx_skb[q], skb); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_rx); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cibool mt76_has_tx_pending(struct mt76_phy *phy) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 5458c2ecf20Sopenharmony_ci struct mt76_queue *q; 5468c2ecf20Sopenharmony_ci int i, offset; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci offset = __MT_TXQ_MAX * (phy != &dev->phy); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci for (i = 0; i < __MT_TXQ_MAX; i++) { 5518c2ecf20Sopenharmony_ci q = dev->q_tx[offset + i]; 5528c2ecf20Sopenharmony_ci if (q && q->queued) 5538c2ecf20Sopenharmony_ci return true; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return false; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_has_tx_pending); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic struct mt76_channel_state * 5618c2ecf20Sopenharmony_cimt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct mt76_sband *msband; 5648c2ecf20Sopenharmony_ci int idx; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (c->band == NL80211_BAND_2GHZ) 5678c2ecf20Sopenharmony_ci msband = &phy->sband_2g; 5688c2ecf20Sopenharmony_ci else 5698c2ecf20Sopenharmony_ci msband = &phy->sband_5g; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci idx = c - &msband->sband.channels[0]; 5728c2ecf20Sopenharmony_ci return &msband->chan[idx]; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_civoid mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct mt76_channel_state *state = phy->chan_state; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci state->cc_active += ktime_to_us(ktime_sub(time, 5808c2ecf20Sopenharmony_ci phy->survey_time)); 5818c2ecf20Sopenharmony_ci phy->survey_time = time; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_update_survey_active_time); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_civoid mt76_update_survey(struct mt76_dev *dev) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci ktime_t cur_time; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (dev->drv->update_survey) 5908c2ecf20Sopenharmony_ci dev->drv->update_survey(dev); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci cur_time = ktime_get_boottime(); 5938c2ecf20Sopenharmony_ci mt76_update_survey_active_time(&dev->phy, cur_time); 5948c2ecf20Sopenharmony_ci if (dev->phy2) 5958c2ecf20Sopenharmony_ci mt76_update_survey_active_time(dev->phy2, cur_time); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { 5988c2ecf20Sopenharmony_ci struct mt76_channel_state *state = dev->phy.chan_state; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci spin_lock_bh(&dev->cc_lock); 6018c2ecf20Sopenharmony_ci state->cc_bss_rx += dev->cur_cc_bss_rx; 6028c2ecf20Sopenharmony_ci dev->cur_cc_bss_rx = 0; 6038c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->cc_lock); 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_update_survey); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_civoid mt76_set_channel(struct mt76_phy *phy) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 6118c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = phy->hw; 6128c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef = &hw->conf.chandef; 6138c2ecf20Sopenharmony_ci bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; 6148c2ecf20Sopenharmony_ci int timeout = HZ / 5; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); 6178c2ecf20Sopenharmony_ci mt76_update_survey(dev); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci phy->chandef = *chandef; 6208c2ecf20Sopenharmony_ci phy->chan_state = mt76_channel_state(phy, chandef->chan); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (!offchannel) 6238c2ecf20Sopenharmony_ci phy->main_chan = chandef->chan; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (chandef->chan != phy->main_chan) 6268c2ecf20Sopenharmony_ci memset(phy->chan_state, 0, sizeof(*phy->chan_state)); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_set_channel); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ciint mt76_get_survey(struct ieee80211_hw *hw, int idx, 6318c2ecf20Sopenharmony_ci struct survey_info *survey) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 6348c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 6358c2ecf20Sopenharmony_ci struct mt76_sband *sband; 6368c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 6378c2ecf20Sopenharmony_ci struct mt76_channel_state *state; 6388c2ecf20Sopenharmony_ci int ret = 0; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci mutex_lock(&dev->mutex); 6418c2ecf20Sopenharmony_ci if (idx == 0 && dev->drv->update_survey) 6428c2ecf20Sopenharmony_ci mt76_update_survey(dev); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci sband = &phy->sband_2g; 6458c2ecf20Sopenharmony_ci if (idx >= sband->sband.n_channels) { 6468c2ecf20Sopenharmony_ci idx -= sband->sband.n_channels; 6478c2ecf20Sopenharmony_ci sband = &phy->sband_5g; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (idx >= sband->sband.n_channels) { 6518c2ecf20Sopenharmony_ci ret = -ENOENT; 6528c2ecf20Sopenharmony_ci goto out; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci chan = &sband->sband.channels[idx]; 6568c2ecf20Sopenharmony_ci state = mt76_channel_state(phy, chan); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci memset(survey, 0, sizeof(*survey)); 6598c2ecf20Sopenharmony_ci survey->channel = chan; 6608c2ecf20Sopenharmony_ci survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; 6618c2ecf20Sopenharmony_ci survey->filled |= dev->drv->survey_flags; 6628c2ecf20Sopenharmony_ci if (state->noise) 6638c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_NOISE_DBM; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (chan == phy->main_chan) { 6668c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_IN_USE; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) 6698c2ecf20Sopenharmony_ci survey->filled |= SURVEY_INFO_TIME_BSS_RX; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci survey->time_busy = div_u64(state->cc_busy, 1000); 6738c2ecf20Sopenharmony_ci survey->time_rx = div_u64(state->cc_rx, 1000); 6748c2ecf20Sopenharmony_ci survey->time = div_u64(state->cc_active, 1000); 6758c2ecf20Sopenharmony_ci survey->noise = state->noise; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci spin_lock_bh(&dev->cc_lock); 6788c2ecf20Sopenharmony_ci survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); 6798c2ecf20Sopenharmony_ci survey->time_tx = div_u64(state->cc_tx, 1000); 6808c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->cc_lock); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciout: 6838c2ecf20Sopenharmony_ci mutex_unlock(&dev->mutex); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return ret; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_get_survey); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_civoid mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, 6908c2ecf20Sopenharmony_ci struct ieee80211_key_conf *key) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct ieee80211_key_seq seq; 6938c2ecf20Sopenharmony_ci int i; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci wcid->rx_check_pn = false; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (!key) 6988c2ecf20Sopenharmony_ci return; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (key->cipher != WLAN_CIPHER_SUITE_CCMP) 7018c2ecf20Sopenharmony_ci return; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci wcid->rx_check_pn = true; 7048c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_TIDS; i++) { 7058c2ecf20Sopenharmony_ci ieee80211_get_key_rx_seq(key, i, &seq); 7068c2ecf20Sopenharmony_ci memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mt76_wcid_key_setup); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic void 7128c2ecf20Sopenharmony_cimt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, 7138c2ecf20Sopenharmony_ci struct ieee80211_hw **hw, 7148c2ecf20Sopenharmony_ci struct ieee80211_sta **sta) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); 7178c2ecf20Sopenharmony_ci struct mt76_rx_status mstat; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci mstat = *((struct mt76_rx_status *)skb->cb); 7208c2ecf20Sopenharmony_ci memset(status, 0, sizeof(*status)); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci status->flag = mstat.flag; 7238c2ecf20Sopenharmony_ci status->freq = mstat.freq; 7248c2ecf20Sopenharmony_ci status->enc_flags = mstat.enc_flags; 7258c2ecf20Sopenharmony_ci status->encoding = mstat.encoding; 7268c2ecf20Sopenharmony_ci status->bw = mstat.bw; 7278c2ecf20Sopenharmony_ci status->he_ru = mstat.he_ru; 7288c2ecf20Sopenharmony_ci status->he_gi = mstat.he_gi; 7298c2ecf20Sopenharmony_ci status->he_dcm = mstat.he_dcm; 7308c2ecf20Sopenharmony_ci status->rate_idx = mstat.rate_idx; 7318c2ecf20Sopenharmony_ci status->nss = mstat.nss; 7328c2ecf20Sopenharmony_ci status->band = mstat.band; 7338c2ecf20Sopenharmony_ci status->signal = mstat.signal; 7348c2ecf20Sopenharmony_ci status->chains = mstat.chains; 7358c2ecf20Sopenharmony_ci status->ampdu_reference = mstat.ampdu_ref; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); 7388c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(status->chain_signal) != 7398c2ecf20Sopenharmony_ci sizeof(mstat.chain_signal)); 7408c2ecf20Sopenharmony_ci memcpy(status->chain_signal, mstat.chain_signal, 7418c2ecf20Sopenharmony_ci sizeof(mstat.chain_signal)); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci *sta = wcid_to_sta(mstat.wcid); 7448c2ecf20Sopenharmony_ci *hw = mt76_phy_hw(dev, mstat.ext_phy); 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int 7488c2ecf20Sopenharmony_cimt76_check_ccmp_pn(struct sk_buff *skb) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 7518c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = status->wcid; 7528c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr; 7538c2ecf20Sopenharmony_ci int ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_DECRYPTED)) 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (!wcid || !wcid->rx_check_pn) 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_IV_STRIPPED)) { 7628c2ecf20Sopenharmony_ci /* 7638c2ecf20Sopenharmony_ci * Validate the first fragment both here and in mac80211 7648c2ecf20Sopenharmony_ci * All further fragments will be validated by mac80211 only. 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci hdr = mt76_skb_get_hdr(skb); 7678c2ecf20Sopenharmony_ci if (ieee80211_is_frag(hdr) && 7688c2ecf20Sopenharmony_ci !ieee80211_is_first_frag(hdr->frame_control)) 7698c2ecf20Sopenharmony_ci return 0; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(status->iv) != sizeof(wcid->rx_key_pn[0])); 7738c2ecf20Sopenharmony_ci ret = memcmp(status->iv, wcid->rx_key_pn[status->tid], 7748c2ecf20Sopenharmony_ci sizeof(status->iv)); 7758c2ecf20Sopenharmony_ci if (ret <= 0) 7768c2ecf20Sopenharmony_ci return -EINVAL; /* replay */ 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci memcpy(wcid->rx_key_pn[status->tid], status->iv, sizeof(status->iv)); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_IV_STRIPPED) 7818c2ecf20Sopenharmony_ci status->flag |= RX_FLAG_PN_VALIDATED; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return 0; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic void 7878c2ecf20Sopenharmony_cimt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, 7888c2ecf20Sopenharmony_ci int len) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = status->wcid; 7918c2ecf20Sopenharmony_ci struct ieee80211_rx_status info = { 7928c2ecf20Sopenharmony_ci .enc_flags = status->enc_flags, 7938c2ecf20Sopenharmony_ci .rate_idx = status->rate_idx, 7948c2ecf20Sopenharmony_ci .encoding = status->encoding, 7958c2ecf20Sopenharmony_ci .band = status->band, 7968c2ecf20Sopenharmony_ci .nss = status->nss, 7978c2ecf20Sopenharmony_ci .bw = status->bw, 7988c2ecf20Sopenharmony_ci }; 7998c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 8008c2ecf20Sopenharmony_ci u32 airtime; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci airtime = ieee80211_calc_rx_airtime(dev->hw, &info, len); 8038c2ecf20Sopenharmony_ci spin_lock(&dev->cc_lock); 8048c2ecf20Sopenharmony_ci dev->cur_cc_bss_rx += airtime; 8058c2ecf20Sopenharmony_ci spin_unlock(&dev->cc_lock); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (!wcid || !wcid->sta) 8088c2ecf20Sopenharmony_ci return; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 8118c2ecf20Sopenharmony_ci ieee80211_sta_register_airtime(sta, status->tid, 0, airtime); 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic void 8158c2ecf20Sopenharmony_cimt76_airtime_flush_ampdu(struct mt76_dev *dev) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct mt76_wcid *wcid; 8188c2ecf20Sopenharmony_ci int wcid_idx; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (!dev->rx_ampdu_len) 8218c2ecf20Sopenharmony_ci return; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci wcid_idx = dev->rx_ampdu_status.wcid_idx; 8248c2ecf20Sopenharmony_ci if (wcid_idx < ARRAY_SIZE(dev->wcid)) 8258c2ecf20Sopenharmony_ci wcid = rcu_dereference(dev->wcid[wcid_idx]); 8268c2ecf20Sopenharmony_ci else 8278c2ecf20Sopenharmony_ci wcid = NULL; 8288c2ecf20Sopenharmony_ci dev->rx_ampdu_status.wcid = wcid; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci dev->rx_ampdu_len = 0; 8338c2ecf20Sopenharmony_ci dev->rx_ampdu_ref = 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic void 8378c2ecf20Sopenharmony_cimt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 8408c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 8418c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = status->wcid; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) 8448c2ecf20Sopenharmony_ci return; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (!wcid || !wcid->sta) { 8478c2ecf20Sopenharmony_ci if (!ether_addr_equal(hdr->addr1, dev->macaddr)) 8488c2ecf20Sopenharmony_ci return; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci wcid = NULL; 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || 8548c2ecf20Sopenharmony_ci status->ampdu_ref != dev->rx_ampdu_ref) 8558c2ecf20Sopenharmony_ci mt76_airtime_flush_ampdu(dev); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (status->flag & RX_FLAG_AMPDU_DETAILS) { 8588c2ecf20Sopenharmony_ci if (!dev->rx_ampdu_len || 8598c2ecf20Sopenharmony_ci status->ampdu_ref != dev->rx_ampdu_ref) { 8608c2ecf20Sopenharmony_ci dev->rx_ampdu_status = *status; 8618c2ecf20Sopenharmony_ci dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; 8628c2ecf20Sopenharmony_ci dev->rx_ampdu_ref = status->ampdu_ref; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci dev->rx_ampdu_len += skb->len; 8668c2ecf20Sopenharmony_ci return; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci mt76_airtime_report(dev, status, skb->len); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic void 8738c2ecf20Sopenharmony_cimt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 8768c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); 8778c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 8788c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 8798c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = status->wcid; 8808c2ecf20Sopenharmony_ci bool ps; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci hw = mt76_phy_hw(dev, status->ext_phy); 8838c2ecf20Sopenharmony_ci if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { 8848c2ecf20Sopenharmony_ci sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); 8858c2ecf20Sopenharmony_ci if (sta) 8868c2ecf20Sopenharmony_ci wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci mt76_airtime_check(dev, skb); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (!wcid || !wcid->sta) 8928c2ecf20Sopenharmony_ci return; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci if (status->signal <= 0) 8978c2ecf20Sopenharmony_ci ewma_signal_add(&wcid->rssi, -status->signal); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci wcid->inactive_count = 0; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (!test_bit(MT_WCID_FLAG_CHECK_PS, &wcid->flags)) 9028c2ecf20Sopenharmony_ci return; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (ieee80211_is_pspoll(hdr->frame_control)) { 9058c2ecf20Sopenharmony_ci ieee80211_sta_pspoll(sta); 9068c2ecf20Sopenharmony_ci return; 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (ieee80211_has_morefrags(hdr->frame_control) || 9108c2ecf20Sopenharmony_ci !(ieee80211_is_mgmt(hdr->frame_control) || 9118c2ecf20Sopenharmony_ci ieee80211_is_data(hdr->frame_control))) 9128c2ecf20Sopenharmony_ci return; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci ps = ieee80211_has_pm(hdr->frame_control); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci if (ps && (ieee80211_is_data_qos(hdr->frame_control) || 9178c2ecf20Sopenharmony_ci ieee80211_is_qos_nullfunc(hdr->frame_control))) 9188c2ecf20Sopenharmony_ci ieee80211_sta_uapsd_trigger(sta, status->tid); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (!!test_bit(MT_WCID_FLAG_PS, &wcid->flags) == ps) 9218c2ecf20Sopenharmony_ci return; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (ps) 9248c2ecf20Sopenharmony_ci set_bit(MT_WCID_FLAG_PS, &wcid->flags); 9258c2ecf20Sopenharmony_ci else 9268c2ecf20Sopenharmony_ci clear_bit(MT_WCID_FLAG_PS, &wcid->flags); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci dev->drv->sta_ps(dev, sta, ps); 9298c2ecf20Sopenharmony_ci ieee80211_sta_ps_transition(sta, ps); 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_civoid mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, 9338c2ecf20Sopenharmony_ci struct napi_struct *napi) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct ieee80211_sta *sta; 9368c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 9378c2ecf20Sopenharmony_ci struct sk_buff *skb; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci spin_lock(&dev->rx_lock); 9408c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(frames)) != NULL) { 9418c2ecf20Sopenharmony_ci if (mt76_check_ccmp_pn(skb)) { 9428c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 9438c2ecf20Sopenharmony_ci continue; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci mt76_rx_convert(dev, skb, &hw, &sta); 9478c2ecf20Sopenharmony_ci ieee80211_rx_napi(hw, sta, skb, napi); 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci spin_unlock(&dev->rx_lock); 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_civoid mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, 9538c2ecf20Sopenharmony_ci struct napi_struct *napi) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci struct sk_buff_head frames; 9568c2ecf20Sopenharmony_ci struct sk_buff *skb; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci __skb_queue_head_init(&frames); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&dev->rx_skb[q])) != NULL) { 9618c2ecf20Sopenharmony_ci mt76_check_sta(dev, skb); 9628c2ecf20Sopenharmony_ci mt76_rx_aggr_reorder(skb, &frames); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci mt76_rx_complete(dev, &frames, napi); 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_rx_poll_complete); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic int 9708c2ecf20Sopenharmony_cimt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif, 9718c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, bool ext_phy) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 9748c2ecf20Sopenharmony_ci int ret; 9758c2ecf20Sopenharmony_ci int i; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci mutex_lock(&dev->mutex); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci ret = dev->drv->sta_add(dev, vif, sta); 9808c2ecf20Sopenharmony_ci if (ret) 9818c2ecf20Sopenharmony_ci goto out; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { 9848c2ecf20Sopenharmony_ci struct mt76_txq *mtxq; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (!sta->txq[i]) 9878c2ecf20Sopenharmony_ci continue; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; 9908c2ecf20Sopenharmony_ci mtxq->wcid = wcid; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci ewma_signal_init(&wcid->rssi); 9948c2ecf20Sopenharmony_ci if (ext_phy) 9958c2ecf20Sopenharmony_ci mt76_wcid_mask_set(dev->wcid_phy_mask, wcid->idx); 9968c2ecf20Sopenharmony_ci wcid->ext_phy = ext_phy; 9978c2ecf20Sopenharmony_ci rcu_assign_pointer(dev->wcid[wcid->idx], wcid); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ciout: 10008c2ecf20Sopenharmony_ci mutex_unlock(&dev->mutex); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return ret; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_civoid __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 10068c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 10098c2ecf20Sopenharmony_ci int i, idx = wcid->idx; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) 10128c2ecf20Sopenharmony_ci mt76_rx_aggr_stop(dev, wcid, i); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (dev->drv->sta_remove) 10158c2ecf20Sopenharmony_ci dev->drv->sta_remove(dev, vif, sta); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci mt76_tx_status_check(dev, wcid, true); 10188c2ecf20Sopenharmony_ci mt76_wcid_mask_clear(dev->wcid_mask, idx); 10198c2ecf20Sopenharmony_ci mt76_wcid_mask_clear(dev->wcid_phy_mask, idx); 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__mt76_sta_remove); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic void 10248c2ecf20Sopenharmony_cimt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, 10258c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci mutex_lock(&dev->mutex); 10288c2ecf20Sopenharmony_ci __mt76_sta_remove(dev, vif, sta); 10298c2ecf20Sopenharmony_ci mutex_unlock(&dev->mutex); 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ciint mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 10338c2ecf20Sopenharmony_ci struct ieee80211_sta *sta, 10348c2ecf20Sopenharmony_ci enum ieee80211_sta_state old_state, 10358c2ecf20Sopenharmony_ci enum ieee80211_sta_state new_state) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 10388c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 10398c2ecf20Sopenharmony_ci bool ext_phy = phy != &dev->phy; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST && 10428c2ecf20Sopenharmony_ci new_state == IEEE80211_STA_NONE) 10438c2ecf20Sopenharmony_ci return mt76_sta_add(dev, vif, sta, ext_phy); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (old_state == IEEE80211_STA_AUTH && 10468c2ecf20Sopenharmony_ci new_state == IEEE80211_STA_ASSOC && 10478c2ecf20Sopenharmony_ci dev->drv->sta_assoc) 10488c2ecf20Sopenharmony_ci dev->drv->sta_assoc(dev, vif, sta); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (old_state == IEEE80211_STA_NONE && 10518c2ecf20Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST) 10528c2ecf20Sopenharmony_ci mt76_sta_remove(dev, vif, sta); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_sta_state); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_civoid mt76_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 10598c2ecf20Sopenharmony_ci struct ieee80211_sta *sta) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 10628c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 10638c2ecf20Sopenharmony_ci struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci mutex_lock(&dev->mutex); 10668c2ecf20Sopenharmony_ci rcu_assign_pointer(dev->wcid[wcid->idx], NULL); 10678c2ecf20Sopenharmony_ci mutex_unlock(&dev->mutex); 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_sta_pre_rcu_remove); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ciint mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 10728c2ecf20Sopenharmony_ci int *dbm) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 10758c2ecf20Sopenharmony_ci int n_chains = hweight8(phy->antenna_mask); 10768c2ecf20Sopenharmony_ci int delta = mt76_tx_power_nss_delta(n_chains); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci *dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return 0; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_get_txpower); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic void 10858c2ecf20Sopenharmony_ci__mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci if (vif->csa_active && ieee80211_beacon_cntdwn_is_complete(vif)) 10888c2ecf20Sopenharmony_ci ieee80211_csa_finish(vif); 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_civoid mt76_csa_finish(struct mt76_dev *dev) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci if (!dev->csa_complete) 10948c2ecf20Sopenharmony_ci return; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(dev->hw, 10978c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 10988c2ecf20Sopenharmony_ci __mt76_csa_finish, dev); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci dev->csa_complete = 0; 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_csa_finish); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void 11058c2ecf20Sopenharmony_ci__mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct mt76_dev *dev = priv; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (!vif->csa_active) 11108c2ecf20Sopenharmony_ci return; 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif); 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_civoid mt76_csa_check(struct mt76_dev *dev) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic(dev->hw, 11188c2ecf20Sopenharmony_ci IEEE80211_IFACE_ITER_RESUME_ALL, 11198c2ecf20Sopenharmony_ci __mt76_csa_check, dev); 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_csa_check); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ciint 11248c2ecf20Sopenharmony_cimt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci return 0; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_set_tim); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_civoid mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; 11338c2ecf20Sopenharmony_ci int hdr_len = ieee80211_get_hdrlen_from_skb(skb); 11348c2ecf20Sopenharmony_ci u8 *hdr, *pn = status->iv; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci __skb_push(skb, 8); 11378c2ecf20Sopenharmony_ci memmove(skb->data, skb->data + 8, hdr_len); 11388c2ecf20Sopenharmony_ci hdr = skb->data + hdr_len; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci hdr[0] = pn[5]; 11418c2ecf20Sopenharmony_ci hdr[1] = pn[4]; 11428c2ecf20Sopenharmony_ci hdr[2] = 0; 11438c2ecf20Sopenharmony_ci hdr[3] = 0x20 | (key_id << 6); 11448c2ecf20Sopenharmony_ci hdr[4] = pn[3]; 11458c2ecf20Sopenharmony_ci hdr[5] = pn[2]; 11468c2ecf20Sopenharmony_ci hdr[6] = pn[1]; 11478c2ecf20Sopenharmony_ci hdr[7] = pn[0]; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci status->flag &= ~RX_FLAG_IV_STRIPPED; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_insert_ccmp_hdr); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ciint mt76_get_rate(struct mt76_dev *dev, 11548c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband, 11558c2ecf20Sopenharmony_ci int idx, bool cck) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci int i, offset = 0, len = sband->n_bitrates; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (cck) { 11608c2ecf20Sopenharmony_ci if (sband == &dev->phy.sband_5g.sband) 11618c2ecf20Sopenharmony_ci return 0; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci idx &= ~BIT(2); /* short preamble */ 11648c2ecf20Sopenharmony_ci } else if (sband == &dev->phy.sband_2g.sband) { 11658c2ecf20Sopenharmony_ci offset = 4; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci for (i = offset; i < len; i++) { 11698c2ecf20Sopenharmony_ci if ((sband->bitrates[i].hw_value & GENMASK(7, 0)) == idx) 11708c2ecf20Sopenharmony_ci return i; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci return 0; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_get_rate); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_civoid mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 11788c2ecf20Sopenharmony_ci const u8 *mac) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci set_bit(MT76_SCANNING, &phy->state); 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_sw_scan); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_civoid mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci clear_bit(MT76_SCANNING, &phy->state); 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_sw_scan_complete); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ciint mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct mt76_phy *phy = hw->priv; 11978c2ecf20Sopenharmony_ci struct mt76_dev *dev = phy->dev; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci mutex_lock(&dev->mutex); 12008c2ecf20Sopenharmony_ci *tx_ant = phy->antenna_mask; 12018c2ecf20Sopenharmony_ci *rx_ant = phy->antenna_mask; 12028c2ecf20Sopenharmony_ci mutex_unlock(&dev->mutex); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci return 0; 12058c2ecf20Sopenharmony_ci} 12068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76_get_antenna); 1207