162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/etherdevice.h> 562306a36Sopenharmony_ci#include <linux/platform_device.h> 662306a36Sopenharmony_ci#include <linux/pci.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include "mt7915.h" 962306a36Sopenharmony_ci#include "mcu.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic bool mt7915_dev_running(struct mt7915_dev *dev) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci struct mt7915_phy *phy; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 1662306a36Sopenharmony_ci return true; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci phy = mt7915_ext_phy(dev); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciint mt7915_run(struct ieee80211_hw *hw) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 2662306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 2762306a36Sopenharmony_ci bool running; 2862306a36Sopenharmony_ci int ret; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci running = mt7915_dev_running(dev); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (!running) { 3362306a36Sopenharmony_ci ret = mt76_connac_mcu_set_pm(&dev->mt76, 3462306a36Sopenharmony_ci dev->phy.mt76->band_idx, 0); 3562306a36Sopenharmony_ci if (ret) 3662306a36Sopenharmony_ci goto out; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci ret = mt7915_mcu_set_mac(dev, dev->phy.mt76->band_idx, 3962306a36Sopenharmony_ci true, true); 4062306a36Sopenharmony_ci if (ret) 4162306a36Sopenharmony_ci goto out; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci mt7915_mac_enable_nf(dev, dev->phy.mt76->band_idx); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (phy != &dev->phy) { 4762306a36Sopenharmony_ci ret = mt76_connac_mcu_set_pm(&dev->mt76, 4862306a36Sopenharmony_ci phy->mt76->band_idx, 0); 4962306a36Sopenharmony_ci if (ret) 5062306a36Sopenharmony_ci goto out; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci ret = mt7915_mcu_set_mac(dev, phy->mt76->band_idx, 5362306a36Sopenharmony_ci true, true); 5462306a36Sopenharmony_ci if (ret) 5562306a36Sopenharmony_ci goto out; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci mt7915_mac_enable_nf(dev, phy->mt76->band_idx); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci ret = mt7915_mcu_set_thermal_throttling(phy, 6162306a36Sopenharmony_ci MT7915_THERMAL_THROTTLE_MAX); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (ret) 6462306a36Sopenharmony_ci goto out; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret = mt7915_mcu_set_thermal_protect(phy); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (ret) 6962306a36Sopenharmony_ci goto out; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 7262306a36Sopenharmony_ci phy->mt76->band_idx); 7362306a36Sopenharmony_ci if (ret) 7462306a36Sopenharmony_ci goto out; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ret = mt7915_mcu_set_sku_en(phy, true); 7762306a36Sopenharmony_ci if (ret) 7862306a36Sopenharmony_ci goto out; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); 8162306a36Sopenharmony_ci if (ret) 8262306a36Sopenharmony_ci goto out; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci set_bit(MT76_STATE_RUNNING, &phy->mt76->state); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!mt76_testmode_enabled(phy->mt76)) 8762306a36Sopenharmony_ci ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, 8862306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!running) 9162306a36Sopenharmony_ci mt7915_mac_reset_counters(phy); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ciout: 9462306a36Sopenharmony_ci return ret; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int mt7915_start(struct ieee80211_hw *hw) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 10062306a36Sopenharmony_ci int ret; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci flush_work(&dev->init_work); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 10562306a36Sopenharmony_ci ret = mt7915_run(hw); 10662306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return ret; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void mt7915_stop(struct ieee80211_hw *hw) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 11462306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci cancel_delayed_work_sync(&phy->mt76->mac_work); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci mt76_testmode_reset(phy->mt76, true); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (phy != &dev->phy) { 12562306a36Sopenharmony_ci mt76_connac_mcu_set_pm(&dev->mt76, phy->mt76->band_idx, 1); 12662306a36Sopenharmony_ci mt7915_mcu_set_mac(dev, phy->mt76->band_idx, false, false); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (!mt7915_dev_running(dev)) { 13062306a36Sopenharmony_ci mt76_connac_mcu_set_pm(&dev->mt76, dev->phy.mt76->band_idx, 1); 13162306a36Sopenharmony_ci mt7915_mcu_set_mac(dev, dev->phy.mt76->band_idx, false, false); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline int get_free_idx(u32 mask, u8 start, u8 end) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci return ffs(~mask & GENMASK(end, start)); 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int get_omac_idx(enum nl80211_iftype type, u64 mask) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci int i; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci switch (type) { 14762306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 14862306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 14962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 15062306a36Sopenharmony_ci /* prefer hw bssid slot 1-3 */ 15162306a36Sopenharmony_ci i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); 15262306a36Sopenharmony_ci if (i) 15362306a36Sopenharmony_ci return i - 1; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (type != NL80211_IFTYPE_STATION) 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 15962306a36Sopenharmony_ci if (i) 16062306a36Sopenharmony_ci return i - 1; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (~mask & BIT(HW_BSSID_0)) 16362306a36Sopenharmony_ci return HW_BSSID_0; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 16762306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 16862306a36Sopenharmony_ci /* ap uses hw bssid 0 and ext bssid */ 16962306a36Sopenharmony_ci if (~mask & BIT(HW_BSSID_0)) 17062306a36Sopenharmony_ci return HW_BSSID_0; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 17362306a36Sopenharmony_ci if (i) 17462306a36Sopenharmony_ci return i - 1; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci default: 17862306a36Sopenharmony_ci WARN_ON(1); 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return -1; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void mt7915_init_bitrate_mask(struct ieee80211_vif *vif) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 18862306a36Sopenharmony_ci int i; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { 19162306a36Sopenharmony_ci mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; 19262306a36Sopenharmony_ci mvif->bitrate_mask.control[i].he_gi = 0xff; 19362306a36Sopenharmony_ci mvif->bitrate_mask.control[i].he_ltf = 0xff; 19462306a36Sopenharmony_ci mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); 19562306a36Sopenharmony_ci memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, 19662306a36Sopenharmony_ci sizeof(mvif->bitrate_mask.control[i].ht_mcs)); 19762306a36Sopenharmony_ci memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, 19862306a36Sopenharmony_ci sizeof(mvif->bitrate_mask.control[i].vht_mcs)); 19962306a36Sopenharmony_ci memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, 20062306a36Sopenharmony_ci sizeof(mvif->bitrate_mask.control[i].he_mcs)); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int mt7915_add_interface(struct ieee80211_hw *hw, 20562306a36Sopenharmony_ci struct ieee80211_vif *vif) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 20862306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 20962306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 21062306a36Sopenharmony_ci struct mt76_txq *mtxq; 21162306a36Sopenharmony_ci bool ext_phy = phy != &dev->phy; 21262306a36Sopenharmony_ci int idx, ret = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci mt76_testmode_reset(phy->mt76, true); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_MONITOR && 21962306a36Sopenharmony_ci is_zero_ether_addr(vif->addr)) 22062306a36Sopenharmony_ci phy->monitor_vif = vif; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); 22362306a36Sopenharmony_ci if (mvif->mt76.idx >= (MT7915_MAX_INTERFACES << dev->dbdc_support)) { 22462306a36Sopenharmony_ci ret = -ENOSPC; 22562306a36Sopenharmony_ci goto out; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci idx = get_omac_idx(vif->type, phy->omac_mask); 22962306a36Sopenharmony_ci if (idx < 0) { 23062306a36Sopenharmony_ci ret = -ENOSPC; 23162306a36Sopenharmony_ci goto out; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci mvif->mt76.omac_idx = idx; 23462306a36Sopenharmony_ci mvif->phy = phy; 23562306a36Sopenharmony_ci mvif->mt76.band_idx = phy->mt76->band_idx; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; 23862306a36Sopenharmony_ci if (ext_phy) 23962306a36Sopenharmony_ci mvif->mt76.wmm_idx += 2; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ret = mt7915_mcu_add_dev_info(phy, vif, true); 24262306a36Sopenharmony_ci if (ret) 24362306a36Sopenharmony_ci goto out; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); 24662306a36Sopenharmony_ci phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci idx = MT7915_WTBL_RESERVED - mvif->mt76.idx; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci INIT_LIST_HEAD(&mvif->sta.rc_list); 25162306a36Sopenharmony_ci INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); 25262306a36Sopenharmony_ci mvif->sta.wcid.idx = idx; 25362306a36Sopenharmony_ci mvif->sta.wcid.phy_idx = ext_phy; 25462306a36Sopenharmony_ci mvif->sta.wcid.hw_key_idx = -1; 25562306a36Sopenharmony_ci mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; 25662306a36Sopenharmony_ci mt76_packet_id_init(&mvif->sta.wcid); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci mt7915_mac_wtbl_update(dev, idx, 25962306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (vif->txq) { 26262306a36Sopenharmony_ci mtxq = (struct mt76_txq *)vif->txq->drv_priv; 26362306a36Sopenharmony_ci mtxq->wcid = idx; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP && 26762306a36Sopenharmony_ci (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) 26862306a36Sopenharmony_ci vif->offload_flags = 0; 26962306a36Sopenharmony_ci vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci mt7915_init_bitrate_mask(vif); 27262306a36Sopenharmony_ci memset(&mvif->cap, -1, sizeof(mvif->cap)); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci mt7915_mcu_add_bss_info(phy, vif, true); 27562306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, vif, NULL, true); 27662306a36Sopenharmony_ci rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ciout: 27962306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return ret; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic void mt7915_remove_interface(struct ieee80211_hw *hw, 28562306a36Sopenharmony_ci struct ieee80211_vif *vif) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 28862306a36Sopenharmony_ci struct mt7915_sta *msta = &mvif->sta; 28962306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 29062306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 29162306a36Sopenharmony_ci int idx = msta->wcid.idx; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci mt7915_mcu_add_bss_info(phy, vif, false); 29462306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, vif, NULL, false); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 29762306a36Sopenharmony_ci mt76_testmode_reset(phy->mt76, true); 29862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (vif == phy->monitor_vif) 30162306a36Sopenharmony_ci phy->monitor_vif = NULL; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci mt7915_mcu_add_dev_info(phy, vif, false); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci rcu_assign_pointer(dev->mt76.wcid[idx], NULL); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 30862306a36Sopenharmony_ci dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); 30962306a36Sopenharmony_ci phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); 31062306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 31362306a36Sopenharmony_ci if (!list_empty(&msta->wcid.poll_list)) 31462306a36Sopenharmony_ci list_del_init(&msta->wcid.poll_list); 31562306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci mt76_packet_id_flush(&dev->mt76, &msta->wcid); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ciint mt7915_set_channel(struct mt7915_phy *phy) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 32362306a36Sopenharmony_ci int ret; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci cancel_delayed_work_sync(&phy->mt76->mac_work); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 32862306a36Sopenharmony_ci set_bit(MT76_RESET, &phy->mt76->state); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci mt76_set_channel(phy->mt76); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (dev->flash_mode) { 33362306a36Sopenharmony_ci ret = mt7915_mcu_apply_tx_dpd(phy); 33462306a36Sopenharmony_ci if (ret) 33562306a36Sopenharmony_ci goto out; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH)); 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci goto out; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci mt7915_mac_set_timing(phy); 34362306a36Sopenharmony_ci ret = mt7915_dfs_init_radar_detector(phy); 34462306a36Sopenharmony_ci mt7915_mac_cca_stats_reset(phy); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci mt7915_mac_reset_counters(phy); 34762306a36Sopenharmony_ci phy->noise = 0; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ciout: 35062306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy->mt76->state); 35162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci mt76_txq_schedule_all(phy->mt76); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (!mt76_testmode_enabled(phy->mt76)) 35662306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy->mt76->hw, 35762306a36Sopenharmony_ci &phy->mt76->mac_work, 35862306a36Sopenharmony_ci MT7915_WATCHDOG_TIME); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return ret; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 36462306a36Sopenharmony_ci struct ieee80211_vif *vif, struct ieee80211_sta *sta, 36562306a36Sopenharmony_ci struct ieee80211_key_conf *key) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 36862306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 36962306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 37062306a36Sopenharmony_ci struct mt7915_sta *msta = sta ? (struct mt7915_sta *)sta->drv_priv : 37162306a36Sopenharmony_ci &mvif->sta; 37262306a36Sopenharmony_ci struct mt76_wcid *wcid = &msta->wcid; 37362306a36Sopenharmony_ci u8 *wcid_keyidx = &wcid->hw_key_idx; 37462306a36Sopenharmony_ci int idx = key->keyidx; 37562306a36Sopenharmony_ci int err = 0; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* The hardware does not support per-STA RX GTK, fallback 37862306a36Sopenharmony_ci * to software mode for these. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_ADHOC || 38162306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT) && 38262306a36Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_TKIP || 38362306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_CCMP) && 38462306a36Sopenharmony_ci !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 38562306a36Sopenharmony_ci return -EOPNOTSUPP; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* fall back to sw encryption for unsupported ciphers */ 38862306a36Sopenharmony_ci switch (key->cipher) { 38962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 39062306a36Sopenharmony_ci wcid_keyidx = &wcid->hw_key_idx2; 39162306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 39462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 39562306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 39662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 39762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 39862306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_SMS4: 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 40162306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 40262306a36Sopenharmony_ci default: 40362306a36Sopenharmony_ci return -EOPNOTSUPP; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { 40962306a36Sopenharmony_ci mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); 41062306a36Sopenharmony_ci mt7915_mcu_add_bss_info(phy, vif, true); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (cmd == SET_KEY) { 41462306a36Sopenharmony_ci *wcid_keyidx = idx; 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci if (idx == *wcid_keyidx) 41762306a36Sopenharmony_ci *wcid_keyidx = -1; 41862306a36Sopenharmony_ci goto out; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci mt76_wcid_key_setup(&dev->mt76, wcid, key); 42262306a36Sopenharmony_ci err = mt76_connac_mcu_add_key(&dev->mt76, vif, &msta->bip, 42362306a36Sopenharmony_ci key, MCU_EXT_CMD(STA_REC_UPDATE), 42462306a36Sopenharmony_ci &msta->wcid, cmd); 42562306a36Sopenharmony_ciout: 42662306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return err; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int mt7915_set_sar_specs(struct ieee80211_hw *hw, 43262306a36Sopenharmony_ci const struct cfg80211_sar_specs *sar) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 43562306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 43662306a36Sopenharmony_ci int err = -EINVAL; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 43962306a36Sopenharmony_ci if (!cfg80211_chandef_valid(&phy->mt76->chandef)) 44062306a36Sopenharmony_ci goto out; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci err = mt76_init_sar_power(hw, sar); 44362306a36Sopenharmony_ci if (err) 44462306a36Sopenharmony_ci goto out; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci err = mt7915_mcu_set_txpower_sku(phy); 44762306a36Sopenharmony_ciout: 44862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return err; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int mt7915_config(struct ieee80211_hw *hw, u32 changed) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 45662306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 45762306a36Sopenharmony_ci int ret; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 46062306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE 46162306a36Sopenharmony_ci if (phy->mt76->test.state != MT76_TM_STATE_OFF) { 46262306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 46362306a36Sopenharmony_ci mt76_testmode_reset(phy->mt76, false); 46462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci#endif 46762306a36Sopenharmony_ci ieee80211_stop_queues(hw); 46862306a36Sopenharmony_ci ret = mt7915_set_channel(phy); 46962306a36Sopenharmony_ci if (ret) 47062306a36Sopenharmony_ci return ret; 47162306a36Sopenharmony_ci ieee80211_wake_queues(hw); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (changed & (IEEE80211_CONF_CHANGE_POWER | 47562306a36Sopenharmony_ci IEEE80211_CONF_CHANGE_CHANNEL)) { 47662306a36Sopenharmony_ci ret = mt7915_mcu_set_txpower_sku(phy); 47762306a36Sopenharmony_ci if (ret) 47862306a36Sopenharmony_ci return ret; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 48462306a36Sopenharmony_ci bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); 48562306a36Sopenharmony_ci bool band = phy->mt76->band_idx; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (!enabled) 48862306a36Sopenharmony_ci phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN, 49362306a36Sopenharmony_ci enabled); 49462306a36Sopenharmony_ci mt76_testmode_reset(phy->mt76, true); 49562306a36Sopenharmony_ci mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic int 50462306a36Sopenharmony_cimt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 50562306a36Sopenharmony_ci unsigned int link_id, u16 queue, 50662306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* no need to update right away, we'll get BSS_CHANGED_QOS */ 51162306a36Sopenharmony_ci queue = mt76_connac_lmac_mapping(queue); 51262306a36Sopenharmony_ci mvif->queue_params[queue] = *params; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return 0; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void mt7915_configure_filter(struct ieee80211_hw *hw, 51862306a36Sopenharmony_ci unsigned int changed_flags, 51962306a36Sopenharmony_ci unsigned int *total_flags, 52062306a36Sopenharmony_ci u64 multicast) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 52362306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 52462306a36Sopenharmony_ci bool band = phy->mt76->band_idx; 52562306a36Sopenharmony_ci u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | 52662306a36Sopenharmony_ci MT_WF_RFCR1_DROP_BF_POLL | 52762306a36Sopenharmony_ci MT_WF_RFCR1_DROP_BA | 52862306a36Sopenharmony_ci MT_WF_RFCR1_DROP_CFEND | 52962306a36Sopenharmony_ci MT_WF_RFCR1_DROP_CFACK; 53062306a36Sopenharmony_ci u32 flags = 0; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci#define MT76_FILTER(_flag, _hw) do { \ 53362306a36Sopenharmony_ci flags |= *total_flags & FIF_##_flag; \ 53462306a36Sopenharmony_ci phy->rxfilter &= ~(_hw); \ 53562306a36Sopenharmony_ci phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 53662306a36Sopenharmony_ci } while (0) 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | 54162306a36Sopenharmony_ci MT_WF_RFCR_DROP_OTHER_BEACON | 54262306a36Sopenharmony_ci MT_WF_RFCR_DROP_FRAME_REPORT | 54362306a36Sopenharmony_ci MT_WF_RFCR_DROP_PROBEREQ | 54462306a36Sopenharmony_ci MT_WF_RFCR_DROP_MCAST_FILTERED | 54562306a36Sopenharmony_ci MT_WF_RFCR_DROP_MCAST | 54662306a36Sopenharmony_ci MT_WF_RFCR_DROP_BCAST | 54762306a36Sopenharmony_ci MT_WF_RFCR_DROP_DUPLICATE | 54862306a36Sopenharmony_ci MT_WF_RFCR_DROP_A2_BSSID | 54962306a36Sopenharmony_ci MT_WF_RFCR_DROP_UNWANTED_CTL | 55062306a36Sopenharmony_ci MT_WF_RFCR_DROP_STBC_MULTI); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | 55362306a36Sopenharmony_ci MT_WF_RFCR_DROP_A3_MAC | 55462306a36Sopenharmony_ci MT_WF_RFCR_DROP_A3_BSSID); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | 55962306a36Sopenharmony_ci MT_WF_RFCR_DROP_RTS | 56062306a36Sopenharmony_ci MT_WF_RFCR_DROP_CTL_RSV | 56162306a36Sopenharmony_ci MT_WF_RFCR_DROP_NDPA); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci *total_flags = flags; 56462306a36Sopenharmony_ci mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (*total_flags & FIF_CONTROL) 56762306a36Sopenharmony_ci mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); 56862306a36Sopenharmony_ci else 56962306a36Sopenharmony_ci mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void 57562306a36Sopenharmony_cimt7915_update_bss_color(struct ieee80211_hw *hw, 57662306a36Sopenharmony_ci struct ieee80211_vif *vif, 57762306a36Sopenharmony_ci struct cfg80211_he_bss_color *bss_color) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci switch (vif->type) { 58262306a36Sopenharmony_ci case NL80211_IFTYPE_AP: { 58362306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (mvif->mt76.omac_idx > HW_BSSID_MAX) 58662306a36Sopenharmony_ci return; 58762306a36Sopenharmony_ci fallthrough; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 59062306a36Sopenharmony_ci mt7915_mcu_update_bss_color(dev, vif, bss_color); 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci default: 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void mt7915_bss_info_changed(struct ieee80211_hw *hw, 59862306a36Sopenharmony_ci struct ieee80211_vif *vif, 59962306a36Sopenharmony_ci struct ieee80211_bss_conf *info, 60062306a36Sopenharmony_ci u64 changed) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 60362306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 60462306a36Sopenharmony_ci int set_bss_info = -1, set_sta = -1; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* 60962306a36Sopenharmony_ci * station mode uses BSSID to map the wlan entry to a peer, 61062306a36Sopenharmony_ci * and then peer references bss_info_rfch to set bandwidth cap. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci if (changed & BSS_CHANGED_BSSID && 61362306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_STATION) 61462306a36Sopenharmony_ci set_bss_info = set_sta = !is_zero_ether_addr(info->bssid); 61562306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) 61662306a36Sopenharmony_ci set_bss_info = vif->cfg.assoc; 61762306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED && 61862306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_AP) 61962306a36Sopenharmony_ci set_bss_info = set_sta = info->enable_beacon; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (set_bss_info == 1) 62262306a36Sopenharmony_ci mt7915_mcu_add_bss_info(phy, vif, true); 62362306a36Sopenharmony_ci if (set_sta == 1) 62462306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, vif, NULL, true); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_CTS_PROT) 62762306a36Sopenharmony_ci mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 63062306a36Sopenharmony_ci int slottime = info->use_short_slot ? 9 : 20; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (slottime != phy->slottime) { 63362306a36Sopenharmony_ci phy->slottime = slottime; 63462306a36Sopenharmony_ci mt7915_mac_set_timing(phy); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* ensure that enable txcmd_mode after bss_info */ 63962306a36Sopenharmony_ci if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) 64062306a36Sopenharmony_ci mt7915_mcu_set_tx(dev, vif); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_OBSS_PD) 64362306a36Sopenharmony_ci mt7915_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_BSS_COLOR) 64662306a36Sopenharmony_ci mt7915_update_bss_color(hw, vif, &info->he_bss_color); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (changed & (BSS_CHANGED_BEACON | 64962306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED)) 65062306a36Sopenharmony_ci mt7915_mcu_add_beacon(hw, vif, info->enable_beacon, changed); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | 65362306a36Sopenharmony_ci BSS_CHANGED_FILS_DISCOVERY)) 65462306a36Sopenharmony_ci mt7915_mcu_add_inband_discov(dev, vif, changed); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (set_bss_info == 0) 65762306a36Sopenharmony_ci mt7915_mcu_add_bss_info(phy, vif, false); 65862306a36Sopenharmony_ci if (set_sta == 0) 65962306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, vif, NULL, false); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic void 66562306a36Sopenharmony_cimt7915_vif_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 66862306a36Sopenharmony_ci struct mt7915_vif_cap *vc = &mvif->cap; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci vc->ht_ldpc = vif->bss_conf.ht_ldpc; 67162306a36Sopenharmony_ci vc->vht_ldpc = vif->bss_conf.vht_ldpc; 67262306a36Sopenharmony_ci vc->vht_su_ebfer = vif->bss_conf.vht_su_beamformer; 67362306a36Sopenharmony_ci vc->vht_su_ebfee = vif->bss_conf.vht_su_beamformee; 67462306a36Sopenharmony_ci vc->vht_mu_ebfer = vif->bss_conf.vht_mu_beamformer; 67562306a36Sopenharmony_ci vc->vht_mu_ebfee = vif->bss_conf.vht_mu_beamformee; 67662306a36Sopenharmony_ci vc->he_ldpc = vif->bss_conf.he_ldpc; 67762306a36Sopenharmony_ci vc->he_su_ebfer = vif->bss_conf.he_su_beamformer; 67862306a36Sopenharmony_ci vc->he_su_ebfee = vif->bss_conf.he_su_beamformee; 67962306a36Sopenharmony_ci vc->he_mu_ebfer = vif->bss_conf.he_mu_beamformer; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int 68362306a36Sopenharmony_cimt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 68462306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 68762306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 68862306a36Sopenharmony_ci int err; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci mt7915_vif_check_caps(phy, vif); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci err = mt7915_mcu_add_bss_info(phy, vif, true); 69562306a36Sopenharmony_ci if (err) 69662306a36Sopenharmony_ci goto out; 69762306a36Sopenharmony_ci err = mt7915_mcu_add_sta(dev, vif, NULL, true); 69862306a36Sopenharmony_ciout: 69962306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return err; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic void 70562306a36Sopenharmony_cimt7915_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 70662306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 71162306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, vif, NULL, false); 71262306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic void 71662306a36Sopenharmony_cimt7915_channel_switch_beacon(struct ieee80211_hw *hw, 71762306a36Sopenharmony_ci struct ieee80211_vif *vif, 71862306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 72362306a36Sopenharmony_ci mt7915_mcu_add_beacon(hw, vif, true, BSS_CHANGED_BEACON); 72462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ciint mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 72862306a36Sopenharmony_ci struct ieee80211_sta *sta) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 73162306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 73262306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 73362306a36Sopenharmony_ci bool ext_phy = mvif->phy != &dev->phy; 73462306a36Sopenharmony_ci int ret, idx; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); 73762306a36Sopenharmony_ci if (idx < 0) 73862306a36Sopenharmony_ci return -ENOSPC; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci INIT_LIST_HEAD(&msta->rc_list); 74162306a36Sopenharmony_ci INIT_LIST_HEAD(&msta->wcid.poll_list); 74262306a36Sopenharmony_ci msta->vif = mvif; 74362306a36Sopenharmony_ci msta->wcid.sta = 1; 74462306a36Sopenharmony_ci msta->wcid.idx = idx; 74562306a36Sopenharmony_ci msta->wcid.phy_idx = ext_phy; 74662306a36Sopenharmony_ci msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 74762306a36Sopenharmony_ci msta->jiffies = jiffies; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci ewma_avg_signal_init(&msta->avg_ack_signal); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci mt7915_mac_wtbl_update(dev, idx, 75262306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = mt7915_mcu_add_sta(dev, vif, sta, true); 75562306a36Sopenharmony_ci if (ret) 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci return mt7915_mcu_add_rate_ctrl(dev, vif, sta, false); 75962306a36Sopenharmony_ci} 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_civoid mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 76262306a36Sopenharmony_ci struct ieee80211_sta *sta) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76); 76562306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 76662306a36Sopenharmony_ci int i; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, vif, sta, false); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci mt7915_mac_wtbl_update(dev, msta->wcid.idx, 77162306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) 77462306a36Sopenharmony_ci mt7915_mac_twt_teardown_flow(dev, msta, i); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci spin_lock_bh(&mdev->sta_poll_lock); 77762306a36Sopenharmony_ci if (!list_empty(&msta->wcid.poll_list)) 77862306a36Sopenharmony_ci list_del_init(&msta->wcid.poll_list); 77962306a36Sopenharmony_ci if (!list_empty(&msta->rc_list)) 78062306a36Sopenharmony_ci list_del_init(&msta->rc_list); 78162306a36Sopenharmony_ci spin_unlock_bh(&mdev->sta_poll_lock); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic void mt7915_tx(struct ieee80211_hw *hw, 78562306a36Sopenharmony_ci struct ieee80211_tx_control *control, 78662306a36Sopenharmony_ci struct sk_buff *skb) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 78962306a36Sopenharmony_ci struct mt76_phy *mphy = hw->priv; 79062306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 79162306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 79262306a36Sopenharmony_ci struct mt76_wcid *wcid = &dev->mt76.global_wcid; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (control->sta) { 79562306a36Sopenharmony_ci struct mt7915_sta *sta; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci sta = (struct mt7915_sta *)control->sta->drv_priv; 79862306a36Sopenharmony_ci wcid = &sta->wcid; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (vif && !control->sta) { 80262306a36Sopenharmony_ci struct mt7915_vif *mvif; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci mvif = (struct mt7915_vif *)vif->drv_priv; 80562306a36Sopenharmony_ci wcid = &mvif->sta.wcid; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci mt76_tx(mphy, control->sta, wcid, skb); 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 81462306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 81562306a36Sopenharmony_ci int ret; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 81862306a36Sopenharmony_ci ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, val, 81962306a36Sopenharmony_ci phy->mt76->band_idx); 82062306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci return ret; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int 82662306a36Sopenharmony_cimt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 82762306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 83062306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 83162306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 83262306a36Sopenharmony_ci struct ieee80211_txq *txq = sta->txq[params->tid]; 83362306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 83462306a36Sopenharmony_ci u16 tid = params->tid; 83562306a36Sopenharmony_ci u16 ssn = params->ssn; 83662306a36Sopenharmony_ci struct mt76_txq *mtxq; 83762306a36Sopenharmony_ci int ret = 0; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (!txq) 84062306a36Sopenharmony_ci return -EINVAL; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci mtxq = (struct mt76_txq *)txq->drv_priv; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 84562306a36Sopenharmony_ci switch (action) { 84662306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 84762306a36Sopenharmony_ci mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, 84862306a36Sopenharmony_ci params->buf_size); 84962306a36Sopenharmony_ci ret = mt7915_mcu_add_rx_ba(dev, params, true); 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 85262306a36Sopenharmony_ci mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 85362306a36Sopenharmony_ci ret = mt7915_mcu_add_rx_ba(dev, params, false); 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 85662306a36Sopenharmony_ci mtxq->aggr = true; 85762306a36Sopenharmony_ci mtxq->send_bar = false; 85862306a36Sopenharmony_ci ret = mt7915_mcu_add_tx_ba(dev, params, true); 85962306a36Sopenharmony_ci break; 86062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 86162306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 86262306a36Sopenharmony_ci mtxq->aggr = false; 86362306a36Sopenharmony_ci clear_bit(tid, &msta->wcid.ampdu_state); 86462306a36Sopenharmony_ci ret = mt7915_mcu_add_tx_ba(dev, params, false); 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 86762306a36Sopenharmony_ci set_bit(tid, &msta->wcid.ampdu_state); 86862306a36Sopenharmony_ci ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 87162306a36Sopenharmony_ci mtxq->aggr = false; 87262306a36Sopenharmony_ci clear_bit(tid, &msta->wcid.ampdu_state); 87362306a36Sopenharmony_ci ret = mt7915_mcu_add_tx_ba(dev, params, false); 87462306a36Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return ret; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic int 88362306a36Sopenharmony_cimt7915_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 88462306a36Sopenharmony_ci struct ieee80211_sta *sta) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, 88762306a36Sopenharmony_ci IEEE80211_STA_NONE); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic int 89162306a36Sopenharmony_cimt7915_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 89262306a36Sopenharmony_ci struct ieee80211_sta *sta) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, 89562306a36Sopenharmony_ci IEEE80211_STA_NOTEXIST); 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic int 89962306a36Sopenharmony_cimt7915_get_stats(struct ieee80211_hw *hw, 90062306a36Sopenharmony_ci struct ieee80211_low_level_stats *stats) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 90362306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 90462306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci stats->dot11RTSSuccessCount = mib->rts_cnt; 90962306a36Sopenharmony_ci stats->dot11RTSFailureCount = mib->rts_retries_cnt; 91062306a36Sopenharmony_ci stats->dot11FCSErrorCount = mib->fcs_err_cnt; 91162306a36Sopenharmony_ci stats->dot11ACKFailureCount = mib->ack_fail_cnt; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ciu64 __mt7915_get_tsf(struct ieee80211_hw *hw, struct mt7915_vif *mvif) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 92162306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 92262306a36Sopenharmony_ci bool band = phy->mt76->band_idx; 92362306a36Sopenharmony_ci union { 92462306a36Sopenharmony_ci u64 t64; 92562306a36Sopenharmony_ci u32 t32[2]; 92662306a36Sopenharmony_ci } tsf; 92762306a36Sopenharmony_ci u16 n; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci lockdep_assert_held(&dev->mt76.mutex); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 93262306a36Sopenharmony_ci : mvif->mt76.omac_idx; 93362306a36Sopenharmony_ci /* TSF software read */ 93462306a36Sopenharmony_ci if (is_mt7915(&dev->mt76)) 93562306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, 93662306a36Sopenharmony_ci MT_LPON_TCR_SW_READ); 93762306a36Sopenharmony_ci else 93862306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR_MT7916(band, n), MT_LPON_TCR_SW_MODE, 93962306a36Sopenharmony_ci MT_LPON_TCR_SW_READ); 94062306a36Sopenharmony_ci tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(band)); 94162306a36Sopenharmony_ci tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(band)); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci return tsf.t64; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic u64 94762306a36Sopenharmony_cimt7915_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 95062306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 95162306a36Sopenharmony_ci u64 ret; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 95462306a36Sopenharmony_ci ret = __mt7915_get_tsf(hw, mvif); 95562306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return ret; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic void 96162306a36Sopenharmony_cimt7915_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 96262306a36Sopenharmony_ci u64 timestamp) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 96562306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 96662306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 96762306a36Sopenharmony_ci bool band = phy->mt76->band_idx; 96862306a36Sopenharmony_ci union { 96962306a36Sopenharmony_ci u64 t64; 97062306a36Sopenharmony_ci u32 t32[2]; 97162306a36Sopenharmony_ci } tsf = { .t64 = timestamp, }; 97262306a36Sopenharmony_ci u16 n; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 97762306a36Sopenharmony_ci : mvif->mt76.omac_idx; 97862306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); 97962306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); 98062306a36Sopenharmony_ci /* TSF software overwrite */ 98162306a36Sopenharmony_ci if (is_mt7915(&dev->mt76)) 98262306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, 98362306a36Sopenharmony_ci MT_LPON_TCR_SW_WRITE); 98462306a36Sopenharmony_ci else 98562306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR_MT7916(band, n), MT_LPON_TCR_SW_MODE, 98662306a36Sopenharmony_ci MT_LPON_TCR_SW_WRITE); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic void 99262306a36Sopenharmony_cimt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 99362306a36Sopenharmony_ci s64 timestamp) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 99662306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 99762306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 99862306a36Sopenharmony_ci bool band = phy->mt76->band_idx; 99962306a36Sopenharmony_ci union { 100062306a36Sopenharmony_ci u64 t64; 100162306a36Sopenharmony_ci u32 t32[2]; 100262306a36Sopenharmony_ci } tsf = { .t64 = timestamp, }; 100362306a36Sopenharmony_ci u16 n; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 100862306a36Sopenharmony_ci : mvif->mt76.omac_idx; 100962306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR0(band), tsf.t32[0]); 101062306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR1(band), tsf.t32[1]); 101162306a36Sopenharmony_ci /* TSF software adjust*/ 101262306a36Sopenharmony_ci if (is_mt7915(&dev->mt76)) 101362306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR(band, n), MT_LPON_TCR_SW_MODE, 101462306a36Sopenharmony_ci MT_LPON_TCR_SW_ADJUST); 101562306a36Sopenharmony_ci else 101662306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR_MT7916(band, n), MT_LPON_TCR_SW_MODE, 101762306a36Sopenharmony_ci MT_LPON_TCR_SW_ADJUST); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic void 102362306a36Sopenharmony_cimt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 102662306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 102962306a36Sopenharmony_ci phy->coverage_class = max_t(s16, coverage_class, 0); 103062306a36Sopenharmony_ci mt7915_mac_set_timing(phy); 103162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int 103562306a36Sopenharmony_cimt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 103862306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 103962306a36Sopenharmony_ci int max_nss = hweight8(hw->wiphy->available_antennas_tx); 104062306a36Sopenharmony_ci u8 chainshift = dev->chainshift; 104162306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) 104462306a36Sopenharmony_ci return -EINVAL; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci phy->mt76->antenna_mask = tx_ant; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ 105162306a36Sopenharmony_ci if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) && 105262306a36Sopenharmony_ci band && hweight8(tx_ant) == max_nss) 105362306a36Sopenharmony_ci phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; 105462306a36Sopenharmony_ci else 105562306a36Sopenharmony_ci phy->mt76->chainmask = tx_ant << (chainshift * band); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci mt76_set_stream_caps(phy->mt76, true); 105862306a36Sopenharmony_ci mt7915_set_stream_vht_txbf_caps(phy); 105962306a36Sopenharmony_ci mt7915_set_stream_he_caps(phy); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci return 0; 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic void mt7915_sta_statistics(struct ieee80211_hw *hw, 106762306a36Sopenharmony_ci struct ieee80211_vif *vif, 106862306a36Sopenharmony_ci struct ieee80211_sta *sta, 106962306a36Sopenharmony_ci struct station_info *sinfo) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 107262306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 107362306a36Sopenharmony_ci struct rate_info *txrate = &msta->wcid.rate; 107462306a36Sopenharmony_ci struct rate_info rxrate = {}; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (is_mt7915(&phy->dev->mt76) && 107762306a36Sopenharmony_ci !mt7915_mcu_get_rx_rate(phy, vif, sta, &rxrate)) { 107862306a36Sopenharmony_ci sinfo->rxrate = rxrate; 107962306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE); 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (txrate->legacy || txrate->flags) { 108362306a36Sopenharmony_ci if (txrate->legacy) { 108462306a36Sopenharmony_ci sinfo->txrate.legacy = txrate->legacy; 108562306a36Sopenharmony_ci } else { 108662306a36Sopenharmony_ci sinfo->txrate.mcs = txrate->mcs; 108762306a36Sopenharmony_ci sinfo->txrate.nss = txrate->nss; 108862306a36Sopenharmony_ci sinfo->txrate.bw = txrate->bw; 108962306a36Sopenharmony_ci sinfo->txrate.he_gi = txrate->he_gi; 109062306a36Sopenharmony_ci sinfo->txrate.he_dcm = txrate->he_dcm; 109162306a36Sopenharmony_ci sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci sinfo->txrate.flags = txrate->flags; 109462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* offloading flows bypass networking stack, so driver counts and 109862306a36Sopenharmony_ci * reports sta statistics via NL80211_STA_INFO when WED is active. 109962306a36Sopenharmony_ci */ 110062306a36Sopenharmony_ci if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { 110162306a36Sopenharmony_ci sinfo->tx_bytes = msta->wcid.stats.tx_bytes; 110262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (!mt7915_mcu_wed_wa_tx_stats(phy->dev, msta->wcid.idx)) { 110562306a36Sopenharmony_ci sinfo->tx_packets = msta->wcid.stats.tx_packets; 110662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (mtk_wed_get_rx_capa(&phy->dev->mt76.mmio.wed)) { 111062306a36Sopenharmony_ci sinfo->rx_bytes = msta->wcid.stats.rx_bytes; 111162306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci sinfo->rx_packets = msta->wcid.stats.rx_packets; 111462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci sinfo->tx_failed = msta->wcid.stats.tx_failed; 111962306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci sinfo->tx_retries = msta->wcid.stats.tx_retries; 112262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci sinfo->ack_signal = (s8)msta->ack_signal; 112562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); 112862306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_cistatic void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 113462306a36Sopenharmony_ci struct mt7915_dev *dev = msta->vif->phy->dev; 113562306a36Sopenharmony_ci u32 *changed = data; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 113862306a36Sopenharmony_ci msta->changed |= *changed; 113962306a36Sopenharmony_ci if (list_empty(&msta->rc_list)) 114062306a36Sopenharmony_ci list_add_tail(&msta->rc_list, &dev->sta_rc_list); 114162306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic void mt7915_sta_rc_update(struct ieee80211_hw *hw, 114562306a36Sopenharmony_ci struct ieee80211_vif *vif, 114662306a36Sopenharmony_ci struct ieee80211_sta *sta, 114762306a36Sopenharmony_ci u32 changed) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 115062306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci mt7915_sta_rc_work(&changed, sta); 115362306a36Sopenharmony_ci ieee80211_queue_work(hw, &dev->rc_work); 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic int 115762306a36Sopenharmony_cimt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 115862306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 116162306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 116262306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 116362306a36Sopenharmony_ci u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci mvif->bitrate_mask = *mask; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci /* if multiple rates across different preambles are given we can 116862306a36Sopenharmony_ci * reconfigure this info with all peers using sta_rec command with 116962306a36Sopenharmony_ci * the below exception cases. 117062306a36Sopenharmony_ci * - single rate : if a rate is passed along with different preambles, 117162306a36Sopenharmony_ci * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. 117262306a36Sopenharmony_ci * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT 117362306a36Sopenharmony_ci * then multiple MCS setting (MCS 4,5,6) is not supported. 117462306a36Sopenharmony_ci */ 117562306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, mt7915_sta_rc_work, &changed); 117662306a36Sopenharmony_ci ieee80211_queue_work(hw, &dev->rc_work); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci return 0; 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cistatic void mt7915_sta_set_4addr(struct ieee80211_hw *hw, 118262306a36Sopenharmony_ci struct ieee80211_vif *vif, 118362306a36Sopenharmony_ci struct ieee80211_sta *sta, 118462306a36Sopenharmony_ci bool enabled) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 118762306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (enabled) 119062306a36Sopenharmony_ci set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 119162306a36Sopenharmony_ci else 119262306a36Sopenharmony_ci clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic void mt7915_sta_set_decap_offload(struct ieee80211_hw *hw, 119862306a36Sopenharmony_ci struct ieee80211_vif *vif, 119962306a36Sopenharmony_ci struct ieee80211_sta *sta, 120062306a36Sopenharmony_ci bool enabled) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 120362306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (enabled) 120662306a36Sopenharmony_ci set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 120762306a36Sopenharmony_ci else 120862306a36Sopenharmony_ci clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci mt76_connac_mcu_wtbl_update_hdr_trans(&dev->mt76, vif, sta); 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic int mt7915_sta_set_txpwr(struct ieee80211_hw *hw, 121462306a36Sopenharmony_ci struct ieee80211_vif *vif, 121562306a36Sopenharmony_ci struct ieee80211_sta *sta) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 121862306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 121962306a36Sopenharmony_ci s16 txpower = sta->deflink.txpwr.power; 122062306a36Sopenharmony_ci int ret; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (sta->deflink.txpwr.type == NL80211_TX_POWER_AUTOMATIC) 122362306a36Sopenharmony_ci txpower = 0; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* NOTE: temporarily use 0 as minimum limit, which is a 122862306a36Sopenharmony_ci * global setting and will be applied to all stations. 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_ci ret = mt7915_mcu_set_txpower_frame_min(phy, 0); 123162306a36Sopenharmony_ci if (ret) 123262306a36Sopenharmony_ci goto out; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci /* This only applies to data frames while pushing traffic, 123562306a36Sopenharmony_ci * whereas the management frames or other packets that are 123662306a36Sopenharmony_ci * using fixed rate can be configured via TxD. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_ci ret = mt7915_mcu_set_txpower_frame(phy, vif, sta, txpower); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ciout: 124162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci return ret; 124462306a36Sopenharmony_ci} 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_cistatic const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = { 124762306a36Sopenharmony_ci "tx_ampdu_cnt", 124862306a36Sopenharmony_ci "tx_stop_q_empty_cnt", 124962306a36Sopenharmony_ci "tx_mpdu_attempts", 125062306a36Sopenharmony_ci "tx_mpdu_success", 125162306a36Sopenharmony_ci "tx_rwp_fail_cnt", 125262306a36Sopenharmony_ci "tx_rwp_need_cnt", 125362306a36Sopenharmony_ci "tx_pkt_ebf_cnt", 125462306a36Sopenharmony_ci "tx_pkt_ibf_cnt", 125562306a36Sopenharmony_ci "tx_ampdu_len:0-1", 125662306a36Sopenharmony_ci "tx_ampdu_len:2-10", 125762306a36Sopenharmony_ci "tx_ampdu_len:11-19", 125862306a36Sopenharmony_ci "tx_ampdu_len:20-28", 125962306a36Sopenharmony_ci "tx_ampdu_len:29-37", 126062306a36Sopenharmony_ci "tx_ampdu_len:38-46", 126162306a36Sopenharmony_ci "tx_ampdu_len:47-55", 126262306a36Sopenharmony_ci "tx_ampdu_len:56-79", 126362306a36Sopenharmony_ci "tx_ampdu_len:80-103", 126462306a36Sopenharmony_ci "tx_ampdu_len:104-127", 126562306a36Sopenharmony_ci "tx_ampdu_len:128-151", 126662306a36Sopenharmony_ci "tx_ampdu_len:152-175", 126762306a36Sopenharmony_ci "tx_ampdu_len:176-199", 126862306a36Sopenharmony_ci "tx_ampdu_len:200-223", 126962306a36Sopenharmony_ci "tx_ampdu_len:224-247", 127062306a36Sopenharmony_ci "ba_miss_count", 127162306a36Sopenharmony_ci "tx_beamformer_ppdu_iBF", 127262306a36Sopenharmony_ci "tx_beamformer_ppdu_eBF", 127362306a36Sopenharmony_ci "tx_beamformer_rx_feedback_all", 127462306a36Sopenharmony_ci "tx_beamformer_rx_feedback_he", 127562306a36Sopenharmony_ci "tx_beamformer_rx_feedback_vht", 127662306a36Sopenharmony_ci "tx_beamformer_rx_feedback_ht", 127762306a36Sopenharmony_ci "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ 127862306a36Sopenharmony_ci "tx_beamformer_rx_feedback_nc", 127962306a36Sopenharmony_ci "tx_beamformer_rx_feedback_nr", 128062306a36Sopenharmony_ci "tx_beamformee_ok_feedback_pkts", 128162306a36Sopenharmony_ci "tx_beamformee_feedback_trig", 128262306a36Sopenharmony_ci "tx_mu_beamforming", 128362306a36Sopenharmony_ci "tx_mu_mpdu", 128462306a36Sopenharmony_ci "tx_mu_successful_mpdu", 128562306a36Sopenharmony_ci "tx_su_successful_mpdu", 128662306a36Sopenharmony_ci "tx_msdu_pack_1", 128762306a36Sopenharmony_ci "tx_msdu_pack_2", 128862306a36Sopenharmony_ci "tx_msdu_pack_3", 128962306a36Sopenharmony_ci "tx_msdu_pack_4", 129062306a36Sopenharmony_ci "tx_msdu_pack_5", 129162306a36Sopenharmony_ci "tx_msdu_pack_6", 129262306a36Sopenharmony_ci "tx_msdu_pack_7", 129362306a36Sopenharmony_ci "tx_msdu_pack_8", 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci /* rx counters */ 129662306a36Sopenharmony_ci "rx_fifo_full_cnt", 129762306a36Sopenharmony_ci "rx_mpdu_cnt", 129862306a36Sopenharmony_ci "channel_idle_cnt", 129962306a36Sopenharmony_ci "primary_cca_busy_time", 130062306a36Sopenharmony_ci "secondary_cca_busy_time", 130162306a36Sopenharmony_ci "primary_energy_detect_time", 130262306a36Sopenharmony_ci "cck_mdrdy_time", 130362306a36Sopenharmony_ci "ofdm_mdrdy_time", 130462306a36Sopenharmony_ci "green_mdrdy_time", 130562306a36Sopenharmony_ci "rx_vector_mismatch_cnt", 130662306a36Sopenharmony_ci "rx_delimiter_fail_cnt", 130762306a36Sopenharmony_ci "rx_mrdy_cnt", 130862306a36Sopenharmony_ci "rx_len_mismatch_cnt", 130962306a36Sopenharmony_ci "rx_ampdu_cnt", 131062306a36Sopenharmony_ci "rx_ampdu_bytes_cnt", 131162306a36Sopenharmony_ci "rx_ampdu_valid_subframe_cnt", 131262306a36Sopenharmony_ci "rx_ampdu_valid_subframe_b_cnt", 131362306a36Sopenharmony_ci "rx_pfdrop_cnt", 131462306a36Sopenharmony_ci "rx_vec_queue_overflow_drop_cnt", 131562306a36Sopenharmony_ci "rx_ba_cnt", 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci /* muru mu-mimo and ofdma related stats */ 131862306a36Sopenharmony_ci "dl_cck_cnt", 131962306a36Sopenharmony_ci "dl_ofdm_cnt", 132062306a36Sopenharmony_ci "dl_htmix_cnt", 132162306a36Sopenharmony_ci "dl_htgf_cnt", 132262306a36Sopenharmony_ci "dl_vht_su_cnt", 132362306a36Sopenharmony_ci "dl_vht_2mu_cnt", 132462306a36Sopenharmony_ci "dl_vht_3mu_cnt", 132562306a36Sopenharmony_ci "dl_vht_4mu_cnt", 132662306a36Sopenharmony_ci "dl_he_su_cnt", 132762306a36Sopenharmony_ci "dl_he_ext_su_cnt", 132862306a36Sopenharmony_ci "dl_he_2ru_cnt", 132962306a36Sopenharmony_ci "dl_he_2mu_cnt", 133062306a36Sopenharmony_ci "dl_he_3ru_cnt", 133162306a36Sopenharmony_ci "dl_he_3mu_cnt", 133262306a36Sopenharmony_ci "dl_he_4ru_cnt", 133362306a36Sopenharmony_ci "dl_he_4mu_cnt", 133462306a36Sopenharmony_ci "dl_he_5to8ru_cnt", 133562306a36Sopenharmony_ci "dl_he_9to16ru_cnt", 133662306a36Sopenharmony_ci "dl_he_gtr16ru_cnt", 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci "ul_hetrig_su_cnt", 133962306a36Sopenharmony_ci "ul_hetrig_2ru_cnt", 134062306a36Sopenharmony_ci "ul_hetrig_3ru_cnt", 134162306a36Sopenharmony_ci "ul_hetrig_4ru_cnt", 134262306a36Sopenharmony_ci "ul_hetrig_5to8ru_cnt", 134362306a36Sopenharmony_ci "ul_hetrig_9to16ru_cnt", 134462306a36Sopenharmony_ci "ul_hetrig_gtr16ru_cnt", 134562306a36Sopenharmony_ci "ul_hetrig_2mu_cnt", 134662306a36Sopenharmony_ci "ul_hetrig_3mu_cnt", 134762306a36Sopenharmony_ci "ul_hetrig_4mu_cnt", 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci /* per vif counters */ 135062306a36Sopenharmony_ci "v_tx_mode_cck", 135162306a36Sopenharmony_ci "v_tx_mode_ofdm", 135262306a36Sopenharmony_ci "v_tx_mode_ht", 135362306a36Sopenharmony_ci "v_tx_mode_ht_gf", 135462306a36Sopenharmony_ci "v_tx_mode_vht", 135562306a36Sopenharmony_ci "v_tx_mode_he_su", 135662306a36Sopenharmony_ci "v_tx_mode_he_ext_su", 135762306a36Sopenharmony_ci "v_tx_mode_he_tb", 135862306a36Sopenharmony_ci "v_tx_mode_he_mu", 135962306a36Sopenharmony_ci "v_tx_bw_20", 136062306a36Sopenharmony_ci "v_tx_bw_40", 136162306a36Sopenharmony_ci "v_tx_bw_80", 136262306a36Sopenharmony_ci "v_tx_bw_160", 136362306a36Sopenharmony_ci "v_tx_mcs_0", 136462306a36Sopenharmony_ci "v_tx_mcs_1", 136562306a36Sopenharmony_ci "v_tx_mcs_2", 136662306a36Sopenharmony_ci "v_tx_mcs_3", 136762306a36Sopenharmony_ci "v_tx_mcs_4", 136862306a36Sopenharmony_ci "v_tx_mcs_5", 136962306a36Sopenharmony_ci "v_tx_mcs_6", 137062306a36Sopenharmony_ci "v_tx_mcs_7", 137162306a36Sopenharmony_ci "v_tx_mcs_8", 137262306a36Sopenharmony_ci "v_tx_mcs_9", 137362306a36Sopenharmony_ci "v_tx_mcs_10", 137462306a36Sopenharmony_ci "v_tx_mcs_11", 137562306a36Sopenharmony_ci "v_tx_nss_1", 137662306a36Sopenharmony_ci "v_tx_nss_2", 137762306a36Sopenharmony_ci "v_tx_nss_3", 137862306a36Sopenharmony_ci "v_tx_nss_4", 137962306a36Sopenharmony_ci}; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci#define MT7915_SSTATS_LEN ARRAY_SIZE(mt7915_gstrings_stats) 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci/* Ethtool related API */ 138462306a36Sopenharmony_cistatic 138562306a36Sopenharmony_civoid mt7915_get_et_strings(struct ieee80211_hw *hw, 138662306a36Sopenharmony_ci struct ieee80211_vif *vif, 138762306a36Sopenharmony_ci u32 sset, u8 *data) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci if (sset != ETH_SS_STATS) 139062306a36Sopenharmony_ci return; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci memcpy(data, mt7915_gstrings_stats, sizeof(mt7915_gstrings_stats)); 139362306a36Sopenharmony_ci data += sizeof(mt7915_gstrings_stats); 139462306a36Sopenharmony_ci page_pool_ethtool_stats_get_strings(data); 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic 139862306a36Sopenharmony_ciint mt7915_get_et_sset_count(struct ieee80211_hw *hw, 139962306a36Sopenharmony_ci struct ieee80211_vif *vif, int sset) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci if (sset != ETH_SS_STATS) 140262306a36Sopenharmony_ci return 0; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count(); 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci struct mt76_ethtool_worker_info *wi = wi_data; 141062306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (msta->vif->mt76.idx != wi->idx) 141362306a36Sopenharmony_ci return; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci mt76_ethtool_worker(wi, &msta->wcid.stats, false); 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_cistatic 141962306a36Sopenharmony_civoid mt7915_get_et_stats(struct ieee80211_hw *hw, 142062306a36Sopenharmony_ci struct ieee80211_vif *vif, 142162306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 142262306a36Sopenharmony_ci{ 142362306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 142462306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 142562306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 142662306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 142762306a36Sopenharmony_ci struct mt76_ethtool_worker_info wi = { 142862306a36Sopenharmony_ci .data = data, 142962306a36Sopenharmony_ci .idx = mvif->mt76.idx, 143062306a36Sopenharmony_ci }; 143162306a36Sopenharmony_ci /* See mt7915_ampdu_stat_read_phy, etc */ 143262306a36Sopenharmony_ci int i, ei = 0, stats_size; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci mt7915_mac_update_stats(phy); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci data[ei++] = mib->tx_ampdu_cnt; 143962306a36Sopenharmony_ci data[ei++] = mib->tx_stop_q_empty_cnt; 144062306a36Sopenharmony_ci data[ei++] = mib->tx_mpdu_attempts_cnt; 144162306a36Sopenharmony_ci data[ei++] = mib->tx_mpdu_success_cnt; 144262306a36Sopenharmony_ci data[ei++] = mib->tx_rwp_fail_cnt; 144362306a36Sopenharmony_ci data[ei++] = mib->tx_rwp_need_cnt; 144462306a36Sopenharmony_ci data[ei++] = mib->tx_pkt_ebf_cnt; 144562306a36Sopenharmony_ci data[ei++] = mib->tx_pkt_ibf_cnt; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* Tx ampdu stat */ 144862306a36Sopenharmony_ci for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) 144962306a36Sopenharmony_ci data[ei++] = phy->mt76->aggr_stats[i]; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci data[ei++] = phy->mib.ba_miss_cnt; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* Tx Beamformer monitor */ 145462306a36Sopenharmony_ci data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 145562306a36Sopenharmony_ci data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci /* Tx Beamformer Rx feedback monitor */ 145862306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_all_cnt; 145962306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_he_cnt; 146062306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_vht_cnt; 146162306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_ht_cnt; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_bw; 146462306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_nc_cnt; 146562306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_nr_cnt; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* Tx Beamformee Rx NDPA & Tx feedback report */ 146862306a36Sopenharmony_ci data[ei++] = mib->tx_bf_fb_cpl_cnt; 146962306a36Sopenharmony_ci data[ei++] = mib->tx_bf_fb_trig_cnt; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* Tx SU & MU counters */ 147262306a36Sopenharmony_ci data[ei++] = mib->tx_bf_cnt; 147362306a36Sopenharmony_ci data[ei++] = mib->tx_mu_mpdu_cnt; 147462306a36Sopenharmony_ci data[ei++] = mib->tx_mu_acked_mpdu_cnt; 147562306a36Sopenharmony_ci data[ei++] = mib->tx_su_acked_mpdu_cnt; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci /* Tx amsdu info (pack-count histogram) */ 147862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) 147962306a36Sopenharmony_ci data[ei++] = mib->tx_amsdu[i]; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci /* rx counters */ 148262306a36Sopenharmony_ci data[ei++] = mib->rx_fifo_full_cnt; 148362306a36Sopenharmony_ci data[ei++] = mib->rx_mpdu_cnt; 148462306a36Sopenharmony_ci data[ei++] = mib->channel_idle_cnt; 148562306a36Sopenharmony_ci data[ei++] = mib->primary_cca_busy_time; 148662306a36Sopenharmony_ci data[ei++] = mib->secondary_cca_busy_time; 148762306a36Sopenharmony_ci data[ei++] = mib->primary_energy_detect_time; 148862306a36Sopenharmony_ci data[ei++] = mib->cck_mdrdy_time; 148962306a36Sopenharmony_ci data[ei++] = mib->ofdm_mdrdy_time; 149062306a36Sopenharmony_ci data[ei++] = mib->green_mdrdy_time; 149162306a36Sopenharmony_ci data[ei++] = mib->rx_vector_mismatch_cnt; 149262306a36Sopenharmony_ci data[ei++] = mib->rx_delimiter_fail_cnt; 149362306a36Sopenharmony_ci data[ei++] = mib->rx_mrdy_cnt; 149462306a36Sopenharmony_ci data[ei++] = mib->rx_len_mismatch_cnt; 149562306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_cnt; 149662306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_bytes_cnt; 149762306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_valid_subframe_cnt; 149862306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; 149962306a36Sopenharmony_ci data[ei++] = mib->rx_pfdrop_cnt; 150062306a36Sopenharmony_ci data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; 150162306a36Sopenharmony_ci data[ei++] = mib->rx_ba_cnt; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci data[ei++] = mib->dl_cck_cnt; 150462306a36Sopenharmony_ci data[ei++] = mib->dl_ofdm_cnt; 150562306a36Sopenharmony_ci data[ei++] = mib->dl_htmix_cnt; 150662306a36Sopenharmony_ci data[ei++] = mib->dl_htgf_cnt; 150762306a36Sopenharmony_ci data[ei++] = mib->dl_vht_su_cnt; 150862306a36Sopenharmony_ci data[ei++] = mib->dl_vht_2mu_cnt; 150962306a36Sopenharmony_ci data[ei++] = mib->dl_vht_3mu_cnt; 151062306a36Sopenharmony_ci data[ei++] = mib->dl_vht_4mu_cnt; 151162306a36Sopenharmony_ci data[ei++] = mib->dl_he_su_cnt; 151262306a36Sopenharmony_ci data[ei++] = mib->dl_he_ext_su_cnt; 151362306a36Sopenharmony_ci data[ei++] = mib->dl_he_2ru_cnt; 151462306a36Sopenharmony_ci data[ei++] = mib->dl_he_2mu_cnt; 151562306a36Sopenharmony_ci data[ei++] = mib->dl_he_3ru_cnt; 151662306a36Sopenharmony_ci data[ei++] = mib->dl_he_3mu_cnt; 151762306a36Sopenharmony_ci data[ei++] = mib->dl_he_4ru_cnt; 151862306a36Sopenharmony_ci data[ei++] = mib->dl_he_4mu_cnt; 151962306a36Sopenharmony_ci data[ei++] = mib->dl_he_5to8ru_cnt; 152062306a36Sopenharmony_ci data[ei++] = mib->dl_he_9to16ru_cnt; 152162306a36Sopenharmony_ci data[ei++] = mib->dl_he_gtr16ru_cnt; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_su_cnt; 152462306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_2ru_cnt; 152562306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_3ru_cnt; 152662306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_4ru_cnt; 152762306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_5to8ru_cnt; 152862306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_9to16ru_cnt; 152962306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_gtr16ru_cnt; 153062306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_2mu_cnt; 153162306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_3mu_cnt; 153262306a36Sopenharmony_ci data[ei++] = mib->ul_hetrig_4mu_cnt; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci /* Add values for all stations owned by this vif */ 153562306a36Sopenharmony_ci wi.initial_stat_idx = ei; 153662306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (wi.sta_count == 0) 154162306a36Sopenharmony_ci return; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci ei += wi.worker_stat_count; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei); 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci stats_size = MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count(); 154862306a36Sopenharmony_ci if (ei != stats_size) 154962306a36Sopenharmony_ci dev_err(dev->mt76.dev, "ei: %d size: %d", ei, stats_size); 155062306a36Sopenharmony_ci} 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic void 155362306a36Sopenharmony_cimt7915_twt_teardown_request(struct ieee80211_hw *hw, 155462306a36Sopenharmony_ci struct ieee80211_sta *sta, 155562306a36Sopenharmony_ci u8 flowid) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 155862306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 156162306a36Sopenharmony_ci mt7915_mac_twt_teardown_flow(dev, msta, flowid); 156262306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 156362306a36Sopenharmony_ci} 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic int 156662306a36Sopenharmony_cimt7915_set_radar_background(struct ieee80211_hw *hw, 156762306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 156862306a36Sopenharmony_ci{ 156962306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 157062306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 157162306a36Sopenharmony_ci int ret = -EINVAL; 157262306a36Sopenharmony_ci bool running; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (dev->mt76.region == NL80211_DFS_UNSET) 157762306a36Sopenharmony_ci goto out; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (dev->rdd2_phy && dev->rdd2_phy != phy) { 158062306a36Sopenharmony_ci /* rdd2 is already locked */ 158162306a36Sopenharmony_ci ret = -EBUSY; 158262306a36Sopenharmony_ci goto out; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* rdd2 already configured on a radar channel */ 158662306a36Sopenharmony_ci running = dev->rdd2_phy && 158762306a36Sopenharmony_ci cfg80211_chandef_valid(&dev->rdd2_chandef) && 158862306a36Sopenharmony_ci !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci if (!chandef || running || 159162306a36Sopenharmony_ci !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { 159262306a36Sopenharmony_ci ret = mt7915_mcu_rdd_background_enable(phy, NULL); 159362306a36Sopenharmony_ci if (ret) 159462306a36Sopenharmony_ci goto out; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (!running) 159762306a36Sopenharmony_ci goto update_phy; 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci ret = mt7915_mcu_rdd_background_enable(phy, chandef); 160162306a36Sopenharmony_ci if (ret) 160262306a36Sopenharmony_ci goto out; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ciupdate_phy: 160562306a36Sopenharmony_ci dev->rdd2_phy = chandef ? phy : NULL; 160662306a36Sopenharmony_ci if (chandef) 160762306a36Sopenharmony_ci dev->rdd2_chandef = *chandef; 160862306a36Sopenharmony_ciout: 160962306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci return ret; 161262306a36Sopenharmony_ci} 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci#ifdef CONFIG_NET_MEDIATEK_SOC_WED 161562306a36Sopenharmony_cistatic int 161662306a36Sopenharmony_cimt7915_net_fill_forward_path(struct ieee80211_hw *hw, 161762306a36Sopenharmony_ci struct ieee80211_vif *vif, 161862306a36Sopenharmony_ci struct ieee80211_sta *sta, 161962306a36Sopenharmony_ci struct net_device_path_ctx *ctx, 162062306a36Sopenharmony_ci struct net_device_path *path) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; 162362306a36Sopenharmony_ci struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; 162462306a36Sopenharmony_ci struct mt7915_dev *dev = mt7915_hw_dev(hw); 162562306a36Sopenharmony_ci struct mt7915_phy *phy = mt7915_hw_phy(hw); 162662306a36Sopenharmony_ci struct mtk_wed_device *wed = &dev->mt76.mmio.wed; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci if (!mtk_wed_device_active(wed)) 162962306a36Sopenharmony_ci return -ENODEV; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci if (msta->wcid.idx > 0xff) 163262306a36Sopenharmony_ci return -EIO; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci path->type = DEV_PATH_MTK_WDMA; 163562306a36Sopenharmony_ci path->dev = ctx->dev; 163662306a36Sopenharmony_ci path->mtk_wdma.wdma_idx = wed->wdma_idx; 163762306a36Sopenharmony_ci path->mtk_wdma.bss = mvif->mt76.idx; 163862306a36Sopenharmony_ci path->mtk_wdma.wcid = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff; 163962306a36Sopenharmony_ci path->mtk_wdma.queue = phy != &dev->phy; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci ctx->dev = NULL; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci return 0; 164462306a36Sopenharmony_ci} 164562306a36Sopenharmony_ci#endif 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ciconst struct ieee80211_ops mt7915_ops = { 164862306a36Sopenharmony_ci .tx = mt7915_tx, 164962306a36Sopenharmony_ci .start = mt7915_start, 165062306a36Sopenharmony_ci .stop = mt7915_stop, 165162306a36Sopenharmony_ci .add_interface = mt7915_add_interface, 165262306a36Sopenharmony_ci .remove_interface = mt7915_remove_interface, 165362306a36Sopenharmony_ci .config = mt7915_config, 165462306a36Sopenharmony_ci .conf_tx = mt7915_conf_tx, 165562306a36Sopenharmony_ci .configure_filter = mt7915_configure_filter, 165662306a36Sopenharmony_ci .bss_info_changed = mt7915_bss_info_changed, 165762306a36Sopenharmony_ci .start_ap = mt7915_start_ap, 165862306a36Sopenharmony_ci .stop_ap = mt7915_stop_ap, 165962306a36Sopenharmony_ci .sta_add = mt7915_sta_add, 166062306a36Sopenharmony_ci .sta_remove = mt7915_sta_remove, 166162306a36Sopenharmony_ci .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 166262306a36Sopenharmony_ci .sta_rc_update = mt7915_sta_rc_update, 166362306a36Sopenharmony_ci .set_key = mt7915_set_key, 166462306a36Sopenharmony_ci .ampdu_action = mt7915_ampdu_action, 166562306a36Sopenharmony_ci .set_rts_threshold = mt7915_set_rts_threshold, 166662306a36Sopenharmony_ci .wake_tx_queue = mt76_wake_tx_queue, 166762306a36Sopenharmony_ci .sw_scan_start = mt76_sw_scan, 166862306a36Sopenharmony_ci .sw_scan_complete = mt76_sw_scan_complete, 166962306a36Sopenharmony_ci .release_buffered_frames = mt76_release_buffered_frames, 167062306a36Sopenharmony_ci .get_txpower = mt76_get_txpower, 167162306a36Sopenharmony_ci .set_sar_specs = mt7915_set_sar_specs, 167262306a36Sopenharmony_ci .channel_switch_beacon = mt7915_channel_switch_beacon, 167362306a36Sopenharmony_ci .get_stats = mt7915_get_stats, 167462306a36Sopenharmony_ci .get_et_sset_count = mt7915_get_et_sset_count, 167562306a36Sopenharmony_ci .get_et_stats = mt7915_get_et_stats, 167662306a36Sopenharmony_ci .get_et_strings = mt7915_get_et_strings, 167762306a36Sopenharmony_ci .get_tsf = mt7915_get_tsf, 167862306a36Sopenharmony_ci .set_tsf = mt7915_set_tsf, 167962306a36Sopenharmony_ci .offset_tsf = mt7915_offset_tsf, 168062306a36Sopenharmony_ci .get_survey = mt76_get_survey, 168162306a36Sopenharmony_ci .get_antenna = mt76_get_antenna, 168262306a36Sopenharmony_ci .set_antenna = mt7915_set_antenna, 168362306a36Sopenharmony_ci .set_bitrate_mask = mt7915_set_bitrate_mask, 168462306a36Sopenharmony_ci .set_coverage_class = mt7915_set_coverage_class, 168562306a36Sopenharmony_ci .sta_statistics = mt7915_sta_statistics, 168662306a36Sopenharmony_ci .sta_set_txpwr = mt7915_sta_set_txpwr, 168762306a36Sopenharmony_ci .sta_set_4addr = mt7915_sta_set_4addr, 168862306a36Sopenharmony_ci .sta_set_decap_offload = mt7915_sta_set_decap_offload, 168962306a36Sopenharmony_ci .add_twt_setup = mt7915_mac_add_twt_setup, 169062306a36Sopenharmony_ci .twt_teardown_request = mt7915_twt_teardown_request, 169162306a36Sopenharmony_ci CFG80211_TESTMODE_CMD(mt76_testmode_cmd) 169262306a36Sopenharmony_ci CFG80211_TESTMODE_DUMP(mt76_testmode_dump) 169362306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS 169462306a36Sopenharmony_ci .sta_add_debugfs = mt7915_sta_add_debugfs, 169562306a36Sopenharmony_ci#endif 169662306a36Sopenharmony_ci .set_radar_background = mt7915_set_radar_background, 169762306a36Sopenharmony_ci#ifdef CONFIG_NET_MEDIATEK_SOC_WED 169862306a36Sopenharmony_ci .net_fill_forward_path = mt7915_net_fill_forward_path, 169962306a36Sopenharmony_ci#endif 170062306a36Sopenharmony_ci}; 1701