198686cd2SShayne Chen // SPDX-License-Identifier: ISC 298686cd2SShayne Chen /* 398686cd2SShayne Chen * Copyright (C) 2022 MediaTek Inc. 498686cd2SShayne Chen */ 598686cd2SShayne Chen 698686cd2SShayne Chen #include "mt7996.h" 798686cd2SShayne Chen #include "mcu.h" 815ee62e7SRyder Lee #include "mac.h" 998686cd2SShayne Chen 1098686cd2SShayne Chen static bool mt7996_dev_running(struct mt7996_dev *dev) 1198686cd2SShayne Chen { 1298686cd2SShayne Chen struct mt7996_phy *phy; 1398686cd2SShayne Chen 1498686cd2SShayne Chen if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 1598686cd2SShayne Chen return true; 1698686cd2SShayne Chen 1798686cd2SShayne Chen phy = mt7996_phy2(dev); 1898686cd2SShayne Chen if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 1998686cd2SShayne Chen return true; 2098686cd2SShayne Chen 2198686cd2SShayne Chen phy = mt7996_phy3(dev); 2298686cd2SShayne Chen 2398686cd2SShayne Chen return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); 2498686cd2SShayne Chen } 2598686cd2SShayne Chen 2627015b6fSBo Jiao int mt7996_run(struct ieee80211_hw *hw) 2798686cd2SShayne Chen { 2898686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 2998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 3098686cd2SShayne Chen bool running; 3198686cd2SShayne Chen int ret; 3298686cd2SShayne Chen 3398686cd2SShayne Chen running = mt7996_dev_running(dev); 3498686cd2SShayne Chen if (!running) { 3598686cd2SShayne Chen ret = mt7996_mcu_set_hdr_trans(dev, true); 3698686cd2SShayne Chen if (ret) 3798686cd2SShayne Chen goto out; 3898686cd2SShayne Chen } 3998686cd2SShayne Chen 4098686cd2SShayne Chen mt7996_mac_enable_nf(dev, phy->mt76->band_idx); 4198686cd2SShayne Chen 4298686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, 0x92b); 4398686cd2SShayne Chen if (ret) 4498686cd2SShayne Chen goto out; 4598686cd2SShayne Chen 46d73dab22SShayne Chen ret = mt7996_mcu_set_radio_en(phy, true); 47d73dab22SShayne Chen if (ret) 48d73dab22SShayne Chen goto out; 49d73dab22SShayne Chen 5098686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); 5198686cd2SShayne Chen if (ret) 5298686cd2SShayne Chen goto out; 5398686cd2SShayne Chen 5498686cd2SShayne Chen set_bit(MT76_STATE_RUNNING, &phy->mt76->state); 5598686cd2SShayne Chen 5698686cd2SShayne Chen ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, 5798686cd2SShayne Chen MT7996_WATCHDOG_TIME); 5898686cd2SShayne Chen 5998686cd2SShayne Chen if (!running) 6098686cd2SShayne Chen mt7996_mac_reset_counters(phy); 6198686cd2SShayne Chen 6298686cd2SShayne Chen out: 6327015b6fSBo Jiao return ret; 6427015b6fSBo Jiao } 6527015b6fSBo Jiao 6627015b6fSBo Jiao static int mt7996_start(struct ieee80211_hw *hw) 6727015b6fSBo Jiao { 6827015b6fSBo Jiao struct mt7996_dev *dev = mt7996_hw_dev(hw); 6927015b6fSBo Jiao int ret; 7027015b6fSBo Jiao 7127015b6fSBo Jiao flush_work(&dev->init_work); 7227015b6fSBo Jiao 7327015b6fSBo Jiao mutex_lock(&dev->mt76.mutex); 7427015b6fSBo Jiao ret = mt7996_run(hw); 7598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 7698686cd2SShayne Chen 7798686cd2SShayne Chen return ret; 7898686cd2SShayne Chen } 7998686cd2SShayne Chen 8098686cd2SShayne Chen static void mt7996_stop(struct ieee80211_hw *hw) 8198686cd2SShayne Chen { 8298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 8398686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 8498686cd2SShayne Chen 8598686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 8698686cd2SShayne Chen 8798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 8898686cd2SShayne Chen 89d73dab22SShayne Chen mt7996_mcu_set_radio_en(phy, false); 90d73dab22SShayne Chen 9198686cd2SShayne Chen clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); 9298686cd2SShayne Chen 9398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 9498686cd2SShayne Chen } 9598686cd2SShayne Chen 9698686cd2SShayne Chen static inline int get_free_idx(u32 mask, u8 start, u8 end) 9798686cd2SShayne Chen { 9898686cd2SShayne Chen return ffs(~mask & GENMASK(end, start)); 9998686cd2SShayne Chen } 10098686cd2SShayne Chen 10198686cd2SShayne Chen static int get_omac_idx(enum nl80211_iftype type, u64 mask) 10298686cd2SShayne Chen { 10398686cd2SShayne Chen int i; 10498686cd2SShayne Chen 10598686cd2SShayne Chen switch (type) { 10698686cd2SShayne Chen case NL80211_IFTYPE_MESH_POINT: 10798686cd2SShayne Chen case NL80211_IFTYPE_ADHOC: 10898686cd2SShayne Chen case NL80211_IFTYPE_STATION: 10998686cd2SShayne Chen /* prefer hw bssid slot 1-3 */ 11098686cd2SShayne Chen i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); 11198686cd2SShayne Chen if (i) 11298686cd2SShayne Chen return i - 1; 11398686cd2SShayne Chen 11498686cd2SShayne Chen if (type != NL80211_IFTYPE_STATION) 11598686cd2SShayne Chen break; 11698686cd2SShayne Chen 11798686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 11898686cd2SShayne Chen if (i) 11998686cd2SShayne Chen return i - 1; 12098686cd2SShayne Chen 12198686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 12298686cd2SShayne Chen return HW_BSSID_0; 12398686cd2SShayne Chen 12498686cd2SShayne Chen break; 12598686cd2SShayne Chen case NL80211_IFTYPE_MONITOR: 12698686cd2SShayne Chen case NL80211_IFTYPE_AP: 12798686cd2SShayne Chen /* ap uses hw bssid 0 and ext bssid */ 12898686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 12998686cd2SShayne Chen return HW_BSSID_0; 13098686cd2SShayne Chen 13198686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 13298686cd2SShayne Chen if (i) 13398686cd2SShayne Chen return i - 1; 13498686cd2SShayne Chen 13598686cd2SShayne Chen break; 13698686cd2SShayne Chen default: 13798686cd2SShayne Chen WARN_ON(1); 13898686cd2SShayne Chen break; 13998686cd2SShayne Chen } 14098686cd2SShayne Chen 14198686cd2SShayne Chen return -1; 14298686cd2SShayne Chen } 14398686cd2SShayne Chen 14498686cd2SShayne Chen static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif) 14598686cd2SShayne Chen { 14698686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 14798686cd2SShayne Chen int i; 14898686cd2SShayne Chen 14998686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { 15098686cd2SShayne Chen mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; 15198686cd2SShayne Chen mvif->bitrate_mask.control[i].he_gi = 0xff; 15298686cd2SShayne Chen mvif->bitrate_mask.control[i].he_ltf = 0xff; 15398686cd2SShayne Chen mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); 15498686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, 15598686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].ht_mcs)); 15698686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, 15798686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].vht_mcs)); 15898686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, 15998686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].he_mcs)); 16098686cd2SShayne Chen } 16198686cd2SShayne Chen } 16298686cd2SShayne Chen 16398686cd2SShayne Chen static int mt7996_add_interface(struct ieee80211_hw *hw, 16498686cd2SShayne Chen struct ieee80211_vif *vif) 16598686cd2SShayne Chen { 16698686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 16798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 16898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 16998686cd2SShayne Chen struct mt76_txq *mtxq; 17098686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx; 17198686cd2SShayne Chen int idx, ret = 0; 17298686cd2SShayne Chen 17398686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 17498686cd2SShayne Chen 17598686cd2SShayne Chen if (vif->type == NL80211_IFTYPE_MONITOR && 17698686cd2SShayne Chen is_zero_ether_addr(vif->addr)) 17798686cd2SShayne Chen phy->monitor_vif = vif; 17898686cd2SShayne Chen 17998686cd2SShayne Chen mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); 18043482540SShayne Chen if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) { 18198686cd2SShayne Chen ret = -ENOSPC; 18298686cd2SShayne Chen goto out; 18398686cd2SShayne Chen } 18498686cd2SShayne Chen 18598686cd2SShayne Chen idx = get_omac_idx(vif->type, phy->omac_mask); 18698686cd2SShayne Chen if (idx < 0) { 18798686cd2SShayne Chen ret = -ENOSPC; 18898686cd2SShayne Chen goto out; 18998686cd2SShayne Chen } 19098686cd2SShayne Chen mvif->mt76.omac_idx = idx; 19198686cd2SShayne Chen mvif->phy = phy; 19298686cd2SShayne Chen mvif->mt76.band_idx = band_idx; 193*9b11696eSPeter Chiu mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; 19498686cd2SShayne Chen 19598686cd2SShayne Chen ret = mt7996_mcu_add_dev_info(phy, vif, true); 19698686cd2SShayne Chen if (ret) 19798686cd2SShayne Chen goto out; 19898686cd2SShayne Chen 19998686cd2SShayne Chen dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); 20098686cd2SShayne Chen phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); 20198686cd2SShayne Chen 20298686cd2SShayne Chen idx = MT7996_WTBL_RESERVED - mvif->mt76.idx; 20398686cd2SShayne Chen 20498686cd2SShayne Chen INIT_LIST_HEAD(&mvif->sta.rc_list); 205e3b0311fSLorenzo Bianconi INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); 20698686cd2SShayne Chen mvif->sta.wcid.idx = idx; 20798686cd2SShayne Chen mvif->sta.wcid.phy_idx = band_idx; 20898686cd2SShayne Chen mvif->sta.wcid.hw_key_idx = -1; 20998686cd2SShayne Chen mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; 2100335c034SFelix Fietkau mt76_wcid_init(&mvif->sta.wcid); 21198686cd2SShayne Chen 21298686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 21398686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 21498686cd2SShayne Chen 21598686cd2SShayne Chen if (vif->txq) { 21698686cd2SShayne Chen mtxq = (struct mt76_txq *)vif->txq->drv_priv; 21798686cd2SShayne Chen mtxq->wcid = idx; 21898686cd2SShayne Chen } 21998686cd2SShayne Chen 22098686cd2SShayne Chen if (vif->type != NL80211_IFTYPE_AP && 22198686cd2SShayne Chen (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) 22298686cd2SShayne Chen vif->offload_flags = 0; 22398686cd2SShayne Chen vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; 22498686cd2SShayne Chen 22515ee62e7SRyder Lee if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) 2260cb065b9SLorenzo Bianconi mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; 22715ee62e7SRyder Lee else 2280cb065b9SLorenzo Bianconi mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL; 22915ee62e7SRyder Lee 23098686cd2SShayne Chen mt7996_init_bitrate_mask(vif); 23198686cd2SShayne Chen 23298686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 23398686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 23498686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); 23598686cd2SShayne Chen 23698686cd2SShayne Chen out: 23798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 23898686cd2SShayne Chen 23998686cd2SShayne Chen return ret; 24098686cd2SShayne Chen } 24198686cd2SShayne Chen 24298686cd2SShayne Chen static void mt7996_remove_interface(struct ieee80211_hw *hw, 24398686cd2SShayne Chen struct ieee80211_vif *vif) 24498686cd2SShayne Chen { 24598686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 24698686cd2SShayne Chen struct mt7996_sta *msta = &mvif->sta; 24798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 24898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 24998686cd2SShayne Chen int idx = msta->wcid.idx; 25098686cd2SShayne Chen 25198686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, false); 25298686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, false); 25398686cd2SShayne Chen 25498686cd2SShayne Chen if (vif == phy->monitor_vif) 25598686cd2SShayne Chen phy->monitor_vif = NULL; 25698686cd2SShayne Chen 25798686cd2SShayne Chen mt7996_mcu_add_dev_info(phy, vif, false); 25898686cd2SShayne Chen 25998686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], NULL); 26098686cd2SShayne Chen 26198686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 26298686cd2SShayne Chen dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); 26398686cd2SShayne Chen phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); 26498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 26598686cd2SShayne Chen 266ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock); 267e3b0311fSLorenzo Bianconi if (!list_empty(&msta->wcid.poll_list)) 268e3b0311fSLorenzo Bianconi list_del_init(&msta->wcid.poll_list); 269ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock); 27098686cd2SShayne Chen 2710335c034SFelix Fietkau mt76_wcid_cleanup(&dev->mt76, &msta->wcid); 27298686cd2SShayne Chen } 27398686cd2SShayne Chen 27498686cd2SShayne Chen int mt7996_set_channel(struct mt7996_phy *phy) 27598686cd2SShayne Chen { 27698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 27798686cd2SShayne Chen int ret; 27898686cd2SShayne Chen 27998686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 28098686cd2SShayne Chen 28198686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 28298686cd2SShayne Chen set_bit(MT76_RESET, &phy->mt76->state); 28398686cd2SShayne Chen 28498686cd2SShayne Chen mt76_set_channel(phy->mt76); 28598686cd2SShayne Chen 28698686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); 28798686cd2SShayne Chen if (ret) 28898686cd2SShayne Chen goto out; 28998686cd2SShayne Chen 29098686cd2SShayne Chen ret = mt7996_dfs_init_radar_detector(phy); 29198686cd2SShayne Chen mt7996_mac_cca_stats_reset(phy); 29298686cd2SShayne Chen 29398686cd2SShayne Chen mt7996_mac_reset_counters(phy); 29498686cd2SShayne Chen phy->noise = 0; 29598686cd2SShayne Chen 29698686cd2SShayne Chen out: 29798686cd2SShayne Chen clear_bit(MT76_RESET, &phy->mt76->state); 29898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 29998686cd2SShayne Chen 30098686cd2SShayne Chen mt76_txq_schedule_all(phy->mt76); 30198686cd2SShayne Chen 30298686cd2SShayne Chen ieee80211_queue_delayed_work(phy->mt76->hw, 30398686cd2SShayne Chen &phy->mt76->mac_work, 30498686cd2SShayne Chen MT7996_WATCHDOG_TIME); 30598686cd2SShayne Chen 30698686cd2SShayne Chen return ret; 30798686cd2SShayne Chen } 30898686cd2SShayne Chen 30998686cd2SShayne Chen static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 31098686cd2SShayne Chen struct ieee80211_vif *vif, struct ieee80211_sta *sta, 31198686cd2SShayne Chen struct ieee80211_key_conf *key) 31298686cd2SShayne Chen { 31398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 31498686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 31598686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 31698686cd2SShayne Chen struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : 31798686cd2SShayne Chen &mvif->sta; 31898686cd2SShayne Chen struct mt76_wcid *wcid = &msta->wcid; 31998686cd2SShayne Chen u8 *wcid_keyidx = &wcid->hw_key_idx; 32098686cd2SShayne Chen int idx = key->keyidx; 32198686cd2SShayne Chen int err = 0; 32298686cd2SShayne Chen 32398686cd2SShayne Chen /* The hardware does not support per-STA RX GTK, fallback 32498686cd2SShayne Chen * to software mode for these. 32598686cd2SShayne Chen */ 32698686cd2SShayne Chen if ((vif->type == NL80211_IFTYPE_ADHOC || 32798686cd2SShayne Chen vif->type == NL80211_IFTYPE_MESH_POINT) && 32898686cd2SShayne Chen (key->cipher == WLAN_CIPHER_SUITE_TKIP || 32998686cd2SShayne Chen key->cipher == WLAN_CIPHER_SUITE_CCMP) && 33098686cd2SShayne Chen !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 33198686cd2SShayne Chen return -EOPNOTSUPP; 33298686cd2SShayne Chen 33398686cd2SShayne Chen /* fall back to sw encryption for unsupported ciphers */ 33498686cd2SShayne Chen switch (key->cipher) { 33598686cd2SShayne Chen case WLAN_CIPHER_SUITE_AES_CMAC: 33698686cd2SShayne Chen wcid_keyidx = &wcid->hw_key_idx2; 33798686cd2SShayne Chen key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; 33898686cd2SShayne Chen break; 33998686cd2SShayne Chen case WLAN_CIPHER_SUITE_TKIP: 34098686cd2SShayne Chen case WLAN_CIPHER_SUITE_CCMP: 34198686cd2SShayne Chen case WLAN_CIPHER_SUITE_CCMP_256: 34298686cd2SShayne Chen case WLAN_CIPHER_SUITE_GCMP: 34398686cd2SShayne Chen case WLAN_CIPHER_SUITE_GCMP_256: 34498686cd2SShayne Chen case WLAN_CIPHER_SUITE_SMS4: 34598686cd2SShayne Chen break; 34698686cd2SShayne Chen case WLAN_CIPHER_SUITE_WEP40: 34798686cd2SShayne Chen case WLAN_CIPHER_SUITE_WEP104: 34898686cd2SShayne Chen default: 34998686cd2SShayne Chen return -EOPNOTSUPP; 35098686cd2SShayne Chen } 35198686cd2SShayne Chen 35298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 35398686cd2SShayne Chen 35498686cd2SShayne Chen if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { 35598686cd2SShayne Chen mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); 35698686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 35798686cd2SShayne Chen } 35898686cd2SShayne Chen 359e6db67faSFelix Fietkau if (cmd == SET_KEY) { 36098686cd2SShayne Chen *wcid_keyidx = idx; 361e6db67faSFelix Fietkau } else { 362e6db67faSFelix Fietkau if (idx == *wcid_keyidx) 36398686cd2SShayne Chen *wcid_keyidx = -1; 36498686cd2SShayne Chen goto out; 365e6db67faSFelix Fietkau } 36698686cd2SShayne Chen 367e6db67faSFelix Fietkau mt76_wcid_key_setup(&dev->mt76, wcid, key); 36898686cd2SShayne Chen err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, 36998686cd2SShayne Chen key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), 37098686cd2SShayne Chen &msta->wcid, cmd); 37198686cd2SShayne Chen out: 37298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 37398686cd2SShayne Chen 37498686cd2SShayne Chen return err; 37598686cd2SShayne Chen } 37698686cd2SShayne Chen 37798686cd2SShayne Chen static int mt7996_config(struct ieee80211_hw *hw, u32 changed) 37898686cd2SShayne Chen { 37998686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 38098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 38198686cd2SShayne Chen int ret; 38298686cd2SShayne Chen 38398686cd2SShayne Chen if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 38498686cd2SShayne Chen ieee80211_stop_queues(hw); 38598686cd2SShayne Chen ret = mt7996_set_channel(phy); 38698686cd2SShayne Chen if (ret) 38798686cd2SShayne Chen return ret; 38898686cd2SShayne Chen ieee80211_wake_queues(hw); 38998686cd2SShayne Chen } 39098686cd2SShayne Chen 39198686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 39298686cd2SShayne Chen 39398686cd2SShayne Chen if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 39498686cd2SShayne Chen bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); 39598686cd2SShayne Chen 39698686cd2SShayne Chen if (!enabled) 39798686cd2SShayne Chen phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; 39898686cd2SShayne Chen else 39998686cd2SShayne Chen phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; 40098686cd2SShayne Chen 40198686cd2SShayne Chen mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), 40298686cd2SShayne Chen MT_DMA_DCR0_RXD_G5_EN, enabled); 40398686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 40498686cd2SShayne Chen } 40598686cd2SShayne Chen 40698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 40798686cd2SShayne Chen 40898686cd2SShayne Chen return 0; 40998686cd2SShayne Chen } 41098686cd2SShayne Chen 41198686cd2SShayne Chen static int 41298686cd2SShayne Chen mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 41398686cd2SShayne Chen unsigned int link_id, u16 queue, 41498686cd2SShayne Chen const struct ieee80211_tx_queue_params *params) 41598686cd2SShayne Chen { 41698686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 417*9b11696eSPeter Chiu const u8 mq_to_aci[] = { 418*9b11696eSPeter Chiu [IEEE80211_AC_VO] = 3, 419*9b11696eSPeter Chiu [IEEE80211_AC_VI] = 2, 420*9b11696eSPeter Chiu [IEEE80211_AC_BE] = 0, 421*9b11696eSPeter Chiu [IEEE80211_AC_BK] = 1, 422*9b11696eSPeter Chiu }; 42398686cd2SShayne Chen 424*9b11696eSPeter Chiu /* firmware uses access class index */ 425*9b11696eSPeter Chiu mvif->queue_params[mq_to_aci[queue]] = *params; 42698686cd2SShayne Chen /* no need to update right away, we'll get BSS_CHANGED_QOS */ 42798686cd2SShayne Chen 42898686cd2SShayne Chen return 0; 42998686cd2SShayne Chen } 43098686cd2SShayne Chen 43198686cd2SShayne Chen static void mt7996_configure_filter(struct ieee80211_hw *hw, 43298686cd2SShayne Chen unsigned int changed_flags, 43398686cd2SShayne Chen unsigned int *total_flags, 43498686cd2SShayne Chen u64 multicast) 43598686cd2SShayne Chen { 43698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 43798686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 43898686cd2SShayne Chen u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | 43998686cd2SShayne Chen MT_WF_RFCR1_DROP_BF_POLL | 44098686cd2SShayne Chen MT_WF_RFCR1_DROP_BA | 44198686cd2SShayne Chen MT_WF_RFCR1_DROP_CFEND | 44298686cd2SShayne Chen MT_WF_RFCR1_DROP_CFACK; 44398686cd2SShayne Chen u32 flags = 0; 44498686cd2SShayne Chen 44598686cd2SShayne Chen #define MT76_FILTER(_flag, _hw) do { \ 44698686cd2SShayne Chen flags |= *total_flags & FIF_##_flag; \ 44798686cd2SShayne Chen phy->rxfilter &= ~(_hw); \ 44898686cd2SShayne Chen phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 44998686cd2SShayne Chen } while (0) 45098686cd2SShayne Chen 45198686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 45298686cd2SShayne Chen 45398686cd2SShayne Chen phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | 45498686cd2SShayne Chen MT_WF_RFCR_DROP_OTHER_BEACON | 45598686cd2SShayne Chen MT_WF_RFCR_DROP_FRAME_REPORT | 45698686cd2SShayne Chen MT_WF_RFCR_DROP_PROBEREQ | 45798686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST_FILTERED | 45898686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST | 45998686cd2SShayne Chen MT_WF_RFCR_DROP_BCAST | 46098686cd2SShayne Chen MT_WF_RFCR_DROP_DUPLICATE | 46198686cd2SShayne Chen MT_WF_RFCR_DROP_A2_BSSID | 46298686cd2SShayne Chen MT_WF_RFCR_DROP_UNWANTED_CTL | 46398686cd2SShayne Chen MT_WF_RFCR_DROP_STBC_MULTI); 46498686cd2SShayne Chen 46598686cd2SShayne Chen MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | 46698686cd2SShayne Chen MT_WF_RFCR_DROP_A3_MAC | 46798686cd2SShayne Chen MT_WF_RFCR_DROP_A3_BSSID); 46898686cd2SShayne Chen 46998686cd2SShayne Chen MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); 47098686cd2SShayne Chen 47198686cd2SShayne Chen MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | 47298686cd2SShayne Chen MT_WF_RFCR_DROP_RTS | 47398686cd2SShayne Chen MT_WF_RFCR_DROP_CTL_RSV | 47498686cd2SShayne Chen MT_WF_RFCR_DROP_NDPA); 47598686cd2SShayne Chen 47698686cd2SShayne Chen *total_flags = flags; 47798686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 47898686cd2SShayne Chen 47998686cd2SShayne Chen if (*total_flags & FIF_CONTROL) 48098686cd2SShayne Chen mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 48198686cd2SShayne Chen else 48298686cd2SShayne Chen mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 48398686cd2SShayne Chen 48498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 48598686cd2SShayne Chen } 48698686cd2SShayne Chen 48798686cd2SShayne Chen static void 48898686cd2SShayne Chen mt7996_update_bss_color(struct ieee80211_hw *hw, 48998686cd2SShayne Chen struct ieee80211_vif *vif, 49098686cd2SShayne Chen struct cfg80211_he_bss_color *bss_color) 49198686cd2SShayne Chen { 49298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 49398686cd2SShayne Chen 49498686cd2SShayne Chen switch (vif->type) { 49598686cd2SShayne Chen case NL80211_IFTYPE_AP: { 49698686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 49798686cd2SShayne Chen 49898686cd2SShayne Chen if (mvif->mt76.omac_idx > HW_BSSID_MAX) 49998686cd2SShayne Chen return; 50098686cd2SShayne Chen fallthrough; 50198686cd2SShayne Chen } 50298686cd2SShayne Chen case NL80211_IFTYPE_STATION: 50398686cd2SShayne Chen mt7996_mcu_update_bss_color(dev, vif, bss_color); 50498686cd2SShayne Chen break; 50598686cd2SShayne Chen default: 50698686cd2SShayne Chen break; 50798686cd2SShayne Chen } 50898686cd2SShayne Chen } 50998686cd2SShayne Chen 51015ee62e7SRyder Lee static u8 511ab0eec4bSRyder Lee mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 512c2171b06SRyder Lee bool beacon, bool mcast) 51315ee62e7SRyder Lee { 5140cb065b9SLorenzo Bianconi struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 51515ee62e7SRyder Lee struct mt76_phy *mphy = hw->priv; 51615ee62e7SRyder Lee u16 rate; 517c2171b06SRyder Lee u8 i, idx, ht; 51815ee62e7SRyder Lee 519c2171b06SRyder Lee rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); 520c2171b06SRyder Lee ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; 521c2171b06SRyder Lee 522c2171b06SRyder Lee if (beacon && ht) { 523c2171b06SRyder Lee struct mt7996_dev *dev = mt7996_hw_dev(hw); 524c2171b06SRyder Lee 525c2171b06SRyder Lee /* must odd index */ 5260cb065b9SLorenzo Bianconi idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20); 527c2171b06SRyder Lee mt7996_mac_set_fixed_rate_table(dev, idx, rate); 528c2171b06SRyder Lee return idx; 529c2171b06SRyder Lee } 53015ee62e7SRyder Lee 53115ee62e7SRyder Lee idx = FIELD_GET(MT_TX_RATE_IDX, rate); 53215ee62e7SRyder Lee for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) 53315ee62e7SRyder Lee if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) 53415ee62e7SRyder Lee return MT7996_BASIC_RATES_TBL + i; 53515ee62e7SRyder Lee 53615ee62e7SRyder Lee return mvif->basic_rates_idx; 53715ee62e7SRyder Lee } 53815ee62e7SRyder Lee 53968f1c3eaSRyder Lee static void 54068f1c3eaSRyder Lee mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 54168f1c3eaSRyder Lee struct ieee80211_bss_conf *info) 54268f1c3eaSRyder Lee { 54368f1c3eaSRyder Lee struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 54468f1c3eaSRyder Lee struct mt7996_dev *dev = mt7996_hw_dev(hw); 54568f1c3eaSRyder Lee u8 band = mvif->mt76.band_idx; 54668f1c3eaSRyder Lee u32 *mu; 54768f1c3eaSRyder Lee 54868f1c3eaSRyder Lee mu = (u32 *)info->mu_group.membership; 54968f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]); 55068f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]); 55168f1c3eaSRyder Lee 55268f1c3eaSRyder Lee mu = (u32 *)info->mu_group.position; 55368f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]); 55468f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]); 55568f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]); 55668f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]); 55768f1c3eaSRyder Lee } 55868f1c3eaSRyder Lee 55998686cd2SShayne Chen static void mt7996_bss_info_changed(struct ieee80211_hw *hw, 56098686cd2SShayne Chen struct ieee80211_vif *vif, 56198686cd2SShayne Chen struct ieee80211_bss_conf *info, 56298686cd2SShayne Chen u64 changed) 56398686cd2SShayne Chen { 5640cb065b9SLorenzo Bianconi struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 56598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 56698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 56798686cd2SShayne Chen 56898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 56998686cd2SShayne Chen 57098686cd2SShayne Chen /* station mode uses BSSID to map the wlan entry to a peer, 57198686cd2SShayne Chen * and then peer references bss_info_rfch to set bandwidth cap. 57298686cd2SShayne Chen */ 57398686cd2SShayne Chen if (changed & BSS_CHANGED_BSSID && 57498686cd2SShayne Chen vif->type == NL80211_IFTYPE_STATION) { 57598686cd2SShayne Chen bool join = !is_zero_ether_addr(info->bssid); 57698686cd2SShayne Chen 57798686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, join); 57898686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, join); 57998686cd2SShayne Chen } 58098686cd2SShayne Chen 581cf6dc2dbSRyder Lee if (changed & BSS_CHANGED_ASSOC) 58298686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc); 58398686cd2SShayne Chen 584d75e739bSRyder Lee if (changed & BSS_CHANGED_ERP_CTS_PROT) 585d75e739bSRyder Lee mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); 586d75e739bSRyder Lee 58798686cd2SShayne Chen if (changed & BSS_CHANGED_ERP_SLOT) { 58898686cd2SShayne Chen int slottime = info->use_short_slot ? 9 : 20; 58998686cd2SShayne Chen 59098686cd2SShayne Chen if (slottime != phy->slottime) { 59198686cd2SShayne Chen phy->slottime = slottime; 59283a10ae2SPeter Chiu mt7996_mcu_set_timing(phy, vif); 59398686cd2SShayne Chen } 59498686cd2SShayne Chen } 59598686cd2SShayne Chen 596ab0eec4bSRyder Lee if (changed & BSS_CHANGED_MCAST_RATE) 597ab0eec4bSRyder Lee mvif->mcast_rates_idx = 598c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, false, true); 599ab0eec4bSRyder Lee 60015ee62e7SRyder Lee if (changed & BSS_CHANGED_BASIC_RATES) 601ab0eec4bSRyder Lee mvif->basic_rates_idx = 602c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, false, false); 60315ee62e7SRyder Lee 60498686cd2SShayne Chen if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { 60598686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 60698686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 60798686cd2SShayne Chen } 60898686cd2SShayne Chen 60998686cd2SShayne Chen /* ensure that enable txcmd_mode after bss_info */ 61098686cd2SShayne Chen if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) 61198686cd2SShayne Chen mt7996_mcu_set_tx(dev, vif); 61298686cd2SShayne Chen 61398686cd2SShayne Chen if (changed & BSS_CHANGED_HE_OBSS_PD) 614cf6dc2dbSRyder Lee mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 61598686cd2SShayne Chen 61698686cd2SShayne Chen if (changed & BSS_CHANGED_HE_BSS_COLOR) 61798686cd2SShayne Chen mt7996_update_bss_color(hw, vif, &info->he_bss_color); 61898686cd2SShayne Chen 61998686cd2SShayne Chen if (changed & (BSS_CHANGED_BEACON | 620c2171b06SRyder Lee BSS_CHANGED_BEACON_ENABLED)) { 621c2171b06SRyder Lee mvif->beacon_rates_idx = 622c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, true, false); 623c2171b06SRyder Lee 62498686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); 625c2171b06SRyder Lee } 62698686cd2SShayne Chen 62798686cd2SShayne Chen if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP || 62898686cd2SShayne Chen changed & BSS_CHANGED_FILS_DISCOVERY) 62998686cd2SShayne Chen mt7996_mcu_beacon_inband_discov(dev, vif, changed); 63098686cd2SShayne Chen 63168f1c3eaSRyder Lee if (changed & BSS_CHANGED_MU_GROUPS) 63268f1c3eaSRyder Lee mt7996_update_mu_group(hw, vif, info); 63368f1c3eaSRyder Lee 63498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 63598686cd2SShayne Chen } 63698686cd2SShayne Chen 63798686cd2SShayne Chen static void 63898686cd2SShayne Chen mt7996_channel_switch_beacon(struct ieee80211_hw *hw, 63998686cd2SShayne Chen struct ieee80211_vif *vif, 64098686cd2SShayne Chen struct cfg80211_chan_def *chandef) 64198686cd2SShayne Chen { 64298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 64398686cd2SShayne Chen 64498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 64598686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, true); 64698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 64798686cd2SShayne Chen } 64898686cd2SShayne Chen 64998686cd2SShayne Chen int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 65098686cd2SShayne Chen struct ieee80211_sta *sta) 65198686cd2SShayne Chen { 65298686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 65398686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 65498686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 65598686cd2SShayne Chen u8 band_idx = mvif->phy->mt76->band_idx; 65698686cd2SShayne Chen int ret, idx; 65798686cd2SShayne Chen 65898686cd2SShayne Chen idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); 65998686cd2SShayne Chen if (idx < 0) 66098686cd2SShayne Chen return -ENOSPC; 66198686cd2SShayne Chen 66298686cd2SShayne Chen INIT_LIST_HEAD(&msta->rc_list); 663e3b0311fSLorenzo Bianconi INIT_LIST_HEAD(&msta->wcid.poll_list); 66498686cd2SShayne Chen msta->vif = mvif; 66598686cd2SShayne Chen msta->wcid.sta = 1; 66698686cd2SShayne Chen msta->wcid.idx = idx; 66798686cd2SShayne Chen msta->wcid.phy_idx = band_idx; 66898686cd2SShayne Chen msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 66998686cd2SShayne Chen msta->jiffies = jiffies; 67098686cd2SShayne Chen 671ea5d99d0SRyder Lee ewma_avg_signal_init(&msta->avg_ack_signal); 672ea5d99d0SRyder Lee 67398686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 67498686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 67598686cd2SShayne Chen 67698686cd2SShayne Chen ret = mt7996_mcu_add_sta(dev, vif, sta, true); 67798686cd2SShayne Chen if (ret) 67898686cd2SShayne Chen return ret; 67998686cd2SShayne Chen 68098686cd2SShayne Chen return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); 68198686cd2SShayne Chen } 68298686cd2SShayne Chen 68398686cd2SShayne Chen void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 68498686cd2SShayne Chen struct ieee80211_sta *sta) 68598686cd2SShayne Chen { 68698686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 68798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 68898686cd2SShayne Chen int i; 68998686cd2SShayne Chen 69098686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, sta, false); 69198686cd2SShayne Chen 69298686cd2SShayne Chen mt7996_mac_wtbl_update(dev, msta->wcid.idx, 69398686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 69498686cd2SShayne Chen 69598686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) 69698686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, i); 69798686cd2SShayne Chen 698ea0f3867SLorenzo Bianconi spin_lock_bh(&mdev->sta_poll_lock); 699e3b0311fSLorenzo Bianconi if (!list_empty(&msta->wcid.poll_list)) 700e3b0311fSLorenzo Bianconi list_del_init(&msta->wcid.poll_list); 70198686cd2SShayne Chen if (!list_empty(&msta->rc_list)) 70298686cd2SShayne Chen list_del_init(&msta->rc_list); 703ea0f3867SLorenzo Bianconi spin_unlock_bh(&mdev->sta_poll_lock); 70498686cd2SShayne Chen } 70598686cd2SShayne Chen 70698686cd2SShayne Chen static void mt7996_tx(struct ieee80211_hw *hw, 70798686cd2SShayne Chen struct ieee80211_tx_control *control, 70898686cd2SShayne Chen struct sk_buff *skb) 70998686cd2SShayne Chen { 71098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 71198686cd2SShayne Chen struct mt76_phy *mphy = hw->priv; 71298686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 71398686cd2SShayne Chen struct ieee80211_vif *vif = info->control.vif; 71498686cd2SShayne Chen struct mt76_wcid *wcid = &dev->mt76.global_wcid; 71598686cd2SShayne Chen 71698686cd2SShayne Chen if (control->sta) { 71798686cd2SShayne Chen struct mt7996_sta *sta; 71898686cd2SShayne Chen 71998686cd2SShayne Chen sta = (struct mt7996_sta *)control->sta->drv_priv; 72098686cd2SShayne Chen wcid = &sta->wcid; 72198686cd2SShayne Chen } 72298686cd2SShayne Chen 72398686cd2SShayne Chen if (vif && !control->sta) { 72498686cd2SShayne Chen struct mt7996_vif *mvif; 72598686cd2SShayne Chen 72698686cd2SShayne Chen mvif = (struct mt7996_vif *)vif->drv_priv; 72798686cd2SShayne Chen wcid = &mvif->sta.wcid; 72898686cd2SShayne Chen } 72998686cd2SShayne Chen 73098686cd2SShayne Chen mt76_tx(mphy, control->sta, wcid, skb); 73198686cd2SShayne Chen } 73298686cd2SShayne Chen 73398686cd2SShayne Chen static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 73498686cd2SShayne Chen { 73598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 73698686cd2SShayne Chen int ret; 73798686cd2SShayne Chen 73898686cd2SShayne Chen mutex_lock(&phy->dev->mt76.mutex); 73998686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, val); 74098686cd2SShayne Chen mutex_unlock(&phy->dev->mt76.mutex); 74198686cd2SShayne Chen 74298686cd2SShayne Chen return ret; 74398686cd2SShayne Chen } 74498686cd2SShayne Chen 74598686cd2SShayne Chen static int 74698686cd2SShayne Chen mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 74798686cd2SShayne Chen struct ieee80211_ampdu_params *params) 74898686cd2SShayne Chen { 74998686cd2SShayne Chen enum ieee80211_ampdu_mlme_action action = params->action; 75098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 75198686cd2SShayne Chen struct ieee80211_sta *sta = params->sta; 75298686cd2SShayne Chen struct ieee80211_txq *txq = sta->txq[params->tid]; 75398686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 75498686cd2SShayne Chen u16 tid = params->tid; 75598686cd2SShayne Chen u16 ssn = params->ssn; 75698686cd2SShayne Chen struct mt76_txq *mtxq; 75798686cd2SShayne Chen int ret = 0; 75898686cd2SShayne Chen 75998686cd2SShayne Chen if (!txq) 76098686cd2SShayne Chen return -EINVAL; 76198686cd2SShayne Chen 76298686cd2SShayne Chen mtxq = (struct mt76_txq *)txq->drv_priv; 76398686cd2SShayne Chen 76498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 76598686cd2SShayne Chen switch (action) { 76698686cd2SShayne Chen case IEEE80211_AMPDU_RX_START: 76798686cd2SShayne Chen mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, 76898686cd2SShayne Chen params->buf_size); 76998686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, true); 77098686cd2SShayne Chen break; 77198686cd2SShayne Chen case IEEE80211_AMPDU_RX_STOP: 77298686cd2SShayne Chen mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 77398686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, false); 77498686cd2SShayne Chen break; 77598686cd2SShayne Chen case IEEE80211_AMPDU_TX_OPERATIONAL: 77698686cd2SShayne Chen mtxq->aggr = true; 77798686cd2SShayne Chen mtxq->send_bar = false; 77898686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, true); 77998686cd2SShayne Chen break; 78098686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH: 78198686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 78298686cd2SShayne Chen mtxq->aggr = false; 783ef591d74SLorenzo Bianconi clear_bit(tid, &msta->wcid.ampdu_state); 78498686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 78598686cd2SShayne Chen break; 78698686cd2SShayne Chen case IEEE80211_AMPDU_TX_START: 787ef591d74SLorenzo Bianconi set_bit(tid, &msta->wcid.ampdu_state); 78898686cd2SShayne Chen ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 78998686cd2SShayne Chen break; 79098686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_CONT: 79198686cd2SShayne Chen mtxq->aggr = false; 792ef591d74SLorenzo Bianconi clear_bit(tid, &msta->wcid.ampdu_state); 79398686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 79498686cd2SShayne Chen ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 79598686cd2SShayne Chen break; 79698686cd2SShayne Chen } 79798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 79898686cd2SShayne Chen 79998686cd2SShayne Chen return ret; 80098686cd2SShayne Chen } 80198686cd2SShayne Chen 80298686cd2SShayne Chen static int 80398686cd2SShayne Chen mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 80498686cd2SShayne Chen struct ieee80211_sta *sta) 80598686cd2SShayne Chen { 80698686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, 80798686cd2SShayne Chen IEEE80211_STA_NONE); 80898686cd2SShayne Chen } 80998686cd2SShayne Chen 81098686cd2SShayne Chen static int 81198686cd2SShayne Chen mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 81298686cd2SShayne Chen struct ieee80211_sta *sta) 81398686cd2SShayne Chen { 81498686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, 81598686cd2SShayne Chen IEEE80211_STA_NOTEXIST); 81698686cd2SShayne Chen } 81798686cd2SShayne Chen 81898686cd2SShayne Chen static int 81998686cd2SShayne Chen mt7996_get_stats(struct ieee80211_hw *hw, 82098686cd2SShayne Chen struct ieee80211_low_level_stats *stats) 82198686cd2SShayne Chen { 82298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 82398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 82498214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib; 82598686cd2SShayne Chen 82698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 82798686cd2SShayne Chen 82898686cd2SShayne Chen stats->dot11RTSSuccessCount = mib->rts_cnt; 82998686cd2SShayne Chen stats->dot11RTSFailureCount = mib->rts_retries_cnt; 83098686cd2SShayne Chen stats->dot11FCSErrorCount = mib->fcs_err_cnt; 83198686cd2SShayne Chen stats->dot11ACKFailureCount = mib->ack_fail_cnt; 83298686cd2SShayne Chen 83398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 83498686cd2SShayne Chen 83598686cd2SShayne Chen return 0; 83698686cd2SShayne Chen } 83798686cd2SShayne Chen 83898686cd2SShayne Chen u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) 83998686cd2SShayne Chen { 84098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 84198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 84298686cd2SShayne Chen union { 84398686cd2SShayne Chen u64 t64; 84498686cd2SShayne Chen u32 t32[2]; 84598686cd2SShayne Chen } tsf; 84698686cd2SShayne Chen u16 n; 84798686cd2SShayne Chen 84898686cd2SShayne Chen lockdep_assert_held(&dev->mt76.mutex); 84998686cd2SShayne Chen 85098686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 85198686cd2SShayne Chen : mvif->mt76.omac_idx; 85298686cd2SShayne Chen /* TSF software read */ 85398686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 85498686cd2SShayne Chen MT_LPON_TCR_SW_READ); 85598686cd2SShayne Chen tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(phy->mt76->band_idx)); 85698686cd2SShayne Chen tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(phy->mt76->band_idx)); 85798686cd2SShayne Chen 85898686cd2SShayne Chen return tsf.t64; 85998686cd2SShayne Chen } 86098686cd2SShayne Chen 86198686cd2SShayne Chen static u64 86298686cd2SShayne Chen mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 86398686cd2SShayne Chen { 86498686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 86598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 86698686cd2SShayne Chen u64 ret; 86798686cd2SShayne Chen 86898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 86998686cd2SShayne Chen ret = __mt7996_get_tsf(hw, mvif); 87098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 87198686cd2SShayne Chen 87298686cd2SShayne Chen return ret; 87398686cd2SShayne Chen } 87498686cd2SShayne Chen 87598686cd2SShayne Chen static void 87698686cd2SShayne Chen mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 87798686cd2SShayne Chen u64 timestamp) 87898686cd2SShayne Chen { 87998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 88098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 88198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 88298686cd2SShayne Chen union { 88398686cd2SShayne Chen u64 t64; 88498686cd2SShayne Chen u32 t32[2]; 88598686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 88698686cd2SShayne Chen u16 n; 88798686cd2SShayne Chen 88898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 88998686cd2SShayne Chen 89098686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 89198686cd2SShayne Chen : mvif->mt76.omac_idx; 89298686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 89398686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 89498686cd2SShayne Chen /* TSF software overwrite */ 89598686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 89698686cd2SShayne Chen MT_LPON_TCR_SW_WRITE); 89798686cd2SShayne Chen 89898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 89998686cd2SShayne Chen } 90098686cd2SShayne Chen 90198686cd2SShayne Chen static void 90298686cd2SShayne Chen mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 90398686cd2SShayne Chen s64 timestamp) 90498686cd2SShayne Chen { 90598686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 90698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 90798686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 90898686cd2SShayne Chen union { 90998686cd2SShayne Chen u64 t64; 91098686cd2SShayne Chen u32 t32[2]; 91198686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 91298686cd2SShayne Chen u16 n; 91398686cd2SShayne Chen 91498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 91598686cd2SShayne Chen 91698686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 91798686cd2SShayne Chen : mvif->mt76.omac_idx; 91898686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 91998686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 92098686cd2SShayne Chen /* TSF software adjust*/ 92198686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 92298686cd2SShayne Chen MT_LPON_TCR_SW_ADJUST); 92398686cd2SShayne Chen 92498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 92598686cd2SShayne Chen } 92698686cd2SShayne Chen 92798686cd2SShayne Chen static void 92898686cd2SShayne Chen mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) 92998686cd2SShayne Chen { 93098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 93198686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 93298686cd2SShayne Chen 93398686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 93498686cd2SShayne Chen phy->coverage_class = max_t(s16, coverage_class, 0); 93583a10ae2SPeter Chiu mt7996_mac_set_coverage_class(phy); 93698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 93798686cd2SShayne Chen } 93898686cd2SShayne Chen 93998686cd2SShayne Chen static int 94098686cd2SShayne Chen mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 94198686cd2SShayne Chen { 94298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 94398686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 94498686cd2SShayne Chen int max_nss = hweight8(hw->wiphy->available_antennas_tx); 94598686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; 94698686cd2SShayne Chen 94798686cd2SShayne Chen if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) 94898686cd2SShayne Chen return -EINVAL; 94998686cd2SShayne Chen 95098686cd2SShayne Chen if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) 95198686cd2SShayne Chen tx_ant = BIT(ffs(tx_ant) - 1) - 1; 95298686cd2SShayne Chen 95398686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 95498686cd2SShayne Chen 95598686cd2SShayne Chen phy->mt76->antenna_mask = tx_ant; 95698686cd2SShayne Chen 95798686cd2SShayne Chen /* restore to the origin chainmask which might have auxiliary path */ 958eb1fdb9fSShayne Chen if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) 959eb1fdb9fSShayne Chen phy->mt76->chainmask = ((dev->chainmask >> shift) & 960eb1fdb9fSShayne Chen (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; 961eb1fdb9fSShayne Chen else if (hweight8(tx_ant) == max_nss) 96298686cd2SShayne Chen phy->mt76->chainmask = (dev->chainmask >> shift) << shift; 96398686cd2SShayne Chen else 96498686cd2SShayne Chen phy->mt76->chainmask = tx_ant << shift; 96598686cd2SShayne Chen 96698686cd2SShayne Chen mt76_set_stream_caps(phy->mt76, true); 96798686cd2SShayne Chen mt7996_set_stream_vht_txbf_caps(phy); 968348533ebSShayne Chen mt7996_set_stream_he_eht_caps(phy); 96998686cd2SShayne Chen 97015ee62e7SRyder Lee /* TODO: update bmc_wtbl spe_idx when antenna changes */ 97198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 97298686cd2SShayne Chen 97398686cd2SShayne Chen return 0; 97498686cd2SShayne Chen } 97598686cd2SShayne Chen 97698686cd2SShayne Chen static void mt7996_sta_statistics(struct ieee80211_hw *hw, 97798686cd2SShayne Chen struct ieee80211_vif *vif, 97898686cd2SShayne Chen struct ieee80211_sta *sta, 97998686cd2SShayne Chen struct station_info *sinfo) 98098686cd2SShayne Chen { 98198686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 98298686cd2SShayne Chen struct rate_info *txrate = &msta->wcid.rate; 98398686cd2SShayne Chen 984b34f346bSRyder Lee if (txrate->legacy || txrate->flags) { 98598686cd2SShayne Chen if (txrate->legacy) { 98698686cd2SShayne Chen sinfo->txrate.legacy = txrate->legacy; 98798686cd2SShayne Chen } else { 98898686cd2SShayne Chen sinfo->txrate.mcs = txrate->mcs; 98998686cd2SShayne Chen sinfo->txrate.nss = txrate->nss; 99098686cd2SShayne Chen sinfo->txrate.bw = txrate->bw; 99198686cd2SShayne Chen sinfo->txrate.he_gi = txrate->he_gi; 99298686cd2SShayne Chen sinfo->txrate.he_dcm = txrate->he_dcm; 99398686cd2SShayne Chen sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; 99498686cd2SShayne Chen } 99598686cd2SShayne Chen sinfo->txrate.flags = txrate->flags; 99698686cd2SShayne Chen sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 997b34f346bSRyder Lee } 998b34f346bSRyder Lee sinfo->txrate.flags = txrate->flags; 999b34f346bSRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 1000ea5d99d0SRyder Lee 1001ea5d99d0SRyder Lee sinfo->ack_signal = (s8)msta->ack_signal; 1002ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 1003ea5d99d0SRyder Lee 1004ea5d99d0SRyder Lee sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); 1005ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 100698686cd2SShayne Chen } 100798686cd2SShayne Chen 100898686cd2SShayne Chen static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) 100998686cd2SShayne Chen { 101098686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 101198686cd2SShayne Chen struct mt7996_dev *dev = msta->vif->phy->dev; 101298686cd2SShayne Chen u32 *changed = data; 101398686cd2SShayne Chen 1014ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock); 101598686cd2SShayne Chen msta->changed |= *changed; 101698686cd2SShayne Chen if (list_empty(&msta->rc_list)) 101798686cd2SShayne Chen list_add_tail(&msta->rc_list, &dev->sta_rc_list); 1018ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock); 101998686cd2SShayne Chen } 102098686cd2SShayne Chen 102198686cd2SShayne Chen static void mt7996_sta_rc_update(struct ieee80211_hw *hw, 102298686cd2SShayne Chen struct ieee80211_vif *vif, 102398686cd2SShayne Chen struct ieee80211_sta *sta, 102498686cd2SShayne Chen u32 changed) 102598686cd2SShayne Chen { 102698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 102798686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 102898686cd2SShayne Chen 102998686cd2SShayne Chen mt7996_sta_rc_work(&changed, sta); 103098686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 103198686cd2SShayne Chen } 103298686cd2SShayne Chen 103398686cd2SShayne Chen static int 103498686cd2SShayne Chen mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 103598686cd2SShayne Chen const struct cfg80211_bitrate_mask *mask) 103698686cd2SShayne Chen { 103798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 103898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 103998686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 104098686cd2SShayne Chen u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; 104198686cd2SShayne Chen 104298686cd2SShayne Chen mvif->bitrate_mask = *mask; 104398686cd2SShayne Chen 104498686cd2SShayne Chen /* if multiple rates across different preambles are given we can 104598686cd2SShayne Chen * reconfigure this info with all peers using sta_rec command with 104698686cd2SShayne Chen * the below exception cases. 104798686cd2SShayne Chen * - single rate : if a rate is passed along with different preambles, 104898686cd2SShayne Chen * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. 104998686cd2SShayne Chen * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT 105098686cd2SShayne Chen * then multiple MCS setting (MCS 4,5,6) is not supported. 105198686cd2SShayne Chen */ 105298686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); 105398686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 105498686cd2SShayne Chen 105598686cd2SShayne Chen return 0; 105698686cd2SShayne Chen } 105798686cd2SShayne Chen 105898686cd2SShayne Chen static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, 105998686cd2SShayne Chen struct ieee80211_vif *vif, 106098686cd2SShayne Chen struct ieee80211_sta *sta, 106198686cd2SShayne Chen bool enabled) 106298686cd2SShayne Chen { 106398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 106498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 106598686cd2SShayne Chen 106698686cd2SShayne Chen if (enabled) 106798686cd2SShayne Chen set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 106898686cd2SShayne Chen else 106998686cd2SShayne Chen clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 107098686cd2SShayne Chen 107198686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 107298686cd2SShayne Chen } 107398686cd2SShayne Chen 107498686cd2SShayne Chen static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, 107598686cd2SShayne Chen struct ieee80211_vif *vif, 107698686cd2SShayne Chen struct ieee80211_sta *sta, 107798686cd2SShayne Chen bool enabled) 107898686cd2SShayne Chen { 107998686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 108098686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 108198686cd2SShayne Chen 108298686cd2SShayne Chen if (enabled) 108398686cd2SShayne Chen set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 108498686cd2SShayne Chen else 108598686cd2SShayne Chen clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 108698686cd2SShayne Chen 108798686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 108898686cd2SShayne Chen } 108998686cd2SShayne Chen 109098686cd2SShayne Chen static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = { 109198686cd2SShayne Chen "tx_ampdu_cnt", 109298686cd2SShayne Chen "tx_stop_q_empty_cnt", 109398686cd2SShayne Chen "tx_mpdu_attempts", 109498686cd2SShayne Chen "tx_mpdu_success", 109598686cd2SShayne Chen "tx_rwp_fail_cnt", 109698686cd2SShayne Chen "tx_rwp_need_cnt", 109798686cd2SShayne Chen "tx_pkt_ebf_cnt", 109898686cd2SShayne Chen "tx_pkt_ibf_cnt", 109998686cd2SShayne Chen "tx_ampdu_len:0-1", 110098686cd2SShayne Chen "tx_ampdu_len:2-10", 110198686cd2SShayne Chen "tx_ampdu_len:11-19", 110298686cd2SShayne Chen "tx_ampdu_len:20-28", 110398686cd2SShayne Chen "tx_ampdu_len:29-37", 110498686cd2SShayne Chen "tx_ampdu_len:38-46", 110598686cd2SShayne Chen "tx_ampdu_len:47-55", 110698686cd2SShayne Chen "tx_ampdu_len:56-79", 110798686cd2SShayne Chen "tx_ampdu_len:80-103", 110898686cd2SShayne Chen "tx_ampdu_len:104-127", 110998686cd2SShayne Chen "tx_ampdu_len:128-151", 111098686cd2SShayne Chen "tx_ampdu_len:152-175", 111198686cd2SShayne Chen "tx_ampdu_len:176-199", 111298686cd2SShayne Chen "tx_ampdu_len:200-223", 111398686cd2SShayne Chen "tx_ampdu_len:224-247", 111498686cd2SShayne Chen "ba_miss_count", 111598686cd2SShayne Chen "tx_beamformer_ppdu_iBF", 111698686cd2SShayne Chen "tx_beamformer_ppdu_eBF", 111798686cd2SShayne Chen "tx_beamformer_rx_feedback_all", 111898686cd2SShayne Chen "tx_beamformer_rx_feedback_he", 111998686cd2SShayne Chen "tx_beamformer_rx_feedback_vht", 112098686cd2SShayne Chen "tx_beamformer_rx_feedback_ht", 112198686cd2SShayne Chen "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ 112298686cd2SShayne Chen "tx_beamformer_rx_feedback_nc", 112398686cd2SShayne Chen "tx_beamformer_rx_feedback_nr", 112498686cd2SShayne Chen "tx_beamformee_ok_feedback_pkts", 112598686cd2SShayne Chen "tx_beamformee_feedback_trig", 112698686cd2SShayne Chen "tx_mu_beamforming", 112798686cd2SShayne Chen "tx_mu_mpdu", 112898686cd2SShayne Chen "tx_mu_successful_mpdu", 112998686cd2SShayne Chen "tx_su_successful_mpdu", 113098686cd2SShayne Chen "tx_msdu_pack_1", 113198686cd2SShayne Chen "tx_msdu_pack_2", 113298686cd2SShayne Chen "tx_msdu_pack_3", 113398686cd2SShayne Chen "tx_msdu_pack_4", 113498686cd2SShayne Chen "tx_msdu_pack_5", 113598686cd2SShayne Chen "tx_msdu_pack_6", 113698686cd2SShayne Chen "tx_msdu_pack_7", 113798686cd2SShayne Chen "tx_msdu_pack_8", 113898686cd2SShayne Chen 113998686cd2SShayne Chen /* rx counters */ 114098686cd2SShayne Chen "rx_fifo_full_cnt", 114198686cd2SShayne Chen "rx_mpdu_cnt", 114298686cd2SShayne Chen "channel_idle_cnt", 114398686cd2SShayne Chen "rx_vector_mismatch_cnt", 114498686cd2SShayne Chen "rx_delimiter_fail_cnt", 114598686cd2SShayne Chen "rx_len_mismatch_cnt", 114698686cd2SShayne Chen "rx_ampdu_cnt", 114798686cd2SShayne Chen "rx_ampdu_bytes_cnt", 114898686cd2SShayne Chen "rx_ampdu_valid_subframe_cnt", 114998686cd2SShayne Chen "rx_ampdu_valid_subframe_b_cnt", 115098686cd2SShayne Chen "rx_pfdrop_cnt", 115198686cd2SShayne Chen "rx_vec_queue_overflow_drop_cnt", 115298686cd2SShayne Chen "rx_ba_cnt", 115398686cd2SShayne Chen 115498686cd2SShayne Chen /* per vif counters */ 115598686cd2SShayne Chen "v_tx_mode_cck", 115698686cd2SShayne Chen "v_tx_mode_ofdm", 115798686cd2SShayne Chen "v_tx_mode_ht", 115898686cd2SShayne Chen "v_tx_mode_ht_gf", 115998686cd2SShayne Chen "v_tx_mode_vht", 116098686cd2SShayne Chen "v_tx_mode_he_su", 116198686cd2SShayne Chen "v_tx_mode_he_ext_su", 116298686cd2SShayne Chen "v_tx_mode_he_tb", 116398686cd2SShayne Chen "v_tx_mode_he_mu", 1164731425f3SShayne Chen "v_tx_mode_eht_su", 1165731425f3SShayne Chen "v_tx_mode_eht_trig", 1166731425f3SShayne Chen "v_tx_mode_eht_mu", 116798686cd2SShayne Chen "v_tx_bw_20", 116898686cd2SShayne Chen "v_tx_bw_40", 116998686cd2SShayne Chen "v_tx_bw_80", 117098686cd2SShayne Chen "v_tx_bw_160", 1171731425f3SShayne Chen "v_tx_bw_320", 117298686cd2SShayne Chen "v_tx_mcs_0", 117398686cd2SShayne Chen "v_tx_mcs_1", 117498686cd2SShayne Chen "v_tx_mcs_2", 117598686cd2SShayne Chen "v_tx_mcs_3", 117698686cd2SShayne Chen "v_tx_mcs_4", 117798686cd2SShayne Chen "v_tx_mcs_5", 117898686cd2SShayne Chen "v_tx_mcs_6", 117998686cd2SShayne Chen "v_tx_mcs_7", 118098686cd2SShayne Chen "v_tx_mcs_8", 118198686cd2SShayne Chen "v_tx_mcs_9", 118298686cd2SShayne Chen "v_tx_mcs_10", 118398686cd2SShayne Chen "v_tx_mcs_11", 1184731425f3SShayne Chen "v_tx_mcs_12", 1185731425f3SShayne Chen "v_tx_mcs_13", 1186749c2c2bSRyder Lee "v_tx_nss_1", 1187749c2c2bSRyder Lee "v_tx_nss_2", 1188749c2c2bSRyder Lee "v_tx_nss_3", 1189749c2c2bSRyder Lee "v_tx_nss_4", 119098686cd2SShayne Chen }; 119198686cd2SShayne Chen 119298686cd2SShayne Chen #define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats) 119398686cd2SShayne Chen 119498686cd2SShayne Chen /* Ethtool related API */ 119598686cd2SShayne Chen static 119698686cd2SShayne Chen void mt7996_get_et_strings(struct ieee80211_hw *hw, 119798686cd2SShayne Chen struct ieee80211_vif *vif, 119898686cd2SShayne Chen u32 sset, u8 *data) 119998686cd2SShayne Chen { 120098686cd2SShayne Chen if (sset == ETH_SS_STATS) 120198686cd2SShayne Chen memcpy(data, *mt7996_gstrings_stats, 120298686cd2SShayne Chen sizeof(mt7996_gstrings_stats)); 120398686cd2SShayne Chen } 120498686cd2SShayne Chen 120598686cd2SShayne Chen static 120698686cd2SShayne Chen int mt7996_get_et_sset_count(struct ieee80211_hw *hw, 120798686cd2SShayne Chen struct ieee80211_vif *vif, int sset) 120898686cd2SShayne Chen { 120998686cd2SShayne Chen if (sset == ETH_SS_STATS) 121098686cd2SShayne Chen return MT7996_SSTATS_LEN; 121198686cd2SShayne Chen 121298686cd2SShayne Chen return 0; 121398686cd2SShayne Chen } 121498686cd2SShayne Chen 121598686cd2SShayne Chen static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) 121698686cd2SShayne Chen { 121798686cd2SShayne Chen struct mt76_ethtool_worker_info *wi = wi_data; 121898686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 121998686cd2SShayne Chen 122098686cd2SShayne Chen if (msta->vif->mt76.idx != wi->idx) 122198686cd2SShayne Chen return; 122298686cd2SShayne Chen 1223d82e7c67SLorenzo Bianconi mt76_ethtool_worker(wi, &msta->wcid.stats, true); 122498686cd2SShayne Chen } 122598686cd2SShayne Chen 122698686cd2SShayne Chen static 122798686cd2SShayne Chen void mt7996_get_et_stats(struct ieee80211_hw *hw, 122898686cd2SShayne Chen struct ieee80211_vif *vif, 122998686cd2SShayne Chen struct ethtool_stats *stats, u64 *data) 123098686cd2SShayne Chen { 123198686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 123298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 123398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 123498214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib; 123598686cd2SShayne Chen struct mt76_ethtool_worker_info wi = { 123698686cd2SShayne Chen .data = data, 123798686cd2SShayne Chen .idx = mvif->mt76.idx, 123898686cd2SShayne Chen }; 123998686cd2SShayne Chen /* See mt7996_ampdu_stat_read_phy, etc */ 124098686cd2SShayne Chen int i, ei = 0; 124198686cd2SShayne Chen 124298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 124398686cd2SShayne Chen 124498686cd2SShayne Chen mt7996_mac_update_stats(phy); 124598686cd2SShayne Chen 124698686cd2SShayne Chen data[ei++] = mib->tx_ampdu_cnt; 124798686cd2SShayne Chen data[ei++] = mib->tx_stop_q_empty_cnt; 124898686cd2SShayne Chen data[ei++] = mib->tx_mpdu_attempts_cnt; 124998686cd2SShayne Chen data[ei++] = mib->tx_mpdu_success_cnt; 125098686cd2SShayne Chen data[ei++] = mib->tx_rwp_fail_cnt; 125198686cd2SShayne Chen data[ei++] = mib->tx_rwp_need_cnt; 125298686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 125398686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 125498686cd2SShayne Chen 125598686cd2SShayne Chen /* Tx ampdu stat */ 125698686cd2SShayne Chen for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) 125798686cd2SShayne Chen data[ei++] = phy->mt76->aggr_stats[i]; 125898686cd2SShayne Chen data[ei++] = phy->mib.ba_miss_cnt; 125998686cd2SShayne Chen 126098686cd2SShayne Chen /* Tx Beamformer monitor */ 126198686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 126298686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 126398686cd2SShayne Chen 126498686cd2SShayne Chen /* Tx Beamformer Rx feedback monitor */ 126598686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_all_cnt; 126698686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_he_cnt; 126798686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_vht_cnt; 126898686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_ht_cnt; 126998686cd2SShayne Chen 127098686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_bw; 127198686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nc_cnt; 127298686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nr_cnt; 127398686cd2SShayne Chen 127498686cd2SShayne Chen /* Tx Beamformee Rx NDPA & Tx feedback report */ 127598686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_cpl_cnt; 127698686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_trig_cnt; 127798686cd2SShayne Chen 127898686cd2SShayne Chen /* Tx SU & MU counters */ 127998686cd2SShayne Chen data[ei++] = mib->tx_mu_bf_cnt; 128098686cd2SShayne Chen data[ei++] = mib->tx_mu_mpdu_cnt; 128198686cd2SShayne Chen data[ei++] = mib->tx_mu_acked_mpdu_cnt; 128298686cd2SShayne Chen data[ei++] = mib->tx_su_acked_mpdu_cnt; 128398686cd2SShayne Chen 128498686cd2SShayne Chen /* Tx amsdu info (pack-count histogram) */ 128598686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) 128698686cd2SShayne Chen data[ei++] = mib->tx_amsdu[i]; 128798686cd2SShayne Chen 128898686cd2SShayne Chen /* rx counters */ 128998686cd2SShayne Chen data[ei++] = mib->rx_fifo_full_cnt; 129098686cd2SShayne Chen data[ei++] = mib->rx_mpdu_cnt; 129198686cd2SShayne Chen data[ei++] = mib->channel_idle_cnt; 129298686cd2SShayne Chen data[ei++] = mib->rx_vector_mismatch_cnt; 129398686cd2SShayne Chen data[ei++] = mib->rx_delimiter_fail_cnt; 129498686cd2SShayne Chen data[ei++] = mib->rx_len_mismatch_cnt; 129598686cd2SShayne Chen data[ei++] = mib->rx_ampdu_cnt; 129698686cd2SShayne Chen data[ei++] = mib->rx_ampdu_bytes_cnt; 129798686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_cnt; 129898686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; 129998686cd2SShayne Chen data[ei++] = mib->rx_pfdrop_cnt; 130098686cd2SShayne Chen data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; 130198686cd2SShayne Chen data[ei++] = mib->rx_ba_cnt; 130298686cd2SShayne Chen 130398686cd2SShayne Chen /* Add values for all stations owned by this vif */ 130498686cd2SShayne Chen wi.initial_stat_idx = ei; 130598686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_ethtool_worker, &wi); 130698686cd2SShayne Chen 130798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 130898686cd2SShayne Chen 130998686cd2SShayne Chen if (wi.sta_count == 0) 131098686cd2SShayne Chen return; 131198686cd2SShayne Chen 131298686cd2SShayne Chen ei += wi.worker_stat_count; 131398686cd2SShayne Chen if (ei != MT7996_SSTATS_LEN) 131498686cd2SShayne Chen dev_err(dev->mt76.dev, "ei: %d MT7996_SSTATS_LEN: %d", 131598686cd2SShayne Chen ei, (int)MT7996_SSTATS_LEN); 131698686cd2SShayne Chen } 131798686cd2SShayne Chen 131898686cd2SShayne Chen static void 131998686cd2SShayne Chen mt7996_twt_teardown_request(struct ieee80211_hw *hw, 132098686cd2SShayne Chen struct ieee80211_sta *sta, 132198686cd2SShayne Chen u8 flowid) 132298686cd2SShayne Chen { 132398686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 132498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 132598686cd2SShayne Chen 132698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 132798686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, flowid); 132898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 132998686cd2SShayne Chen } 133098686cd2SShayne Chen 133198686cd2SShayne Chen static int 133298686cd2SShayne Chen mt7996_set_radar_background(struct ieee80211_hw *hw, 133398686cd2SShayne Chen struct cfg80211_chan_def *chandef) 133498686cd2SShayne Chen { 133598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 133698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 133798686cd2SShayne Chen int ret = -EINVAL; 133898686cd2SShayne Chen bool running; 133998686cd2SShayne Chen 134098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 134198686cd2SShayne Chen 134298686cd2SShayne Chen if (dev->mt76.region == NL80211_DFS_UNSET) 134398686cd2SShayne Chen goto out; 134498686cd2SShayne Chen 134598686cd2SShayne Chen if (dev->rdd2_phy && dev->rdd2_phy != phy) { 134698686cd2SShayne Chen /* rdd2 is already locked */ 134798686cd2SShayne Chen ret = -EBUSY; 134898686cd2SShayne Chen goto out; 134998686cd2SShayne Chen } 135098686cd2SShayne Chen 135198686cd2SShayne Chen /* rdd2 already configured on a radar channel */ 135298686cd2SShayne Chen running = dev->rdd2_phy && 135398686cd2SShayne Chen cfg80211_chandef_valid(&dev->rdd2_chandef) && 135498686cd2SShayne Chen !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); 135598686cd2SShayne Chen 135698686cd2SShayne Chen if (!chandef || running || 135798686cd2SShayne Chen !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { 135898686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, NULL); 135998686cd2SShayne Chen if (ret) 136098686cd2SShayne Chen goto out; 136198686cd2SShayne Chen 136298686cd2SShayne Chen if (!running) 136398686cd2SShayne Chen goto update_phy; 136498686cd2SShayne Chen } 136598686cd2SShayne Chen 136698686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, chandef); 136798686cd2SShayne Chen if (ret) 136898686cd2SShayne Chen goto out; 136998686cd2SShayne Chen 137098686cd2SShayne Chen update_phy: 137198686cd2SShayne Chen dev->rdd2_phy = chandef ? phy : NULL; 137298686cd2SShayne Chen if (chandef) 137398686cd2SShayne Chen dev->rdd2_chandef = *chandef; 137498686cd2SShayne Chen out: 137598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 137698686cd2SShayne Chen 137798686cd2SShayne Chen return ret; 137898686cd2SShayne Chen } 137998686cd2SShayne Chen 138098686cd2SShayne Chen const struct ieee80211_ops mt7996_ops = { 138198686cd2SShayne Chen .tx = mt7996_tx, 138298686cd2SShayne Chen .start = mt7996_start, 138398686cd2SShayne Chen .stop = mt7996_stop, 138498686cd2SShayne Chen .add_interface = mt7996_add_interface, 138598686cd2SShayne Chen .remove_interface = mt7996_remove_interface, 138698686cd2SShayne Chen .config = mt7996_config, 138798686cd2SShayne Chen .conf_tx = mt7996_conf_tx, 138898686cd2SShayne Chen .configure_filter = mt7996_configure_filter, 138998686cd2SShayne Chen .bss_info_changed = mt7996_bss_info_changed, 139098686cd2SShayne Chen .sta_add = mt7996_sta_add, 139198686cd2SShayne Chen .sta_remove = mt7996_sta_remove, 139298686cd2SShayne Chen .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 139398686cd2SShayne Chen .sta_rc_update = mt7996_sta_rc_update, 139498686cd2SShayne Chen .set_key = mt7996_set_key, 139598686cd2SShayne Chen .ampdu_action = mt7996_ampdu_action, 139698686cd2SShayne Chen .set_rts_threshold = mt7996_set_rts_threshold, 139798686cd2SShayne Chen .wake_tx_queue = mt76_wake_tx_queue, 139898686cd2SShayne Chen .sw_scan_start = mt76_sw_scan, 139998686cd2SShayne Chen .sw_scan_complete = mt76_sw_scan_complete, 140098686cd2SShayne Chen .release_buffered_frames = mt76_release_buffered_frames, 140198686cd2SShayne Chen .get_txpower = mt76_get_txpower, 140298686cd2SShayne Chen .channel_switch_beacon = mt7996_channel_switch_beacon, 140398686cd2SShayne Chen .get_stats = mt7996_get_stats, 140498686cd2SShayne Chen .get_et_sset_count = mt7996_get_et_sset_count, 140598686cd2SShayne Chen .get_et_stats = mt7996_get_et_stats, 140698686cd2SShayne Chen .get_et_strings = mt7996_get_et_strings, 140798686cd2SShayne Chen .get_tsf = mt7996_get_tsf, 140898686cd2SShayne Chen .set_tsf = mt7996_set_tsf, 140998686cd2SShayne Chen .offset_tsf = mt7996_offset_tsf, 141098686cd2SShayne Chen .get_survey = mt76_get_survey, 141198686cd2SShayne Chen .get_antenna = mt76_get_antenna, 141298686cd2SShayne Chen .set_antenna = mt7996_set_antenna, 141398686cd2SShayne Chen .set_bitrate_mask = mt7996_set_bitrate_mask, 141498686cd2SShayne Chen .set_coverage_class = mt7996_set_coverage_class, 141598686cd2SShayne Chen .sta_statistics = mt7996_sta_statistics, 141698686cd2SShayne Chen .sta_set_4addr = mt7996_sta_set_4addr, 141798686cd2SShayne Chen .sta_set_decap_offload = mt7996_sta_set_decap_offload, 141898686cd2SShayne Chen .add_twt_setup = mt7996_mac_add_twt_setup, 141998686cd2SShayne Chen .twt_teardown_request = mt7996_twt_teardown_request, 142098686cd2SShayne Chen #ifdef CONFIG_MAC80211_DEBUGFS 142198686cd2SShayne Chen .sta_add_debugfs = mt7996_sta_add_debugfs, 142298686cd2SShayne Chen #endif 142398686cd2SShayne Chen .set_radar_background = mt7996_set_radar_background, 142498686cd2SShayne Chen }; 1425