162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2022 MediaTek Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "mt7996.h" 762306a36Sopenharmony_ci#include "mcu.h" 862306a36Sopenharmony_ci#include "mac.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic bool mt7996_dev_running(struct mt7996_dev *dev) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci struct mt7996_phy *phy; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 1562306a36Sopenharmony_ci return true; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci phy = mt7996_phy2(dev); 1862306a36Sopenharmony_ci if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 1962306a36Sopenharmony_ci return true; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci phy = mt7996_phy3(dev); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint mt7996_run(struct ieee80211_hw *hw) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 2962306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 3062306a36Sopenharmony_ci bool running; 3162306a36Sopenharmony_ci int ret; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci running = mt7996_dev_running(dev); 3462306a36Sopenharmony_ci if (!running) { 3562306a36Sopenharmony_ci ret = mt7996_mcu_set_hdr_trans(dev, true); 3662306a36Sopenharmony_ci if (ret) 3762306a36Sopenharmony_ci goto out; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci mt7996_mac_enable_nf(dev, phy->mt76->band_idx); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci ret = mt7996_mcu_set_rts_thresh(phy, 0x92b); 4362306a36Sopenharmony_ci if (ret) 4462306a36Sopenharmony_ci goto out; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci ret = mt7996_mcu_set_radio_en(phy, true); 4762306a36Sopenharmony_ci if (ret) 4862306a36Sopenharmony_ci goto out; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); 5162306a36Sopenharmony_ci if (ret) 5262306a36Sopenharmony_ci goto out; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci set_bit(MT76_STATE_RUNNING, &phy->mt76->state); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, 5762306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (!running) 6062306a36Sopenharmony_ci mt7996_mac_reset_counters(phy); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciout: 6362306a36Sopenharmony_ci return ret; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int mt7996_start(struct ieee80211_hw *hw) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 6962306a36Sopenharmony_ci int ret; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci flush_work(&dev->init_work); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 7462306a36Sopenharmony_ci ret = mt7996_run(hw); 7562306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return ret; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void mt7996_stop(struct ieee80211_hw *hw) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 8362306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci cancel_delayed_work_sync(&phy->mt76->mac_work); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci mt7996_mcu_set_radio_en(phy, false); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic inline int get_free_idx(u32 mask, u8 start, u8 end) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci return ffs(~mask & GENMASK(end, start)); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int get_omac_idx(enum nl80211_iftype type, u64 mask) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int i; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci switch (type) { 10662306a36Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 10762306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 10862306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 10962306a36Sopenharmony_ci /* prefer hw bssid slot 1-3 */ 11062306a36Sopenharmony_ci i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); 11162306a36Sopenharmony_ci if (i) 11262306a36Sopenharmony_ci return i - 1; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (type != NL80211_IFTYPE_STATION) 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 11862306a36Sopenharmony_ci if (i) 11962306a36Sopenharmony_ci return i - 1; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (~mask & BIT(HW_BSSID_0)) 12262306a36Sopenharmony_ci return HW_BSSID_0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case NL80211_IFTYPE_MONITOR: 12662306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 12762306a36Sopenharmony_ci /* ap uses hw bssid 0 and ext bssid */ 12862306a36Sopenharmony_ci if (~mask & BIT(HW_BSSID_0)) 12962306a36Sopenharmony_ci return HW_BSSID_0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 13262306a36Sopenharmony_ci if (i) 13362306a36Sopenharmony_ci return i - 1; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci WARN_ON(1); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return -1; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void mt7996_init_bitrate_mask(struct ieee80211_vif *vif) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 14762306a36Sopenharmony_ci int i; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { 15062306a36Sopenharmony_ci mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; 15162306a36Sopenharmony_ci mvif->bitrate_mask.control[i].he_gi = 0xff; 15262306a36Sopenharmony_ci mvif->bitrate_mask.control[i].he_ltf = 0xff; 15362306a36Sopenharmony_ci mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); 15462306a36Sopenharmony_ci memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, 15562306a36Sopenharmony_ci sizeof(mvif->bitrate_mask.control[i].ht_mcs)); 15662306a36Sopenharmony_ci memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, 15762306a36Sopenharmony_ci sizeof(mvif->bitrate_mask.control[i].vht_mcs)); 15862306a36Sopenharmony_ci memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, 15962306a36Sopenharmony_ci sizeof(mvif->bitrate_mask.control[i].he_mcs)); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int mt7996_add_interface(struct ieee80211_hw *hw, 16462306a36Sopenharmony_ci struct ieee80211_vif *vif) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 16762306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 16862306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 16962306a36Sopenharmony_ci struct mt76_txq *mtxq; 17062306a36Sopenharmony_ci u8 band_idx = phy->mt76->band_idx; 17162306a36Sopenharmony_ci int idx, ret = 0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_MONITOR && 17662306a36Sopenharmony_ci is_zero_ether_addr(vif->addr)) 17762306a36Sopenharmony_ci phy->monitor_vif = vif; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); 18062306a36Sopenharmony_ci if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) { 18162306a36Sopenharmony_ci ret = -ENOSPC; 18262306a36Sopenharmony_ci goto out; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci idx = get_omac_idx(vif->type, phy->omac_mask); 18662306a36Sopenharmony_ci if (idx < 0) { 18762306a36Sopenharmony_ci ret = -ENOSPC; 18862306a36Sopenharmony_ci goto out; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci mvif->mt76.omac_idx = idx; 19162306a36Sopenharmony_ci mvif->phy = phy; 19262306a36Sopenharmony_ci mvif->mt76.band_idx = band_idx; 19362306a36Sopenharmony_ci mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ret = mt7996_mcu_add_dev_info(phy, vif, true); 19662306a36Sopenharmony_ci if (ret) 19762306a36Sopenharmony_ci goto out; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); 20062306a36Sopenharmony_ci phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci idx = MT7996_WTBL_RESERVED - mvif->mt76.idx; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci INIT_LIST_HEAD(&mvif->sta.rc_list); 20562306a36Sopenharmony_ci INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); 20662306a36Sopenharmony_ci mvif->sta.wcid.idx = idx; 20762306a36Sopenharmony_ci mvif->sta.wcid.phy_idx = band_idx; 20862306a36Sopenharmony_ci mvif->sta.wcid.hw_key_idx = -1; 20962306a36Sopenharmony_ci mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; 21062306a36Sopenharmony_ci mt76_packet_id_init(&mvif->sta.wcid); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci mt7996_mac_wtbl_update(dev, idx, 21362306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (vif->txq) { 21662306a36Sopenharmony_ci mtxq = (struct mt76_txq *)vif->txq->drv_priv; 21762306a36Sopenharmony_ci mtxq->wcid = idx; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP && 22162306a36Sopenharmony_ci (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) 22262306a36Sopenharmony_ci vif->offload_flags = 0; 22362306a36Sopenharmony_ci vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) 22662306a36Sopenharmony_ci mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci mt7996_init_bitrate_mask(vif); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci mt7996_mcu_add_bss_info(phy, vif, true); 23362306a36Sopenharmony_ci mt7996_mcu_add_sta(dev, vif, NULL, true); 23462306a36Sopenharmony_ci rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciout: 23762306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return ret; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void mt7996_remove_interface(struct ieee80211_hw *hw, 24362306a36Sopenharmony_ci struct ieee80211_vif *vif) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 24662306a36Sopenharmony_ci struct mt7996_sta *msta = &mvif->sta; 24762306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 24862306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 24962306a36Sopenharmony_ci int idx = msta->wcid.idx; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci mt7996_mcu_add_bss_info(phy, vif, false); 25262306a36Sopenharmony_ci mt7996_mcu_add_sta(dev, vif, NULL, false); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (vif == phy->monitor_vif) 25562306a36Sopenharmony_ci phy->monitor_vif = NULL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci mt7996_mcu_add_dev_info(phy, vif, false); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci rcu_assign_pointer(dev->mt76.wcid[idx], NULL); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 26262306a36Sopenharmony_ci dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); 26362306a36Sopenharmony_ci phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); 26462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 26762306a36Sopenharmony_ci if (!list_empty(&msta->wcid.poll_list)) 26862306a36Sopenharmony_ci list_del_init(&msta->wcid.poll_list); 26962306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci mt76_packet_id_flush(&dev->mt76, &msta->wcid); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ciint mt7996_set_channel(struct mt7996_phy *phy) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 27762306a36Sopenharmony_ci int ret; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci cancel_delayed_work_sync(&phy->mt76->mac_work); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 28262306a36Sopenharmony_ci set_bit(MT76_RESET, &phy->mt76->state); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci mt76_set_channel(phy->mt76); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); 28762306a36Sopenharmony_ci if (ret) 28862306a36Sopenharmony_ci goto out; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ret = mt7996_dfs_init_radar_detector(phy); 29162306a36Sopenharmony_ci mt7996_mac_cca_stats_reset(phy); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci mt7996_mac_reset_counters(phy); 29462306a36Sopenharmony_ci phy->noise = 0; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciout: 29762306a36Sopenharmony_ci clear_bit(MT76_RESET, &phy->mt76->state); 29862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci mt76_txq_schedule_all(phy->mt76); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ieee80211_queue_delayed_work(phy->mt76->hw, 30362306a36Sopenharmony_ci &phy->mt76->mac_work, 30462306a36Sopenharmony_ci MT7996_WATCHDOG_TIME); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return ret; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 31062306a36Sopenharmony_ci struct ieee80211_vif *vif, struct ieee80211_sta *sta, 31162306a36Sopenharmony_ci struct ieee80211_key_conf *key) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 31462306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 31562306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 31662306a36Sopenharmony_ci struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : 31762306a36Sopenharmony_ci &mvif->sta; 31862306a36Sopenharmony_ci struct mt76_wcid *wcid = &msta->wcid; 31962306a36Sopenharmony_ci u8 *wcid_keyidx = &wcid->hw_key_idx; 32062306a36Sopenharmony_ci int idx = key->keyidx; 32162306a36Sopenharmony_ci int err = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* The hardware does not support per-STA RX GTK, fallback 32462306a36Sopenharmony_ci * to software mode for these. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci if ((vif->type == NL80211_IFTYPE_ADHOC || 32762306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_MESH_POINT) && 32862306a36Sopenharmony_ci (key->cipher == WLAN_CIPHER_SUITE_TKIP || 32962306a36Sopenharmony_ci key->cipher == WLAN_CIPHER_SUITE_CCMP) && 33062306a36Sopenharmony_ci !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 33162306a36Sopenharmony_ci return -EOPNOTSUPP; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* fall back to sw encryption for unsupported ciphers */ 33462306a36Sopenharmony_ci switch (key->cipher) { 33562306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_AES_CMAC: 33662306a36Sopenharmony_ci wcid_keyidx = &wcid->hw_key_idx2; 33762306a36Sopenharmony_ci key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 34062306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 34162306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 34262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 34362306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 34462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_SMS4: 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 34762306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci return -EOPNOTSUPP; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { 35562306a36Sopenharmony_ci mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); 35662306a36Sopenharmony_ci mt7996_mcu_add_bss_info(phy, vif, true); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (cmd == SET_KEY) { 36062306a36Sopenharmony_ci *wcid_keyidx = idx; 36162306a36Sopenharmony_ci } else { 36262306a36Sopenharmony_ci if (idx == *wcid_keyidx) 36362306a36Sopenharmony_ci *wcid_keyidx = -1; 36462306a36Sopenharmony_ci goto out; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci mt76_wcid_key_setup(&dev->mt76, wcid, key); 36862306a36Sopenharmony_ci err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, 36962306a36Sopenharmony_ci key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), 37062306a36Sopenharmony_ci &msta->wcid, cmd); 37162306a36Sopenharmony_ciout: 37262306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return err; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int mt7996_config(struct ieee80211_hw *hw, u32 changed) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 38062306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 38162306a36Sopenharmony_ci int ret; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 38462306a36Sopenharmony_ci ieee80211_stop_queues(hw); 38562306a36Sopenharmony_ci ret = mt7996_set_channel(phy); 38662306a36Sopenharmony_ci if (ret) 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci ieee80211_wake_queues(hw); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 39462306a36Sopenharmony_ci bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!enabled) 39762306a36Sopenharmony_ci phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; 39862306a36Sopenharmony_ci else 39962306a36Sopenharmony_ci phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), 40262306a36Sopenharmony_ci MT_DMA_DCR0_RXD_G5_EN, enabled); 40362306a36Sopenharmony_ci mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int 41262306a36Sopenharmony_cimt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 41362306a36Sopenharmony_ci unsigned int link_id, u16 queue, 41462306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 41762306a36Sopenharmony_ci const u8 mq_to_aci[] = { 41862306a36Sopenharmony_ci [IEEE80211_AC_VO] = 3, 41962306a36Sopenharmony_ci [IEEE80211_AC_VI] = 2, 42062306a36Sopenharmony_ci [IEEE80211_AC_BE] = 0, 42162306a36Sopenharmony_ci [IEEE80211_AC_BK] = 1, 42262306a36Sopenharmony_ci }; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* firmware uses access class index */ 42562306a36Sopenharmony_ci mvif->queue_params[mq_to_aci[queue]] = *params; 42662306a36Sopenharmony_ci /* no need to update right away, we'll get BSS_CHANGED_QOS */ 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void mt7996_configure_filter(struct ieee80211_hw *hw, 43262306a36Sopenharmony_ci unsigned int changed_flags, 43362306a36Sopenharmony_ci unsigned int *total_flags, 43462306a36Sopenharmony_ci u64 multicast) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 43762306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 43862306a36Sopenharmony_ci u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | 43962306a36Sopenharmony_ci MT_WF_RFCR1_DROP_BF_POLL | 44062306a36Sopenharmony_ci MT_WF_RFCR1_DROP_BA | 44162306a36Sopenharmony_ci MT_WF_RFCR1_DROP_CFEND | 44262306a36Sopenharmony_ci MT_WF_RFCR1_DROP_CFACK; 44362306a36Sopenharmony_ci u32 flags = 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci#define MT76_FILTER(_flag, _hw) do { \ 44662306a36Sopenharmony_ci flags |= *total_flags & FIF_##_flag; \ 44762306a36Sopenharmony_ci phy->rxfilter &= ~(_hw); \ 44862306a36Sopenharmony_ci phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 44962306a36Sopenharmony_ci } while (0) 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | 45462306a36Sopenharmony_ci MT_WF_RFCR_DROP_OTHER_BEACON | 45562306a36Sopenharmony_ci MT_WF_RFCR_DROP_FRAME_REPORT | 45662306a36Sopenharmony_ci MT_WF_RFCR_DROP_PROBEREQ | 45762306a36Sopenharmony_ci MT_WF_RFCR_DROP_MCAST_FILTERED | 45862306a36Sopenharmony_ci MT_WF_RFCR_DROP_MCAST | 45962306a36Sopenharmony_ci MT_WF_RFCR_DROP_BCAST | 46062306a36Sopenharmony_ci MT_WF_RFCR_DROP_DUPLICATE | 46162306a36Sopenharmony_ci MT_WF_RFCR_DROP_A2_BSSID | 46262306a36Sopenharmony_ci MT_WF_RFCR_DROP_UNWANTED_CTL | 46362306a36Sopenharmony_ci MT_WF_RFCR_DROP_STBC_MULTI); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | 46662306a36Sopenharmony_ci MT_WF_RFCR_DROP_A3_MAC | 46762306a36Sopenharmony_ci MT_WF_RFCR_DROP_A3_BSSID); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | 47262306a36Sopenharmony_ci MT_WF_RFCR_DROP_RTS | 47362306a36Sopenharmony_ci MT_WF_RFCR_DROP_CTL_RSV | 47462306a36Sopenharmony_ci MT_WF_RFCR_DROP_NDPA); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci *total_flags = flags; 47762306a36Sopenharmony_ci mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (*total_flags & FIF_CONTROL) 48062306a36Sopenharmony_ci mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 48162306a36Sopenharmony_ci else 48262306a36Sopenharmony_ci mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void 48862306a36Sopenharmony_cimt7996_update_bss_color(struct ieee80211_hw *hw, 48962306a36Sopenharmony_ci struct ieee80211_vif *vif, 49062306a36Sopenharmony_ci struct cfg80211_he_bss_color *bss_color) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci switch (vif->type) { 49562306a36Sopenharmony_ci case NL80211_IFTYPE_AP: { 49662306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (mvif->mt76.omac_idx > HW_BSSID_MAX) 49962306a36Sopenharmony_ci return; 50062306a36Sopenharmony_ci fallthrough; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 50362306a36Sopenharmony_ci mt7996_mcu_update_bss_color(dev, vif, bss_color); 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci default: 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic u8 51162306a36Sopenharmony_cimt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 51262306a36Sopenharmony_ci bool beacon, bool mcast) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 51562306a36Sopenharmony_ci struct mt76_phy *mphy = hw->priv; 51662306a36Sopenharmony_ci u16 rate; 51762306a36Sopenharmony_ci u8 i, idx, ht; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); 52062306a36Sopenharmony_ci ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (beacon && ht) { 52362306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* must odd index */ 52662306a36Sopenharmony_ci idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20); 52762306a36Sopenharmony_ci mt7996_mac_set_fixed_rate_table(dev, idx, rate); 52862306a36Sopenharmony_ci return idx; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci idx = FIELD_GET(MT_TX_RATE_IDX, rate); 53262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) 53362306a36Sopenharmony_ci if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) 53462306a36Sopenharmony_ci return MT7996_BASIC_RATES_TBL + i; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return mvif->basic_rates_idx; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void 54062306a36Sopenharmony_cimt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 54162306a36Sopenharmony_ci struct ieee80211_bss_conf *info) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 54462306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 54562306a36Sopenharmony_ci u8 band = mvif->mt76.band_idx; 54662306a36Sopenharmony_ci u32 *mu; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci mu = (u32 *)info->mu_group.membership; 54962306a36Sopenharmony_ci mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]); 55062306a36Sopenharmony_ci mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci mu = (u32 *)info->mu_group.position; 55362306a36Sopenharmony_ci mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]); 55462306a36Sopenharmony_ci mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]); 55562306a36Sopenharmony_ci mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]); 55662306a36Sopenharmony_ci mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic void mt7996_bss_info_changed(struct ieee80211_hw *hw, 56062306a36Sopenharmony_ci struct ieee80211_vif *vif, 56162306a36Sopenharmony_ci struct ieee80211_bss_conf *info, 56262306a36Sopenharmony_ci u64 changed) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 56562306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 56662306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* station mode uses BSSID to map the wlan entry to a peer, 57162306a36Sopenharmony_ci * and then peer references bss_info_rfch to set bandwidth cap. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci if (changed & BSS_CHANGED_BSSID && 57462306a36Sopenharmony_ci vif->type == NL80211_IFTYPE_STATION) { 57562306a36Sopenharmony_ci bool join = !is_zero_ether_addr(info->bssid); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci mt7996_mcu_add_bss_info(phy, vif, join); 57862306a36Sopenharmony_ci mt7996_mcu_add_sta(dev, vif, NULL, join); 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) 58262306a36Sopenharmony_ci mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_CTS_PROT) 58562306a36Sopenharmony_ci mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) { 58862306a36Sopenharmony_ci int slottime = info->use_short_slot ? 9 : 20; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (slottime != phy->slottime) { 59162306a36Sopenharmony_ci phy->slottime = slottime; 59262306a36Sopenharmony_ci mt7996_mcu_set_timing(phy, vif); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (changed & BSS_CHANGED_MCAST_RATE) 59762306a36Sopenharmony_ci mvif->mcast_rates_idx = 59862306a36Sopenharmony_ci mt7996_get_rates_table(hw, vif, false, true); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (changed & BSS_CHANGED_BASIC_RATES) 60162306a36Sopenharmony_ci mvif->basic_rates_idx = 60262306a36Sopenharmony_ci mt7996_get_rates_table(hw, vif, false, false); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { 60562306a36Sopenharmony_ci mt7996_mcu_add_bss_info(phy, vif, true); 60662306a36Sopenharmony_ci mt7996_mcu_add_sta(dev, vif, NULL, true); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* ensure that enable txcmd_mode after bss_info */ 61062306a36Sopenharmony_ci if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) 61162306a36Sopenharmony_ci mt7996_mcu_set_tx(dev, vif); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_OBSS_PD) 61462306a36Sopenharmony_ci mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_BSS_COLOR) 61762306a36Sopenharmony_ci mt7996_update_bss_color(hw, vif, &info->he_bss_color); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (changed & (BSS_CHANGED_BEACON | 62062306a36Sopenharmony_ci BSS_CHANGED_BEACON_ENABLED)) { 62162306a36Sopenharmony_ci mvif->beacon_rates_idx = 62262306a36Sopenharmony_ci mt7996_get_rates_table(hw, vif, true, false); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | 62862306a36Sopenharmony_ci BSS_CHANGED_FILS_DISCOVERY)) 62962306a36Sopenharmony_ci mt7996_mcu_beacon_inband_discov(dev, vif, changed); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (changed & BSS_CHANGED_MU_GROUPS) 63262306a36Sopenharmony_ci mt7996_update_mu_group(hw, vif, info); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic void 63862306a36Sopenharmony_cimt7996_channel_switch_beacon(struct ieee80211_hw *hw, 63962306a36Sopenharmony_ci struct ieee80211_vif *vif, 64062306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 64562306a36Sopenharmony_ci mt7996_mcu_add_beacon(hw, vif, true); 64662306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ciint mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 65062306a36Sopenharmony_ci struct ieee80211_sta *sta) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 65362306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 65462306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 65562306a36Sopenharmony_ci u8 band_idx = mvif->phy->mt76->band_idx; 65662306a36Sopenharmony_ci int ret, idx; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); 65962306a36Sopenharmony_ci if (idx < 0) 66062306a36Sopenharmony_ci return -ENOSPC; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci INIT_LIST_HEAD(&msta->rc_list); 66362306a36Sopenharmony_ci INIT_LIST_HEAD(&msta->wcid.poll_list); 66462306a36Sopenharmony_ci msta->vif = mvif; 66562306a36Sopenharmony_ci msta->wcid.sta = 1; 66662306a36Sopenharmony_ci msta->wcid.idx = idx; 66762306a36Sopenharmony_ci msta->wcid.phy_idx = band_idx; 66862306a36Sopenharmony_ci msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 66962306a36Sopenharmony_ci msta->jiffies = jiffies; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ewma_avg_signal_init(&msta->avg_ack_signal); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci mt7996_mac_wtbl_update(dev, idx, 67462306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ret = mt7996_mcu_add_sta(dev, vif, sta, true); 67762306a36Sopenharmony_ci if (ret) 67862306a36Sopenharmony_ci return ret; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_civoid mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 68462306a36Sopenharmony_ci struct ieee80211_sta *sta) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 68762306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 68862306a36Sopenharmony_ci int i; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci mt7996_mcu_add_sta(dev, vif, sta, false); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci mt7996_mac_wtbl_update(dev, msta->wcid.idx, 69362306a36Sopenharmony_ci MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) 69662306a36Sopenharmony_ci mt7996_mac_twt_teardown_flow(dev, msta, i); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci spin_lock_bh(&mdev->sta_poll_lock); 69962306a36Sopenharmony_ci if (!list_empty(&msta->wcid.poll_list)) 70062306a36Sopenharmony_ci list_del_init(&msta->wcid.poll_list); 70162306a36Sopenharmony_ci if (!list_empty(&msta->rc_list)) 70262306a36Sopenharmony_ci list_del_init(&msta->rc_list); 70362306a36Sopenharmony_ci spin_unlock_bh(&mdev->sta_poll_lock); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic void mt7996_tx(struct ieee80211_hw *hw, 70762306a36Sopenharmony_ci struct ieee80211_tx_control *control, 70862306a36Sopenharmony_ci struct sk_buff *skb) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 71162306a36Sopenharmony_ci struct mt76_phy *mphy = hw->priv; 71262306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 71362306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 71462306a36Sopenharmony_ci struct mt76_wcid *wcid = &dev->mt76.global_wcid; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (control->sta) { 71762306a36Sopenharmony_ci struct mt7996_sta *sta; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci sta = (struct mt7996_sta *)control->sta->drv_priv; 72062306a36Sopenharmony_ci wcid = &sta->wcid; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (vif && !control->sta) { 72462306a36Sopenharmony_ci struct mt7996_vif *mvif; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci mvif = (struct mt7996_vif *)vif->drv_priv; 72762306a36Sopenharmony_ci wcid = &mvif->sta.wcid; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci mt76_tx(mphy, control->sta, wcid, skb); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 73662306a36Sopenharmony_ci int ret; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci mutex_lock(&phy->dev->mt76.mutex); 73962306a36Sopenharmony_ci ret = mt7996_mcu_set_rts_thresh(phy, val); 74062306a36Sopenharmony_ci mutex_unlock(&phy->dev->mt76.mutex); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci return ret; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic int 74662306a36Sopenharmony_cimt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 74762306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci enum ieee80211_ampdu_mlme_action action = params->action; 75062306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 75162306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 75262306a36Sopenharmony_ci struct ieee80211_txq *txq = sta->txq[params->tid]; 75362306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 75462306a36Sopenharmony_ci u16 tid = params->tid; 75562306a36Sopenharmony_ci u16 ssn = params->ssn; 75662306a36Sopenharmony_ci struct mt76_txq *mtxq; 75762306a36Sopenharmony_ci int ret = 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (!txq) 76062306a36Sopenharmony_ci return -EINVAL; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci mtxq = (struct mt76_txq *)txq->drv_priv; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 76562306a36Sopenharmony_ci switch (action) { 76662306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 76762306a36Sopenharmony_ci mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, 76862306a36Sopenharmony_ci params->buf_size); 76962306a36Sopenharmony_ci ret = mt7996_mcu_add_rx_ba(dev, params, true); 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 77262306a36Sopenharmony_ci mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 77362306a36Sopenharmony_ci ret = mt7996_mcu_add_rx_ba(dev, params, false); 77462306a36Sopenharmony_ci break; 77562306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 77662306a36Sopenharmony_ci mtxq->aggr = true; 77762306a36Sopenharmony_ci mtxq->send_bar = false; 77862306a36Sopenharmony_ci ret = mt7996_mcu_add_tx_ba(dev, params, true); 77962306a36Sopenharmony_ci break; 78062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 78162306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 78262306a36Sopenharmony_ci mtxq->aggr = false; 78362306a36Sopenharmony_ci clear_bit(tid, &msta->wcid.ampdu_state); 78462306a36Sopenharmony_ci ret = mt7996_mcu_add_tx_ba(dev, params, false); 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 78762306a36Sopenharmony_ci set_bit(tid, &msta->wcid.ampdu_state); 78862306a36Sopenharmony_ci ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 79162306a36Sopenharmony_ci mtxq->aggr = false; 79262306a36Sopenharmony_ci clear_bit(tid, &msta->wcid.ampdu_state); 79362306a36Sopenharmony_ci ret = mt7996_mcu_add_tx_ba(dev, params, false); 79462306a36Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return ret; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic int 80362306a36Sopenharmony_cimt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 80462306a36Sopenharmony_ci struct ieee80211_sta *sta) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, 80762306a36Sopenharmony_ci IEEE80211_STA_NONE); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic int 81162306a36Sopenharmony_cimt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 81262306a36Sopenharmony_ci struct ieee80211_sta *sta) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, 81562306a36Sopenharmony_ci IEEE80211_STA_NOTEXIST); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic int 81962306a36Sopenharmony_cimt7996_get_stats(struct ieee80211_hw *hw, 82062306a36Sopenharmony_ci struct ieee80211_low_level_stats *stats) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 82362306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 82462306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci stats->dot11RTSSuccessCount = mib->rts_cnt; 82962306a36Sopenharmony_ci stats->dot11RTSFailureCount = mib->rts_retries_cnt; 83062306a36Sopenharmony_ci stats->dot11FCSErrorCount = mib->fcs_err_cnt; 83162306a36Sopenharmony_ci stats->dot11ACKFailureCount = mib->ack_fail_cnt; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci return 0; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ciu64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 84162306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 84262306a36Sopenharmony_ci union { 84362306a36Sopenharmony_ci u64 t64; 84462306a36Sopenharmony_ci u32 t32[2]; 84562306a36Sopenharmony_ci } tsf; 84662306a36Sopenharmony_ci u16 n; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci lockdep_assert_held(&dev->mt76.mutex); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 85162306a36Sopenharmony_ci : mvif->mt76.omac_idx; 85262306a36Sopenharmony_ci /* TSF software read */ 85362306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 85462306a36Sopenharmony_ci MT_LPON_TCR_SW_READ); 85562306a36Sopenharmony_ci tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(phy->mt76->band_idx)); 85662306a36Sopenharmony_ci tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(phy->mt76->band_idx)); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci return tsf.t64; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic u64 86262306a36Sopenharmony_cimt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 86562306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 86662306a36Sopenharmony_ci u64 ret; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 86962306a36Sopenharmony_ci ret = __mt7996_get_tsf(hw, mvif); 87062306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return ret; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic void 87662306a36Sopenharmony_cimt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 87762306a36Sopenharmony_ci u64 timestamp) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 88062306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 88162306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 88262306a36Sopenharmony_ci union { 88362306a36Sopenharmony_ci u64 t64; 88462306a36Sopenharmony_ci u32 t32[2]; 88562306a36Sopenharmony_ci } tsf = { .t64 = timestamp, }; 88662306a36Sopenharmony_ci u16 n; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 89162306a36Sopenharmony_ci : mvif->mt76.omac_idx; 89262306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 89362306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 89462306a36Sopenharmony_ci /* TSF software overwrite */ 89562306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 89662306a36Sopenharmony_ci MT_LPON_TCR_SW_WRITE); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic void 90262306a36Sopenharmony_cimt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 90362306a36Sopenharmony_ci s64 timestamp) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 90662306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 90762306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 90862306a36Sopenharmony_ci union { 90962306a36Sopenharmony_ci u64 t64; 91062306a36Sopenharmony_ci u32 t32[2]; 91162306a36Sopenharmony_ci } tsf = { .t64 = timestamp, }; 91262306a36Sopenharmony_ci u16 n; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 91762306a36Sopenharmony_ci : mvif->mt76.omac_idx; 91862306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 91962306a36Sopenharmony_ci mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 92062306a36Sopenharmony_ci /* TSF software adjust*/ 92162306a36Sopenharmony_ci mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 92262306a36Sopenharmony_ci MT_LPON_TCR_SW_ADJUST); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic void 92862306a36Sopenharmony_cimt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 93162306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 93462306a36Sopenharmony_ci phy->coverage_class = max_t(s16, coverage_class, 0); 93562306a36Sopenharmony_ci mt7996_mac_set_coverage_class(phy); 93662306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic int 94062306a36Sopenharmony_cimt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 94362306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 94462306a36Sopenharmony_ci int max_nss = hweight8(hw->wiphy->available_antennas_tx); 94562306a36Sopenharmony_ci u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) 94862306a36Sopenharmony_ci return -EINVAL; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) 95162306a36Sopenharmony_ci tx_ant = BIT(ffs(tx_ant) - 1) - 1; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci phy->mt76->antenna_mask = tx_ant; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci /* restore to the origin chainmask which might have auxiliary path */ 95862306a36Sopenharmony_ci if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) 95962306a36Sopenharmony_ci phy->mt76->chainmask = ((dev->chainmask >> shift) & 96062306a36Sopenharmony_ci (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; 96162306a36Sopenharmony_ci else if (hweight8(tx_ant) == max_nss) 96262306a36Sopenharmony_ci phy->mt76->chainmask = (dev->chainmask >> shift) << shift; 96362306a36Sopenharmony_ci else 96462306a36Sopenharmony_ci phy->mt76->chainmask = tx_ant << shift; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci mt76_set_stream_caps(phy->mt76, true); 96762306a36Sopenharmony_ci mt7996_set_stream_vht_txbf_caps(phy); 96862306a36Sopenharmony_ci mt7996_set_stream_he_eht_caps(phy); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* TODO: update bmc_wtbl spe_idx when antenna changes */ 97162306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return 0; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic void mt7996_sta_statistics(struct ieee80211_hw *hw, 97762306a36Sopenharmony_ci struct ieee80211_vif *vif, 97862306a36Sopenharmony_ci struct ieee80211_sta *sta, 97962306a36Sopenharmony_ci struct station_info *sinfo) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 98262306a36Sopenharmony_ci struct rate_info *txrate = &msta->wcid.rate; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (txrate->legacy || txrate->flags) { 98562306a36Sopenharmony_ci if (txrate->legacy) { 98662306a36Sopenharmony_ci sinfo->txrate.legacy = txrate->legacy; 98762306a36Sopenharmony_ci } else { 98862306a36Sopenharmony_ci sinfo->txrate.mcs = txrate->mcs; 98962306a36Sopenharmony_ci sinfo->txrate.nss = txrate->nss; 99062306a36Sopenharmony_ci sinfo->txrate.bw = txrate->bw; 99162306a36Sopenharmony_ci sinfo->txrate.he_gi = txrate->he_gi; 99262306a36Sopenharmony_ci sinfo->txrate.he_dcm = txrate->he_dcm; 99362306a36Sopenharmony_ci sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci sinfo->txrate.flags = txrate->flags; 99662306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci sinfo->txrate.flags = txrate->flags; 99962306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci sinfo->ack_signal = (s8)msta->ack_signal; 100262306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); 100562306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 101162306a36Sopenharmony_ci struct mt7996_dev *dev = msta->vif->phy->dev; 101262306a36Sopenharmony_ci u32 *changed = data; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci spin_lock_bh(&dev->mt76.sta_poll_lock); 101562306a36Sopenharmony_ci msta->changed |= *changed; 101662306a36Sopenharmony_ci if (list_empty(&msta->rc_list)) 101762306a36Sopenharmony_ci list_add_tail(&msta->rc_list, &dev->sta_rc_list); 101862306a36Sopenharmony_ci spin_unlock_bh(&dev->mt76.sta_poll_lock); 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic void mt7996_sta_rc_update(struct ieee80211_hw *hw, 102262306a36Sopenharmony_ci struct ieee80211_vif *vif, 102362306a36Sopenharmony_ci struct ieee80211_sta *sta, 102462306a36Sopenharmony_ci u32 changed) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 102762306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci mt7996_sta_rc_work(&changed, sta); 103062306a36Sopenharmony_ci ieee80211_queue_work(hw, &dev->rc_work); 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_cistatic int 103462306a36Sopenharmony_cimt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 103562306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 103862306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 103962306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 104062306a36Sopenharmony_ci u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci mvif->bitrate_mask = *mask; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* if multiple rates across different preambles are given we can 104562306a36Sopenharmony_ci * reconfigure this info with all peers using sta_rec command with 104662306a36Sopenharmony_ci * the below exception cases. 104762306a36Sopenharmony_ci * - single rate : if a rate is passed along with different preambles, 104862306a36Sopenharmony_ci * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. 104962306a36Sopenharmony_ci * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT 105062306a36Sopenharmony_ci * then multiple MCS setting (MCS 4,5,6) is not supported. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); 105362306a36Sopenharmony_ci ieee80211_queue_work(hw, &dev->rc_work); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return 0; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic void mt7996_sta_set_4addr(struct ieee80211_hw *hw, 105962306a36Sopenharmony_ci struct ieee80211_vif *vif, 106062306a36Sopenharmony_ci struct ieee80211_sta *sta, 106162306a36Sopenharmony_ci bool enabled) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 106462306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (enabled) 106762306a36Sopenharmony_ci set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 106862306a36Sopenharmony_ci else 106962306a36Sopenharmony_ci clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, 107562306a36Sopenharmony_ci struct ieee80211_vif *vif, 107662306a36Sopenharmony_ci struct ieee80211_sta *sta, 107762306a36Sopenharmony_ci bool enabled) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 108062306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (enabled) 108362306a36Sopenharmony_ci set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 108462306a36Sopenharmony_ci else 108562306a36Sopenharmony_ci clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = { 109162306a36Sopenharmony_ci "tx_ampdu_cnt", 109262306a36Sopenharmony_ci "tx_stop_q_empty_cnt", 109362306a36Sopenharmony_ci "tx_mpdu_attempts", 109462306a36Sopenharmony_ci "tx_mpdu_success", 109562306a36Sopenharmony_ci "tx_rwp_fail_cnt", 109662306a36Sopenharmony_ci "tx_rwp_need_cnt", 109762306a36Sopenharmony_ci "tx_pkt_ebf_cnt", 109862306a36Sopenharmony_ci "tx_pkt_ibf_cnt", 109962306a36Sopenharmony_ci "tx_ampdu_len:0-1", 110062306a36Sopenharmony_ci "tx_ampdu_len:2-10", 110162306a36Sopenharmony_ci "tx_ampdu_len:11-19", 110262306a36Sopenharmony_ci "tx_ampdu_len:20-28", 110362306a36Sopenharmony_ci "tx_ampdu_len:29-37", 110462306a36Sopenharmony_ci "tx_ampdu_len:38-46", 110562306a36Sopenharmony_ci "tx_ampdu_len:47-55", 110662306a36Sopenharmony_ci "tx_ampdu_len:56-79", 110762306a36Sopenharmony_ci "tx_ampdu_len:80-103", 110862306a36Sopenharmony_ci "tx_ampdu_len:104-127", 110962306a36Sopenharmony_ci "tx_ampdu_len:128-151", 111062306a36Sopenharmony_ci "tx_ampdu_len:152-175", 111162306a36Sopenharmony_ci "tx_ampdu_len:176-199", 111262306a36Sopenharmony_ci "tx_ampdu_len:200-223", 111362306a36Sopenharmony_ci "tx_ampdu_len:224-247", 111462306a36Sopenharmony_ci "ba_miss_count", 111562306a36Sopenharmony_ci "tx_beamformer_ppdu_iBF", 111662306a36Sopenharmony_ci "tx_beamformer_ppdu_eBF", 111762306a36Sopenharmony_ci "tx_beamformer_rx_feedback_all", 111862306a36Sopenharmony_ci "tx_beamformer_rx_feedback_he", 111962306a36Sopenharmony_ci "tx_beamformer_rx_feedback_vht", 112062306a36Sopenharmony_ci "tx_beamformer_rx_feedback_ht", 112162306a36Sopenharmony_ci "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ 112262306a36Sopenharmony_ci "tx_beamformer_rx_feedback_nc", 112362306a36Sopenharmony_ci "tx_beamformer_rx_feedback_nr", 112462306a36Sopenharmony_ci "tx_beamformee_ok_feedback_pkts", 112562306a36Sopenharmony_ci "tx_beamformee_feedback_trig", 112662306a36Sopenharmony_ci "tx_mu_beamforming", 112762306a36Sopenharmony_ci "tx_mu_mpdu", 112862306a36Sopenharmony_ci "tx_mu_successful_mpdu", 112962306a36Sopenharmony_ci "tx_su_successful_mpdu", 113062306a36Sopenharmony_ci "tx_msdu_pack_1", 113162306a36Sopenharmony_ci "tx_msdu_pack_2", 113262306a36Sopenharmony_ci "tx_msdu_pack_3", 113362306a36Sopenharmony_ci "tx_msdu_pack_4", 113462306a36Sopenharmony_ci "tx_msdu_pack_5", 113562306a36Sopenharmony_ci "tx_msdu_pack_6", 113662306a36Sopenharmony_ci "tx_msdu_pack_7", 113762306a36Sopenharmony_ci "tx_msdu_pack_8", 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci /* rx counters */ 114062306a36Sopenharmony_ci "rx_fifo_full_cnt", 114162306a36Sopenharmony_ci "rx_mpdu_cnt", 114262306a36Sopenharmony_ci "channel_idle_cnt", 114362306a36Sopenharmony_ci "rx_vector_mismatch_cnt", 114462306a36Sopenharmony_ci "rx_delimiter_fail_cnt", 114562306a36Sopenharmony_ci "rx_len_mismatch_cnt", 114662306a36Sopenharmony_ci "rx_ampdu_cnt", 114762306a36Sopenharmony_ci "rx_ampdu_bytes_cnt", 114862306a36Sopenharmony_ci "rx_ampdu_valid_subframe_cnt", 114962306a36Sopenharmony_ci "rx_ampdu_valid_subframe_b_cnt", 115062306a36Sopenharmony_ci "rx_pfdrop_cnt", 115162306a36Sopenharmony_ci "rx_vec_queue_overflow_drop_cnt", 115262306a36Sopenharmony_ci "rx_ba_cnt", 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* per vif counters */ 115562306a36Sopenharmony_ci "v_tx_mode_cck", 115662306a36Sopenharmony_ci "v_tx_mode_ofdm", 115762306a36Sopenharmony_ci "v_tx_mode_ht", 115862306a36Sopenharmony_ci "v_tx_mode_ht_gf", 115962306a36Sopenharmony_ci "v_tx_mode_vht", 116062306a36Sopenharmony_ci "v_tx_mode_he_su", 116162306a36Sopenharmony_ci "v_tx_mode_he_ext_su", 116262306a36Sopenharmony_ci "v_tx_mode_he_tb", 116362306a36Sopenharmony_ci "v_tx_mode_he_mu", 116462306a36Sopenharmony_ci "v_tx_mode_eht_su", 116562306a36Sopenharmony_ci "v_tx_mode_eht_trig", 116662306a36Sopenharmony_ci "v_tx_mode_eht_mu", 116762306a36Sopenharmony_ci "v_tx_bw_20", 116862306a36Sopenharmony_ci "v_tx_bw_40", 116962306a36Sopenharmony_ci "v_tx_bw_80", 117062306a36Sopenharmony_ci "v_tx_bw_160", 117162306a36Sopenharmony_ci "v_tx_bw_320", 117262306a36Sopenharmony_ci "v_tx_mcs_0", 117362306a36Sopenharmony_ci "v_tx_mcs_1", 117462306a36Sopenharmony_ci "v_tx_mcs_2", 117562306a36Sopenharmony_ci "v_tx_mcs_3", 117662306a36Sopenharmony_ci "v_tx_mcs_4", 117762306a36Sopenharmony_ci "v_tx_mcs_5", 117862306a36Sopenharmony_ci "v_tx_mcs_6", 117962306a36Sopenharmony_ci "v_tx_mcs_7", 118062306a36Sopenharmony_ci "v_tx_mcs_8", 118162306a36Sopenharmony_ci "v_tx_mcs_9", 118262306a36Sopenharmony_ci "v_tx_mcs_10", 118362306a36Sopenharmony_ci "v_tx_mcs_11", 118462306a36Sopenharmony_ci "v_tx_mcs_12", 118562306a36Sopenharmony_ci "v_tx_mcs_13", 118662306a36Sopenharmony_ci "v_tx_nss_1", 118762306a36Sopenharmony_ci "v_tx_nss_2", 118862306a36Sopenharmony_ci "v_tx_nss_3", 118962306a36Sopenharmony_ci "v_tx_nss_4", 119062306a36Sopenharmony_ci}; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci#define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats) 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci/* Ethtool related API */ 119562306a36Sopenharmony_cistatic 119662306a36Sopenharmony_civoid mt7996_get_et_strings(struct ieee80211_hw *hw, 119762306a36Sopenharmony_ci struct ieee80211_vif *vif, 119862306a36Sopenharmony_ci u32 sset, u8 *data) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci if (sset == ETH_SS_STATS) 120162306a36Sopenharmony_ci memcpy(data, mt7996_gstrings_stats, 120262306a36Sopenharmony_ci sizeof(mt7996_gstrings_stats)); 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic 120662306a36Sopenharmony_ciint mt7996_get_et_sset_count(struct ieee80211_hw *hw, 120762306a36Sopenharmony_ci struct ieee80211_vif *vif, int sset) 120862306a36Sopenharmony_ci{ 120962306a36Sopenharmony_ci if (sset == ETH_SS_STATS) 121062306a36Sopenharmony_ci return MT7996_SSTATS_LEN; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci return 0; 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci struct mt76_ethtool_worker_info *wi = wi_data; 121862306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (msta->vif->mt76.idx != wi->idx) 122162306a36Sopenharmony_ci return; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci mt76_ethtool_worker(wi, &msta->wcid.stats, true); 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_cistatic 122762306a36Sopenharmony_civoid mt7996_get_et_stats(struct ieee80211_hw *hw, 122862306a36Sopenharmony_ci struct ieee80211_vif *vif, 122962306a36Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 123262306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 123362306a36Sopenharmony_ci struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 123462306a36Sopenharmony_ci struct mt76_mib_stats *mib = &phy->mib; 123562306a36Sopenharmony_ci struct mt76_ethtool_worker_info wi = { 123662306a36Sopenharmony_ci .data = data, 123762306a36Sopenharmony_ci .idx = mvif->mt76.idx, 123862306a36Sopenharmony_ci }; 123962306a36Sopenharmony_ci /* See mt7996_ampdu_stat_read_phy, etc */ 124062306a36Sopenharmony_ci int i, ei = 0; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci mt7996_mac_update_stats(phy); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci data[ei++] = mib->tx_ampdu_cnt; 124762306a36Sopenharmony_ci data[ei++] = mib->tx_stop_q_empty_cnt; 124862306a36Sopenharmony_ci data[ei++] = mib->tx_mpdu_attempts_cnt; 124962306a36Sopenharmony_ci data[ei++] = mib->tx_mpdu_success_cnt; 125062306a36Sopenharmony_ci data[ei++] = mib->tx_rwp_fail_cnt; 125162306a36Sopenharmony_ci data[ei++] = mib->tx_rwp_need_cnt; 125262306a36Sopenharmony_ci data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 125362306a36Sopenharmony_ci data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci /* Tx ampdu stat */ 125662306a36Sopenharmony_ci for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) 125762306a36Sopenharmony_ci data[ei++] = phy->mt76->aggr_stats[i]; 125862306a36Sopenharmony_ci data[ei++] = phy->mib.ba_miss_cnt; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci /* Tx Beamformer monitor */ 126162306a36Sopenharmony_ci data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 126262306a36Sopenharmony_ci data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* Tx Beamformer Rx feedback monitor */ 126562306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_all_cnt; 126662306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_he_cnt; 126762306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_vht_cnt; 126862306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_ht_cnt; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_bw; 127162306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_nc_cnt; 127262306a36Sopenharmony_ci data[ei++] = mib->tx_bf_rx_fb_nr_cnt; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* Tx Beamformee Rx NDPA & Tx feedback report */ 127562306a36Sopenharmony_ci data[ei++] = mib->tx_bf_fb_cpl_cnt; 127662306a36Sopenharmony_ci data[ei++] = mib->tx_bf_fb_trig_cnt; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci /* Tx SU & MU counters */ 127962306a36Sopenharmony_ci data[ei++] = mib->tx_mu_bf_cnt; 128062306a36Sopenharmony_ci data[ei++] = mib->tx_mu_mpdu_cnt; 128162306a36Sopenharmony_ci data[ei++] = mib->tx_mu_acked_mpdu_cnt; 128262306a36Sopenharmony_ci data[ei++] = mib->tx_su_acked_mpdu_cnt; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci /* Tx amsdu info (pack-count histogram) */ 128562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) 128662306a36Sopenharmony_ci data[ei++] = mib->tx_amsdu[i]; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci /* rx counters */ 128962306a36Sopenharmony_ci data[ei++] = mib->rx_fifo_full_cnt; 129062306a36Sopenharmony_ci data[ei++] = mib->rx_mpdu_cnt; 129162306a36Sopenharmony_ci data[ei++] = mib->channel_idle_cnt; 129262306a36Sopenharmony_ci data[ei++] = mib->rx_vector_mismatch_cnt; 129362306a36Sopenharmony_ci data[ei++] = mib->rx_delimiter_fail_cnt; 129462306a36Sopenharmony_ci data[ei++] = mib->rx_len_mismatch_cnt; 129562306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_cnt; 129662306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_bytes_cnt; 129762306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_valid_subframe_cnt; 129862306a36Sopenharmony_ci data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; 129962306a36Sopenharmony_ci data[ei++] = mib->rx_pfdrop_cnt; 130062306a36Sopenharmony_ci data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; 130162306a36Sopenharmony_ci data[ei++] = mib->rx_ba_cnt; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci /* Add values for all stations owned by this vif */ 130462306a36Sopenharmony_ci wi.initial_stat_idx = ei; 130562306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(hw, mt7996_ethtool_worker, &wi); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci if (wi.sta_count == 0) 131062306a36Sopenharmony_ci return; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci ei += wi.worker_stat_count; 131362306a36Sopenharmony_ci if (ei != MT7996_SSTATS_LEN) 131462306a36Sopenharmony_ci dev_err(dev->mt76.dev, "ei: %d MT7996_SSTATS_LEN: %d", 131562306a36Sopenharmony_ci ei, (int)MT7996_SSTATS_LEN); 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic void 131962306a36Sopenharmony_cimt7996_twt_teardown_request(struct ieee80211_hw *hw, 132062306a36Sopenharmony_ci struct ieee80211_sta *sta, 132162306a36Sopenharmony_ci u8 flowid) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 132462306a36Sopenharmony_ci struct mt7996_dev *dev = mt7996_hw_dev(hw); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 132762306a36Sopenharmony_ci mt7996_mac_twt_teardown_flow(dev, msta, flowid); 132862306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic int 133262306a36Sopenharmony_cimt7996_set_radar_background(struct ieee80211_hw *hw, 133362306a36Sopenharmony_ci struct cfg80211_chan_def *chandef) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci struct mt7996_phy *phy = mt7996_hw_phy(hw); 133662306a36Sopenharmony_ci struct mt7996_dev *dev = phy->dev; 133762306a36Sopenharmony_ci int ret = -EINVAL; 133862306a36Sopenharmony_ci bool running; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci mutex_lock(&dev->mt76.mutex); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (dev->mt76.region == NL80211_DFS_UNSET) 134362306a36Sopenharmony_ci goto out; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (dev->rdd2_phy && dev->rdd2_phy != phy) { 134662306a36Sopenharmony_ci /* rdd2 is already locked */ 134762306a36Sopenharmony_ci ret = -EBUSY; 134862306a36Sopenharmony_ci goto out; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* rdd2 already configured on a radar channel */ 135262306a36Sopenharmony_ci running = dev->rdd2_phy && 135362306a36Sopenharmony_ci cfg80211_chandef_valid(&dev->rdd2_chandef) && 135462306a36Sopenharmony_ci !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (!chandef || running || 135762306a36Sopenharmony_ci !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { 135862306a36Sopenharmony_ci ret = mt7996_mcu_rdd_background_enable(phy, NULL); 135962306a36Sopenharmony_ci if (ret) 136062306a36Sopenharmony_ci goto out; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (!running) 136362306a36Sopenharmony_ci goto update_phy; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci ret = mt7996_mcu_rdd_background_enable(phy, chandef); 136762306a36Sopenharmony_ci if (ret) 136862306a36Sopenharmony_ci goto out; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ciupdate_phy: 137162306a36Sopenharmony_ci dev->rdd2_phy = chandef ? phy : NULL; 137262306a36Sopenharmony_ci if (chandef) 137362306a36Sopenharmony_ci dev->rdd2_chandef = *chandef; 137462306a36Sopenharmony_ciout: 137562306a36Sopenharmony_ci mutex_unlock(&dev->mt76.mutex); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci return ret; 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ciconst struct ieee80211_ops mt7996_ops = { 138162306a36Sopenharmony_ci .tx = mt7996_tx, 138262306a36Sopenharmony_ci .start = mt7996_start, 138362306a36Sopenharmony_ci .stop = mt7996_stop, 138462306a36Sopenharmony_ci .add_interface = mt7996_add_interface, 138562306a36Sopenharmony_ci .remove_interface = mt7996_remove_interface, 138662306a36Sopenharmony_ci .config = mt7996_config, 138762306a36Sopenharmony_ci .conf_tx = mt7996_conf_tx, 138862306a36Sopenharmony_ci .configure_filter = mt7996_configure_filter, 138962306a36Sopenharmony_ci .bss_info_changed = mt7996_bss_info_changed, 139062306a36Sopenharmony_ci .sta_add = mt7996_sta_add, 139162306a36Sopenharmony_ci .sta_remove = mt7996_sta_remove, 139262306a36Sopenharmony_ci .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 139362306a36Sopenharmony_ci .sta_rc_update = mt7996_sta_rc_update, 139462306a36Sopenharmony_ci .set_key = mt7996_set_key, 139562306a36Sopenharmony_ci .ampdu_action = mt7996_ampdu_action, 139662306a36Sopenharmony_ci .set_rts_threshold = mt7996_set_rts_threshold, 139762306a36Sopenharmony_ci .wake_tx_queue = mt76_wake_tx_queue, 139862306a36Sopenharmony_ci .sw_scan_start = mt76_sw_scan, 139962306a36Sopenharmony_ci .sw_scan_complete = mt76_sw_scan_complete, 140062306a36Sopenharmony_ci .release_buffered_frames = mt76_release_buffered_frames, 140162306a36Sopenharmony_ci .get_txpower = mt76_get_txpower, 140262306a36Sopenharmony_ci .channel_switch_beacon = mt7996_channel_switch_beacon, 140362306a36Sopenharmony_ci .get_stats = mt7996_get_stats, 140462306a36Sopenharmony_ci .get_et_sset_count = mt7996_get_et_sset_count, 140562306a36Sopenharmony_ci .get_et_stats = mt7996_get_et_stats, 140662306a36Sopenharmony_ci .get_et_strings = mt7996_get_et_strings, 140762306a36Sopenharmony_ci .get_tsf = mt7996_get_tsf, 140862306a36Sopenharmony_ci .set_tsf = mt7996_set_tsf, 140962306a36Sopenharmony_ci .offset_tsf = mt7996_offset_tsf, 141062306a36Sopenharmony_ci .get_survey = mt76_get_survey, 141162306a36Sopenharmony_ci .get_antenna = mt76_get_antenna, 141262306a36Sopenharmony_ci .set_antenna = mt7996_set_antenna, 141362306a36Sopenharmony_ci .set_bitrate_mask = mt7996_set_bitrate_mask, 141462306a36Sopenharmony_ci .set_coverage_class = mt7996_set_coverage_class, 141562306a36Sopenharmony_ci .sta_statistics = mt7996_sta_statistics, 141662306a36Sopenharmony_ci .sta_set_4addr = mt7996_sta_set_4addr, 141762306a36Sopenharmony_ci .sta_set_decap_offload = mt7996_sta_set_decap_offload, 141862306a36Sopenharmony_ci .add_twt_setup = mt7996_mac_add_twt_setup, 141962306a36Sopenharmony_ci .twt_teardown_request = mt7996_twt_teardown_request, 142062306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_DEBUGFS 142162306a36Sopenharmony_ci .sta_add_debugfs = mt7996_sta_add_debugfs, 142262306a36Sopenharmony_ci#endif 142362306a36Sopenharmony_ci .set_radar_background = mt7996_set_radar_background, 142462306a36Sopenharmony_ci}; 1425