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" 898686cd2SShayne Chen 998686cd2SShayne Chen static bool mt7996_dev_running(struct mt7996_dev *dev) 1098686cd2SShayne Chen { 1198686cd2SShayne Chen struct mt7996_phy *phy; 1298686cd2SShayne Chen 1398686cd2SShayne Chen if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 1498686cd2SShayne Chen return true; 1598686cd2SShayne Chen 1698686cd2SShayne Chen phy = mt7996_phy2(dev); 1798686cd2SShayne Chen if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 1898686cd2SShayne Chen return true; 1998686cd2SShayne Chen 2098686cd2SShayne Chen phy = mt7996_phy3(dev); 2198686cd2SShayne Chen 2298686cd2SShayne Chen return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); 2398686cd2SShayne Chen } 2498686cd2SShayne Chen 25*27015b6fSBo Jiao int mt7996_run(struct ieee80211_hw *hw) 2698686cd2SShayne Chen { 2798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 2898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 2998686cd2SShayne Chen bool running; 3098686cd2SShayne Chen int ret; 3198686cd2SShayne Chen 3298686cd2SShayne Chen running = mt7996_dev_running(dev); 3398686cd2SShayne Chen if (!running) { 3498686cd2SShayne Chen ret = mt7996_mcu_set_hdr_trans(dev, true); 3598686cd2SShayne Chen if (ret) 3698686cd2SShayne Chen goto out; 3798686cd2SShayne Chen } 3898686cd2SShayne Chen 3998686cd2SShayne Chen mt7996_mac_enable_nf(dev, phy->mt76->band_idx); 4098686cd2SShayne Chen 4198686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, 0x92b); 4298686cd2SShayne Chen if (ret) 4398686cd2SShayne Chen goto out; 4498686cd2SShayne Chen 4598686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); 4698686cd2SShayne Chen if (ret) 4798686cd2SShayne Chen goto out; 4898686cd2SShayne Chen 4998686cd2SShayne Chen set_bit(MT76_STATE_RUNNING, &phy->mt76->state); 5098686cd2SShayne Chen 5198686cd2SShayne Chen ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, 5298686cd2SShayne Chen MT7996_WATCHDOG_TIME); 5398686cd2SShayne Chen 5498686cd2SShayne Chen if (!running) 5598686cd2SShayne Chen mt7996_mac_reset_counters(phy); 5698686cd2SShayne Chen 5798686cd2SShayne Chen out: 58*27015b6fSBo Jiao return ret; 59*27015b6fSBo Jiao } 60*27015b6fSBo Jiao 61*27015b6fSBo Jiao static int mt7996_start(struct ieee80211_hw *hw) 62*27015b6fSBo Jiao { 63*27015b6fSBo Jiao struct mt7996_dev *dev = mt7996_hw_dev(hw); 64*27015b6fSBo Jiao int ret; 65*27015b6fSBo Jiao 66*27015b6fSBo Jiao flush_work(&dev->init_work); 67*27015b6fSBo Jiao 68*27015b6fSBo Jiao mutex_lock(&dev->mt76.mutex); 69*27015b6fSBo Jiao ret = mt7996_run(hw); 7098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 7198686cd2SShayne Chen 7298686cd2SShayne Chen return ret; 7398686cd2SShayne Chen } 7498686cd2SShayne Chen 7598686cd2SShayne Chen static void mt7996_stop(struct ieee80211_hw *hw) 7698686cd2SShayne Chen { 7798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 7898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 7998686cd2SShayne Chen 8098686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 8198686cd2SShayne Chen 8298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 8398686cd2SShayne Chen 8498686cd2SShayne Chen clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); 8598686cd2SShayne Chen 8698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 8798686cd2SShayne Chen } 8898686cd2SShayne Chen 8998686cd2SShayne Chen static inline int get_free_idx(u32 mask, u8 start, u8 end) 9098686cd2SShayne Chen { 9198686cd2SShayne Chen return ffs(~mask & GENMASK(end, start)); 9298686cd2SShayne Chen } 9398686cd2SShayne Chen 9498686cd2SShayne Chen static int get_omac_idx(enum nl80211_iftype type, u64 mask) 9598686cd2SShayne Chen { 9698686cd2SShayne Chen int i; 9798686cd2SShayne Chen 9898686cd2SShayne Chen switch (type) { 9998686cd2SShayne Chen case NL80211_IFTYPE_MESH_POINT: 10098686cd2SShayne Chen case NL80211_IFTYPE_ADHOC: 10198686cd2SShayne Chen case NL80211_IFTYPE_STATION: 10298686cd2SShayne Chen /* prefer hw bssid slot 1-3 */ 10398686cd2SShayne Chen i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); 10498686cd2SShayne Chen if (i) 10598686cd2SShayne Chen return i - 1; 10698686cd2SShayne Chen 10798686cd2SShayne Chen if (type != NL80211_IFTYPE_STATION) 10898686cd2SShayne Chen break; 10998686cd2SShayne Chen 11098686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 11198686cd2SShayne Chen if (i) 11298686cd2SShayne Chen return i - 1; 11398686cd2SShayne Chen 11498686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 11598686cd2SShayne Chen return HW_BSSID_0; 11698686cd2SShayne Chen 11798686cd2SShayne Chen break; 11898686cd2SShayne Chen case NL80211_IFTYPE_MONITOR: 11998686cd2SShayne Chen case NL80211_IFTYPE_AP: 12098686cd2SShayne Chen /* ap uses hw bssid 0 and ext bssid */ 12198686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 12298686cd2SShayne Chen return HW_BSSID_0; 12398686cd2SShayne Chen 12498686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 12598686cd2SShayne Chen if (i) 12698686cd2SShayne Chen return i - 1; 12798686cd2SShayne Chen 12898686cd2SShayne Chen break; 12998686cd2SShayne Chen default: 13098686cd2SShayne Chen WARN_ON(1); 13198686cd2SShayne Chen break; 13298686cd2SShayne Chen } 13398686cd2SShayne Chen 13498686cd2SShayne Chen return -1; 13598686cd2SShayne Chen } 13698686cd2SShayne Chen 13798686cd2SShayne Chen static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif) 13898686cd2SShayne Chen { 13998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 14098686cd2SShayne Chen int i; 14198686cd2SShayne Chen 14298686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { 14398686cd2SShayne Chen mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; 14498686cd2SShayne Chen mvif->bitrate_mask.control[i].he_gi = 0xff; 14598686cd2SShayne Chen mvif->bitrate_mask.control[i].he_ltf = 0xff; 14698686cd2SShayne Chen mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); 14798686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, 14898686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].ht_mcs)); 14998686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, 15098686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].vht_mcs)); 15198686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, 15298686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].he_mcs)); 15398686cd2SShayne Chen } 15498686cd2SShayne Chen } 15598686cd2SShayne Chen 15698686cd2SShayne Chen static int mt7996_add_interface(struct ieee80211_hw *hw, 15798686cd2SShayne Chen struct ieee80211_vif *vif) 15898686cd2SShayne Chen { 15998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 16098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 16198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 16298686cd2SShayne Chen struct mt76_txq *mtxq; 16398686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx; 16498686cd2SShayne Chen int idx, ret = 0; 16598686cd2SShayne Chen 16698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 16798686cd2SShayne Chen 16898686cd2SShayne Chen if (vif->type == NL80211_IFTYPE_MONITOR && 16998686cd2SShayne Chen is_zero_ether_addr(vif->addr)) 17098686cd2SShayne Chen phy->monitor_vif = vif; 17198686cd2SShayne Chen 17298686cd2SShayne Chen mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); 17343482540SShayne Chen if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) { 17498686cd2SShayne Chen ret = -ENOSPC; 17598686cd2SShayne Chen goto out; 17698686cd2SShayne Chen } 17798686cd2SShayne Chen 17898686cd2SShayne Chen idx = get_omac_idx(vif->type, phy->omac_mask); 17998686cd2SShayne Chen if (idx < 0) { 18098686cd2SShayne Chen ret = -ENOSPC; 18198686cd2SShayne Chen goto out; 18298686cd2SShayne Chen } 18398686cd2SShayne Chen mvif->mt76.omac_idx = idx; 18498686cd2SShayne Chen mvif->phy = phy; 18598686cd2SShayne Chen mvif->mt76.band_idx = band_idx; 18698686cd2SShayne Chen mvif->mt76.wmm_idx = band_idx; 18798686cd2SShayne Chen 18898686cd2SShayne Chen ret = mt7996_mcu_add_dev_info(phy, vif, true); 18998686cd2SShayne Chen if (ret) 19098686cd2SShayne Chen goto out; 19198686cd2SShayne Chen 19298686cd2SShayne Chen ret = mt7996_mcu_set_radio_en(phy, true); 19398686cd2SShayne Chen if (ret) 19498686cd2SShayne Chen goto out; 19598686cd2SShayne Chen 19698686cd2SShayne Chen dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); 19798686cd2SShayne Chen phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); 19898686cd2SShayne Chen 19998686cd2SShayne Chen idx = MT7996_WTBL_RESERVED - mvif->mt76.idx; 20098686cd2SShayne Chen 20198686cd2SShayne Chen INIT_LIST_HEAD(&mvif->sta.rc_list); 20298686cd2SShayne Chen INIT_LIST_HEAD(&mvif->sta.poll_list); 20398686cd2SShayne Chen mvif->sta.wcid.idx = idx; 20498686cd2SShayne Chen mvif->sta.wcid.phy_idx = band_idx; 20598686cd2SShayne Chen mvif->sta.wcid.hw_key_idx = -1; 20698686cd2SShayne Chen mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; 20798686cd2SShayne Chen mt76_packet_id_init(&mvif->sta.wcid); 20898686cd2SShayne Chen 20998686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 21098686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 21198686cd2SShayne Chen 21298686cd2SShayne Chen if (vif->txq) { 21398686cd2SShayne Chen mtxq = (struct mt76_txq *)vif->txq->drv_priv; 21498686cd2SShayne Chen mtxq->wcid = idx; 21598686cd2SShayne Chen } 21698686cd2SShayne Chen 21798686cd2SShayne Chen if (vif->type != NL80211_IFTYPE_AP && 21898686cd2SShayne Chen (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) 21998686cd2SShayne Chen vif->offload_flags = 0; 22098686cd2SShayne Chen vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; 22198686cd2SShayne Chen 22298686cd2SShayne Chen mt7996_init_bitrate_mask(vif); 22398686cd2SShayne Chen 22498686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 22598686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 22698686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); 22798686cd2SShayne Chen 22898686cd2SShayne Chen out: 22998686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 23098686cd2SShayne Chen 23198686cd2SShayne Chen return ret; 23298686cd2SShayne Chen } 23398686cd2SShayne Chen 23498686cd2SShayne Chen static void mt7996_remove_interface(struct ieee80211_hw *hw, 23598686cd2SShayne Chen struct ieee80211_vif *vif) 23698686cd2SShayne Chen { 23798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 23898686cd2SShayne Chen struct mt7996_sta *msta = &mvif->sta; 23998686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 24098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 24198686cd2SShayne Chen int idx = msta->wcid.idx; 24298686cd2SShayne Chen 24398686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, false); 24498686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, false); 24598686cd2SShayne Chen 24698686cd2SShayne Chen if (vif == phy->monitor_vif) 24798686cd2SShayne Chen phy->monitor_vif = NULL; 24898686cd2SShayne Chen 24998686cd2SShayne Chen mt7996_mcu_add_dev_info(phy, vif, false); 25098686cd2SShayne Chen mt7996_mcu_set_radio_en(phy, false); 25198686cd2SShayne Chen 25298686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], NULL); 25398686cd2SShayne Chen 25498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 25598686cd2SShayne Chen dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); 25698686cd2SShayne Chen phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); 25798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 25898686cd2SShayne Chen 25998686cd2SShayne Chen spin_lock_bh(&dev->sta_poll_lock); 26098686cd2SShayne Chen if (!list_empty(&msta->poll_list)) 26198686cd2SShayne Chen list_del_init(&msta->poll_list); 26298686cd2SShayne Chen spin_unlock_bh(&dev->sta_poll_lock); 26398686cd2SShayne Chen 26498686cd2SShayne Chen mt76_packet_id_flush(&dev->mt76, &msta->wcid); 26598686cd2SShayne Chen } 26698686cd2SShayne Chen 26798686cd2SShayne Chen int mt7996_set_channel(struct mt7996_phy *phy) 26898686cd2SShayne Chen { 26998686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 27098686cd2SShayne Chen int ret; 27198686cd2SShayne Chen 27298686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 27398686cd2SShayne Chen 27498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 27598686cd2SShayne Chen set_bit(MT76_RESET, &phy->mt76->state); 27698686cd2SShayne Chen 27798686cd2SShayne Chen mt76_set_channel(phy->mt76); 27898686cd2SShayne Chen 27998686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); 28098686cd2SShayne Chen if (ret) 28198686cd2SShayne Chen goto out; 28298686cd2SShayne Chen 28398686cd2SShayne Chen mt7996_mac_set_timing(phy); 28498686cd2SShayne Chen ret = mt7996_dfs_init_radar_detector(phy); 28598686cd2SShayne Chen mt7996_mac_cca_stats_reset(phy); 28698686cd2SShayne Chen 28798686cd2SShayne Chen mt7996_mac_reset_counters(phy); 28898686cd2SShayne Chen phy->noise = 0; 28998686cd2SShayne Chen 29098686cd2SShayne Chen out: 29198686cd2SShayne Chen clear_bit(MT76_RESET, &phy->mt76->state); 29298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 29398686cd2SShayne Chen 29498686cd2SShayne Chen mt76_txq_schedule_all(phy->mt76); 29598686cd2SShayne Chen 29698686cd2SShayne Chen ieee80211_queue_delayed_work(phy->mt76->hw, 29798686cd2SShayne Chen &phy->mt76->mac_work, 29898686cd2SShayne Chen MT7996_WATCHDOG_TIME); 29998686cd2SShayne Chen 30098686cd2SShayne Chen return ret; 30198686cd2SShayne Chen } 30298686cd2SShayne Chen 30398686cd2SShayne Chen static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 30498686cd2SShayne Chen struct ieee80211_vif *vif, struct ieee80211_sta *sta, 30598686cd2SShayne Chen struct ieee80211_key_conf *key) 30698686cd2SShayne Chen { 30798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 30898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 30998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 31098686cd2SShayne Chen struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : 31198686cd2SShayne Chen &mvif->sta; 31298686cd2SShayne Chen struct mt76_wcid *wcid = &msta->wcid; 31398686cd2SShayne Chen u8 *wcid_keyidx = &wcid->hw_key_idx; 31498686cd2SShayne Chen int idx = key->keyidx; 31598686cd2SShayne Chen int err = 0; 31698686cd2SShayne Chen 31798686cd2SShayne Chen /* The hardware does not support per-STA RX GTK, fallback 31898686cd2SShayne Chen * to software mode for these. 31998686cd2SShayne Chen */ 32098686cd2SShayne Chen if ((vif->type == NL80211_IFTYPE_ADHOC || 32198686cd2SShayne Chen vif->type == NL80211_IFTYPE_MESH_POINT) && 32298686cd2SShayne Chen (key->cipher == WLAN_CIPHER_SUITE_TKIP || 32398686cd2SShayne Chen key->cipher == WLAN_CIPHER_SUITE_CCMP) && 32498686cd2SShayne Chen !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 32598686cd2SShayne Chen return -EOPNOTSUPP; 32698686cd2SShayne Chen 32798686cd2SShayne Chen /* fall back to sw encryption for unsupported ciphers */ 32898686cd2SShayne Chen switch (key->cipher) { 32998686cd2SShayne Chen case WLAN_CIPHER_SUITE_AES_CMAC: 33098686cd2SShayne Chen wcid_keyidx = &wcid->hw_key_idx2; 33198686cd2SShayne Chen key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; 33298686cd2SShayne Chen break; 33398686cd2SShayne Chen case WLAN_CIPHER_SUITE_TKIP: 33498686cd2SShayne Chen case WLAN_CIPHER_SUITE_CCMP: 33598686cd2SShayne Chen case WLAN_CIPHER_SUITE_CCMP_256: 33698686cd2SShayne Chen case WLAN_CIPHER_SUITE_GCMP: 33798686cd2SShayne Chen case WLAN_CIPHER_SUITE_GCMP_256: 33898686cd2SShayne Chen case WLAN_CIPHER_SUITE_SMS4: 33998686cd2SShayne Chen break; 34098686cd2SShayne Chen case WLAN_CIPHER_SUITE_WEP40: 34198686cd2SShayne Chen case WLAN_CIPHER_SUITE_WEP104: 34298686cd2SShayne Chen default: 34398686cd2SShayne Chen return -EOPNOTSUPP; 34498686cd2SShayne Chen } 34598686cd2SShayne Chen 34698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 34798686cd2SShayne Chen 34898686cd2SShayne Chen if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { 34998686cd2SShayne Chen mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); 35098686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 35198686cd2SShayne Chen } 35298686cd2SShayne Chen 35398686cd2SShayne Chen if (cmd == SET_KEY) 35498686cd2SShayne Chen *wcid_keyidx = idx; 35598686cd2SShayne Chen else if (idx == *wcid_keyidx) 35698686cd2SShayne Chen *wcid_keyidx = -1; 35798686cd2SShayne Chen else 35898686cd2SShayne Chen goto out; 35998686cd2SShayne Chen 36098686cd2SShayne Chen mt76_wcid_key_setup(&dev->mt76, wcid, 36198686cd2SShayne Chen cmd == SET_KEY ? key : NULL); 36298686cd2SShayne Chen 36398686cd2SShayne Chen err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip, 36498686cd2SShayne Chen key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), 36598686cd2SShayne Chen &msta->wcid, cmd); 36698686cd2SShayne Chen out: 36798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 36898686cd2SShayne Chen 36998686cd2SShayne Chen return err; 37098686cd2SShayne Chen } 37198686cd2SShayne Chen 37298686cd2SShayne Chen static int mt7996_config(struct ieee80211_hw *hw, u32 changed) 37398686cd2SShayne Chen { 37498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 37598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 37698686cd2SShayne Chen int ret; 37798686cd2SShayne Chen 37898686cd2SShayne Chen if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 37998686cd2SShayne Chen ieee80211_stop_queues(hw); 38098686cd2SShayne Chen ret = mt7996_set_channel(phy); 38198686cd2SShayne Chen if (ret) 38298686cd2SShayne Chen return ret; 38398686cd2SShayne Chen ieee80211_wake_queues(hw); 38498686cd2SShayne Chen } 38598686cd2SShayne Chen 38698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 38798686cd2SShayne Chen 38898686cd2SShayne Chen if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 38998686cd2SShayne Chen bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); 39098686cd2SShayne Chen 39198686cd2SShayne Chen if (!enabled) 39298686cd2SShayne Chen phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; 39398686cd2SShayne Chen else 39498686cd2SShayne Chen phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; 39598686cd2SShayne Chen 39698686cd2SShayne Chen mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), 39798686cd2SShayne Chen MT_DMA_DCR0_RXD_G5_EN, enabled); 39898686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 39998686cd2SShayne Chen } 40098686cd2SShayne Chen 40198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 40298686cd2SShayne Chen 40398686cd2SShayne Chen return 0; 40498686cd2SShayne Chen } 40598686cd2SShayne Chen 40698686cd2SShayne Chen static int 40798686cd2SShayne Chen mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 40898686cd2SShayne Chen unsigned int link_id, u16 queue, 40998686cd2SShayne Chen const struct ieee80211_tx_queue_params *params) 41098686cd2SShayne Chen { 41198686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 41298686cd2SShayne Chen 41398686cd2SShayne Chen /* no need to update right away, we'll get BSS_CHANGED_QOS */ 41498686cd2SShayne Chen queue = mt76_connac_lmac_mapping(queue); 41598686cd2SShayne Chen mvif->queue_params[queue] = *params; 41698686cd2SShayne Chen 41798686cd2SShayne Chen return 0; 41898686cd2SShayne Chen } 41998686cd2SShayne Chen 42098686cd2SShayne Chen static void mt7996_configure_filter(struct ieee80211_hw *hw, 42198686cd2SShayne Chen unsigned int changed_flags, 42298686cd2SShayne Chen unsigned int *total_flags, 42398686cd2SShayne Chen u64 multicast) 42498686cd2SShayne Chen { 42598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 42698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 42798686cd2SShayne Chen u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | 42898686cd2SShayne Chen MT_WF_RFCR1_DROP_BF_POLL | 42998686cd2SShayne Chen MT_WF_RFCR1_DROP_BA | 43098686cd2SShayne Chen MT_WF_RFCR1_DROP_CFEND | 43198686cd2SShayne Chen MT_WF_RFCR1_DROP_CFACK; 43298686cd2SShayne Chen u32 flags = 0; 43398686cd2SShayne Chen 43498686cd2SShayne Chen #define MT76_FILTER(_flag, _hw) do { \ 43598686cd2SShayne Chen flags |= *total_flags & FIF_##_flag; \ 43698686cd2SShayne Chen phy->rxfilter &= ~(_hw); \ 43798686cd2SShayne Chen phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 43898686cd2SShayne Chen } while (0) 43998686cd2SShayne Chen 44098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 44198686cd2SShayne Chen 44298686cd2SShayne Chen phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | 44398686cd2SShayne Chen MT_WF_RFCR_DROP_OTHER_BEACON | 44498686cd2SShayne Chen MT_WF_RFCR_DROP_FRAME_REPORT | 44598686cd2SShayne Chen MT_WF_RFCR_DROP_PROBEREQ | 44698686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST_FILTERED | 44798686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST | 44898686cd2SShayne Chen MT_WF_RFCR_DROP_BCAST | 44998686cd2SShayne Chen MT_WF_RFCR_DROP_DUPLICATE | 45098686cd2SShayne Chen MT_WF_RFCR_DROP_A2_BSSID | 45198686cd2SShayne Chen MT_WF_RFCR_DROP_UNWANTED_CTL | 45298686cd2SShayne Chen MT_WF_RFCR_DROP_STBC_MULTI); 45398686cd2SShayne Chen 45498686cd2SShayne Chen MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | 45598686cd2SShayne Chen MT_WF_RFCR_DROP_A3_MAC | 45698686cd2SShayne Chen MT_WF_RFCR_DROP_A3_BSSID); 45798686cd2SShayne Chen 45898686cd2SShayne Chen MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); 45998686cd2SShayne Chen 46098686cd2SShayne Chen MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | 46198686cd2SShayne Chen MT_WF_RFCR_DROP_RTS | 46298686cd2SShayne Chen MT_WF_RFCR_DROP_CTL_RSV | 46398686cd2SShayne Chen MT_WF_RFCR_DROP_NDPA); 46498686cd2SShayne Chen 46598686cd2SShayne Chen *total_flags = flags; 46698686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 46798686cd2SShayne Chen 46898686cd2SShayne Chen if (*total_flags & FIF_CONTROL) 46998686cd2SShayne Chen mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 47098686cd2SShayne Chen else 47198686cd2SShayne Chen mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 47298686cd2SShayne Chen 47398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 47498686cd2SShayne Chen } 47598686cd2SShayne Chen 47698686cd2SShayne Chen static void 47798686cd2SShayne Chen mt7996_update_bss_color(struct ieee80211_hw *hw, 47898686cd2SShayne Chen struct ieee80211_vif *vif, 47998686cd2SShayne Chen struct cfg80211_he_bss_color *bss_color) 48098686cd2SShayne Chen { 48198686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 48298686cd2SShayne Chen 48398686cd2SShayne Chen switch (vif->type) { 48498686cd2SShayne Chen case NL80211_IFTYPE_AP: { 48598686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 48698686cd2SShayne Chen 48798686cd2SShayne Chen if (mvif->mt76.omac_idx > HW_BSSID_MAX) 48898686cd2SShayne Chen return; 48998686cd2SShayne Chen fallthrough; 49098686cd2SShayne Chen } 49198686cd2SShayne Chen case NL80211_IFTYPE_STATION: 49298686cd2SShayne Chen mt7996_mcu_update_bss_color(dev, vif, bss_color); 49398686cd2SShayne Chen break; 49498686cd2SShayne Chen default: 49598686cd2SShayne Chen break; 49698686cd2SShayne Chen } 49798686cd2SShayne Chen } 49898686cd2SShayne Chen 49998686cd2SShayne Chen static void mt7996_bss_info_changed(struct ieee80211_hw *hw, 50098686cd2SShayne Chen struct ieee80211_vif *vif, 50198686cd2SShayne Chen struct ieee80211_bss_conf *info, 50298686cd2SShayne Chen u64 changed) 50398686cd2SShayne Chen { 50498686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 50598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 50698686cd2SShayne Chen 50798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 50898686cd2SShayne Chen 50998686cd2SShayne Chen /* station mode uses BSSID to map the wlan entry to a peer, 51098686cd2SShayne Chen * and then peer references bss_info_rfch to set bandwidth cap. 51198686cd2SShayne Chen */ 51298686cd2SShayne Chen if (changed & BSS_CHANGED_BSSID && 51398686cd2SShayne Chen vif->type == NL80211_IFTYPE_STATION) { 51498686cd2SShayne Chen bool join = !is_zero_ether_addr(info->bssid); 51598686cd2SShayne Chen 51698686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, join); 51798686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, join); 51898686cd2SShayne Chen } 51998686cd2SShayne Chen 520cf6dc2dbSRyder Lee if (changed & BSS_CHANGED_ASSOC) 52198686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc); 52298686cd2SShayne Chen 523d75e739bSRyder Lee if (changed & BSS_CHANGED_ERP_CTS_PROT) 524d75e739bSRyder Lee mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); 525d75e739bSRyder Lee 52698686cd2SShayne Chen if (changed & BSS_CHANGED_ERP_SLOT) { 52798686cd2SShayne Chen int slottime = info->use_short_slot ? 9 : 20; 52898686cd2SShayne Chen 52998686cd2SShayne Chen if (slottime != phy->slottime) { 53098686cd2SShayne Chen phy->slottime = slottime; 53198686cd2SShayne Chen mt7996_mac_set_timing(phy); 53298686cd2SShayne Chen } 53398686cd2SShayne Chen } 53498686cd2SShayne Chen 53598686cd2SShayne Chen if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { 53698686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 53798686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 53898686cd2SShayne Chen } 53998686cd2SShayne Chen 54098686cd2SShayne Chen /* ensure that enable txcmd_mode after bss_info */ 54198686cd2SShayne Chen if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) 54298686cd2SShayne Chen mt7996_mcu_set_tx(dev, vif); 54398686cd2SShayne Chen 54498686cd2SShayne Chen if (changed & BSS_CHANGED_HE_OBSS_PD) 545cf6dc2dbSRyder Lee mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 54698686cd2SShayne Chen 54798686cd2SShayne Chen if (changed & BSS_CHANGED_HE_BSS_COLOR) 54898686cd2SShayne Chen mt7996_update_bss_color(hw, vif, &info->he_bss_color); 54998686cd2SShayne Chen 55098686cd2SShayne Chen if (changed & (BSS_CHANGED_BEACON | 55198686cd2SShayne Chen BSS_CHANGED_BEACON_ENABLED)) 55298686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); 55398686cd2SShayne Chen 55498686cd2SShayne Chen if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP || 55598686cd2SShayne Chen changed & BSS_CHANGED_FILS_DISCOVERY) 55698686cd2SShayne Chen mt7996_mcu_beacon_inband_discov(dev, vif, changed); 55798686cd2SShayne Chen 55898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 55998686cd2SShayne Chen } 56098686cd2SShayne Chen 56198686cd2SShayne Chen static void 56298686cd2SShayne Chen mt7996_channel_switch_beacon(struct ieee80211_hw *hw, 56398686cd2SShayne Chen struct ieee80211_vif *vif, 56498686cd2SShayne Chen struct cfg80211_chan_def *chandef) 56598686cd2SShayne Chen { 56698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 56798686cd2SShayne Chen 56898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 56998686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, true); 57098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 57198686cd2SShayne Chen } 57298686cd2SShayne Chen 57398686cd2SShayne Chen int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 57498686cd2SShayne Chen struct ieee80211_sta *sta) 57598686cd2SShayne Chen { 57698686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 57798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 57898686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 57998686cd2SShayne Chen u8 band_idx = mvif->phy->mt76->band_idx; 58098686cd2SShayne Chen int ret, idx; 58198686cd2SShayne Chen 58298686cd2SShayne Chen idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); 58398686cd2SShayne Chen if (idx < 0) 58498686cd2SShayne Chen return -ENOSPC; 58598686cd2SShayne Chen 58698686cd2SShayne Chen INIT_LIST_HEAD(&msta->rc_list); 58798686cd2SShayne Chen INIT_LIST_HEAD(&msta->poll_list); 58898686cd2SShayne Chen msta->vif = mvif; 58998686cd2SShayne Chen msta->wcid.sta = 1; 59098686cd2SShayne Chen msta->wcid.idx = idx; 59198686cd2SShayne Chen msta->wcid.phy_idx = band_idx; 59298686cd2SShayne Chen msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 59398686cd2SShayne Chen msta->jiffies = jiffies; 59498686cd2SShayne Chen 595ea5d99d0SRyder Lee ewma_avg_signal_init(&msta->avg_ack_signal); 596ea5d99d0SRyder Lee 59798686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 59898686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 59998686cd2SShayne Chen 60098686cd2SShayne Chen ret = mt7996_mcu_add_sta(dev, vif, sta, true); 60198686cd2SShayne Chen if (ret) 60298686cd2SShayne Chen return ret; 60398686cd2SShayne Chen 60498686cd2SShayne Chen return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); 60598686cd2SShayne Chen } 60698686cd2SShayne Chen 60798686cd2SShayne Chen void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 60898686cd2SShayne Chen struct ieee80211_sta *sta) 60998686cd2SShayne Chen { 61098686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 61198686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 61298686cd2SShayne Chen int i; 61398686cd2SShayne Chen 61498686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, sta, false); 61598686cd2SShayne Chen 61698686cd2SShayne Chen mt7996_mac_wtbl_update(dev, msta->wcid.idx, 61798686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 61898686cd2SShayne Chen 61998686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) 62098686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, i); 62198686cd2SShayne Chen 62298686cd2SShayne Chen spin_lock_bh(&dev->sta_poll_lock); 62398686cd2SShayne Chen if (!list_empty(&msta->poll_list)) 62498686cd2SShayne Chen list_del_init(&msta->poll_list); 62598686cd2SShayne Chen if (!list_empty(&msta->rc_list)) 62698686cd2SShayne Chen list_del_init(&msta->rc_list); 62798686cd2SShayne Chen spin_unlock_bh(&dev->sta_poll_lock); 62898686cd2SShayne Chen } 62998686cd2SShayne Chen 63098686cd2SShayne Chen static void mt7996_tx(struct ieee80211_hw *hw, 63198686cd2SShayne Chen struct ieee80211_tx_control *control, 63298686cd2SShayne Chen struct sk_buff *skb) 63398686cd2SShayne Chen { 63498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 63598686cd2SShayne Chen struct mt76_phy *mphy = hw->priv; 63698686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 63798686cd2SShayne Chen struct ieee80211_vif *vif = info->control.vif; 63898686cd2SShayne Chen struct mt76_wcid *wcid = &dev->mt76.global_wcid; 63998686cd2SShayne Chen 64098686cd2SShayne Chen if (control->sta) { 64198686cd2SShayne Chen struct mt7996_sta *sta; 64298686cd2SShayne Chen 64398686cd2SShayne Chen sta = (struct mt7996_sta *)control->sta->drv_priv; 64498686cd2SShayne Chen wcid = &sta->wcid; 64598686cd2SShayne Chen } 64698686cd2SShayne Chen 64798686cd2SShayne Chen if (vif && !control->sta) { 64898686cd2SShayne Chen struct mt7996_vif *mvif; 64998686cd2SShayne Chen 65098686cd2SShayne Chen mvif = (struct mt7996_vif *)vif->drv_priv; 65198686cd2SShayne Chen wcid = &mvif->sta.wcid; 65298686cd2SShayne Chen } 65398686cd2SShayne Chen 65498686cd2SShayne Chen mt76_tx(mphy, control->sta, wcid, skb); 65598686cd2SShayne Chen } 65698686cd2SShayne Chen 65798686cd2SShayne Chen static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 65898686cd2SShayne Chen { 65998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 66098686cd2SShayne Chen int ret; 66198686cd2SShayne Chen 66298686cd2SShayne Chen mutex_lock(&phy->dev->mt76.mutex); 66398686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, val); 66498686cd2SShayne Chen mutex_unlock(&phy->dev->mt76.mutex); 66598686cd2SShayne Chen 66698686cd2SShayne Chen return ret; 66798686cd2SShayne Chen } 66898686cd2SShayne Chen 66998686cd2SShayne Chen static int 67098686cd2SShayne Chen mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 67198686cd2SShayne Chen struct ieee80211_ampdu_params *params) 67298686cd2SShayne Chen { 67398686cd2SShayne Chen enum ieee80211_ampdu_mlme_action action = params->action; 67498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 67598686cd2SShayne Chen struct ieee80211_sta *sta = params->sta; 67698686cd2SShayne Chen struct ieee80211_txq *txq = sta->txq[params->tid]; 67798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 67898686cd2SShayne Chen u16 tid = params->tid; 67998686cd2SShayne Chen u16 ssn = params->ssn; 68098686cd2SShayne Chen struct mt76_txq *mtxq; 68198686cd2SShayne Chen int ret = 0; 68298686cd2SShayne Chen 68398686cd2SShayne Chen if (!txq) 68498686cd2SShayne Chen return -EINVAL; 68598686cd2SShayne Chen 68698686cd2SShayne Chen mtxq = (struct mt76_txq *)txq->drv_priv; 68798686cd2SShayne Chen 68898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 68998686cd2SShayne Chen switch (action) { 69098686cd2SShayne Chen case IEEE80211_AMPDU_RX_START: 69198686cd2SShayne Chen mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, 69298686cd2SShayne Chen params->buf_size); 69398686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, true); 69498686cd2SShayne Chen break; 69598686cd2SShayne Chen case IEEE80211_AMPDU_RX_STOP: 69698686cd2SShayne Chen mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 69798686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, false); 69898686cd2SShayne Chen break; 69998686cd2SShayne Chen case IEEE80211_AMPDU_TX_OPERATIONAL: 70098686cd2SShayne Chen mtxq->aggr = true; 70198686cd2SShayne Chen mtxq->send_bar = false; 70298686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, true); 70398686cd2SShayne Chen break; 70498686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH: 70598686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 70698686cd2SShayne Chen mtxq->aggr = false; 70798686cd2SShayne Chen clear_bit(tid, &msta->ampdu_state); 70898686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 70998686cd2SShayne Chen break; 71098686cd2SShayne Chen case IEEE80211_AMPDU_TX_START: 71198686cd2SShayne Chen set_bit(tid, &msta->ampdu_state); 71298686cd2SShayne Chen ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 71398686cd2SShayne Chen break; 71498686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_CONT: 71598686cd2SShayne Chen mtxq->aggr = false; 71698686cd2SShayne Chen clear_bit(tid, &msta->ampdu_state); 71798686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 71898686cd2SShayne Chen ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 71998686cd2SShayne Chen break; 72098686cd2SShayne Chen } 72198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 72298686cd2SShayne Chen 72398686cd2SShayne Chen return ret; 72498686cd2SShayne Chen } 72598686cd2SShayne Chen 72698686cd2SShayne Chen static int 72798686cd2SShayne Chen mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 72898686cd2SShayne Chen struct ieee80211_sta *sta) 72998686cd2SShayne Chen { 73098686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, 73198686cd2SShayne Chen IEEE80211_STA_NONE); 73298686cd2SShayne Chen } 73398686cd2SShayne Chen 73498686cd2SShayne Chen static int 73598686cd2SShayne Chen mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 73698686cd2SShayne Chen struct ieee80211_sta *sta) 73798686cd2SShayne Chen { 73898686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, 73998686cd2SShayne Chen IEEE80211_STA_NOTEXIST); 74098686cd2SShayne Chen } 74198686cd2SShayne Chen 74298686cd2SShayne Chen static int 74398686cd2SShayne Chen mt7996_get_stats(struct ieee80211_hw *hw, 74498686cd2SShayne Chen struct ieee80211_low_level_stats *stats) 74598686cd2SShayne Chen { 74698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 74798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 74898686cd2SShayne Chen struct mib_stats *mib = &phy->mib; 74998686cd2SShayne Chen 75098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 75198686cd2SShayne Chen 75298686cd2SShayne Chen stats->dot11RTSSuccessCount = mib->rts_cnt; 75398686cd2SShayne Chen stats->dot11RTSFailureCount = mib->rts_retries_cnt; 75498686cd2SShayne Chen stats->dot11FCSErrorCount = mib->fcs_err_cnt; 75598686cd2SShayne Chen stats->dot11ACKFailureCount = mib->ack_fail_cnt; 75698686cd2SShayne Chen 75798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 75898686cd2SShayne Chen 75998686cd2SShayne Chen return 0; 76098686cd2SShayne Chen } 76198686cd2SShayne Chen 76298686cd2SShayne Chen u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) 76398686cd2SShayne Chen { 76498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 76598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 76698686cd2SShayne Chen union { 76798686cd2SShayne Chen u64 t64; 76898686cd2SShayne Chen u32 t32[2]; 76998686cd2SShayne Chen } tsf; 77098686cd2SShayne Chen u16 n; 77198686cd2SShayne Chen 77298686cd2SShayne Chen lockdep_assert_held(&dev->mt76.mutex); 77398686cd2SShayne Chen 77498686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 77598686cd2SShayne Chen : mvif->mt76.omac_idx; 77698686cd2SShayne Chen /* TSF software read */ 77798686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 77898686cd2SShayne Chen MT_LPON_TCR_SW_READ); 77998686cd2SShayne Chen tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(phy->mt76->band_idx)); 78098686cd2SShayne Chen tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(phy->mt76->band_idx)); 78198686cd2SShayne Chen 78298686cd2SShayne Chen return tsf.t64; 78398686cd2SShayne Chen } 78498686cd2SShayne Chen 78598686cd2SShayne Chen static u64 78698686cd2SShayne Chen mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 78798686cd2SShayne Chen { 78898686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 78998686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 79098686cd2SShayne Chen u64 ret; 79198686cd2SShayne Chen 79298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 79398686cd2SShayne Chen ret = __mt7996_get_tsf(hw, mvif); 79498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 79598686cd2SShayne Chen 79698686cd2SShayne Chen return ret; 79798686cd2SShayne Chen } 79898686cd2SShayne Chen 79998686cd2SShayne Chen static void 80098686cd2SShayne Chen mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 80198686cd2SShayne Chen u64 timestamp) 80298686cd2SShayne Chen { 80398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 80498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 80598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 80698686cd2SShayne Chen union { 80798686cd2SShayne Chen u64 t64; 80898686cd2SShayne Chen u32 t32[2]; 80998686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 81098686cd2SShayne Chen u16 n; 81198686cd2SShayne Chen 81298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 81398686cd2SShayne Chen 81498686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 81598686cd2SShayne Chen : mvif->mt76.omac_idx; 81698686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 81798686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 81898686cd2SShayne Chen /* TSF software overwrite */ 81998686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 82098686cd2SShayne Chen MT_LPON_TCR_SW_WRITE); 82198686cd2SShayne Chen 82298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 82398686cd2SShayne Chen } 82498686cd2SShayne Chen 82598686cd2SShayne Chen static void 82698686cd2SShayne Chen mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 82798686cd2SShayne Chen s64 timestamp) 82898686cd2SShayne Chen { 82998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 83098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 83198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 83298686cd2SShayne Chen union { 83398686cd2SShayne Chen u64 t64; 83498686cd2SShayne Chen u32 t32[2]; 83598686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 83698686cd2SShayne Chen u16 n; 83798686cd2SShayne Chen 83898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 83998686cd2SShayne Chen 84098686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 84198686cd2SShayne Chen : mvif->mt76.omac_idx; 84298686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 84398686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 84498686cd2SShayne Chen /* TSF software adjust*/ 84598686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 84698686cd2SShayne Chen MT_LPON_TCR_SW_ADJUST); 84798686cd2SShayne Chen 84898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 84998686cd2SShayne Chen } 85098686cd2SShayne Chen 85198686cd2SShayne Chen static void 85298686cd2SShayne Chen mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) 85398686cd2SShayne Chen { 85498686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 85598686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 85698686cd2SShayne Chen 85798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 85898686cd2SShayne Chen phy->coverage_class = max_t(s16, coverage_class, 0); 85998686cd2SShayne Chen mt7996_mac_set_timing(phy); 86098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 86198686cd2SShayne Chen } 86298686cd2SShayne Chen 86398686cd2SShayne Chen static int 86498686cd2SShayne Chen mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 86598686cd2SShayne Chen { 86698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 86798686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 86898686cd2SShayne Chen int max_nss = hweight8(hw->wiphy->available_antennas_tx); 86998686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; 87098686cd2SShayne Chen 87198686cd2SShayne Chen if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) 87298686cd2SShayne Chen return -EINVAL; 87398686cd2SShayne Chen 87498686cd2SShayne Chen if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) 87598686cd2SShayne Chen tx_ant = BIT(ffs(tx_ant) - 1) - 1; 87698686cd2SShayne Chen 87798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 87898686cd2SShayne Chen 87998686cd2SShayne Chen phy->mt76->antenna_mask = tx_ant; 88098686cd2SShayne Chen 88198686cd2SShayne Chen /* restore to the origin chainmask which might have auxiliary path */ 882eb1fdb9fSShayne Chen if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) 883eb1fdb9fSShayne Chen phy->mt76->chainmask = ((dev->chainmask >> shift) & 884eb1fdb9fSShayne Chen (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; 885eb1fdb9fSShayne Chen else if (hweight8(tx_ant) == max_nss) 88698686cd2SShayne Chen phy->mt76->chainmask = (dev->chainmask >> shift) << shift; 88798686cd2SShayne Chen else 88898686cd2SShayne Chen phy->mt76->chainmask = tx_ant << shift; 88998686cd2SShayne Chen 89098686cd2SShayne Chen mt76_set_stream_caps(phy->mt76, true); 89198686cd2SShayne Chen mt7996_set_stream_vht_txbf_caps(phy); 892348533ebSShayne Chen mt7996_set_stream_he_eht_caps(phy); 89398686cd2SShayne Chen 89498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 89598686cd2SShayne Chen 89698686cd2SShayne Chen return 0; 89798686cd2SShayne Chen } 89898686cd2SShayne Chen 89998686cd2SShayne Chen static void mt7996_sta_statistics(struct ieee80211_hw *hw, 90098686cd2SShayne Chen struct ieee80211_vif *vif, 90198686cd2SShayne Chen struct ieee80211_sta *sta, 90298686cd2SShayne Chen struct station_info *sinfo) 90398686cd2SShayne Chen { 90498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 90598686cd2SShayne Chen struct rate_info *txrate = &msta->wcid.rate; 90698686cd2SShayne Chen 90798686cd2SShayne Chen if (!txrate->legacy && !txrate->flags) 90898686cd2SShayne Chen return; 90998686cd2SShayne Chen 91098686cd2SShayne Chen if (txrate->legacy) { 91198686cd2SShayne Chen sinfo->txrate.legacy = txrate->legacy; 91298686cd2SShayne Chen } else { 91398686cd2SShayne Chen sinfo->txrate.mcs = txrate->mcs; 91498686cd2SShayne Chen sinfo->txrate.nss = txrate->nss; 91598686cd2SShayne Chen sinfo->txrate.bw = txrate->bw; 91698686cd2SShayne Chen sinfo->txrate.he_gi = txrate->he_gi; 91798686cd2SShayne Chen sinfo->txrate.he_dcm = txrate->he_dcm; 91898686cd2SShayne Chen sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; 91998686cd2SShayne Chen } 92098686cd2SShayne Chen sinfo->txrate.flags = txrate->flags; 92198686cd2SShayne Chen sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 922ea5d99d0SRyder Lee 923ea5d99d0SRyder Lee sinfo->ack_signal = (s8)msta->ack_signal; 924ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 925ea5d99d0SRyder Lee 926ea5d99d0SRyder Lee sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); 927ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 92898686cd2SShayne Chen } 92998686cd2SShayne Chen 93098686cd2SShayne Chen static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) 93198686cd2SShayne Chen { 93298686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 93398686cd2SShayne Chen struct mt7996_dev *dev = msta->vif->phy->dev; 93498686cd2SShayne Chen u32 *changed = data; 93598686cd2SShayne Chen 93698686cd2SShayne Chen spin_lock_bh(&dev->sta_poll_lock); 93798686cd2SShayne Chen msta->changed |= *changed; 93898686cd2SShayne Chen if (list_empty(&msta->rc_list)) 93998686cd2SShayne Chen list_add_tail(&msta->rc_list, &dev->sta_rc_list); 94098686cd2SShayne Chen spin_unlock_bh(&dev->sta_poll_lock); 94198686cd2SShayne Chen } 94298686cd2SShayne Chen 94398686cd2SShayne Chen static void mt7996_sta_rc_update(struct ieee80211_hw *hw, 94498686cd2SShayne Chen struct ieee80211_vif *vif, 94598686cd2SShayne Chen struct ieee80211_sta *sta, 94698686cd2SShayne Chen u32 changed) 94798686cd2SShayne Chen { 94898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 94998686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 95098686cd2SShayne Chen 95198686cd2SShayne Chen mt7996_sta_rc_work(&changed, sta); 95298686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 95398686cd2SShayne Chen } 95498686cd2SShayne Chen 95598686cd2SShayne Chen static int 95698686cd2SShayne Chen mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 95798686cd2SShayne Chen const struct cfg80211_bitrate_mask *mask) 95898686cd2SShayne Chen { 95998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 96098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 96198686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 96298686cd2SShayne Chen u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; 96398686cd2SShayne Chen 96498686cd2SShayne Chen mvif->bitrate_mask = *mask; 96598686cd2SShayne Chen 96698686cd2SShayne Chen /* if multiple rates across different preambles are given we can 96798686cd2SShayne Chen * reconfigure this info with all peers using sta_rec command with 96898686cd2SShayne Chen * the below exception cases. 96998686cd2SShayne Chen * - single rate : if a rate is passed along with different preambles, 97098686cd2SShayne Chen * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. 97198686cd2SShayne Chen * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT 97298686cd2SShayne Chen * then multiple MCS setting (MCS 4,5,6) is not supported. 97398686cd2SShayne Chen */ 97498686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); 97598686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 97698686cd2SShayne Chen 97798686cd2SShayne Chen return 0; 97898686cd2SShayne Chen } 97998686cd2SShayne Chen 98098686cd2SShayne Chen static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, 98198686cd2SShayne Chen struct ieee80211_vif *vif, 98298686cd2SShayne Chen struct ieee80211_sta *sta, 98398686cd2SShayne Chen bool enabled) 98498686cd2SShayne Chen { 98598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 98698686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 98798686cd2SShayne Chen 98898686cd2SShayne Chen if (enabled) 98998686cd2SShayne Chen set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 99098686cd2SShayne Chen else 99198686cd2SShayne Chen clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 99298686cd2SShayne Chen 99398686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 99498686cd2SShayne Chen } 99598686cd2SShayne Chen 99698686cd2SShayne Chen static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, 99798686cd2SShayne Chen struct ieee80211_vif *vif, 99898686cd2SShayne Chen struct ieee80211_sta *sta, 99998686cd2SShayne Chen bool enabled) 100098686cd2SShayne Chen { 100198686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 100298686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 100398686cd2SShayne Chen 100498686cd2SShayne Chen if (enabled) 100598686cd2SShayne Chen set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 100698686cd2SShayne Chen else 100798686cd2SShayne Chen clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 100898686cd2SShayne Chen 100998686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 101098686cd2SShayne Chen } 101198686cd2SShayne Chen 101298686cd2SShayne Chen static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = { 101398686cd2SShayne Chen "tx_ampdu_cnt", 101498686cd2SShayne Chen "tx_stop_q_empty_cnt", 101598686cd2SShayne Chen "tx_mpdu_attempts", 101698686cd2SShayne Chen "tx_mpdu_success", 101798686cd2SShayne Chen "tx_rwp_fail_cnt", 101898686cd2SShayne Chen "tx_rwp_need_cnt", 101998686cd2SShayne Chen "tx_pkt_ebf_cnt", 102098686cd2SShayne Chen "tx_pkt_ibf_cnt", 102198686cd2SShayne Chen "tx_ampdu_len:0-1", 102298686cd2SShayne Chen "tx_ampdu_len:2-10", 102398686cd2SShayne Chen "tx_ampdu_len:11-19", 102498686cd2SShayne Chen "tx_ampdu_len:20-28", 102598686cd2SShayne Chen "tx_ampdu_len:29-37", 102698686cd2SShayne Chen "tx_ampdu_len:38-46", 102798686cd2SShayne Chen "tx_ampdu_len:47-55", 102898686cd2SShayne Chen "tx_ampdu_len:56-79", 102998686cd2SShayne Chen "tx_ampdu_len:80-103", 103098686cd2SShayne Chen "tx_ampdu_len:104-127", 103198686cd2SShayne Chen "tx_ampdu_len:128-151", 103298686cd2SShayne Chen "tx_ampdu_len:152-175", 103398686cd2SShayne Chen "tx_ampdu_len:176-199", 103498686cd2SShayne Chen "tx_ampdu_len:200-223", 103598686cd2SShayne Chen "tx_ampdu_len:224-247", 103698686cd2SShayne Chen "ba_miss_count", 103798686cd2SShayne Chen "tx_beamformer_ppdu_iBF", 103898686cd2SShayne Chen "tx_beamformer_ppdu_eBF", 103998686cd2SShayne Chen "tx_beamformer_rx_feedback_all", 104098686cd2SShayne Chen "tx_beamformer_rx_feedback_he", 104198686cd2SShayne Chen "tx_beamformer_rx_feedback_vht", 104298686cd2SShayne Chen "tx_beamformer_rx_feedback_ht", 104398686cd2SShayne Chen "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ 104498686cd2SShayne Chen "tx_beamformer_rx_feedback_nc", 104598686cd2SShayne Chen "tx_beamformer_rx_feedback_nr", 104698686cd2SShayne Chen "tx_beamformee_ok_feedback_pkts", 104798686cd2SShayne Chen "tx_beamformee_feedback_trig", 104898686cd2SShayne Chen "tx_mu_beamforming", 104998686cd2SShayne Chen "tx_mu_mpdu", 105098686cd2SShayne Chen "tx_mu_successful_mpdu", 105198686cd2SShayne Chen "tx_su_successful_mpdu", 105298686cd2SShayne Chen "tx_msdu_pack_1", 105398686cd2SShayne Chen "tx_msdu_pack_2", 105498686cd2SShayne Chen "tx_msdu_pack_3", 105598686cd2SShayne Chen "tx_msdu_pack_4", 105698686cd2SShayne Chen "tx_msdu_pack_5", 105798686cd2SShayne Chen "tx_msdu_pack_6", 105898686cd2SShayne Chen "tx_msdu_pack_7", 105998686cd2SShayne Chen "tx_msdu_pack_8", 106098686cd2SShayne Chen 106198686cd2SShayne Chen /* rx counters */ 106298686cd2SShayne Chen "rx_fifo_full_cnt", 106398686cd2SShayne Chen "rx_mpdu_cnt", 106498686cd2SShayne Chen "channel_idle_cnt", 106598686cd2SShayne Chen "rx_vector_mismatch_cnt", 106698686cd2SShayne Chen "rx_delimiter_fail_cnt", 106798686cd2SShayne Chen "rx_len_mismatch_cnt", 106898686cd2SShayne Chen "rx_ampdu_cnt", 106998686cd2SShayne Chen "rx_ampdu_bytes_cnt", 107098686cd2SShayne Chen "rx_ampdu_valid_subframe_cnt", 107198686cd2SShayne Chen "rx_ampdu_valid_subframe_b_cnt", 107298686cd2SShayne Chen "rx_pfdrop_cnt", 107398686cd2SShayne Chen "rx_vec_queue_overflow_drop_cnt", 107498686cd2SShayne Chen "rx_ba_cnt", 107598686cd2SShayne Chen 107698686cd2SShayne Chen /* per vif counters */ 107798686cd2SShayne Chen "v_tx_mode_cck", 107898686cd2SShayne Chen "v_tx_mode_ofdm", 107998686cd2SShayne Chen "v_tx_mode_ht", 108098686cd2SShayne Chen "v_tx_mode_ht_gf", 108198686cd2SShayne Chen "v_tx_mode_vht", 108298686cd2SShayne Chen "v_tx_mode_he_su", 108398686cd2SShayne Chen "v_tx_mode_he_ext_su", 108498686cd2SShayne Chen "v_tx_mode_he_tb", 108598686cd2SShayne Chen "v_tx_mode_he_mu", 1086731425f3SShayne Chen "v_tx_mode_eht_su", 1087731425f3SShayne Chen "v_tx_mode_eht_trig", 1088731425f3SShayne Chen "v_tx_mode_eht_mu", 108998686cd2SShayne Chen "v_tx_bw_20", 109098686cd2SShayne Chen "v_tx_bw_40", 109198686cd2SShayne Chen "v_tx_bw_80", 109298686cd2SShayne Chen "v_tx_bw_160", 1093731425f3SShayne Chen "v_tx_bw_320", 109498686cd2SShayne Chen "v_tx_mcs_0", 109598686cd2SShayne Chen "v_tx_mcs_1", 109698686cd2SShayne Chen "v_tx_mcs_2", 109798686cd2SShayne Chen "v_tx_mcs_3", 109898686cd2SShayne Chen "v_tx_mcs_4", 109998686cd2SShayne Chen "v_tx_mcs_5", 110098686cd2SShayne Chen "v_tx_mcs_6", 110198686cd2SShayne Chen "v_tx_mcs_7", 110298686cd2SShayne Chen "v_tx_mcs_8", 110398686cd2SShayne Chen "v_tx_mcs_9", 110498686cd2SShayne Chen "v_tx_mcs_10", 110598686cd2SShayne Chen "v_tx_mcs_11", 1106731425f3SShayne Chen "v_tx_mcs_12", 1107731425f3SShayne Chen "v_tx_mcs_13", 110898686cd2SShayne Chen }; 110998686cd2SShayne Chen 111098686cd2SShayne Chen #define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats) 111198686cd2SShayne Chen 111298686cd2SShayne Chen /* Ethtool related API */ 111398686cd2SShayne Chen static 111498686cd2SShayne Chen void mt7996_get_et_strings(struct ieee80211_hw *hw, 111598686cd2SShayne Chen struct ieee80211_vif *vif, 111698686cd2SShayne Chen u32 sset, u8 *data) 111798686cd2SShayne Chen { 111898686cd2SShayne Chen if (sset == ETH_SS_STATS) 111998686cd2SShayne Chen memcpy(data, *mt7996_gstrings_stats, 112098686cd2SShayne Chen sizeof(mt7996_gstrings_stats)); 112198686cd2SShayne Chen } 112298686cd2SShayne Chen 112398686cd2SShayne Chen static 112498686cd2SShayne Chen int mt7996_get_et_sset_count(struct ieee80211_hw *hw, 112598686cd2SShayne Chen struct ieee80211_vif *vif, int sset) 112698686cd2SShayne Chen { 112798686cd2SShayne Chen if (sset == ETH_SS_STATS) 112898686cd2SShayne Chen return MT7996_SSTATS_LEN; 112998686cd2SShayne Chen 113098686cd2SShayne Chen return 0; 113198686cd2SShayne Chen } 113298686cd2SShayne Chen 113398686cd2SShayne Chen static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) 113498686cd2SShayne Chen { 113598686cd2SShayne Chen struct mt76_ethtool_worker_info *wi = wi_data; 113698686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 113798686cd2SShayne Chen 113898686cd2SShayne Chen if (msta->vif->mt76.idx != wi->idx) 113998686cd2SShayne Chen return; 114098686cd2SShayne Chen 1141731425f3SShayne Chen mt76_ethtool_worker(wi, &msta->stats, true); 114298686cd2SShayne Chen } 114398686cd2SShayne Chen 114498686cd2SShayne Chen static 114598686cd2SShayne Chen void mt7996_get_et_stats(struct ieee80211_hw *hw, 114698686cd2SShayne Chen struct ieee80211_vif *vif, 114798686cd2SShayne Chen struct ethtool_stats *stats, u64 *data) 114898686cd2SShayne Chen { 114998686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 115098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 115198686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 115298686cd2SShayne Chen struct mt76_ethtool_worker_info wi = { 115398686cd2SShayne Chen .data = data, 115498686cd2SShayne Chen .idx = mvif->mt76.idx, 115598686cd2SShayne Chen }; 115698686cd2SShayne Chen struct mib_stats *mib = &phy->mib; 115798686cd2SShayne Chen /* See mt7996_ampdu_stat_read_phy, etc */ 115898686cd2SShayne Chen int i, ei = 0; 115998686cd2SShayne Chen 116098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 116198686cd2SShayne Chen 116298686cd2SShayne Chen mt7996_mac_update_stats(phy); 116398686cd2SShayne Chen 116498686cd2SShayne Chen data[ei++] = mib->tx_ampdu_cnt; 116598686cd2SShayne Chen data[ei++] = mib->tx_stop_q_empty_cnt; 116698686cd2SShayne Chen data[ei++] = mib->tx_mpdu_attempts_cnt; 116798686cd2SShayne Chen data[ei++] = mib->tx_mpdu_success_cnt; 116898686cd2SShayne Chen data[ei++] = mib->tx_rwp_fail_cnt; 116998686cd2SShayne Chen data[ei++] = mib->tx_rwp_need_cnt; 117098686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 117198686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 117298686cd2SShayne Chen 117398686cd2SShayne Chen /* Tx ampdu stat */ 117498686cd2SShayne Chen for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) 117598686cd2SShayne Chen data[ei++] = phy->mt76->aggr_stats[i]; 117698686cd2SShayne Chen data[ei++] = phy->mib.ba_miss_cnt; 117798686cd2SShayne Chen 117898686cd2SShayne Chen /* Tx Beamformer monitor */ 117998686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 118098686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 118198686cd2SShayne Chen 118298686cd2SShayne Chen /* Tx Beamformer Rx feedback monitor */ 118398686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_all_cnt; 118498686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_he_cnt; 118598686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_vht_cnt; 118698686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_ht_cnt; 118798686cd2SShayne Chen 118898686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_bw; 118998686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nc_cnt; 119098686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nr_cnt; 119198686cd2SShayne Chen 119298686cd2SShayne Chen /* Tx Beamformee Rx NDPA & Tx feedback report */ 119398686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_cpl_cnt; 119498686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_trig_cnt; 119598686cd2SShayne Chen 119698686cd2SShayne Chen /* Tx SU & MU counters */ 119798686cd2SShayne Chen data[ei++] = mib->tx_mu_bf_cnt; 119898686cd2SShayne Chen data[ei++] = mib->tx_mu_mpdu_cnt; 119998686cd2SShayne Chen data[ei++] = mib->tx_mu_acked_mpdu_cnt; 120098686cd2SShayne Chen data[ei++] = mib->tx_su_acked_mpdu_cnt; 120198686cd2SShayne Chen 120298686cd2SShayne Chen /* Tx amsdu info (pack-count histogram) */ 120398686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) 120498686cd2SShayne Chen data[ei++] = mib->tx_amsdu[i]; 120598686cd2SShayne Chen 120698686cd2SShayne Chen /* rx counters */ 120798686cd2SShayne Chen data[ei++] = mib->rx_fifo_full_cnt; 120898686cd2SShayne Chen data[ei++] = mib->rx_mpdu_cnt; 120998686cd2SShayne Chen data[ei++] = mib->channel_idle_cnt; 121098686cd2SShayne Chen data[ei++] = mib->rx_vector_mismatch_cnt; 121198686cd2SShayne Chen data[ei++] = mib->rx_delimiter_fail_cnt; 121298686cd2SShayne Chen data[ei++] = mib->rx_len_mismatch_cnt; 121398686cd2SShayne Chen data[ei++] = mib->rx_ampdu_cnt; 121498686cd2SShayne Chen data[ei++] = mib->rx_ampdu_bytes_cnt; 121598686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_cnt; 121698686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; 121798686cd2SShayne Chen data[ei++] = mib->rx_pfdrop_cnt; 121898686cd2SShayne Chen data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; 121998686cd2SShayne Chen data[ei++] = mib->rx_ba_cnt; 122098686cd2SShayne Chen 122198686cd2SShayne Chen /* Add values for all stations owned by this vif */ 122298686cd2SShayne Chen wi.initial_stat_idx = ei; 122398686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_ethtool_worker, &wi); 122498686cd2SShayne Chen 122598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 122698686cd2SShayne Chen 122798686cd2SShayne Chen if (wi.sta_count == 0) 122898686cd2SShayne Chen return; 122998686cd2SShayne Chen 123098686cd2SShayne Chen ei += wi.worker_stat_count; 123198686cd2SShayne Chen if (ei != MT7996_SSTATS_LEN) 123298686cd2SShayne Chen dev_err(dev->mt76.dev, "ei: %d MT7996_SSTATS_LEN: %d", 123398686cd2SShayne Chen ei, (int)MT7996_SSTATS_LEN); 123498686cd2SShayne Chen } 123598686cd2SShayne Chen 123698686cd2SShayne Chen static void 123798686cd2SShayne Chen mt7996_twt_teardown_request(struct ieee80211_hw *hw, 123898686cd2SShayne Chen struct ieee80211_sta *sta, 123998686cd2SShayne Chen u8 flowid) 124098686cd2SShayne Chen { 124198686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 124298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 124398686cd2SShayne Chen 124498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 124598686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, flowid); 124698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 124798686cd2SShayne Chen } 124898686cd2SShayne Chen 124998686cd2SShayne Chen static int 125098686cd2SShayne Chen mt7996_set_radar_background(struct ieee80211_hw *hw, 125198686cd2SShayne Chen struct cfg80211_chan_def *chandef) 125298686cd2SShayne Chen { 125398686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 125498686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 125598686cd2SShayne Chen int ret = -EINVAL; 125698686cd2SShayne Chen bool running; 125798686cd2SShayne Chen 125898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 125998686cd2SShayne Chen 126098686cd2SShayne Chen if (dev->mt76.region == NL80211_DFS_UNSET) 126198686cd2SShayne Chen goto out; 126298686cd2SShayne Chen 126398686cd2SShayne Chen if (dev->rdd2_phy && dev->rdd2_phy != phy) { 126498686cd2SShayne Chen /* rdd2 is already locked */ 126598686cd2SShayne Chen ret = -EBUSY; 126698686cd2SShayne Chen goto out; 126798686cd2SShayne Chen } 126898686cd2SShayne Chen 126998686cd2SShayne Chen /* rdd2 already configured on a radar channel */ 127098686cd2SShayne Chen running = dev->rdd2_phy && 127198686cd2SShayne Chen cfg80211_chandef_valid(&dev->rdd2_chandef) && 127298686cd2SShayne Chen !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); 127398686cd2SShayne Chen 127498686cd2SShayne Chen if (!chandef || running || 127598686cd2SShayne Chen !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { 127698686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, NULL); 127798686cd2SShayne Chen if (ret) 127898686cd2SShayne Chen goto out; 127998686cd2SShayne Chen 128098686cd2SShayne Chen if (!running) 128198686cd2SShayne Chen goto update_phy; 128298686cd2SShayne Chen } 128398686cd2SShayne Chen 128498686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, chandef); 128598686cd2SShayne Chen if (ret) 128698686cd2SShayne Chen goto out; 128798686cd2SShayne Chen 128898686cd2SShayne Chen update_phy: 128998686cd2SShayne Chen dev->rdd2_phy = chandef ? phy : NULL; 129098686cd2SShayne Chen if (chandef) 129198686cd2SShayne Chen dev->rdd2_chandef = *chandef; 129298686cd2SShayne Chen out: 129398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 129498686cd2SShayne Chen 129598686cd2SShayne Chen return ret; 129698686cd2SShayne Chen } 129798686cd2SShayne Chen 129898686cd2SShayne Chen const struct ieee80211_ops mt7996_ops = { 129998686cd2SShayne Chen .tx = mt7996_tx, 130098686cd2SShayne Chen .start = mt7996_start, 130198686cd2SShayne Chen .stop = mt7996_stop, 130298686cd2SShayne Chen .add_interface = mt7996_add_interface, 130398686cd2SShayne Chen .remove_interface = mt7996_remove_interface, 130498686cd2SShayne Chen .config = mt7996_config, 130598686cd2SShayne Chen .conf_tx = mt7996_conf_tx, 130698686cd2SShayne Chen .configure_filter = mt7996_configure_filter, 130798686cd2SShayne Chen .bss_info_changed = mt7996_bss_info_changed, 130898686cd2SShayne Chen .sta_add = mt7996_sta_add, 130998686cd2SShayne Chen .sta_remove = mt7996_sta_remove, 131098686cd2SShayne Chen .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 131198686cd2SShayne Chen .sta_rc_update = mt7996_sta_rc_update, 131298686cd2SShayne Chen .set_key = mt7996_set_key, 131398686cd2SShayne Chen .ampdu_action = mt7996_ampdu_action, 131498686cd2SShayne Chen .set_rts_threshold = mt7996_set_rts_threshold, 131598686cd2SShayne Chen .wake_tx_queue = mt76_wake_tx_queue, 131698686cd2SShayne Chen .sw_scan_start = mt76_sw_scan, 131798686cd2SShayne Chen .sw_scan_complete = mt76_sw_scan_complete, 131898686cd2SShayne Chen .release_buffered_frames = mt76_release_buffered_frames, 131998686cd2SShayne Chen .get_txpower = mt76_get_txpower, 132098686cd2SShayne Chen .channel_switch_beacon = mt7996_channel_switch_beacon, 132198686cd2SShayne Chen .get_stats = mt7996_get_stats, 132298686cd2SShayne Chen .get_et_sset_count = mt7996_get_et_sset_count, 132398686cd2SShayne Chen .get_et_stats = mt7996_get_et_stats, 132498686cd2SShayne Chen .get_et_strings = mt7996_get_et_strings, 132598686cd2SShayne Chen .get_tsf = mt7996_get_tsf, 132698686cd2SShayne Chen .set_tsf = mt7996_set_tsf, 132798686cd2SShayne Chen .offset_tsf = mt7996_offset_tsf, 132898686cd2SShayne Chen .get_survey = mt76_get_survey, 132998686cd2SShayne Chen .get_antenna = mt76_get_antenna, 133098686cd2SShayne Chen .set_antenna = mt7996_set_antenna, 133198686cd2SShayne Chen .set_bitrate_mask = mt7996_set_bitrate_mask, 133298686cd2SShayne Chen .set_coverage_class = mt7996_set_coverage_class, 133398686cd2SShayne Chen .sta_statistics = mt7996_sta_statistics, 133498686cd2SShayne Chen .sta_set_4addr = mt7996_sta_set_4addr, 133598686cd2SShayne Chen .sta_set_decap_offload = mt7996_sta_set_decap_offload, 133698686cd2SShayne Chen .add_twt_setup = mt7996_mac_add_twt_setup, 133798686cd2SShayne Chen .twt_teardown_request = mt7996_twt_teardown_request, 133898686cd2SShayne Chen #ifdef CONFIG_MAC80211_DEBUGFS 133998686cd2SShayne Chen .sta_add_debugfs = mt7996_sta_add_debugfs, 134098686cd2SShayne Chen #endif 134198686cd2SShayne Chen .set_radar_background = mt7996_set_radar_background, 134298686cd2SShayne Chen }; 1343