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 4698686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); 4798686cd2SShayne Chen if (ret) 4898686cd2SShayne Chen goto out; 4998686cd2SShayne Chen 5098686cd2SShayne Chen set_bit(MT76_STATE_RUNNING, &phy->mt76->state); 5198686cd2SShayne Chen 5298686cd2SShayne Chen ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, 5398686cd2SShayne Chen MT7996_WATCHDOG_TIME); 5498686cd2SShayne Chen 5598686cd2SShayne Chen if (!running) 5698686cd2SShayne Chen mt7996_mac_reset_counters(phy); 5798686cd2SShayne Chen 5898686cd2SShayne Chen out: 5927015b6fSBo Jiao return ret; 6027015b6fSBo Jiao } 6127015b6fSBo Jiao 6227015b6fSBo Jiao static int mt7996_start(struct ieee80211_hw *hw) 6327015b6fSBo Jiao { 6427015b6fSBo Jiao struct mt7996_dev *dev = mt7996_hw_dev(hw); 6527015b6fSBo Jiao int ret; 6627015b6fSBo Jiao 6727015b6fSBo Jiao flush_work(&dev->init_work); 6827015b6fSBo Jiao 6927015b6fSBo Jiao mutex_lock(&dev->mt76.mutex); 7027015b6fSBo Jiao ret = mt7996_run(hw); 7198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 7298686cd2SShayne Chen 7398686cd2SShayne Chen return ret; 7498686cd2SShayne Chen } 7598686cd2SShayne Chen 7698686cd2SShayne Chen static void mt7996_stop(struct ieee80211_hw *hw) 7798686cd2SShayne Chen { 7898686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 7998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 8098686cd2SShayne Chen 8198686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 8298686cd2SShayne Chen 8398686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 8498686cd2SShayne Chen 8598686cd2SShayne Chen clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); 8698686cd2SShayne Chen 8798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 8898686cd2SShayne Chen } 8998686cd2SShayne Chen 9098686cd2SShayne Chen static inline int get_free_idx(u32 mask, u8 start, u8 end) 9198686cd2SShayne Chen { 9298686cd2SShayne Chen return ffs(~mask & GENMASK(end, start)); 9398686cd2SShayne Chen } 9498686cd2SShayne Chen 9598686cd2SShayne Chen static int get_omac_idx(enum nl80211_iftype type, u64 mask) 9698686cd2SShayne Chen { 9798686cd2SShayne Chen int i; 9898686cd2SShayne Chen 9998686cd2SShayne Chen switch (type) { 10098686cd2SShayne Chen case NL80211_IFTYPE_MESH_POINT: 10198686cd2SShayne Chen case NL80211_IFTYPE_ADHOC: 10298686cd2SShayne Chen case NL80211_IFTYPE_STATION: 10398686cd2SShayne Chen /* prefer hw bssid slot 1-3 */ 10498686cd2SShayne Chen i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); 10598686cd2SShayne Chen if (i) 10698686cd2SShayne Chen return i - 1; 10798686cd2SShayne Chen 10898686cd2SShayne Chen if (type != NL80211_IFTYPE_STATION) 10998686cd2SShayne Chen break; 11098686cd2SShayne Chen 11198686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 11298686cd2SShayne Chen if (i) 11398686cd2SShayne Chen return i - 1; 11498686cd2SShayne Chen 11598686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 11698686cd2SShayne Chen return HW_BSSID_0; 11798686cd2SShayne Chen 11898686cd2SShayne Chen break; 11998686cd2SShayne Chen case NL80211_IFTYPE_MONITOR: 12098686cd2SShayne Chen case NL80211_IFTYPE_AP: 12198686cd2SShayne Chen /* ap uses hw bssid 0 and ext bssid */ 12298686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 12398686cd2SShayne Chen return HW_BSSID_0; 12498686cd2SShayne Chen 12598686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 12698686cd2SShayne Chen if (i) 12798686cd2SShayne Chen return i - 1; 12898686cd2SShayne Chen 12998686cd2SShayne Chen break; 13098686cd2SShayne Chen default: 13198686cd2SShayne Chen WARN_ON(1); 13298686cd2SShayne Chen break; 13398686cd2SShayne Chen } 13498686cd2SShayne Chen 13598686cd2SShayne Chen return -1; 13698686cd2SShayne Chen } 13798686cd2SShayne Chen 13898686cd2SShayne Chen static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif) 13998686cd2SShayne Chen { 14098686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 14198686cd2SShayne Chen int i; 14298686cd2SShayne Chen 14398686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { 14498686cd2SShayne Chen mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; 14598686cd2SShayne Chen mvif->bitrate_mask.control[i].he_gi = 0xff; 14698686cd2SShayne Chen mvif->bitrate_mask.control[i].he_ltf = 0xff; 14798686cd2SShayne Chen mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); 14898686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, 14998686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].ht_mcs)); 15098686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, 15198686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].vht_mcs)); 15298686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, 15398686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].he_mcs)); 15498686cd2SShayne Chen } 15598686cd2SShayne Chen } 15698686cd2SShayne Chen 15798686cd2SShayne Chen static int mt7996_add_interface(struct ieee80211_hw *hw, 15898686cd2SShayne Chen struct ieee80211_vif *vif) 15998686cd2SShayne Chen { 16098686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 16198686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 16298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 16398686cd2SShayne Chen struct mt76_txq *mtxq; 16498686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx; 16598686cd2SShayne Chen int idx, ret = 0; 16698686cd2SShayne Chen 16798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 16898686cd2SShayne Chen 16998686cd2SShayne Chen if (vif->type == NL80211_IFTYPE_MONITOR && 17098686cd2SShayne Chen is_zero_ether_addr(vif->addr)) 17198686cd2SShayne Chen phy->monitor_vif = vif; 17298686cd2SShayne Chen 17398686cd2SShayne Chen mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); 17443482540SShayne Chen if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) { 17598686cd2SShayne Chen ret = -ENOSPC; 17698686cd2SShayne Chen goto out; 17798686cd2SShayne Chen } 17898686cd2SShayne Chen 17998686cd2SShayne Chen idx = get_omac_idx(vif->type, phy->omac_mask); 18098686cd2SShayne Chen if (idx < 0) { 18198686cd2SShayne Chen ret = -ENOSPC; 18298686cd2SShayne Chen goto out; 18398686cd2SShayne Chen } 18498686cd2SShayne Chen mvif->mt76.omac_idx = idx; 18598686cd2SShayne Chen mvif->phy = phy; 18698686cd2SShayne Chen mvif->mt76.band_idx = band_idx; 18798686cd2SShayne Chen mvif->mt76.wmm_idx = band_idx; 18898686cd2SShayne Chen 18998686cd2SShayne Chen ret = mt7996_mcu_add_dev_info(phy, vif, true); 19098686cd2SShayne Chen if (ret) 19198686cd2SShayne Chen goto out; 19298686cd2SShayne Chen 19398686cd2SShayne Chen ret = mt7996_mcu_set_radio_en(phy, true); 19498686cd2SShayne Chen if (ret) 19598686cd2SShayne Chen goto out; 19698686cd2SShayne Chen 19798686cd2SShayne Chen dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); 19898686cd2SShayne Chen phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); 19998686cd2SShayne Chen 20098686cd2SShayne Chen idx = MT7996_WTBL_RESERVED - mvif->mt76.idx; 20198686cd2SShayne Chen 20298686cd2SShayne Chen INIT_LIST_HEAD(&mvif->sta.rc_list); 20398686cd2SShayne Chen INIT_LIST_HEAD(&mvif->sta.poll_list); 20498686cd2SShayne Chen mvif->sta.wcid.idx = idx; 20598686cd2SShayne Chen mvif->sta.wcid.phy_idx = band_idx; 20698686cd2SShayne Chen mvif->sta.wcid.hw_key_idx = -1; 20798686cd2SShayne Chen mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; 20898686cd2SShayne Chen mt76_packet_id_init(&mvif->sta.wcid); 20998686cd2SShayne Chen 21098686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 21198686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 21298686cd2SShayne Chen 21398686cd2SShayne Chen if (vif->txq) { 21498686cd2SShayne Chen mtxq = (struct mt76_txq *)vif->txq->drv_priv; 21598686cd2SShayne Chen mtxq->wcid = idx; 21698686cd2SShayne Chen } 21798686cd2SShayne Chen 21898686cd2SShayne Chen if (vif->type != NL80211_IFTYPE_AP && 21998686cd2SShayne Chen (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) 22098686cd2SShayne Chen vif->offload_flags = 0; 22198686cd2SShayne Chen vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; 22298686cd2SShayne Chen 22315ee62e7SRyder Lee if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) 22415ee62e7SRyder Lee mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; 22515ee62e7SRyder Lee else 22615ee62e7SRyder Lee mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL; 22715ee62e7SRyder Lee 22898686cd2SShayne Chen mt7996_init_bitrate_mask(vif); 22998686cd2SShayne Chen 23098686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 23198686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 23298686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); 23398686cd2SShayne Chen 23498686cd2SShayne Chen out: 23598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 23698686cd2SShayne Chen 23798686cd2SShayne Chen return ret; 23898686cd2SShayne Chen } 23998686cd2SShayne Chen 24098686cd2SShayne Chen static void mt7996_remove_interface(struct ieee80211_hw *hw, 24198686cd2SShayne Chen struct ieee80211_vif *vif) 24298686cd2SShayne Chen { 24398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 24498686cd2SShayne Chen struct mt7996_sta *msta = &mvif->sta; 24598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 24698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 24798686cd2SShayne Chen int idx = msta->wcid.idx; 24898686cd2SShayne Chen 24998686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, false); 25098686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, false); 25198686cd2SShayne Chen 25298686cd2SShayne Chen if (vif == phy->monitor_vif) 25398686cd2SShayne Chen phy->monitor_vif = NULL; 25498686cd2SShayne Chen 25598686cd2SShayne Chen mt7996_mcu_add_dev_info(phy, vif, false); 25698686cd2SShayne Chen mt7996_mcu_set_radio_en(phy, false); 25798686cd2SShayne Chen 25898686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], NULL); 25998686cd2SShayne Chen 26098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 26198686cd2SShayne Chen dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); 26298686cd2SShayne Chen phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); 26398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 26498686cd2SShayne Chen 26598686cd2SShayne Chen spin_lock_bh(&dev->sta_poll_lock); 26698686cd2SShayne Chen if (!list_empty(&msta->poll_list)) 26798686cd2SShayne Chen list_del_init(&msta->poll_list); 26898686cd2SShayne Chen spin_unlock_bh(&dev->sta_poll_lock); 26998686cd2SShayne Chen 27098686cd2SShayne Chen mt76_packet_id_flush(&dev->mt76, &msta->wcid); 27198686cd2SShayne Chen } 27298686cd2SShayne Chen 27398686cd2SShayne Chen int mt7996_set_channel(struct mt7996_phy *phy) 27498686cd2SShayne Chen { 27598686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 27698686cd2SShayne Chen int ret; 27798686cd2SShayne Chen 27898686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 27998686cd2SShayne Chen 28098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 28198686cd2SShayne Chen set_bit(MT76_RESET, &phy->mt76->state); 28298686cd2SShayne Chen 28398686cd2SShayne Chen mt76_set_channel(phy->mt76); 28498686cd2SShayne Chen 28598686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); 28698686cd2SShayne Chen if (ret) 28798686cd2SShayne Chen goto out; 28898686cd2SShayne Chen 28998686cd2SShayne Chen mt7996_mac_set_timing(phy); 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; 41798686cd2SShayne Chen 41898686cd2SShayne Chen /* no need to update right away, we'll get BSS_CHANGED_QOS */ 41998686cd2SShayne Chen queue = mt76_connac_lmac_mapping(queue); 42098686cd2SShayne Chen mvif->queue_params[queue] = *params; 42198686cd2SShayne Chen 42298686cd2SShayne Chen return 0; 42398686cd2SShayne Chen } 42498686cd2SShayne Chen 42598686cd2SShayne Chen static void mt7996_configure_filter(struct ieee80211_hw *hw, 42698686cd2SShayne Chen unsigned int changed_flags, 42798686cd2SShayne Chen unsigned int *total_flags, 42898686cd2SShayne Chen u64 multicast) 42998686cd2SShayne Chen { 43098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 43198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 43298686cd2SShayne Chen u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | 43398686cd2SShayne Chen MT_WF_RFCR1_DROP_BF_POLL | 43498686cd2SShayne Chen MT_WF_RFCR1_DROP_BA | 43598686cd2SShayne Chen MT_WF_RFCR1_DROP_CFEND | 43698686cd2SShayne Chen MT_WF_RFCR1_DROP_CFACK; 43798686cd2SShayne Chen u32 flags = 0; 43898686cd2SShayne Chen 43998686cd2SShayne Chen #define MT76_FILTER(_flag, _hw) do { \ 44098686cd2SShayne Chen flags |= *total_flags & FIF_##_flag; \ 44198686cd2SShayne Chen phy->rxfilter &= ~(_hw); \ 44298686cd2SShayne Chen phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 44398686cd2SShayne Chen } while (0) 44498686cd2SShayne Chen 44598686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 44698686cd2SShayne Chen 44798686cd2SShayne Chen phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | 44898686cd2SShayne Chen MT_WF_RFCR_DROP_OTHER_BEACON | 44998686cd2SShayne Chen MT_WF_RFCR_DROP_FRAME_REPORT | 45098686cd2SShayne Chen MT_WF_RFCR_DROP_PROBEREQ | 45198686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST_FILTERED | 45298686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST | 45398686cd2SShayne Chen MT_WF_RFCR_DROP_BCAST | 45498686cd2SShayne Chen MT_WF_RFCR_DROP_DUPLICATE | 45598686cd2SShayne Chen MT_WF_RFCR_DROP_A2_BSSID | 45698686cd2SShayne Chen MT_WF_RFCR_DROP_UNWANTED_CTL | 45798686cd2SShayne Chen MT_WF_RFCR_DROP_STBC_MULTI); 45898686cd2SShayne Chen 45998686cd2SShayne Chen MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | 46098686cd2SShayne Chen MT_WF_RFCR_DROP_A3_MAC | 46198686cd2SShayne Chen MT_WF_RFCR_DROP_A3_BSSID); 46298686cd2SShayne Chen 46398686cd2SShayne Chen MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); 46498686cd2SShayne Chen 46598686cd2SShayne Chen MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | 46698686cd2SShayne Chen MT_WF_RFCR_DROP_RTS | 46798686cd2SShayne Chen MT_WF_RFCR_DROP_CTL_RSV | 46898686cd2SShayne Chen MT_WF_RFCR_DROP_NDPA); 46998686cd2SShayne Chen 47098686cd2SShayne Chen *total_flags = flags; 47198686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 47298686cd2SShayne Chen 47398686cd2SShayne Chen if (*total_flags & FIF_CONTROL) 47498686cd2SShayne Chen mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 47598686cd2SShayne Chen else 47698686cd2SShayne Chen mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 47798686cd2SShayne Chen 47898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 47998686cd2SShayne Chen } 48098686cd2SShayne Chen 48198686cd2SShayne Chen static void 48298686cd2SShayne Chen mt7996_update_bss_color(struct ieee80211_hw *hw, 48398686cd2SShayne Chen struct ieee80211_vif *vif, 48498686cd2SShayne Chen struct cfg80211_he_bss_color *bss_color) 48598686cd2SShayne Chen { 48698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 48798686cd2SShayne Chen 48898686cd2SShayne Chen switch (vif->type) { 48998686cd2SShayne Chen case NL80211_IFTYPE_AP: { 49098686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 49198686cd2SShayne Chen 49298686cd2SShayne Chen if (mvif->mt76.omac_idx > HW_BSSID_MAX) 49398686cd2SShayne Chen return; 49498686cd2SShayne Chen fallthrough; 49598686cd2SShayne Chen } 49698686cd2SShayne Chen case NL80211_IFTYPE_STATION: 49798686cd2SShayne Chen mt7996_mcu_update_bss_color(dev, vif, bss_color); 49898686cd2SShayne Chen break; 49998686cd2SShayne Chen default: 50098686cd2SShayne Chen break; 50198686cd2SShayne Chen } 50298686cd2SShayne Chen } 50398686cd2SShayne Chen 50415ee62e7SRyder Lee static u8 505ab0eec4bSRyder Lee mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 506c2171b06SRyder Lee bool beacon, bool mcast) 50715ee62e7SRyder Lee { 50815ee62e7SRyder Lee struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 50915ee62e7SRyder Lee struct mt76_phy *mphy = hw->priv; 51015ee62e7SRyder Lee u16 rate; 511c2171b06SRyder Lee u8 i, idx, ht; 51215ee62e7SRyder Lee 513c2171b06SRyder Lee rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); 514c2171b06SRyder Lee ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM; 515c2171b06SRyder Lee 516c2171b06SRyder Lee if (beacon && ht) { 517c2171b06SRyder Lee struct mt7996_dev *dev = mt7996_hw_dev(hw); 518c2171b06SRyder Lee 519c2171b06SRyder Lee /* must odd index */ 520c2171b06SRyder Lee idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->mt76.idx % 20); 521c2171b06SRyder Lee mt7996_mac_set_fixed_rate_table(dev, idx, rate); 522c2171b06SRyder Lee return idx; 523c2171b06SRyder Lee } 52415ee62e7SRyder Lee 52515ee62e7SRyder Lee idx = FIELD_GET(MT_TX_RATE_IDX, rate); 52615ee62e7SRyder Lee for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) 52715ee62e7SRyder Lee if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) 52815ee62e7SRyder Lee return MT7996_BASIC_RATES_TBL + i; 52915ee62e7SRyder Lee 53015ee62e7SRyder Lee return mvif->basic_rates_idx; 53115ee62e7SRyder Lee } 53215ee62e7SRyder Lee 53368f1c3eaSRyder Lee static void 53468f1c3eaSRyder Lee mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 53568f1c3eaSRyder Lee struct ieee80211_bss_conf *info) 53668f1c3eaSRyder Lee { 53768f1c3eaSRyder Lee struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 53868f1c3eaSRyder Lee struct mt7996_dev *dev = mt7996_hw_dev(hw); 53968f1c3eaSRyder Lee u8 band = mvif->mt76.band_idx; 54068f1c3eaSRyder Lee u32 *mu; 54168f1c3eaSRyder Lee 54268f1c3eaSRyder Lee mu = (u32 *)info->mu_group.membership; 54368f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]); 54468f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]); 54568f1c3eaSRyder Lee 54668f1c3eaSRyder Lee mu = (u32 *)info->mu_group.position; 54768f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]); 54868f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]); 54968f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]); 55068f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]); 55168f1c3eaSRyder Lee } 55268f1c3eaSRyder Lee 55398686cd2SShayne Chen static void mt7996_bss_info_changed(struct ieee80211_hw *hw, 55498686cd2SShayne Chen struct ieee80211_vif *vif, 55598686cd2SShayne Chen struct ieee80211_bss_conf *info, 55698686cd2SShayne Chen u64 changed) 55798686cd2SShayne Chen { 55815ee62e7SRyder Lee struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 55998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 56098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 56198686cd2SShayne Chen 56298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 56398686cd2SShayne Chen 56498686cd2SShayne Chen /* station mode uses BSSID to map the wlan entry to a peer, 56598686cd2SShayne Chen * and then peer references bss_info_rfch to set bandwidth cap. 56698686cd2SShayne Chen */ 56798686cd2SShayne Chen if (changed & BSS_CHANGED_BSSID && 56898686cd2SShayne Chen vif->type == NL80211_IFTYPE_STATION) { 56998686cd2SShayne Chen bool join = !is_zero_ether_addr(info->bssid); 57098686cd2SShayne Chen 57198686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, join); 57298686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, join); 57398686cd2SShayne Chen } 57498686cd2SShayne Chen 575cf6dc2dbSRyder Lee if (changed & BSS_CHANGED_ASSOC) 57698686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc); 57798686cd2SShayne Chen 578d75e739bSRyder Lee if (changed & BSS_CHANGED_ERP_CTS_PROT) 579d75e739bSRyder Lee mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); 580d75e739bSRyder Lee 58198686cd2SShayne Chen if (changed & BSS_CHANGED_ERP_SLOT) { 58298686cd2SShayne Chen int slottime = info->use_short_slot ? 9 : 20; 58398686cd2SShayne Chen 58498686cd2SShayne Chen if (slottime != phy->slottime) { 58598686cd2SShayne Chen phy->slottime = slottime; 58698686cd2SShayne Chen mt7996_mac_set_timing(phy); 58798686cd2SShayne Chen } 58898686cd2SShayne Chen } 58998686cd2SShayne Chen 590ab0eec4bSRyder Lee if (changed & BSS_CHANGED_MCAST_RATE) 591ab0eec4bSRyder Lee mvif->mcast_rates_idx = 592c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, false, true); 593ab0eec4bSRyder Lee 59415ee62e7SRyder Lee if (changed & BSS_CHANGED_BASIC_RATES) 595ab0eec4bSRyder Lee mvif->basic_rates_idx = 596c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, false, false); 59715ee62e7SRyder Lee 59898686cd2SShayne Chen if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { 59998686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 60098686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 60198686cd2SShayne Chen } 60298686cd2SShayne Chen 60398686cd2SShayne Chen /* ensure that enable txcmd_mode after bss_info */ 60498686cd2SShayne Chen if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) 60598686cd2SShayne Chen mt7996_mcu_set_tx(dev, vif); 60698686cd2SShayne Chen 60798686cd2SShayne Chen if (changed & BSS_CHANGED_HE_OBSS_PD) 608cf6dc2dbSRyder Lee mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 60998686cd2SShayne Chen 61098686cd2SShayne Chen if (changed & BSS_CHANGED_HE_BSS_COLOR) 61198686cd2SShayne Chen mt7996_update_bss_color(hw, vif, &info->he_bss_color); 61298686cd2SShayne Chen 61398686cd2SShayne Chen if (changed & (BSS_CHANGED_BEACON | 614c2171b06SRyder Lee BSS_CHANGED_BEACON_ENABLED)) { 615c2171b06SRyder Lee mvif->beacon_rates_idx = 616c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, true, false); 617c2171b06SRyder Lee 61898686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); 619c2171b06SRyder Lee } 62098686cd2SShayne Chen 62198686cd2SShayne Chen if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP || 62298686cd2SShayne Chen changed & BSS_CHANGED_FILS_DISCOVERY) 62398686cd2SShayne Chen mt7996_mcu_beacon_inband_discov(dev, vif, changed); 62498686cd2SShayne Chen 62568f1c3eaSRyder Lee if (changed & BSS_CHANGED_MU_GROUPS) 62668f1c3eaSRyder Lee mt7996_update_mu_group(hw, vif, info); 62768f1c3eaSRyder Lee 62898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 62998686cd2SShayne Chen } 63098686cd2SShayne Chen 63198686cd2SShayne Chen static void 63298686cd2SShayne Chen mt7996_channel_switch_beacon(struct ieee80211_hw *hw, 63398686cd2SShayne Chen struct ieee80211_vif *vif, 63498686cd2SShayne Chen struct cfg80211_chan_def *chandef) 63598686cd2SShayne Chen { 63698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 63798686cd2SShayne Chen 63898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 63998686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, true); 64098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 64198686cd2SShayne Chen } 64298686cd2SShayne Chen 64398686cd2SShayne Chen int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 64498686cd2SShayne Chen struct ieee80211_sta *sta) 64598686cd2SShayne Chen { 64698686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 64798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 64898686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 64998686cd2SShayne Chen u8 band_idx = mvif->phy->mt76->band_idx; 65098686cd2SShayne Chen int ret, idx; 65198686cd2SShayne Chen 65298686cd2SShayne Chen idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); 65398686cd2SShayne Chen if (idx < 0) 65498686cd2SShayne Chen return -ENOSPC; 65598686cd2SShayne Chen 65698686cd2SShayne Chen INIT_LIST_HEAD(&msta->rc_list); 65798686cd2SShayne Chen INIT_LIST_HEAD(&msta->poll_list); 65898686cd2SShayne Chen msta->vif = mvif; 65998686cd2SShayne Chen msta->wcid.sta = 1; 66098686cd2SShayne Chen msta->wcid.idx = idx; 66198686cd2SShayne Chen msta->wcid.phy_idx = band_idx; 66298686cd2SShayne Chen msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 66398686cd2SShayne Chen msta->jiffies = jiffies; 66498686cd2SShayne Chen 665ea5d99d0SRyder Lee ewma_avg_signal_init(&msta->avg_ack_signal); 666ea5d99d0SRyder Lee 66798686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 66898686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 66998686cd2SShayne Chen 67098686cd2SShayne Chen ret = mt7996_mcu_add_sta(dev, vif, sta, true); 67198686cd2SShayne Chen if (ret) 67298686cd2SShayne Chen return ret; 67398686cd2SShayne Chen 67498686cd2SShayne Chen return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); 67598686cd2SShayne Chen } 67698686cd2SShayne Chen 67798686cd2SShayne Chen void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 67898686cd2SShayne Chen struct ieee80211_sta *sta) 67998686cd2SShayne Chen { 68098686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 68198686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 68298686cd2SShayne Chen int i; 68398686cd2SShayne Chen 68498686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, sta, false); 68598686cd2SShayne Chen 68698686cd2SShayne Chen mt7996_mac_wtbl_update(dev, msta->wcid.idx, 68798686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 68898686cd2SShayne Chen 68998686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) 69098686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, i); 69198686cd2SShayne Chen 69298686cd2SShayne Chen spin_lock_bh(&dev->sta_poll_lock); 69398686cd2SShayne Chen if (!list_empty(&msta->poll_list)) 69498686cd2SShayne Chen list_del_init(&msta->poll_list); 69598686cd2SShayne Chen if (!list_empty(&msta->rc_list)) 69698686cd2SShayne Chen list_del_init(&msta->rc_list); 69798686cd2SShayne Chen spin_unlock_bh(&dev->sta_poll_lock); 69898686cd2SShayne Chen } 69998686cd2SShayne Chen 70098686cd2SShayne Chen static void mt7996_tx(struct ieee80211_hw *hw, 70198686cd2SShayne Chen struct ieee80211_tx_control *control, 70298686cd2SShayne Chen struct sk_buff *skb) 70398686cd2SShayne Chen { 70498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 70598686cd2SShayne Chen struct mt76_phy *mphy = hw->priv; 70698686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 70798686cd2SShayne Chen struct ieee80211_vif *vif = info->control.vif; 70898686cd2SShayne Chen struct mt76_wcid *wcid = &dev->mt76.global_wcid; 70998686cd2SShayne Chen 71098686cd2SShayne Chen if (control->sta) { 71198686cd2SShayne Chen struct mt7996_sta *sta; 71298686cd2SShayne Chen 71398686cd2SShayne Chen sta = (struct mt7996_sta *)control->sta->drv_priv; 71498686cd2SShayne Chen wcid = &sta->wcid; 71598686cd2SShayne Chen } 71698686cd2SShayne Chen 71798686cd2SShayne Chen if (vif && !control->sta) { 71898686cd2SShayne Chen struct mt7996_vif *mvif; 71998686cd2SShayne Chen 72098686cd2SShayne Chen mvif = (struct mt7996_vif *)vif->drv_priv; 72198686cd2SShayne Chen wcid = &mvif->sta.wcid; 72298686cd2SShayne Chen } 72398686cd2SShayne Chen 72498686cd2SShayne Chen mt76_tx(mphy, control->sta, wcid, skb); 72598686cd2SShayne Chen } 72698686cd2SShayne Chen 72798686cd2SShayne Chen static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 72898686cd2SShayne Chen { 72998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 73098686cd2SShayne Chen int ret; 73198686cd2SShayne Chen 73298686cd2SShayne Chen mutex_lock(&phy->dev->mt76.mutex); 73398686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, val); 73498686cd2SShayne Chen mutex_unlock(&phy->dev->mt76.mutex); 73598686cd2SShayne Chen 73698686cd2SShayne Chen return ret; 73798686cd2SShayne Chen } 73898686cd2SShayne Chen 73998686cd2SShayne Chen static int 74098686cd2SShayne Chen mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 74198686cd2SShayne Chen struct ieee80211_ampdu_params *params) 74298686cd2SShayne Chen { 74398686cd2SShayne Chen enum ieee80211_ampdu_mlme_action action = params->action; 74498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 74598686cd2SShayne Chen struct ieee80211_sta *sta = params->sta; 74698686cd2SShayne Chen struct ieee80211_txq *txq = sta->txq[params->tid]; 74798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 74898686cd2SShayne Chen u16 tid = params->tid; 74998686cd2SShayne Chen u16 ssn = params->ssn; 75098686cd2SShayne Chen struct mt76_txq *mtxq; 75198686cd2SShayne Chen int ret = 0; 75298686cd2SShayne Chen 75398686cd2SShayne Chen if (!txq) 75498686cd2SShayne Chen return -EINVAL; 75598686cd2SShayne Chen 75698686cd2SShayne Chen mtxq = (struct mt76_txq *)txq->drv_priv; 75798686cd2SShayne Chen 75898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 75998686cd2SShayne Chen switch (action) { 76098686cd2SShayne Chen case IEEE80211_AMPDU_RX_START: 76198686cd2SShayne Chen mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, 76298686cd2SShayne Chen params->buf_size); 76398686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, true); 76498686cd2SShayne Chen break; 76598686cd2SShayne Chen case IEEE80211_AMPDU_RX_STOP: 76698686cd2SShayne Chen mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 76798686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, false); 76898686cd2SShayne Chen break; 76998686cd2SShayne Chen case IEEE80211_AMPDU_TX_OPERATIONAL: 77098686cd2SShayne Chen mtxq->aggr = true; 77198686cd2SShayne Chen mtxq->send_bar = false; 77298686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, true); 77398686cd2SShayne Chen break; 77498686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH: 77598686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 77698686cd2SShayne Chen mtxq->aggr = false; 77798686cd2SShayne Chen clear_bit(tid, &msta->ampdu_state); 77898686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 77998686cd2SShayne Chen break; 78098686cd2SShayne Chen case IEEE80211_AMPDU_TX_START: 78198686cd2SShayne Chen set_bit(tid, &msta->ampdu_state); 78298686cd2SShayne Chen ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 78398686cd2SShayne Chen break; 78498686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_CONT: 78598686cd2SShayne Chen mtxq->aggr = false; 78698686cd2SShayne Chen clear_bit(tid, &msta->ampdu_state); 78798686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 78898686cd2SShayne Chen ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 78998686cd2SShayne Chen break; 79098686cd2SShayne Chen } 79198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 79298686cd2SShayne Chen 79398686cd2SShayne Chen return ret; 79498686cd2SShayne Chen } 79598686cd2SShayne Chen 79698686cd2SShayne Chen static int 79798686cd2SShayne Chen mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 79898686cd2SShayne Chen struct ieee80211_sta *sta) 79998686cd2SShayne Chen { 80098686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, 80198686cd2SShayne Chen IEEE80211_STA_NONE); 80298686cd2SShayne Chen } 80398686cd2SShayne Chen 80498686cd2SShayne Chen static int 80598686cd2SShayne Chen mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 80698686cd2SShayne Chen struct ieee80211_sta *sta) 80798686cd2SShayne Chen { 80898686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, 80998686cd2SShayne Chen IEEE80211_STA_NOTEXIST); 81098686cd2SShayne Chen } 81198686cd2SShayne Chen 81298686cd2SShayne Chen static int 81398686cd2SShayne Chen mt7996_get_stats(struct ieee80211_hw *hw, 81498686cd2SShayne Chen struct ieee80211_low_level_stats *stats) 81598686cd2SShayne Chen { 81698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 81798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 818*98214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib; 81998686cd2SShayne Chen 82098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 82198686cd2SShayne Chen 82298686cd2SShayne Chen stats->dot11RTSSuccessCount = mib->rts_cnt; 82398686cd2SShayne Chen stats->dot11RTSFailureCount = mib->rts_retries_cnt; 82498686cd2SShayne Chen stats->dot11FCSErrorCount = mib->fcs_err_cnt; 82598686cd2SShayne Chen stats->dot11ACKFailureCount = mib->ack_fail_cnt; 82698686cd2SShayne Chen 82798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 82898686cd2SShayne Chen 82998686cd2SShayne Chen return 0; 83098686cd2SShayne Chen } 83198686cd2SShayne Chen 83298686cd2SShayne Chen u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) 83398686cd2SShayne Chen { 83498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 83598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 83698686cd2SShayne Chen union { 83798686cd2SShayne Chen u64 t64; 83898686cd2SShayne Chen u32 t32[2]; 83998686cd2SShayne Chen } tsf; 84098686cd2SShayne Chen u16 n; 84198686cd2SShayne Chen 84298686cd2SShayne Chen lockdep_assert_held(&dev->mt76.mutex); 84398686cd2SShayne Chen 84498686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 84598686cd2SShayne Chen : mvif->mt76.omac_idx; 84698686cd2SShayne Chen /* TSF software read */ 84798686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 84898686cd2SShayne Chen MT_LPON_TCR_SW_READ); 84998686cd2SShayne Chen tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(phy->mt76->band_idx)); 85098686cd2SShayne Chen tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(phy->mt76->band_idx)); 85198686cd2SShayne Chen 85298686cd2SShayne Chen return tsf.t64; 85398686cd2SShayne Chen } 85498686cd2SShayne Chen 85598686cd2SShayne Chen static u64 85698686cd2SShayne Chen mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 85798686cd2SShayne Chen { 85898686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 85998686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 86098686cd2SShayne Chen u64 ret; 86198686cd2SShayne Chen 86298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 86398686cd2SShayne Chen ret = __mt7996_get_tsf(hw, mvif); 86498686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 86598686cd2SShayne Chen 86698686cd2SShayne Chen return ret; 86798686cd2SShayne Chen } 86898686cd2SShayne Chen 86998686cd2SShayne Chen static void 87098686cd2SShayne Chen mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 87198686cd2SShayne Chen u64 timestamp) 87298686cd2SShayne Chen { 87398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 87498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 87598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 87698686cd2SShayne Chen union { 87798686cd2SShayne Chen u64 t64; 87898686cd2SShayne Chen u32 t32[2]; 87998686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 88098686cd2SShayne Chen u16 n; 88198686cd2SShayne Chen 88298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 88398686cd2SShayne Chen 88498686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 88598686cd2SShayne Chen : mvif->mt76.omac_idx; 88698686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 88798686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 88898686cd2SShayne Chen /* TSF software overwrite */ 88998686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 89098686cd2SShayne Chen MT_LPON_TCR_SW_WRITE); 89198686cd2SShayne Chen 89298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 89398686cd2SShayne Chen } 89498686cd2SShayne Chen 89598686cd2SShayne Chen static void 89698686cd2SShayne Chen mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 89798686cd2SShayne Chen s64 timestamp) 89898686cd2SShayne Chen { 89998686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 90098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 90198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 90298686cd2SShayne Chen union { 90398686cd2SShayne Chen u64 t64; 90498686cd2SShayne Chen u32 t32[2]; 90598686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 90698686cd2SShayne Chen u16 n; 90798686cd2SShayne Chen 90898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 90998686cd2SShayne Chen 91098686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 91198686cd2SShayne Chen : mvif->mt76.omac_idx; 91298686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 91398686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 91498686cd2SShayne Chen /* TSF software adjust*/ 91598686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 91698686cd2SShayne Chen MT_LPON_TCR_SW_ADJUST); 91798686cd2SShayne Chen 91898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 91998686cd2SShayne Chen } 92098686cd2SShayne Chen 92198686cd2SShayne Chen static void 92298686cd2SShayne Chen mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) 92398686cd2SShayne Chen { 92498686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 92598686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 92698686cd2SShayne Chen 92798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 92898686cd2SShayne Chen phy->coverage_class = max_t(s16, coverage_class, 0); 92998686cd2SShayne Chen mt7996_mac_set_timing(phy); 93098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 93198686cd2SShayne Chen } 93298686cd2SShayne Chen 93398686cd2SShayne Chen static int 93498686cd2SShayne Chen mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 93598686cd2SShayne Chen { 93698686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 93798686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 93898686cd2SShayne Chen int max_nss = hweight8(hw->wiphy->available_antennas_tx); 93998686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; 94098686cd2SShayne Chen 94198686cd2SShayne Chen if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) 94298686cd2SShayne Chen return -EINVAL; 94398686cd2SShayne Chen 94498686cd2SShayne Chen if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) 94598686cd2SShayne Chen tx_ant = BIT(ffs(tx_ant) - 1) - 1; 94698686cd2SShayne Chen 94798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 94898686cd2SShayne Chen 94998686cd2SShayne Chen phy->mt76->antenna_mask = tx_ant; 95098686cd2SShayne Chen 95198686cd2SShayne Chen /* restore to the origin chainmask which might have auxiliary path */ 952eb1fdb9fSShayne Chen if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) 953eb1fdb9fSShayne Chen phy->mt76->chainmask = ((dev->chainmask >> shift) & 954eb1fdb9fSShayne Chen (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; 955eb1fdb9fSShayne Chen else if (hweight8(tx_ant) == max_nss) 95698686cd2SShayne Chen phy->mt76->chainmask = (dev->chainmask >> shift) << shift; 95798686cd2SShayne Chen else 95898686cd2SShayne Chen phy->mt76->chainmask = tx_ant << shift; 95998686cd2SShayne Chen 96098686cd2SShayne Chen mt76_set_stream_caps(phy->mt76, true); 96198686cd2SShayne Chen mt7996_set_stream_vht_txbf_caps(phy); 962348533ebSShayne Chen mt7996_set_stream_he_eht_caps(phy); 96398686cd2SShayne Chen 96415ee62e7SRyder Lee /* TODO: update bmc_wtbl spe_idx when antenna changes */ 96598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 96698686cd2SShayne Chen 96798686cd2SShayne Chen return 0; 96898686cd2SShayne Chen } 96998686cd2SShayne Chen 97098686cd2SShayne Chen static void mt7996_sta_statistics(struct ieee80211_hw *hw, 97198686cd2SShayne Chen struct ieee80211_vif *vif, 97298686cd2SShayne Chen struct ieee80211_sta *sta, 97398686cd2SShayne Chen struct station_info *sinfo) 97498686cd2SShayne Chen { 97598686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 97698686cd2SShayne Chen struct rate_info *txrate = &msta->wcid.rate; 97798686cd2SShayne Chen 978b34f346bSRyder Lee if (txrate->legacy || txrate->flags) { 97998686cd2SShayne Chen if (txrate->legacy) { 98098686cd2SShayne Chen sinfo->txrate.legacy = txrate->legacy; 98198686cd2SShayne Chen } else { 98298686cd2SShayne Chen sinfo->txrate.mcs = txrate->mcs; 98398686cd2SShayne Chen sinfo->txrate.nss = txrate->nss; 98498686cd2SShayne Chen sinfo->txrate.bw = txrate->bw; 98598686cd2SShayne Chen sinfo->txrate.he_gi = txrate->he_gi; 98698686cd2SShayne Chen sinfo->txrate.he_dcm = txrate->he_dcm; 98798686cd2SShayne Chen sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; 98898686cd2SShayne Chen } 98998686cd2SShayne Chen sinfo->txrate.flags = txrate->flags; 99098686cd2SShayne Chen sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 991b34f346bSRyder Lee } 992b34f346bSRyder Lee sinfo->txrate.flags = txrate->flags; 993b34f346bSRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 994ea5d99d0SRyder Lee 995ea5d99d0SRyder Lee sinfo->ack_signal = (s8)msta->ack_signal; 996ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 997ea5d99d0SRyder Lee 998ea5d99d0SRyder Lee sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); 999ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 100098686cd2SShayne Chen } 100198686cd2SShayne Chen 100298686cd2SShayne Chen static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) 100398686cd2SShayne Chen { 100498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 100598686cd2SShayne Chen struct mt7996_dev *dev = msta->vif->phy->dev; 100698686cd2SShayne Chen u32 *changed = data; 100798686cd2SShayne Chen 100898686cd2SShayne Chen spin_lock_bh(&dev->sta_poll_lock); 100998686cd2SShayne Chen msta->changed |= *changed; 101098686cd2SShayne Chen if (list_empty(&msta->rc_list)) 101198686cd2SShayne Chen list_add_tail(&msta->rc_list, &dev->sta_rc_list); 101298686cd2SShayne Chen spin_unlock_bh(&dev->sta_poll_lock); 101398686cd2SShayne Chen } 101498686cd2SShayne Chen 101598686cd2SShayne Chen static void mt7996_sta_rc_update(struct ieee80211_hw *hw, 101698686cd2SShayne Chen struct ieee80211_vif *vif, 101798686cd2SShayne Chen struct ieee80211_sta *sta, 101898686cd2SShayne Chen u32 changed) 101998686cd2SShayne Chen { 102098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 102198686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 102298686cd2SShayne Chen 102398686cd2SShayne Chen mt7996_sta_rc_work(&changed, sta); 102498686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 102598686cd2SShayne Chen } 102698686cd2SShayne Chen 102798686cd2SShayne Chen static int 102898686cd2SShayne Chen mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 102998686cd2SShayne Chen const struct cfg80211_bitrate_mask *mask) 103098686cd2SShayne Chen { 103198686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 103298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 103398686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 103498686cd2SShayne Chen u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; 103598686cd2SShayne Chen 103698686cd2SShayne Chen mvif->bitrate_mask = *mask; 103798686cd2SShayne Chen 103898686cd2SShayne Chen /* if multiple rates across different preambles are given we can 103998686cd2SShayne Chen * reconfigure this info with all peers using sta_rec command with 104098686cd2SShayne Chen * the below exception cases. 104198686cd2SShayne Chen * - single rate : if a rate is passed along with different preambles, 104298686cd2SShayne Chen * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. 104398686cd2SShayne Chen * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT 104498686cd2SShayne Chen * then multiple MCS setting (MCS 4,5,6) is not supported. 104598686cd2SShayne Chen */ 104698686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); 104798686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 104898686cd2SShayne Chen 104998686cd2SShayne Chen return 0; 105098686cd2SShayne Chen } 105198686cd2SShayne Chen 105298686cd2SShayne Chen static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, 105398686cd2SShayne Chen struct ieee80211_vif *vif, 105498686cd2SShayne Chen struct ieee80211_sta *sta, 105598686cd2SShayne Chen bool enabled) 105698686cd2SShayne Chen { 105798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 105898686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 105998686cd2SShayne Chen 106098686cd2SShayne Chen if (enabled) 106198686cd2SShayne Chen set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 106298686cd2SShayne Chen else 106398686cd2SShayne Chen clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 106498686cd2SShayne Chen 106598686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 106698686cd2SShayne Chen } 106798686cd2SShayne Chen 106898686cd2SShayne Chen static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, 106998686cd2SShayne Chen struct ieee80211_vif *vif, 107098686cd2SShayne Chen struct ieee80211_sta *sta, 107198686cd2SShayne Chen bool enabled) 107298686cd2SShayne Chen { 107398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 107498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 107598686cd2SShayne Chen 107698686cd2SShayne Chen if (enabled) 107798686cd2SShayne Chen set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 107898686cd2SShayne Chen else 107998686cd2SShayne Chen clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 108098686cd2SShayne Chen 108198686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 108298686cd2SShayne Chen } 108398686cd2SShayne Chen 108498686cd2SShayne Chen static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = { 108598686cd2SShayne Chen "tx_ampdu_cnt", 108698686cd2SShayne Chen "tx_stop_q_empty_cnt", 108798686cd2SShayne Chen "tx_mpdu_attempts", 108898686cd2SShayne Chen "tx_mpdu_success", 108998686cd2SShayne Chen "tx_rwp_fail_cnt", 109098686cd2SShayne Chen "tx_rwp_need_cnt", 109198686cd2SShayne Chen "tx_pkt_ebf_cnt", 109298686cd2SShayne Chen "tx_pkt_ibf_cnt", 109398686cd2SShayne Chen "tx_ampdu_len:0-1", 109498686cd2SShayne Chen "tx_ampdu_len:2-10", 109598686cd2SShayne Chen "tx_ampdu_len:11-19", 109698686cd2SShayne Chen "tx_ampdu_len:20-28", 109798686cd2SShayne Chen "tx_ampdu_len:29-37", 109898686cd2SShayne Chen "tx_ampdu_len:38-46", 109998686cd2SShayne Chen "tx_ampdu_len:47-55", 110098686cd2SShayne Chen "tx_ampdu_len:56-79", 110198686cd2SShayne Chen "tx_ampdu_len:80-103", 110298686cd2SShayne Chen "tx_ampdu_len:104-127", 110398686cd2SShayne Chen "tx_ampdu_len:128-151", 110498686cd2SShayne Chen "tx_ampdu_len:152-175", 110598686cd2SShayne Chen "tx_ampdu_len:176-199", 110698686cd2SShayne Chen "tx_ampdu_len:200-223", 110798686cd2SShayne Chen "tx_ampdu_len:224-247", 110898686cd2SShayne Chen "ba_miss_count", 110998686cd2SShayne Chen "tx_beamformer_ppdu_iBF", 111098686cd2SShayne Chen "tx_beamformer_ppdu_eBF", 111198686cd2SShayne Chen "tx_beamformer_rx_feedback_all", 111298686cd2SShayne Chen "tx_beamformer_rx_feedback_he", 111398686cd2SShayne Chen "tx_beamformer_rx_feedback_vht", 111498686cd2SShayne Chen "tx_beamformer_rx_feedback_ht", 111598686cd2SShayne Chen "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ 111698686cd2SShayne Chen "tx_beamformer_rx_feedback_nc", 111798686cd2SShayne Chen "tx_beamformer_rx_feedback_nr", 111898686cd2SShayne Chen "tx_beamformee_ok_feedback_pkts", 111998686cd2SShayne Chen "tx_beamformee_feedback_trig", 112098686cd2SShayne Chen "tx_mu_beamforming", 112198686cd2SShayne Chen "tx_mu_mpdu", 112298686cd2SShayne Chen "tx_mu_successful_mpdu", 112398686cd2SShayne Chen "tx_su_successful_mpdu", 112498686cd2SShayne Chen "tx_msdu_pack_1", 112598686cd2SShayne Chen "tx_msdu_pack_2", 112698686cd2SShayne Chen "tx_msdu_pack_3", 112798686cd2SShayne Chen "tx_msdu_pack_4", 112898686cd2SShayne Chen "tx_msdu_pack_5", 112998686cd2SShayne Chen "tx_msdu_pack_6", 113098686cd2SShayne Chen "tx_msdu_pack_7", 113198686cd2SShayne Chen "tx_msdu_pack_8", 113298686cd2SShayne Chen 113398686cd2SShayne Chen /* rx counters */ 113498686cd2SShayne Chen "rx_fifo_full_cnt", 113598686cd2SShayne Chen "rx_mpdu_cnt", 113698686cd2SShayne Chen "channel_idle_cnt", 113798686cd2SShayne Chen "rx_vector_mismatch_cnt", 113898686cd2SShayne Chen "rx_delimiter_fail_cnt", 113998686cd2SShayne Chen "rx_len_mismatch_cnt", 114098686cd2SShayne Chen "rx_ampdu_cnt", 114198686cd2SShayne Chen "rx_ampdu_bytes_cnt", 114298686cd2SShayne Chen "rx_ampdu_valid_subframe_cnt", 114398686cd2SShayne Chen "rx_ampdu_valid_subframe_b_cnt", 114498686cd2SShayne Chen "rx_pfdrop_cnt", 114598686cd2SShayne Chen "rx_vec_queue_overflow_drop_cnt", 114698686cd2SShayne Chen "rx_ba_cnt", 114798686cd2SShayne Chen 114898686cd2SShayne Chen /* per vif counters */ 114998686cd2SShayne Chen "v_tx_mode_cck", 115098686cd2SShayne Chen "v_tx_mode_ofdm", 115198686cd2SShayne Chen "v_tx_mode_ht", 115298686cd2SShayne Chen "v_tx_mode_ht_gf", 115398686cd2SShayne Chen "v_tx_mode_vht", 115498686cd2SShayne Chen "v_tx_mode_he_su", 115598686cd2SShayne Chen "v_tx_mode_he_ext_su", 115698686cd2SShayne Chen "v_tx_mode_he_tb", 115798686cd2SShayne Chen "v_tx_mode_he_mu", 1158731425f3SShayne Chen "v_tx_mode_eht_su", 1159731425f3SShayne Chen "v_tx_mode_eht_trig", 1160731425f3SShayne Chen "v_tx_mode_eht_mu", 116198686cd2SShayne Chen "v_tx_bw_20", 116298686cd2SShayne Chen "v_tx_bw_40", 116398686cd2SShayne Chen "v_tx_bw_80", 116498686cd2SShayne Chen "v_tx_bw_160", 1165731425f3SShayne Chen "v_tx_bw_320", 116698686cd2SShayne Chen "v_tx_mcs_0", 116798686cd2SShayne Chen "v_tx_mcs_1", 116898686cd2SShayne Chen "v_tx_mcs_2", 116998686cd2SShayne Chen "v_tx_mcs_3", 117098686cd2SShayne Chen "v_tx_mcs_4", 117198686cd2SShayne Chen "v_tx_mcs_5", 117298686cd2SShayne Chen "v_tx_mcs_6", 117398686cd2SShayne Chen "v_tx_mcs_7", 117498686cd2SShayne Chen "v_tx_mcs_8", 117598686cd2SShayne Chen "v_tx_mcs_9", 117698686cd2SShayne Chen "v_tx_mcs_10", 117798686cd2SShayne Chen "v_tx_mcs_11", 1178731425f3SShayne Chen "v_tx_mcs_12", 1179731425f3SShayne Chen "v_tx_mcs_13", 118098686cd2SShayne Chen }; 118198686cd2SShayne Chen 118298686cd2SShayne Chen #define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats) 118398686cd2SShayne Chen 118498686cd2SShayne Chen /* Ethtool related API */ 118598686cd2SShayne Chen static 118698686cd2SShayne Chen void mt7996_get_et_strings(struct ieee80211_hw *hw, 118798686cd2SShayne Chen struct ieee80211_vif *vif, 118898686cd2SShayne Chen u32 sset, u8 *data) 118998686cd2SShayne Chen { 119098686cd2SShayne Chen if (sset == ETH_SS_STATS) 119198686cd2SShayne Chen memcpy(data, *mt7996_gstrings_stats, 119298686cd2SShayne Chen sizeof(mt7996_gstrings_stats)); 119398686cd2SShayne Chen } 119498686cd2SShayne Chen 119598686cd2SShayne Chen static 119698686cd2SShayne Chen int mt7996_get_et_sset_count(struct ieee80211_hw *hw, 119798686cd2SShayne Chen struct ieee80211_vif *vif, int sset) 119898686cd2SShayne Chen { 119998686cd2SShayne Chen if (sset == ETH_SS_STATS) 120098686cd2SShayne Chen return MT7996_SSTATS_LEN; 120198686cd2SShayne Chen 120298686cd2SShayne Chen return 0; 120398686cd2SShayne Chen } 120498686cd2SShayne Chen 120598686cd2SShayne Chen static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) 120698686cd2SShayne Chen { 120798686cd2SShayne Chen struct mt76_ethtool_worker_info *wi = wi_data; 120898686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 120998686cd2SShayne Chen 121098686cd2SShayne Chen if (msta->vif->mt76.idx != wi->idx) 121198686cd2SShayne Chen return; 121298686cd2SShayne Chen 1213731425f3SShayne Chen mt76_ethtool_worker(wi, &msta->stats, true); 121498686cd2SShayne Chen } 121598686cd2SShayne Chen 121698686cd2SShayne Chen static 121798686cd2SShayne Chen void mt7996_get_et_stats(struct ieee80211_hw *hw, 121898686cd2SShayne Chen struct ieee80211_vif *vif, 121998686cd2SShayne Chen struct ethtool_stats *stats, u64 *data) 122098686cd2SShayne Chen { 122198686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 122298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 122398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 1224*98214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib; 122598686cd2SShayne Chen struct mt76_ethtool_worker_info wi = { 122698686cd2SShayne Chen .data = data, 122798686cd2SShayne Chen .idx = mvif->mt76.idx, 122898686cd2SShayne Chen }; 122998686cd2SShayne Chen /* See mt7996_ampdu_stat_read_phy, etc */ 123098686cd2SShayne Chen int i, ei = 0; 123198686cd2SShayne Chen 123298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 123398686cd2SShayne Chen 123498686cd2SShayne Chen mt7996_mac_update_stats(phy); 123598686cd2SShayne Chen 123698686cd2SShayne Chen data[ei++] = mib->tx_ampdu_cnt; 123798686cd2SShayne Chen data[ei++] = mib->tx_stop_q_empty_cnt; 123898686cd2SShayne Chen data[ei++] = mib->tx_mpdu_attempts_cnt; 123998686cd2SShayne Chen data[ei++] = mib->tx_mpdu_success_cnt; 124098686cd2SShayne Chen data[ei++] = mib->tx_rwp_fail_cnt; 124198686cd2SShayne Chen data[ei++] = mib->tx_rwp_need_cnt; 124298686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 124398686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 124498686cd2SShayne Chen 124598686cd2SShayne Chen /* Tx ampdu stat */ 124698686cd2SShayne Chen for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) 124798686cd2SShayne Chen data[ei++] = phy->mt76->aggr_stats[i]; 124898686cd2SShayne Chen data[ei++] = phy->mib.ba_miss_cnt; 124998686cd2SShayne Chen 125098686cd2SShayne Chen /* Tx Beamformer monitor */ 125198686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 125298686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 125398686cd2SShayne Chen 125498686cd2SShayne Chen /* Tx Beamformer Rx feedback monitor */ 125598686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_all_cnt; 125698686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_he_cnt; 125798686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_vht_cnt; 125898686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_ht_cnt; 125998686cd2SShayne Chen 126098686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_bw; 126198686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nc_cnt; 126298686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nr_cnt; 126398686cd2SShayne Chen 126498686cd2SShayne Chen /* Tx Beamformee Rx NDPA & Tx feedback report */ 126598686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_cpl_cnt; 126698686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_trig_cnt; 126798686cd2SShayne Chen 126898686cd2SShayne Chen /* Tx SU & MU counters */ 126998686cd2SShayne Chen data[ei++] = mib->tx_mu_bf_cnt; 127098686cd2SShayne Chen data[ei++] = mib->tx_mu_mpdu_cnt; 127198686cd2SShayne Chen data[ei++] = mib->tx_mu_acked_mpdu_cnt; 127298686cd2SShayne Chen data[ei++] = mib->tx_su_acked_mpdu_cnt; 127398686cd2SShayne Chen 127498686cd2SShayne Chen /* Tx amsdu info (pack-count histogram) */ 127598686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) 127698686cd2SShayne Chen data[ei++] = mib->tx_amsdu[i]; 127798686cd2SShayne Chen 127898686cd2SShayne Chen /* rx counters */ 127998686cd2SShayne Chen data[ei++] = mib->rx_fifo_full_cnt; 128098686cd2SShayne Chen data[ei++] = mib->rx_mpdu_cnt; 128198686cd2SShayne Chen data[ei++] = mib->channel_idle_cnt; 128298686cd2SShayne Chen data[ei++] = mib->rx_vector_mismatch_cnt; 128398686cd2SShayne Chen data[ei++] = mib->rx_delimiter_fail_cnt; 128498686cd2SShayne Chen data[ei++] = mib->rx_len_mismatch_cnt; 128598686cd2SShayne Chen data[ei++] = mib->rx_ampdu_cnt; 128698686cd2SShayne Chen data[ei++] = mib->rx_ampdu_bytes_cnt; 128798686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_cnt; 128898686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; 128998686cd2SShayne Chen data[ei++] = mib->rx_pfdrop_cnt; 129098686cd2SShayne Chen data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; 129198686cd2SShayne Chen data[ei++] = mib->rx_ba_cnt; 129298686cd2SShayne Chen 129398686cd2SShayne Chen /* Add values for all stations owned by this vif */ 129498686cd2SShayne Chen wi.initial_stat_idx = ei; 129598686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_ethtool_worker, &wi); 129698686cd2SShayne Chen 129798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 129898686cd2SShayne Chen 129998686cd2SShayne Chen if (wi.sta_count == 0) 130098686cd2SShayne Chen return; 130198686cd2SShayne Chen 130298686cd2SShayne Chen ei += wi.worker_stat_count; 130398686cd2SShayne Chen if (ei != MT7996_SSTATS_LEN) 130498686cd2SShayne Chen dev_err(dev->mt76.dev, "ei: %d MT7996_SSTATS_LEN: %d", 130598686cd2SShayne Chen ei, (int)MT7996_SSTATS_LEN); 130698686cd2SShayne Chen } 130798686cd2SShayne Chen 130898686cd2SShayne Chen static void 130998686cd2SShayne Chen mt7996_twt_teardown_request(struct ieee80211_hw *hw, 131098686cd2SShayne Chen struct ieee80211_sta *sta, 131198686cd2SShayne Chen u8 flowid) 131298686cd2SShayne Chen { 131398686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 131498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 131598686cd2SShayne Chen 131698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 131798686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, flowid); 131898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 131998686cd2SShayne Chen } 132098686cd2SShayne Chen 132198686cd2SShayne Chen static int 132298686cd2SShayne Chen mt7996_set_radar_background(struct ieee80211_hw *hw, 132398686cd2SShayne Chen struct cfg80211_chan_def *chandef) 132498686cd2SShayne Chen { 132598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 132698686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 132798686cd2SShayne Chen int ret = -EINVAL; 132898686cd2SShayne Chen bool running; 132998686cd2SShayne Chen 133098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 133198686cd2SShayne Chen 133298686cd2SShayne Chen if (dev->mt76.region == NL80211_DFS_UNSET) 133398686cd2SShayne Chen goto out; 133498686cd2SShayne Chen 133598686cd2SShayne Chen if (dev->rdd2_phy && dev->rdd2_phy != phy) { 133698686cd2SShayne Chen /* rdd2 is already locked */ 133798686cd2SShayne Chen ret = -EBUSY; 133898686cd2SShayne Chen goto out; 133998686cd2SShayne Chen } 134098686cd2SShayne Chen 134198686cd2SShayne Chen /* rdd2 already configured on a radar channel */ 134298686cd2SShayne Chen running = dev->rdd2_phy && 134398686cd2SShayne Chen cfg80211_chandef_valid(&dev->rdd2_chandef) && 134498686cd2SShayne Chen !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); 134598686cd2SShayne Chen 134698686cd2SShayne Chen if (!chandef || running || 134798686cd2SShayne Chen !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { 134898686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, NULL); 134998686cd2SShayne Chen if (ret) 135098686cd2SShayne Chen goto out; 135198686cd2SShayne Chen 135298686cd2SShayne Chen if (!running) 135398686cd2SShayne Chen goto update_phy; 135498686cd2SShayne Chen } 135598686cd2SShayne Chen 135698686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, chandef); 135798686cd2SShayne Chen if (ret) 135898686cd2SShayne Chen goto out; 135998686cd2SShayne Chen 136098686cd2SShayne Chen update_phy: 136198686cd2SShayne Chen dev->rdd2_phy = chandef ? phy : NULL; 136298686cd2SShayne Chen if (chandef) 136398686cd2SShayne Chen dev->rdd2_chandef = *chandef; 136498686cd2SShayne Chen out: 136598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 136698686cd2SShayne Chen 136798686cd2SShayne Chen return ret; 136898686cd2SShayne Chen } 136998686cd2SShayne Chen 137098686cd2SShayne Chen const struct ieee80211_ops mt7996_ops = { 137198686cd2SShayne Chen .tx = mt7996_tx, 137298686cd2SShayne Chen .start = mt7996_start, 137398686cd2SShayne Chen .stop = mt7996_stop, 137498686cd2SShayne Chen .add_interface = mt7996_add_interface, 137598686cd2SShayne Chen .remove_interface = mt7996_remove_interface, 137698686cd2SShayne Chen .config = mt7996_config, 137798686cd2SShayne Chen .conf_tx = mt7996_conf_tx, 137898686cd2SShayne Chen .configure_filter = mt7996_configure_filter, 137998686cd2SShayne Chen .bss_info_changed = mt7996_bss_info_changed, 138098686cd2SShayne Chen .sta_add = mt7996_sta_add, 138198686cd2SShayne Chen .sta_remove = mt7996_sta_remove, 138298686cd2SShayne Chen .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 138398686cd2SShayne Chen .sta_rc_update = mt7996_sta_rc_update, 138498686cd2SShayne Chen .set_key = mt7996_set_key, 138598686cd2SShayne Chen .ampdu_action = mt7996_ampdu_action, 138698686cd2SShayne Chen .set_rts_threshold = mt7996_set_rts_threshold, 138798686cd2SShayne Chen .wake_tx_queue = mt76_wake_tx_queue, 138898686cd2SShayne Chen .sw_scan_start = mt76_sw_scan, 138998686cd2SShayne Chen .sw_scan_complete = mt76_sw_scan_complete, 139098686cd2SShayne Chen .release_buffered_frames = mt76_release_buffered_frames, 139198686cd2SShayne Chen .get_txpower = mt76_get_txpower, 139298686cd2SShayne Chen .channel_switch_beacon = mt7996_channel_switch_beacon, 139398686cd2SShayne Chen .get_stats = mt7996_get_stats, 139498686cd2SShayne Chen .get_et_sset_count = mt7996_get_et_sset_count, 139598686cd2SShayne Chen .get_et_stats = mt7996_get_et_stats, 139698686cd2SShayne Chen .get_et_strings = mt7996_get_et_strings, 139798686cd2SShayne Chen .get_tsf = mt7996_get_tsf, 139898686cd2SShayne Chen .set_tsf = mt7996_set_tsf, 139998686cd2SShayne Chen .offset_tsf = mt7996_offset_tsf, 140098686cd2SShayne Chen .get_survey = mt76_get_survey, 140198686cd2SShayne Chen .get_antenna = mt76_get_antenna, 140298686cd2SShayne Chen .set_antenna = mt7996_set_antenna, 140398686cd2SShayne Chen .set_bitrate_mask = mt7996_set_bitrate_mask, 140498686cd2SShayne Chen .set_coverage_class = mt7996_set_coverage_class, 140598686cd2SShayne Chen .sta_statistics = mt7996_sta_statistics, 140698686cd2SShayne Chen .sta_set_4addr = mt7996_sta_set_4addr, 140798686cd2SShayne Chen .sta_set_decap_offload = mt7996_sta_set_decap_offload, 140898686cd2SShayne Chen .add_twt_setup = mt7996_mac_add_twt_setup, 140998686cd2SShayne Chen .twt_teardown_request = mt7996_twt_teardown_request, 141098686cd2SShayne Chen #ifdef CONFIG_MAC80211_DEBUGFS 141198686cd2SShayne Chen .sta_add_debugfs = mt7996_sta_add_debugfs, 141298686cd2SShayne Chen #endif 141398686cd2SShayne Chen .set_radar_background = mt7996_set_radar_background, 141498686cd2SShayne Chen }; 1415