198686cd2SShayne Chen // SPDX-License-Identifier: ISC 298686cd2SShayne Chen /* 398686cd2SShayne Chen * Copyright (C) 2022 MediaTek Inc. 498686cd2SShayne Chen */ 598686cd2SShayne Chen 698686cd2SShayne Chen #include "mt7996.h" 798686cd2SShayne Chen #include "mcu.h" 815ee62e7SRyder Lee #include "mac.h" 998686cd2SShayne Chen 1098686cd2SShayne Chen static bool mt7996_dev_running(struct mt7996_dev *dev) 1198686cd2SShayne Chen { 1298686cd2SShayne Chen struct mt7996_phy *phy; 1398686cd2SShayne Chen 1498686cd2SShayne Chen if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) 1598686cd2SShayne Chen return true; 1698686cd2SShayne Chen 1798686cd2SShayne Chen phy = mt7996_phy2(dev); 1898686cd2SShayne Chen if (phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 1998686cd2SShayne Chen return true; 2098686cd2SShayne Chen 2198686cd2SShayne Chen phy = mt7996_phy3(dev); 2298686cd2SShayne Chen 2398686cd2SShayne Chen return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); 2498686cd2SShayne Chen } 2598686cd2SShayne Chen 2627015b6fSBo Jiao int mt7996_run(struct ieee80211_hw *hw) 2798686cd2SShayne Chen { 2898686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 2998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 3098686cd2SShayne Chen bool running; 3198686cd2SShayne Chen int ret; 3298686cd2SShayne Chen 3398686cd2SShayne Chen running = mt7996_dev_running(dev); 3498686cd2SShayne Chen if (!running) { 3598686cd2SShayne Chen ret = mt7996_mcu_set_hdr_trans(dev, true); 3698686cd2SShayne Chen if (ret) 3798686cd2SShayne Chen goto out; 3898686cd2SShayne Chen } 3998686cd2SShayne Chen 4098686cd2SShayne Chen mt7996_mac_enable_nf(dev, phy->mt76->band_idx); 4198686cd2SShayne Chen 4298686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, 0x92b); 4398686cd2SShayne Chen if (ret) 4498686cd2SShayne Chen goto out; 4598686cd2SShayne Chen 46d73dab22SShayne Chen ret = mt7996_mcu_set_radio_en(phy, true); 47d73dab22SShayne Chen if (ret) 48d73dab22SShayne Chen goto out; 49d73dab22SShayne Chen 5098686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH); 5198686cd2SShayne Chen if (ret) 5298686cd2SShayne Chen goto out; 5398686cd2SShayne Chen 5421f29088SHoward Hsu ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX); 5521f29088SHoward Hsu if (ret) 5621f29088SHoward Hsu goto out; 5721f29088SHoward Hsu 5821f29088SHoward Hsu ret = mt7996_mcu_set_thermal_protect(phy, true); 5921f29088SHoward Hsu if (ret) 6021f29088SHoward Hsu goto out; 6121f29088SHoward Hsu 6298686cd2SShayne Chen set_bit(MT76_STATE_RUNNING, &phy->mt76->state); 6398686cd2SShayne Chen 6498686cd2SShayne Chen ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, 6598686cd2SShayne Chen MT7996_WATCHDOG_TIME); 6698686cd2SShayne Chen 6798686cd2SShayne Chen if (!running) 6898686cd2SShayne Chen mt7996_mac_reset_counters(phy); 6998686cd2SShayne Chen 7098686cd2SShayne Chen out: 7127015b6fSBo Jiao return ret; 7227015b6fSBo Jiao } 7327015b6fSBo Jiao 7427015b6fSBo Jiao static int mt7996_start(struct ieee80211_hw *hw) 7527015b6fSBo Jiao { 7627015b6fSBo Jiao struct mt7996_dev *dev = mt7996_hw_dev(hw); 7727015b6fSBo Jiao int ret; 7827015b6fSBo Jiao 7927015b6fSBo Jiao flush_work(&dev->init_work); 8027015b6fSBo Jiao 8127015b6fSBo Jiao mutex_lock(&dev->mt76.mutex); 8227015b6fSBo Jiao ret = mt7996_run(hw); 8398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 8498686cd2SShayne Chen 8598686cd2SShayne Chen return ret; 8698686cd2SShayne Chen } 8798686cd2SShayne Chen 8898686cd2SShayne Chen static void mt7996_stop(struct ieee80211_hw *hw) 8998686cd2SShayne Chen { 9098686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 9198686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 9298686cd2SShayne Chen 9398686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 9498686cd2SShayne Chen 9598686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 9698686cd2SShayne Chen 97d73dab22SShayne Chen mt7996_mcu_set_radio_en(phy, false); 98d73dab22SShayne Chen 9998686cd2SShayne Chen clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); 10098686cd2SShayne Chen 10198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 10298686cd2SShayne Chen } 10398686cd2SShayne Chen 10498686cd2SShayne Chen static inline int get_free_idx(u32 mask, u8 start, u8 end) 10598686cd2SShayne Chen { 10698686cd2SShayne Chen return ffs(~mask & GENMASK(end, start)); 10798686cd2SShayne Chen } 10898686cd2SShayne Chen 10998686cd2SShayne Chen static int get_omac_idx(enum nl80211_iftype type, u64 mask) 11098686cd2SShayne Chen { 11198686cd2SShayne Chen int i; 11298686cd2SShayne Chen 11398686cd2SShayne Chen switch (type) { 11498686cd2SShayne Chen case NL80211_IFTYPE_MESH_POINT: 11598686cd2SShayne Chen case NL80211_IFTYPE_ADHOC: 11698686cd2SShayne Chen case NL80211_IFTYPE_STATION: 11798686cd2SShayne Chen /* prefer hw bssid slot 1-3 */ 11898686cd2SShayne Chen i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3); 11998686cd2SShayne Chen if (i) 12098686cd2SShayne Chen return i - 1; 12198686cd2SShayne Chen 12298686cd2SShayne Chen if (type != NL80211_IFTYPE_STATION) 12398686cd2SShayne Chen break; 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 if (~mask & BIT(HW_BSSID_0)) 13098686cd2SShayne Chen return HW_BSSID_0; 13198686cd2SShayne Chen 13298686cd2SShayne Chen break; 13398686cd2SShayne Chen case NL80211_IFTYPE_MONITOR: 13498686cd2SShayne Chen case NL80211_IFTYPE_AP: 13598686cd2SShayne Chen /* ap uses hw bssid 0 and ext bssid */ 13698686cd2SShayne Chen if (~mask & BIT(HW_BSSID_0)) 13798686cd2SShayne Chen return HW_BSSID_0; 13898686cd2SShayne Chen 13998686cd2SShayne Chen i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX); 14098686cd2SShayne Chen if (i) 14198686cd2SShayne Chen return i - 1; 14298686cd2SShayne Chen 14398686cd2SShayne Chen break; 14498686cd2SShayne Chen default: 14598686cd2SShayne Chen WARN_ON(1); 14698686cd2SShayne Chen break; 14798686cd2SShayne Chen } 14898686cd2SShayne Chen 14998686cd2SShayne Chen return -1; 15098686cd2SShayne Chen } 15198686cd2SShayne Chen 15298686cd2SShayne Chen static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif) 15398686cd2SShayne Chen { 15498686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 15598686cd2SShayne Chen int i; 15698686cd2SShayne Chen 15798686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) { 15898686cd2SShayne Chen mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; 15998686cd2SShayne Chen mvif->bitrate_mask.control[i].he_gi = 0xff; 16098686cd2SShayne Chen mvif->bitrate_mask.control[i].he_ltf = 0xff; 16198686cd2SShayne Chen mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0); 16298686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff, 16398686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].ht_mcs)); 16498686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff, 16598686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].vht_mcs)); 16698686cd2SShayne Chen memset(mvif->bitrate_mask.control[i].he_mcs, 0xff, 16798686cd2SShayne Chen sizeof(mvif->bitrate_mask.control[i].he_mcs)); 16898686cd2SShayne Chen } 16998686cd2SShayne Chen } 17098686cd2SShayne Chen 17198686cd2SShayne Chen static int mt7996_add_interface(struct ieee80211_hw *hw, 17298686cd2SShayne Chen struct ieee80211_vif *vif) 17398686cd2SShayne Chen { 17498686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 17598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 17698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 17798686cd2SShayne Chen struct mt76_txq *mtxq; 17898686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx; 17998686cd2SShayne Chen int idx, ret = 0; 18098686cd2SShayne Chen 18198686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 18298686cd2SShayne Chen 18398686cd2SShayne Chen if (vif->type == NL80211_IFTYPE_MONITOR && 18498686cd2SShayne Chen is_zero_ether_addr(vif->addr)) 18598686cd2SShayne Chen phy->monitor_vif = vif; 18698686cd2SShayne Chen 18798686cd2SShayne Chen mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask); 18843482540SShayne Chen if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) { 18998686cd2SShayne Chen ret = -ENOSPC; 19098686cd2SShayne Chen goto out; 19198686cd2SShayne Chen } 19298686cd2SShayne Chen 19398686cd2SShayne Chen idx = get_omac_idx(vif->type, phy->omac_mask); 19498686cd2SShayne Chen if (idx < 0) { 19598686cd2SShayne Chen ret = -ENOSPC; 19698686cd2SShayne Chen goto out; 19798686cd2SShayne Chen } 19898686cd2SShayne Chen mvif->mt76.omac_idx = idx; 19998686cd2SShayne Chen mvif->phy = phy; 20098686cd2SShayne Chen mvif->mt76.band_idx = band_idx; 2019b11696eSPeter Chiu mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP; 20298686cd2SShayne Chen 20398686cd2SShayne Chen ret = mt7996_mcu_add_dev_info(phy, vif, true); 20498686cd2SShayne Chen if (ret) 20598686cd2SShayne Chen goto out; 20698686cd2SShayne Chen 20798686cd2SShayne Chen dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx); 20898686cd2SShayne Chen phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx); 20998686cd2SShayne Chen 21098686cd2SShayne Chen idx = MT7996_WTBL_RESERVED - mvif->mt76.idx; 21198686cd2SShayne Chen 21298686cd2SShayne Chen INIT_LIST_HEAD(&mvif->sta.rc_list); 213e3b0311fSLorenzo Bianconi INIT_LIST_HEAD(&mvif->sta.wcid.poll_list); 21498686cd2SShayne Chen mvif->sta.wcid.idx = idx; 21598686cd2SShayne Chen mvif->sta.wcid.phy_idx = band_idx; 21698686cd2SShayne Chen mvif->sta.wcid.hw_key_idx = -1; 21798686cd2SShayne Chen mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET; 2180335c034SFelix Fietkau mt76_wcid_init(&mvif->sta.wcid); 21998686cd2SShayne Chen 22098686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 22198686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 22298686cd2SShayne Chen 22398686cd2SShayne Chen if (vif->txq) { 22498686cd2SShayne Chen mtxq = (struct mt76_txq *)vif->txq->drv_priv; 22598686cd2SShayne Chen mtxq->wcid = idx; 22698686cd2SShayne Chen } 22798686cd2SShayne Chen 22898686cd2SShayne Chen if (vif->type != NL80211_IFTYPE_AP && 22998686cd2SShayne Chen (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3)) 23098686cd2SShayne Chen vif->offload_flags = 0; 23198686cd2SShayne Chen vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR; 23298686cd2SShayne Chen 23315ee62e7SRyder Lee if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) 2340cb065b9SLorenzo Bianconi mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4; 23515ee62e7SRyder Lee else 2360cb065b9SLorenzo Bianconi mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL; 23715ee62e7SRyder Lee 23898686cd2SShayne Chen mt7996_init_bitrate_mask(vif); 23998686cd2SShayne Chen 24098686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 24198686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 24298686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); 24398686cd2SShayne Chen 24498686cd2SShayne Chen out: 24598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 24698686cd2SShayne Chen 24798686cd2SShayne Chen return ret; 24898686cd2SShayne Chen } 24998686cd2SShayne Chen 25098686cd2SShayne Chen static void mt7996_remove_interface(struct ieee80211_hw *hw, 25198686cd2SShayne Chen struct ieee80211_vif *vif) 25298686cd2SShayne Chen { 25398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 25498686cd2SShayne Chen struct mt7996_sta *msta = &mvif->sta; 25598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 25698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 25798686cd2SShayne Chen int idx = msta->wcid.idx; 25898686cd2SShayne Chen 25998686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, false); 26011ca0163SShayne Chen mt7996_mcu_add_bss_info(phy, vif, false); 26198686cd2SShayne Chen 26298686cd2SShayne Chen if (vif == phy->monitor_vif) 26398686cd2SShayne Chen phy->monitor_vif = NULL; 26498686cd2SShayne Chen 26598686cd2SShayne Chen mt7996_mcu_add_dev_info(phy, vif, false); 26698686cd2SShayne Chen 26798686cd2SShayne Chen rcu_assign_pointer(dev->mt76.wcid[idx], NULL); 26898686cd2SShayne Chen 26998686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 27098686cd2SShayne Chen dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); 27198686cd2SShayne Chen phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); 27298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 27398686cd2SShayne Chen 274ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock); 275e3b0311fSLorenzo Bianconi if (!list_empty(&msta->wcid.poll_list)) 276e3b0311fSLorenzo Bianconi list_del_init(&msta->wcid.poll_list); 277ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock); 27898686cd2SShayne Chen 2790335c034SFelix Fietkau mt76_wcid_cleanup(&dev->mt76, &msta->wcid); 28098686cd2SShayne Chen } 28198686cd2SShayne Chen 28298686cd2SShayne Chen int mt7996_set_channel(struct mt7996_phy *phy) 28398686cd2SShayne Chen { 28498686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 28598686cd2SShayne Chen int ret; 28698686cd2SShayne Chen 28798686cd2SShayne Chen cancel_delayed_work_sync(&phy->mt76->mac_work); 28898686cd2SShayne Chen 28998686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 29098686cd2SShayne Chen set_bit(MT76_RESET, &phy->mt76->state); 29198686cd2SShayne Chen 29298686cd2SShayne Chen mt76_set_channel(phy->mt76); 29398686cd2SShayne Chen 29498686cd2SShayne Chen ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); 29598686cd2SShayne Chen if (ret) 29698686cd2SShayne Chen goto out; 29798686cd2SShayne Chen 29898686cd2SShayne Chen ret = mt7996_dfs_init_radar_detector(phy); 29998686cd2SShayne Chen mt7996_mac_cca_stats_reset(phy); 30098686cd2SShayne Chen 30198686cd2SShayne Chen mt7996_mac_reset_counters(phy); 30298686cd2SShayne Chen phy->noise = 0; 30398686cd2SShayne Chen 30498686cd2SShayne Chen out: 30598686cd2SShayne Chen clear_bit(MT76_RESET, &phy->mt76->state); 30698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 30798686cd2SShayne Chen 30898686cd2SShayne Chen mt76_txq_schedule_all(phy->mt76); 30998686cd2SShayne Chen 31098686cd2SShayne Chen ieee80211_queue_delayed_work(phy->mt76->hw, 31198686cd2SShayne Chen &phy->mt76->mac_work, 31298686cd2SShayne Chen MT7996_WATCHDOG_TIME); 31398686cd2SShayne Chen 31498686cd2SShayne Chen return ret; 31598686cd2SShayne Chen } 31698686cd2SShayne Chen 31798686cd2SShayne Chen static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 31898686cd2SShayne Chen struct ieee80211_vif *vif, struct ieee80211_sta *sta, 31998686cd2SShayne Chen struct ieee80211_key_conf *key) 32098686cd2SShayne Chen { 32198686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 32298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 32398686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 32498686cd2SShayne Chen struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : 32598686cd2SShayne Chen &mvif->sta; 32698686cd2SShayne Chen struct mt76_wcid *wcid = &msta->wcid; 32798686cd2SShayne Chen u8 *wcid_keyidx = &wcid->hw_key_idx; 32898686cd2SShayne Chen int idx = key->keyidx; 32998686cd2SShayne Chen int err = 0; 33098686cd2SShayne Chen 33198686cd2SShayne Chen /* The hardware does not support per-STA RX GTK, fallback 33298686cd2SShayne Chen * to software mode for these. 33398686cd2SShayne Chen */ 33498686cd2SShayne Chen if ((vif->type == NL80211_IFTYPE_ADHOC || 33598686cd2SShayne Chen vif->type == NL80211_IFTYPE_MESH_POINT) && 33698686cd2SShayne Chen (key->cipher == WLAN_CIPHER_SUITE_TKIP || 33798686cd2SShayne Chen key->cipher == WLAN_CIPHER_SUITE_CCMP) && 33898686cd2SShayne Chen !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 33998686cd2SShayne Chen return -EOPNOTSUPP; 34098686cd2SShayne Chen 34198686cd2SShayne Chen /* fall back to sw encryption for unsupported ciphers */ 34298686cd2SShayne Chen switch (key->cipher) { 34398686cd2SShayne Chen case WLAN_CIPHER_SUITE_AES_CMAC: 34498686cd2SShayne Chen wcid_keyidx = &wcid->hw_key_idx2; 34598686cd2SShayne Chen key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; 34698686cd2SShayne Chen break; 34798686cd2SShayne Chen case WLAN_CIPHER_SUITE_TKIP: 34898686cd2SShayne Chen case WLAN_CIPHER_SUITE_CCMP: 34998686cd2SShayne Chen case WLAN_CIPHER_SUITE_CCMP_256: 35098686cd2SShayne Chen case WLAN_CIPHER_SUITE_GCMP: 35198686cd2SShayne Chen case WLAN_CIPHER_SUITE_GCMP_256: 35298686cd2SShayne Chen case WLAN_CIPHER_SUITE_SMS4: 353*eb80e02bSAllen Ye case WLAN_CIPHER_SUITE_BIP_GMAC_128: 354*eb80e02bSAllen Ye case WLAN_CIPHER_SUITE_BIP_GMAC_256: 35598686cd2SShayne Chen break; 35698686cd2SShayne Chen case WLAN_CIPHER_SUITE_WEP40: 35798686cd2SShayne Chen case WLAN_CIPHER_SUITE_WEP104: 35898686cd2SShayne Chen default: 35998686cd2SShayne Chen return -EOPNOTSUPP; 36098686cd2SShayne Chen } 36198686cd2SShayne Chen 36298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 36398686cd2SShayne Chen 36498686cd2SShayne Chen if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) { 36598686cd2SShayne Chen mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); 36698686cd2SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 36798686cd2SShayne Chen } 36898686cd2SShayne Chen 369e6db67faSFelix Fietkau if (cmd == SET_KEY) { 37098686cd2SShayne Chen *wcid_keyidx = idx; 371e6db67faSFelix Fietkau } else { 372e6db67faSFelix Fietkau if (idx == *wcid_keyidx) 37398686cd2SShayne Chen *wcid_keyidx = -1; 37498686cd2SShayne Chen goto out; 375e6db67faSFelix Fietkau } 37698686cd2SShayne Chen 377e6db67faSFelix Fietkau mt76_wcid_key_setup(&dev->mt76, wcid, key); 378*eb80e02bSAllen Ye 379*eb80e02bSAllen Ye if (key->keyidx == 6 || key->keyidx == 7) 380*eb80e02bSAllen Ye err = mt7996_mcu_bcn_prot_enable(dev, vif, key); 381*eb80e02bSAllen Ye else 382*eb80e02bSAllen Ye err = mt7996_mcu_add_key(&dev->mt76, vif, key, 383*eb80e02bSAllen Ye MCU_WMWA_UNI_CMD(STA_REC_UPDATE), 38498686cd2SShayne Chen &msta->wcid, cmd); 38598686cd2SShayne Chen out: 38698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 38798686cd2SShayne Chen 38898686cd2SShayne Chen return err; 38998686cd2SShayne Chen } 39098686cd2SShayne Chen 39198686cd2SShayne Chen static int mt7996_config(struct ieee80211_hw *hw, u32 changed) 39298686cd2SShayne Chen { 39398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 39498686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 39598686cd2SShayne Chen int ret; 39698686cd2SShayne Chen 39798686cd2SShayne Chen if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 39898686cd2SShayne Chen ieee80211_stop_queues(hw); 39998686cd2SShayne Chen ret = mt7996_set_channel(phy); 40098686cd2SShayne Chen if (ret) 40198686cd2SShayne Chen return ret; 40298686cd2SShayne Chen ieee80211_wake_queues(hw); 40398686cd2SShayne Chen } 40498686cd2SShayne Chen 405f75e4779SShayne Chen if (changed & (IEEE80211_CONF_CHANGE_POWER | 406f75e4779SShayne Chen IEEE80211_CONF_CHANGE_CHANNEL)) { 407f75e4779SShayne Chen ret = mt7996_mcu_set_txpower_sku(phy); 408f75e4779SShayne Chen if (ret) 409f75e4779SShayne Chen return ret; 410f75e4779SShayne Chen } 411f75e4779SShayne Chen 41298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 41398686cd2SShayne Chen 41498686cd2SShayne Chen if (changed & IEEE80211_CONF_CHANGE_MONITOR) { 41598686cd2SShayne Chen bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR); 41698686cd2SShayne Chen 41798686cd2SShayne Chen if (!enabled) 41898686cd2SShayne Chen phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; 41998686cd2SShayne Chen else 42098686cd2SShayne Chen phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; 42198686cd2SShayne Chen 42298686cd2SShayne Chen mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), 42398686cd2SShayne Chen MT_DMA_DCR0_RXD_G5_EN, enabled); 42498686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 42598686cd2SShayne Chen } 42698686cd2SShayne Chen 42798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 42898686cd2SShayne Chen 42998686cd2SShayne Chen return 0; 43098686cd2SShayne Chen } 43198686cd2SShayne Chen 43298686cd2SShayne Chen static int 43398686cd2SShayne Chen mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 43498686cd2SShayne Chen unsigned int link_id, u16 queue, 43598686cd2SShayne Chen const struct ieee80211_tx_queue_params *params) 43698686cd2SShayne Chen { 43798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 4389b11696eSPeter Chiu const u8 mq_to_aci[] = { 4399b11696eSPeter Chiu [IEEE80211_AC_VO] = 3, 4409b11696eSPeter Chiu [IEEE80211_AC_VI] = 2, 4419b11696eSPeter Chiu [IEEE80211_AC_BE] = 0, 4429b11696eSPeter Chiu [IEEE80211_AC_BK] = 1, 4439b11696eSPeter Chiu }; 44498686cd2SShayne Chen 4459b11696eSPeter Chiu /* firmware uses access class index */ 4469b11696eSPeter Chiu mvif->queue_params[mq_to_aci[queue]] = *params; 44798686cd2SShayne Chen /* no need to update right away, we'll get BSS_CHANGED_QOS */ 44898686cd2SShayne Chen 44998686cd2SShayne Chen return 0; 45098686cd2SShayne Chen } 45198686cd2SShayne Chen 45298686cd2SShayne Chen static void mt7996_configure_filter(struct ieee80211_hw *hw, 45398686cd2SShayne Chen unsigned int changed_flags, 45498686cd2SShayne Chen unsigned int *total_flags, 45598686cd2SShayne Chen u64 multicast) 45698686cd2SShayne Chen { 45798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 45898686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 45998686cd2SShayne Chen u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | 46098686cd2SShayne Chen MT_WF_RFCR1_DROP_BF_POLL | 46198686cd2SShayne Chen MT_WF_RFCR1_DROP_BA | 46298686cd2SShayne Chen MT_WF_RFCR1_DROP_CFEND | 46398686cd2SShayne Chen MT_WF_RFCR1_DROP_CFACK; 46498686cd2SShayne Chen u32 flags = 0; 46598686cd2SShayne Chen 46698686cd2SShayne Chen #define MT76_FILTER(_flag, _hw) do { \ 46798686cd2SShayne Chen flags |= *total_flags & FIF_##_flag; \ 46898686cd2SShayne Chen phy->rxfilter &= ~(_hw); \ 46998686cd2SShayne Chen phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ 47098686cd2SShayne Chen } while (0) 47198686cd2SShayne Chen 47298686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 47398686cd2SShayne Chen 47498686cd2SShayne Chen phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | 47598686cd2SShayne Chen MT_WF_RFCR_DROP_OTHER_BEACON | 47698686cd2SShayne Chen MT_WF_RFCR_DROP_FRAME_REPORT | 47798686cd2SShayne Chen MT_WF_RFCR_DROP_PROBEREQ | 47898686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST_FILTERED | 47998686cd2SShayne Chen MT_WF_RFCR_DROP_MCAST | 48098686cd2SShayne Chen MT_WF_RFCR_DROP_BCAST | 48198686cd2SShayne Chen MT_WF_RFCR_DROP_DUPLICATE | 48298686cd2SShayne Chen MT_WF_RFCR_DROP_A2_BSSID | 48398686cd2SShayne Chen MT_WF_RFCR_DROP_UNWANTED_CTL | 48498686cd2SShayne Chen MT_WF_RFCR_DROP_STBC_MULTI); 48598686cd2SShayne Chen 48698686cd2SShayne Chen MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | 48798686cd2SShayne Chen MT_WF_RFCR_DROP_A3_MAC | 48898686cd2SShayne Chen MT_WF_RFCR_DROP_A3_BSSID); 48998686cd2SShayne Chen 49098686cd2SShayne Chen MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); 49198686cd2SShayne Chen 49298686cd2SShayne Chen MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | 49398686cd2SShayne Chen MT_WF_RFCR_DROP_RTS | 49498686cd2SShayne Chen MT_WF_RFCR_DROP_CTL_RSV | 49598686cd2SShayne Chen MT_WF_RFCR_DROP_NDPA); 49698686cd2SShayne Chen 49798686cd2SShayne Chen *total_flags = flags; 49898686cd2SShayne Chen mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter); 49998686cd2SShayne Chen 50098686cd2SShayne Chen if (*total_flags & FIF_CONTROL) 50198686cd2SShayne Chen mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 50298686cd2SShayne Chen else 50398686cd2SShayne Chen mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags); 50498686cd2SShayne Chen 50598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 50698686cd2SShayne Chen } 50798686cd2SShayne Chen 50898686cd2SShayne Chen static void 50998686cd2SShayne Chen mt7996_update_bss_color(struct ieee80211_hw *hw, 51098686cd2SShayne Chen struct ieee80211_vif *vif, 51198686cd2SShayne Chen struct cfg80211_he_bss_color *bss_color) 51298686cd2SShayne Chen { 51398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 51498686cd2SShayne Chen 51598686cd2SShayne Chen switch (vif->type) { 51698686cd2SShayne Chen case NL80211_IFTYPE_AP: { 51798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 51898686cd2SShayne Chen 51998686cd2SShayne Chen if (mvif->mt76.omac_idx > HW_BSSID_MAX) 52098686cd2SShayne Chen return; 52198686cd2SShayne Chen fallthrough; 52298686cd2SShayne Chen } 52398686cd2SShayne Chen case NL80211_IFTYPE_STATION: 52498686cd2SShayne Chen mt7996_mcu_update_bss_color(dev, vif, bss_color); 52598686cd2SShayne Chen break; 52698686cd2SShayne Chen default: 52798686cd2SShayne Chen break; 52898686cd2SShayne Chen } 52998686cd2SShayne Chen } 53098686cd2SShayne Chen 53115ee62e7SRyder Lee static u8 532ab0eec4bSRyder Lee mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 533c2171b06SRyder Lee bool beacon, bool mcast) 53415ee62e7SRyder Lee { 5350cb065b9SLorenzo Bianconi struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 53615ee62e7SRyder Lee struct mt76_phy *mphy = hw->priv; 53715ee62e7SRyder Lee u16 rate; 538254ab81fSStanleyYP Wang u8 i, idx; 53915ee62e7SRyder Lee 540c2171b06SRyder Lee rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast); 541c2171b06SRyder Lee 542254ab81fSStanleyYP Wang if (beacon) { 543254ab81fSStanleyYP Wang struct mt7996_phy *phy = mphy->priv; 544c2171b06SRyder Lee 545254ab81fSStanleyYP Wang /* odd index for driver, even index for firmware */ 546254ab81fSStanleyYP Wang idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx; 547254ab81fSStanleyYP Wang if (phy->beacon_rate != rate) 548254ab81fSStanleyYP Wang mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon); 549254ab81fSStanleyYP Wang 550c2171b06SRyder Lee return idx; 551c2171b06SRyder Lee } 55215ee62e7SRyder Lee 55315ee62e7SRyder Lee idx = FIELD_GET(MT_TX_RATE_IDX, rate); 55415ee62e7SRyder Lee for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) 55515ee62e7SRyder Lee if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx) 556254ab81fSStanleyYP Wang return MT7996_BASIC_RATES_TBL + 2 * i; 55715ee62e7SRyder Lee 55815ee62e7SRyder Lee return mvif->basic_rates_idx; 55915ee62e7SRyder Lee } 56015ee62e7SRyder Lee 56168f1c3eaSRyder Lee static void 56268f1c3eaSRyder Lee mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 56368f1c3eaSRyder Lee struct ieee80211_bss_conf *info) 56468f1c3eaSRyder Lee { 56568f1c3eaSRyder Lee struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 56668f1c3eaSRyder Lee struct mt7996_dev *dev = mt7996_hw_dev(hw); 56768f1c3eaSRyder Lee u8 band = mvif->mt76.band_idx; 56868f1c3eaSRyder Lee u32 *mu; 56968f1c3eaSRyder Lee 57068f1c3eaSRyder Lee mu = (u32 *)info->mu_group.membership; 57168f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]); 57268f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]); 57368f1c3eaSRyder Lee 57468f1c3eaSRyder Lee mu = (u32 *)info->mu_group.position; 57568f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]); 57668f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]); 57768f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]); 57868f1c3eaSRyder Lee mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]); 57968f1c3eaSRyder Lee } 58068f1c3eaSRyder Lee 58198686cd2SShayne Chen static void mt7996_bss_info_changed(struct ieee80211_hw *hw, 58298686cd2SShayne Chen struct ieee80211_vif *vif, 58398686cd2SShayne Chen struct ieee80211_bss_conf *info, 58498686cd2SShayne Chen u64 changed) 58598686cd2SShayne Chen { 5860cb065b9SLorenzo Bianconi struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv; 58798686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 58898686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 58998686cd2SShayne Chen 59098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 59198686cd2SShayne Chen 59298686cd2SShayne Chen /* station mode uses BSSID to map the wlan entry to a peer, 59398686cd2SShayne Chen * and then peer references bss_info_rfch to set bandwidth cap. 59498686cd2SShayne Chen */ 59511ca0163SShayne Chen if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) || 59611ca0163SShayne Chen (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) || 59711ca0163SShayne Chen (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) { 59811ca0163SShayne Chen mt7996_mcu_add_bss_info(phy, vif, true); 59911ca0163SShayne Chen mt7996_mcu_add_sta(dev, vif, NULL, true); 60098686cd2SShayne Chen } 60198686cd2SShayne Chen 602d75e739bSRyder Lee if (changed & BSS_CHANGED_ERP_CTS_PROT) 603d75e739bSRyder Lee mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot); 604d75e739bSRyder Lee 60598686cd2SShayne Chen if (changed & BSS_CHANGED_ERP_SLOT) { 60698686cd2SShayne Chen int slottime = info->use_short_slot ? 9 : 20; 60798686cd2SShayne Chen 60898686cd2SShayne Chen if (slottime != phy->slottime) { 60998686cd2SShayne Chen phy->slottime = slottime; 61083a10ae2SPeter Chiu mt7996_mcu_set_timing(phy, vif); 61198686cd2SShayne Chen } 61298686cd2SShayne Chen } 61398686cd2SShayne Chen 614ab0eec4bSRyder Lee if (changed & BSS_CHANGED_MCAST_RATE) 615ab0eec4bSRyder Lee mvif->mcast_rates_idx = 616c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, false, true); 617ab0eec4bSRyder Lee 61815ee62e7SRyder Lee if (changed & BSS_CHANGED_BASIC_RATES) 619ab0eec4bSRyder Lee mvif->basic_rates_idx = 620c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, false, false); 62115ee62e7SRyder Lee 62298686cd2SShayne Chen /* ensure that enable txcmd_mode after bss_info */ 62398686cd2SShayne Chen if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED)) 62498686cd2SShayne Chen mt7996_mcu_set_tx(dev, vif); 62598686cd2SShayne Chen 62698686cd2SShayne Chen if (changed & BSS_CHANGED_HE_OBSS_PD) 627cf6dc2dbSRyder Lee mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd); 62898686cd2SShayne Chen 62998686cd2SShayne Chen if (changed & BSS_CHANGED_HE_BSS_COLOR) 63098686cd2SShayne Chen mt7996_update_bss_color(hw, vif, &info->he_bss_color); 63198686cd2SShayne Chen 63298686cd2SShayne Chen if (changed & (BSS_CHANGED_BEACON | 633c2171b06SRyder Lee BSS_CHANGED_BEACON_ENABLED)) { 634c2171b06SRyder Lee mvif->beacon_rates_idx = 635c2171b06SRyder Lee mt7996_get_rates_table(hw, vif, true, false); 636c2171b06SRyder Lee 63798686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, info->enable_beacon); 638c2171b06SRyder Lee } 63998686cd2SShayne Chen 640de869f81SMeiChia Chiu if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | 641de869f81SMeiChia Chiu BSS_CHANGED_FILS_DISCOVERY)) 64298686cd2SShayne Chen mt7996_mcu_beacon_inband_discov(dev, vif, changed); 64398686cd2SShayne Chen 64468f1c3eaSRyder Lee if (changed & BSS_CHANGED_MU_GROUPS) 64568f1c3eaSRyder Lee mt7996_update_mu_group(hw, vif, info); 64668f1c3eaSRyder Lee 64798686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 64898686cd2SShayne Chen } 64998686cd2SShayne Chen 65098686cd2SShayne Chen static void 65198686cd2SShayne Chen mt7996_channel_switch_beacon(struct ieee80211_hw *hw, 65298686cd2SShayne Chen struct ieee80211_vif *vif, 65398686cd2SShayne Chen struct cfg80211_chan_def *chandef) 65498686cd2SShayne Chen { 65598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 65698686cd2SShayne Chen 65798686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 65898686cd2SShayne Chen mt7996_mcu_add_beacon(hw, vif, true); 65998686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 66098686cd2SShayne Chen } 66198686cd2SShayne Chen 66298686cd2SShayne Chen int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, 66398686cd2SShayne Chen struct ieee80211_sta *sta) 66498686cd2SShayne Chen { 66598686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 66698686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 66798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 66898686cd2SShayne Chen u8 band_idx = mvif->phy->mt76->band_idx; 66998686cd2SShayne Chen int ret, idx; 67098686cd2SShayne Chen 67198686cd2SShayne Chen idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); 67298686cd2SShayne Chen if (idx < 0) 67398686cd2SShayne Chen return -ENOSPC; 67498686cd2SShayne Chen 67598686cd2SShayne Chen INIT_LIST_HEAD(&msta->rc_list); 676e3b0311fSLorenzo Bianconi INIT_LIST_HEAD(&msta->wcid.poll_list); 67798686cd2SShayne Chen msta->vif = mvif; 67898686cd2SShayne Chen msta->wcid.sta = 1; 67998686cd2SShayne Chen msta->wcid.idx = idx; 68098686cd2SShayne Chen msta->wcid.phy_idx = band_idx; 68198686cd2SShayne Chen msta->wcid.tx_info |= MT_WCID_TX_INFO_SET; 68298686cd2SShayne Chen 683ea5d99d0SRyder Lee ewma_avg_signal_init(&msta->avg_ack_signal); 684ea5d99d0SRyder Lee 68598686cd2SShayne Chen mt7996_mac_wtbl_update(dev, idx, 68698686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 68798686cd2SShayne Chen 68898686cd2SShayne Chen ret = mt7996_mcu_add_sta(dev, vif, sta, true); 68998686cd2SShayne Chen if (ret) 69098686cd2SShayne Chen return ret; 69198686cd2SShayne Chen 69298686cd2SShayne Chen return mt7996_mcu_add_rate_ctrl(dev, vif, sta, false); 69398686cd2SShayne Chen } 69498686cd2SShayne Chen 69598686cd2SShayne Chen void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, 69698686cd2SShayne Chen struct ieee80211_sta *sta) 69798686cd2SShayne Chen { 69898686cd2SShayne Chen struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); 69998686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 70098686cd2SShayne Chen int i; 70198686cd2SShayne Chen 70298686cd2SShayne Chen mt7996_mcu_add_sta(dev, vif, sta, false); 70398686cd2SShayne Chen 70498686cd2SShayne Chen mt7996_mac_wtbl_update(dev, msta->wcid.idx, 70598686cd2SShayne Chen MT_WTBL_UPDATE_ADM_COUNT_CLEAR); 70698686cd2SShayne Chen 70798686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) 70898686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, i); 70998686cd2SShayne Chen 710ea0f3867SLorenzo Bianconi spin_lock_bh(&mdev->sta_poll_lock); 711e3b0311fSLorenzo Bianconi if (!list_empty(&msta->wcid.poll_list)) 712e3b0311fSLorenzo Bianconi list_del_init(&msta->wcid.poll_list); 71398686cd2SShayne Chen if (!list_empty(&msta->rc_list)) 71498686cd2SShayne Chen list_del_init(&msta->rc_list); 715ea0f3867SLorenzo Bianconi spin_unlock_bh(&mdev->sta_poll_lock); 71698686cd2SShayne Chen } 71798686cd2SShayne Chen 71898686cd2SShayne Chen static void mt7996_tx(struct ieee80211_hw *hw, 71998686cd2SShayne Chen struct ieee80211_tx_control *control, 72098686cd2SShayne Chen struct sk_buff *skb) 72198686cd2SShayne Chen { 72298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 72398686cd2SShayne Chen struct mt76_phy *mphy = hw->priv; 72498686cd2SShayne Chen struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 72598686cd2SShayne Chen struct ieee80211_vif *vif = info->control.vif; 72698686cd2SShayne Chen struct mt76_wcid *wcid = &dev->mt76.global_wcid; 72798686cd2SShayne Chen 72898686cd2SShayne Chen if (control->sta) { 72998686cd2SShayne Chen struct mt7996_sta *sta; 73098686cd2SShayne Chen 73198686cd2SShayne Chen sta = (struct mt7996_sta *)control->sta->drv_priv; 73298686cd2SShayne Chen wcid = &sta->wcid; 73398686cd2SShayne Chen } 73498686cd2SShayne Chen 73598686cd2SShayne Chen if (vif && !control->sta) { 73698686cd2SShayne Chen struct mt7996_vif *mvif; 73798686cd2SShayne Chen 73898686cd2SShayne Chen mvif = (struct mt7996_vif *)vif->drv_priv; 73998686cd2SShayne Chen wcid = &mvif->sta.wcid; 74098686cd2SShayne Chen } 74198686cd2SShayne Chen 74298686cd2SShayne Chen mt76_tx(mphy, control->sta, wcid, skb); 74398686cd2SShayne Chen } 74498686cd2SShayne Chen 74598686cd2SShayne Chen static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) 74698686cd2SShayne Chen { 74798686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 74898686cd2SShayne Chen int ret; 74998686cd2SShayne Chen 75098686cd2SShayne Chen mutex_lock(&phy->dev->mt76.mutex); 75198686cd2SShayne Chen ret = mt7996_mcu_set_rts_thresh(phy, val); 75298686cd2SShayne Chen mutex_unlock(&phy->dev->mt76.mutex); 75398686cd2SShayne Chen 75498686cd2SShayne Chen return ret; 75598686cd2SShayne Chen } 75698686cd2SShayne Chen 75798686cd2SShayne Chen static int 75898686cd2SShayne Chen mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 75998686cd2SShayne Chen struct ieee80211_ampdu_params *params) 76098686cd2SShayne Chen { 76198686cd2SShayne Chen enum ieee80211_ampdu_mlme_action action = params->action; 76298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 76398686cd2SShayne Chen struct ieee80211_sta *sta = params->sta; 76498686cd2SShayne Chen struct ieee80211_txq *txq = sta->txq[params->tid]; 76598686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 76698686cd2SShayne Chen u16 tid = params->tid; 76798686cd2SShayne Chen u16 ssn = params->ssn; 76898686cd2SShayne Chen struct mt76_txq *mtxq; 76998686cd2SShayne Chen int ret = 0; 77098686cd2SShayne Chen 77198686cd2SShayne Chen if (!txq) 77298686cd2SShayne Chen return -EINVAL; 77398686cd2SShayne Chen 77498686cd2SShayne Chen mtxq = (struct mt76_txq *)txq->drv_priv; 77598686cd2SShayne Chen 77698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 77798686cd2SShayne Chen switch (action) { 77898686cd2SShayne Chen case IEEE80211_AMPDU_RX_START: 77998686cd2SShayne Chen mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, 78098686cd2SShayne Chen params->buf_size); 78198686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, true); 78298686cd2SShayne Chen break; 78398686cd2SShayne Chen case IEEE80211_AMPDU_RX_STOP: 78498686cd2SShayne Chen mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); 78598686cd2SShayne Chen ret = mt7996_mcu_add_rx_ba(dev, params, false); 78698686cd2SShayne Chen break; 78798686cd2SShayne Chen case IEEE80211_AMPDU_TX_OPERATIONAL: 78898686cd2SShayne Chen mtxq->aggr = true; 78998686cd2SShayne Chen mtxq->send_bar = false; 79098686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, true); 79198686cd2SShayne Chen break; 79298686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH: 79398686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 79498686cd2SShayne Chen mtxq->aggr = false; 795ef591d74SLorenzo Bianconi clear_bit(tid, &msta->wcid.ampdu_state); 79698686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 79798686cd2SShayne Chen break; 79898686cd2SShayne Chen case IEEE80211_AMPDU_TX_START: 799ef591d74SLorenzo Bianconi set_bit(tid, &msta->wcid.ampdu_state); 80098686cd2SShayne Chen ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; 80198686cd2SShayne Chen break; 80298686cd2SShayne Chen case IEEE80211_AMPDU_TX_STOP_CONT: 80398686cd2SShayne Chen mtxq->aggr = false; 804ef591d74SLorenzo Bianconi clear_bit(tid, &msta->wcid.ampdu_state); 80598686cd2SShayne Chen ret = mt7996_mcu_add_tx_ba(dev, params, false); 80698686cd2SShayne Chen ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 80798686cd2SShayne Chen break; 80898686cd2SShayne Chen } 80998686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 81098686cd2SShayne Chen 81198686cd2SShayne Chen return ret; 81298686cd2SShayne Chen } 81398686cd2SShayne Chen 81498686cd2SShayne Chen static int 81598686cd2SShayne Chen mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 81698686cd2SShayne Chen struct ieee80211_sta *sta) 81798686cd2SShayne Chen { 81898686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST, 81998686cd2SShayne Chen IEEE80211_STA_NONE); 82098686cd2SShayne Chen } 82198686cd2SShayne Chen 82298686cd2SShayne Chen static int 82398686cd2SShayne Chen mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 82498686cd2SShayne Chen struct ieee80211_sta *sta) 82598686cd2SShayne Chen { 82698686cd2SShayne Chen return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE, 82798686cd2SShayne Chen IEEE80211_STA_NOTEXIST); 82898686cd2SShayne Chen } 82998686cd2SShayne Chen 83098686cd2SShayne Chen static int 83198686cd2SShayne Chen mt7996_get_stats(struct ieee80211_hw *hw, 83298686cd2SShayne Chen struct ieee80211_low_level_stats *stats) 83398686cd2SShayne Chen { 83498686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 83598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 83698214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib; 83798686cd2SShayne Chen 83898686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 83998686cd2SShayne Chen 84098686cd2SShayne Chen stats->dot11RTSSuccessCount = mib->rts_cnt; 84198686cd2SShayne Chen stats->dot11RTSFailureCount = mib->rts_retries_cnt; 84298686cd2SShayne Chen stats->dot11FCSErrorCount = mib->fcs_err_cnt; 84398686cd2SShayne Chen stats->dot11ACKFailureCount = mib->ack_fail_cnt; 84498686cd2SShayne Chen 84598686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 84698686cd2SShayne Chen 84798686cd2SShayne Chen return 0; 84898686cd2SShayne Chen } 84998686cd2SShayne Chen 85098686cd2SShayne Chen u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif) 85198686cd2SShayne Chen { 85298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 85398686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 85498686cd2SShayne Chen union { 85598686cd2SShayne Chen u64 t64; 85698686cd2SShayne Chen u32 t32[2]; 85798686cd2SShayne Chen } tsf; 85898686cd2SShayne Chen u16 n; 85998686cd2SShayne Chen 86098686cd2SShayne Chen lockdep_assert_held(&dev->mt76.mutex); 86198686cd2SShayne Chen 86298686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 86398686cd2SShayne Chen : mvif->mt76.omac_idx; 86498686cd2SShayne Chen /* TSF software read */ 86598686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 86698686cd2SShayne Chen MT_LPON_TCR_SW_READ); 86798686cd2SShayne Chen tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0(phy->mt76->band_idx)); 86898686cd2SShayne Chen tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1(phy->mt76->band_idx)); 86998686cd2SShayne Chen 87098686cd2SShayne Chen return tsf.t64; 87198686cd2SShayne Chen } 87298686cd2SShayne Chen 87398686cd2SShayne Chen static u64 87498686cd2SShayne Chen mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) 87598686cd2SShayne Chen { 87698686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 87798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 87898686cd2SShayne Chen u64 ret; 87998686cd2SShayne Chen 88098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 88198686cd2SShayne Chen ret = __mt7996_get_tsf(hw, mvif); 88298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 88398686cd2SShayne Chen 88498686cd2SShayne Chen return ret; 88598686cd2SShayne Chen } 88698686cd2SShayne Chen 88798686cd2SShayne Chen static void 88898686cd2SShayne Chen mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 88998686cd2SShayne Chen u64 timestamp) 89098686cd2SShayne Chen { 89198686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 89298686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 89398686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 89498686cd2SShayne Chen union { 89598686cd2SShayne Chen u64 t64; 89698686cd2SShayne Chen u32 t32[2]; 89798686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 89898686cd2SShayne Chen u16 n; 89998686cd2SShayne Chen 90098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 90198686cd2SShayne Chen 90298686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 90398686cd2SShayne Chen : mvif->mt76.omac_idx; 90498686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 90598686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 90698686cd2SShayne Chen /* TSF software overwrite */ 90798686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 90898686cd2SShayne Chen MT_LPON_TCR_SW_WRITE); 90998686cd2SShayne Chen 91098686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 91198686cd2SShayne Chen } 91298686cd2SShayne Chen 91398686cd2SShayne Chen static void 91498686cd2SShayne Chen mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 91598686cd2SShayne Chen s64 timestamp) 91698686cd2SShayne Chen { 91798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 91898686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 91998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 92098686cd2SShayne Chen union { 92198686cd2SShayne Chen u64 t64; 92298686cd2SShayne Chen u32 t32[2]; 92398686cd2SShayne Chen } tsf = { .t64 = timestamp, }; 92498686cd2SShayne Chen u16 n; 92598686cd2SShayne Chen 92698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 92798686cd2SShayne Chen 92898686cd2SShayne Chen n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 92998686cd2SShayne Chen : mvif->mt76.omac_idx; 93098686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]); 93198686cd2SShayne Chen mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]); 93298686cd2SShayne Chen /* TSF software adjust*/ 93398686cd2SShayne Chen mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE, 93498686cd2SShayne Chen MT_LPON_TCR_SW_ADJUST); 93598686cd2SShayne Chen 93698686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 93798686cd2SShayne Chen } 93898686cd2SShayne Chen 93998686cd2SShayne Chen static void 94098686cd2SShayne Chen mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) 94198686cd2SShayne Chen { 94298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 94398686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 94498686cd2SShayne Chen 94598686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 94698686cd2SShayne Chen phy->coverage_class = max_t(s16, coverage_class, 0); 94783a10ae2SPeter Chiu mt7996_mac_set_coverage_class(phy); 94898686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 94998686cd2SShayne Chen } 95098686cd2SShayne Chen 95198686cd2SShayne Chen static int 95298686cd2SShayne Chen mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 95398686cd2SShayne Chen { 95498686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 95598686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 95698686cd2SShayne Chen int max_nss = hweight8(hw->wiphy->available_antennas_tx); 95798686cd2SShayne Chen u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx]; 95898686cd2SShayne Chen 95998686cd2SShayne Chen if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) 96098686cd2SShayne Chen return -EINVAL; 96198686cd2SShayne Chen 96298686cd2SShayne Chen if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) 96398686cd2SShayne Chen tx_ant = BIT(ffs(tx_ant) - 1) - 1; 96498686cd2SShayne Chen 96598686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 96698686cd2SShayne Chen 96798686cd2SShayne Chen phy->mt76->antenna_mask = tx_ant; 96898686cd2SShayne Chen 96998686cd2SShayne Chen /* restore to the origin chainmask which might have auxiliary path */ 970eb1fdb9fSShayne Chen if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2) 971eb1fdb9fSShayne Chen phy->mt76->chainmask = ((dev->chainmask >> shift) & 972eb1fdb9fSShayne Chen (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift; 973eb1fdb9fSShayne Chen else if (hweight8(tx_ant) == max_nss) 97498686cd2SShayne Chen phy->mt76->chainmask = (dev->chainmask >> shift) << shift; 97598686cd2SShayne Chen else 97698686cd2SShayne Chen phy->mt76->chainmask = tx_ant << shift; 97798686cd2SShayne Chen 97898686cd2SShayne Chen mt76_set_stream_caps(phy->mt76, true); 97998686cd2SShayne Chen mt7996_set_stream_vht_txbf_caps(phy); 980348533ebSShayne Chen mt7996_set_stream_he_eht_caps(phy); 981f75e4779SShayne Chen mt7996_mcu_set_txpower_sku(phy); 98298686cd2SShayne Chen 98398686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 98498686cd2SShayne Chen 98598686cd2SShayne Chen return 0; 98698686cd2SShayne Chen } 98798686cd2SShayne Chen 98898686cd2SShayne Chen static void mt7996_sta_statistics(struct ieee80211_hw *hw, 98998686cd2SShayne Chen struct ieee80211_vif *vif, 99098686cd2SShayne Chen struct ieee80211_sta *sta, 99198686cd2SShayne Chen struct station_info *sinfo) 99298686cd2SShayne Chen { 993adde3eedSYi-Chia Hsieh struct mt7996_phy *phy = mt7996_hw_phy(hw); 99498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 99598686cd2SShayne Chen struct rate_info *txrate = &msta->wcid.rate; 99698686cd2SShayne Chen 997b34f346bSRyder Lee if (txrate->legacy || txrate->flags) { 99898686cd2SShayne Chen if (txrate->legacy) { 99998686cd2SShayne Chen sinfo->txrate.legacy = txrate->legacy; 100098686cd2SShayne Chen } else { 100198686cd2SShayne Chen sinfo->txrate.mcs = txrate->mcs; 100298686cd2SShayne Chen sinfo->txrate.nss = txrate->nss; 100398686cd2SShayne Chen sinfo->txrate.bw = txrate->bw; 100498686cd2SShayne Chen sinfo->txrate.he_gi = txrate->he_gi; 100598686cd2SShayne Chen sinfo->txrate.he_dcm = txrate->he_dcm; 100698686cd2SShayne Chen sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc; 1007d57e1b25SBenjamin Lin sinfo->txrate.eht_gi = txrate->eht_gi; 100898686cd2SShayne Chen } 100998686cd2SShayne Chen sinfo->txrate.flags = txrate->flags; 101098686cd2SShayne Chen sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 1011b34f346bSRyder Lee } 1012b34f346bSRyder Lee sinfo->txrate.flags = txrate->flags; 1013b34f346bSRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 1014ea5d99d0SRyder Lee 10152461599fSYi-Chia Hsieh sinfo->tx_failed = msta->wcid.stats.tx_failed; 10162461599fSYi-Chia Hsieh sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); 10172461599fSYi-Chia Hsieh 10182461599fSYi-Chia Hsieh sinfo->tx_retries = msta->wcid.stats.tx_retries; 10192461599fSYi-Chia Hsieh sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); 10202461599fSYi-Chia Hsieh 1021ea5d99d0SRyder Lee sinfo->ack_signal = (s8)msta->ack_signal; 1022ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL); 1023ea5d99d0SRyder Lee 1024ea5d99d0SRyder Lee sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal); 1025ea5d99d0SRyder Lee sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG); 1026adde3eedSYi-Chia Hsieh 1027adde3eedSYi-Chia Hsieh if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { 1028adde3eedSYi-Chia Hsieh sinfo->tx_bytes = msta->wcid.stats.tx_bytes; 1029adde3eedSYi-Chia Hsieh sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64); 1030adde3eedSYi-Chia Hsieh 1031adde3eedSYi-Chia Hsieh sinfo->rx_bytes = msta->wcid.stats.rx_bytes; 1032adde3eedSYi-Chia Hsieh sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64); 1033adde3eedSYi-Chia Hsieh 1034adde3eedSYi-Chia Hsieh sinfo->tx_packets = msta->wcid.stats.tx_packets; 1035adde3eedSYi-Chia Hsieh sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS); 1036adde3eedSYi-Chia Hsieh 1037adde3eedSYi-Chia Hsieh sinfo->rx_packets = msta->wcid.stats.rx_packets; 1038adde3eedSYi-Chia Hsieh sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); 1039adde3eedSYi-Chia Hsieh } 104098686cd2SShayne Chen } 104198686cd2SShayne Chen 104298686cd2SShayne Chen static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta) 104398686cd2SShayne Chen { 104498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 104598686cd2SShayne Chen struct mt7996_dev *dev = msta->vif->phy->dev; 104698686cd2SShayne Chen u32 *changed = data; 104798686cd2SShayne Chen 1048ea0f3867SLorenzo Bianconi spin_lock_bh(&dev->mt76.sta_poll_lock); 104998686cd2SShayne Chen msta->changed |= *changed; 105098686cd2SShayne Chen if (list_empty(&msta->rc_list)) 105198686cd2SShayne Chen list_add_tail(&msta->rc_list, &dev->sta_rc_list); 1052ea0f3867SLorenzo Bianconi spin_unlock_bh(&dev->mt76.sta_poll_lock); 105398686cd2SShayne Chen } 105498686cd2SShayne Chen 105598686cd2SShayne Chen static void mt7996_sta_rc_update(struct ieee80211_hw *hw, 105698686cd2SShayne Chen struct ieee80211_vif *vif, 105798686cd2SShayne Chen struct ieee80211_sta *sta, 105898686cd2SShayne Chen u32 changed) 105998686cd2SShayne Chen { 106098686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 106198686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 106298686cd2SShayne Chen 106398686cd2SShayne Chen mt7996_sta_rc_work(&changed, sta); 106498686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 106598686cd2SShayne Chen } 106698686cd2SShayne Chen 106798686cd2SShayne Chen static int 106898686cd2SShayne Chen mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 106998686cd2SShayne Chen const struct cfg80211_bitrate_mask *mask) 107098686cd2SShayne Chen { 107198686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 107298686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 107398686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 107498686cd2SShayne Chen u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED; 107598686cd2SShayne Chen 107698686cd2SShayne Chen mvif->bitrate_mask = *mask; 107798686cd2SShayne Chen 107898686cd2SShayne Chen /* if multiple rates across different preambles are given we can 107998686cd2SShayne Chen * reconfigure this info with all peers using sta_rec command with 108098686cd2SShayne Chen * the below exception cases. 108198686cd2SShayne Chen * - single rate : if a rate is passed along with different preambles, 108298686cd2SShayne Chen * we select the highest one as fixed rate. i.e VHT MCS for VHT peers. 108398686cd2SShayne Chen * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT 108498686cd2SShayne Chen * then multiple MCS setting (MCS 4,5,6) is not supported. 108598686cd2SShayne Chen */ 108698686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_sta_rc_work, &changed); 108798686cd2SShayne Chen ieee80211_queue_work(hw, &dev->rc_work); 108898686cd2SShayne Chen 108998686cd2SShayne Chen return 0; 109098686cd2SShayne Chen } 109198686cd2SShayne Chen 109298686cd2SShayne Chen static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, 109398686cd2SShayne Chen struct ieee80211_vif *vif, 109498686cd2SShayne Chen struct ieee80211_sta *sta, 109598686cd2SShayne Chen bool enabled) 109698686cd2SShayne Chen { 109798686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 109898686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 109998686cd2SShayne Chen 110098686cd2SShayne Chen if (enabled) 110198686cd2SShayne Chen set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 110298686cd2SShayne Chen else 110398686cd2SShayne Chen clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags); 110498686cd2SShayne Chen 110598686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 110698686cd2SShayne Chen } 110798686cd2SShayne Chen 110898686cd2SShayne Chen static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, 110998686cd2SShayne Chen struct ieee80211_vif *vif, 111098686cd2SShayne Chen struct ieee80211_sta *sta, 111198686cd2SShayne Chen bool enabled) 111298686cd2SShayne Chen { 111398686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 111498686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 111598686cd2SShayne Chen 111698686cd2SShayne Chen if (enabled) 111798686cd2SShayne Chen set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 111898686cd2SShayne Chen else 111998686cd2SShayne Chen clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags); 112098686cd2SShayne Chen 112198686cd2SShayne Chen mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta); 112298686cd2SShayne Chen } 112398686cd2SShayne Chen 112498686cd2SShayne Chen static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = { 112598686cd2SShayne Chen "tx_ampdu_cnt", 112698686cd2SShayne Chen "tx_stop_q_empty_cnt", 112798686cd2SShayne Chen "tx_mpdu_attempts", 112898686cd2SShayne Chen "tx_mpdu_success", 112998686cd2SShayne Chen "tx_rwp_fail_cnt", 113098686cd2SShayne Chen "tx_rwp_need_cnt", 113198686cd2SShayne Chen "tx_pkt_ebf_cnt", 113298686cd2SShayne Chen "tx_pkt_ibf_cnt", 113398686cd2SShayne Chen "tx_ampdu_len:0-1", 113498686cd2SShayne Chen "tx_ampdu_len:2-10", 113598686cd2SShayne Chen "tx_ampdu_len:11-19", 113698686cd2SShayne Chen "tx_ampdu_len:20-28", 113798686cd2SShayne Chen "tx_ampdu_len:29-37", 113898686cd2SShayne Chen "tx_ampdu_len:38-46", 113998686cd2SShayne Chen "tx_ampdu_len:47-55", 114098686cd2SShayne Chen "tx_ampdu_len:56-79", 114198686cd2SShayne Chen "tx_ampdu_len:80-103", 114298686cd2SShayne Chen "tx_ampdu_len:104-127", 114398686cd2SShayne Chen "tx_ampdu_len:128-151", 114498686cd2SShayne Chen "tx_ampdu_len:152-175", 114598686cd2SShayne Chen "tx_ampdu_len:176-199", 114698686cd2SShayne Chen "tx_ampdu_len:200-223", 114798686cd2SShayne Chen "tx_ampdu_len:224-247", 114898686cd2SShayne Chen "ba_miss_count", 114998686cd2SShayne Chen "tx_beamformer_ppdu_iBF", 115098686cd2SShayne Chen "tx_beamformer_ppdu_eBF", 115198686cd2SShayne Chen "tx_beamformer_rx_feedback_all", 115298686cd2SShayne Chen "tx_beamformer_rx_feedback_he", 115398686cd2SShayne Chen "tx_beamformer_rx_feedback_vht", 115498686cd2SShayne Chen "tx_beamformer_rx_feedback_ht", 115598686cd2SShayne Chen "tx_beamformer_rx_feedback_bw", /* zero based idx: 20, 40, 80, 160 */ 115698686cd2SShayne Chen "tx_beamformer_rx_feedback_nc", 115798686cd2SShayne Chen "tx_beamformer_rx_feedback_nr", 115898686cd2SShayne Chen "tx_beamformee_ok_feedback_pkts", 115998686cd2SShayne Chen "tx_beamformee_feedback_trig", 116098686cd2SShayne Chen "tx_mu_beamforming", 116198686cd2SShayne Chen "tx_mu_mpdu", 116298686cd2SShayne Chen "tx_mu_successful_mpdu", 116398686cd2SShayne Chen "tx_su_successful_mpdu", 116498686cd2SShayne Chen "tx_msdu_pack_1", 116598686cd2SShayne Chen "tx_msdu_pack_2", 116698686cd2SShayne Chen "tx_msdu_pack_3", 116798686cd2SShayne Chen "tx_msdu_pack_4", 116898686cd2SShayne Chen "tx_msdu_pack_5", 116998686cd2SShayne Chen "tx_msdu_pack_6", 117098686cd2SShayne Chen "tx_msdu_pack_7", 117198686cd2SShayne Chen "tx_msdu_pack_8", 117298686cd2SShayne Chen 117398686cd2SShayne Chen /* rx counters */ 117498686cd2SShayne Chen "rx_fifo_full_cnt", 117598686cd2SShayne Chen "rx_mpdu_cnt", 117698686cd2SShayne Chen "channel_idle_cnt", 117798686cd2SShayne Chen "rx_vector_mismatch_cnt", 117898686cd2SShayne Chen "rx_delimiter_fail_cnt", 117998686cd2SShayne Chen "rx_len_mismatch_cnt", 118098686cd2SShayne Chen "rx_ampdu_cnt", 118198686cd2SShayne Chen "rx_ampdu_bytes_cnt", 118298686cd2SShayne Chen "rx_ampdu_valid_subframe_cnt", 118398686cd2SShayne Chen "rx_ampdu_valid_subframe_b_cnt", 118498686cd2SShayne Chen "rx_pfdrop_cnt", 118598686cd2SShayne Chen "rx_vec_queue_overflow_drop_cnt", 118698686cd2SShayne Chen "rx_ba_cnt", 118798686cd2SShayne Chen 118898686cd2SShayne Chen /* per vif counters */ 118998686cd2SShayne Chen "v_tx_mode_cck", 119098686cd2SShayne Chen "v_tx_mode_ofdm", 119198686cd2SShayne Chen "v_tx_mode_ht", 119298686cd2SShayne Chen "v_tx_mode_ht_gf", 119398686cd2SShayne Chen "v_tx_mode_vht", 119498686cd2SShayne Chen "v_tx_mode_he_su", 119598686cd2SShayne Chen "v_tx_mode_he_ext_su", 119698686cd2SShayne Chen "v_tx_mode_he_tb", 119798686cd2SShayne Chen "v_tx_mode_he_mu", 1198731425f3SShayne Chen "v_tx_mode_eht_su", 1199731425f3SShayne Chen "v_tx_mode_eht_trig", 1200731425f3SShayne Chen "v_tx_mode_eht_mu", 120198686cd2SShayne Chen "v_tx_bw_20", 120298686cd2SShayne Chen "v_tx_bw_40", 120398686cd2SShayne Chen "v_tx_bw_80", 120498686cd2SShayne Chen "v_tx_bw_160", 1205731425f3SShayne Chen "v_tx_bw_320", 120698686cd2SShayne Chen "v_tx_mcs_0", 120798686cd2SShayne Chen "v_tx_mcs_1", 120898686cd2SShayne Chen "v_tx_mcs_2", 120998686cd2SShayne Chen "v_tx_mcs_3", 121098686cd2SShayne Chen "v_tx_mcs_4", 121198686cd2SShayne Chen "v_tx_mcs_5", 121298686cd2SShayne Chen "v_tx_mcs_6", 121398686cd2SShayne Chen "v_tx_mcs_7", 121498686cd2SShayne Chen "v_tx_mcs_8", 121598686cd2SShayne Chen "v_tx_mcs_9", 121698686cd2SShayne Chen "v_tx_mcs_10", 121798686cd2SShayne Chen "v_tx_mcs_11", 1218731425f3SShayne Chen "v_tx_mcs_12", 1219731425f3SShayne Chen "v_tx_mcs_13", 1220749c2c2bSRyder Lee "v_tx_nss_1", 1221749c2c2bSRyder Lee "v_tx_nss_2", 1222749c2c2bSRyder Lee "v_tx_nss_3", 1223749c2c2bSRyder Lee "v_tx_nss_4", 122498686cd2SShayne Chen }; 122598686cd2SShayne Chen 122698686cd2SShayne Chen #define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats) 122798686cd2SShayne Chen 122898686cd2SShayne Chen /* Ethtool related API */ 122998686cd2SShayne Chen static 123098686cd2SShayne Chen void mt7996_get_et_strings(struct ieee80211_hw *hw, 123198686cd2SShayne Chen struct ieee80211_vif *vif, 123298686cd2SShayne Chen u32 sset, u8 *data) 123398686cd2SShayne Chen { 123498686cd2SShayne Chen if (sset == ETH_SS_STATS) 123503f0e11dSDmitry Antipov memcpy(data, mt7996_gstrings_stats, 123698686cd2SShayne Chen sizeof(mt7996_gstrings_stats)); 123798686cd2SShayne Chen } 123898686cd2SShayne Chen 123998686cd2SShayne Chen static 124098686cd2SShayne Chen int mt7996_get_et_sset_count(struct ieee80211_hw *hw, 124198686cd2SShayne Chen struct ieee80211_vif *vif, int sset) 124298686cd2SShayne Chen { 124398686cd2SShayne Chen if (sset == ETH_SS_STATS) 124498686cd2SShayne Chen return MT7996_SSTATS_LEN; 124598686cd2SShayne Chen 124698686cd2SShayne Chen return 0; 124798686cd2SShayne Chen } 124898686cd2SShayne Chen 124998686cd2SShayne Chen static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) 125098686cd2SShayne Chen { 125198686cd2SShayne Chen struct mt76_ethtool_worker_info *wi = wi_data; 125298686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 125398686cd2SShayne Chen 125498686cd2SShayne Chen if (msta->vif->mt76.idx != wi->idx) 125598686cd2SShayne Chen return; 125698686cd2SShayne Chen 1257d82e7c67SLorenzo Bianconi mt76_ethtool_worker(wi, &msta->wcid.stats, true); 125898686cd2SShayne Chen } 125998686cd2SShayne Chen 126098686cd2SShayne Chen static 126198686cd2SShayne Chen void mt7996_get_et_stats(struct ieee80211_hw *hw, 126298686cd2SShayne Chen struct ieee80211_vif *vif, 126398686cd2SShayne Chen struct ethtool_stats *stats, u64 *data) 126498686cd2SShayne Chen { 126598686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 126698686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 126798686cd2SShayne Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 126898214484SLorenzo Bianconi struct mt76_mib_stats *mib = &phy->mib; 126998686cd2SShayne Chen struct mt76_ethtool_worker_info wi = { 127098686cd2SShayne Chen .data = data, 127198686cd2SShayne Chen .idx = mvif->mt76.idx, 127298686cd2SShayne Chen }; 127398686cd2SShayne Chen /* See mt7996_ampdu_stat_read_phy, etc */ 127498686cd2SShayne Chen int i, ei = 0; 127598686cd2SShayne Chen 127698686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 127798686cd2SShayne Chen 127898686cd2SShayne Chen mt7996_mac_update_stats(phy); 127998686cd2SShayne Chen 128098686cd2SShayne Chen data[ei++] = mib->tx_ampdu_cnt; 128198686cd2SShayne Chen data[ei++] = mib->tx_stop_q_empty_cnt; 128298686cd2SShayne Chen data[ei++] = mib->tx_mpdu_attempts_cnt; 128398686cd2SShayne Chen data[ei++] = mib->tx_mpdu_success_cnt; 128498686cd2SShayne Chen data[ei++] = mib->tx_rwp_fail_cnt; 128598686cd2SShayne Chen data[ei++] = mib->tx_rwp_need_cnt; 128698686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 128798686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 128898686cd2SShayne Chen 128998686cd2SShayne Chen /* Tx ampdu stat */ 129098686cd2SShayne Chen for (i = 0; i < 15 /*ARRAY_SIZE(bound)*/; i++) 129198686cd2SShayne Chen data[ei++] = phy->mt76->aggr_stats[i]; 129298686cd2SShayne Chen data[ei++] = phy->mib.ba_miss_cnt; 129398686cd2SShayne Chen 129498686cd2SShayne Chen /* Tx Beamformer monitor */ 129598686cd2SShayne Chen data[ei++] = mib->tx_bf_ibf_ppdu_cnt; 129698686cd2SShayne Chen data[ei++] = mib->tx_bf_ebf_ppdu_cnt; 129798686cd2SShayne Chen 129898686cd2SShayne Chen /* Tx Beamformer Rx feedback monitor */ 129998686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_all_cnt; 130098686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_he_cnt; 130198686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_vht_cnt; 130298686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_ht_cnt; 130398686cd2SShayne Chen 130498686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_bw; 130598686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nc_cnt; 130698686cd2SShayne Chen data[ei++] = mib->tx_bf_rx_fb_nr_cnt; 130798686cd2SShayne Chen 130898686cd2SShayne Chen /* Tx Beamformee Rx NDPA & Tx feedback report */ 130998686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_cpl_cnt; 131098686cd2SShayne Chen data[ei++] = mib->tx_bf_fb_trig_cnt; 131198686cd2SShayne Chen 131298686cd2SShayne Chen /* Tx SU & MU counters */ 131398686cd2SShayne Chen data[ei++] = mib->tx_mu_bf_cnt; 131498686cd2SShayne Chen data[ei++] = mib->tx_mu_mpdu_cnt; 131598686cd2SShayne Chen data[ei++] = mib->tx_mu_acked_mpdu_cnt; 131698686cd2SShayne Chen data[ei++] = mib->tx_su_acked_mpdu_cnt; 131798686cd2SShayne Chen 131898686cd2SShayne Chen /* Tx amsdu info (pack-count histogram) */ 131998686cd2SShayne Chen for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) 132098686cd2SShayne Chen data[ei++] = mib->tx_amsdu[i]; 132198686cd2SShayne Chen 132298686cd2SShayne Chen /* rx counters */ 132398686cd2SShayne Chen data[ei++] = mib->rx_fifo_full_cnt; 132498686cd2SShayne Chen data[ei++] = mib->rx_mpdu_cnt; 132598686cd2SShayne Chen data[ei++] = mib->channel_idle_cnt; 132698686cd2SShayne Chen data[ei++] = mib->rx_vector_mismatch_cnt; 132798686cd2SShayne Chen data[ei++] = mib->rx_delimiter_fail_cnt; 132898686cd2SShayne Chen data[ei++] = mib->rx_len_mismatch_cnt; 132998686cd2SShayne Chen data[ei++] = mib->rx_ampdu_cnt; 133098686cd2SShayne Chen data[ei++] = mib->rx_ampdu_bytes_cnt; 133198686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_cnt; 133298686cd2SShayne Chen data[ei++] = mib->rx_ampdu_valid_subframe_bytes_cnt; 133398686cd2SShayne Chen data[ei++] = mib->rx_pfdrop_cnt; 133498686cd2SShayne Chen data[ei++] = mib->rx_vec_queue_overflow_drop_cnt; 133598686cd2SShayne Chen data[ei++] = mib->rx_ba_cnt; 133698686cd2SShayne Chen 133798686cd2SShayne Chen /* Add values for all stations owned by this vif */ 133898686cd2SShayne Chen wi.initial_stat_idx = ei; 133998686cd2SShayne Chen ieee80211_iterate_stations_atomic(hw, mt7996_ethtool_worker, &wi); 134098686cd2SShayne Chen 134198686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 134298686cd2SShayne Chen 134398686cd2SShayne Chen if (wi.sta_count == 0) 134498686cd2SShayne Chen return; 134598686cd2SShayne Chen 134698686cd2SShayne Chen ei += wi.worker_stat_count; 134798686cd2SShayne Chen if (ei != MT7996_SSTATS_LEN) 134898686cd2SShayne Chen dev_err(dev->mt76.dev, "ei: %d MT7996_SSTATS_LEN: %d", 134998686cd2SShayne Chen ei, (int)MT7996_SSTATS_LEN); 135098686cd2SShayne Chen } 135198686cd2SShayne Chen 135298686cd2SShayne Chen static void 135398686cd2SShayne Chen mt7996_twt_teardown_request(struct ieee80211_hw *hw, 135498686cd2SShayne Chen struct ieee80211_sta *sta, 135598686cd2SShayne Chen u8 flowid) 135698686cd2SShayne Chen { 135798686cd2SShayne Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 135898686cd2SShayne Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 135998686cd2SShayne Chen 136098686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 136198686cd2SShayne Chen mt7996_mac_twt_teardown_flow(dev, msta, flowid); 136298686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 136398686cd2SShayne Chen } 136498686cd2SShayne Chen 136598686cd2SShayne Chen static int 136698686cd2SShayne Chen mt7996_set_radar_background(struct ieee80211_hw *hw, 136798686cd2SShayne Chen struct cfg80211_chan_def *chandef) 136898686cd2SShayne Chen { 136998686cd2SShayne Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 137098686cd2SShayne Chen struct mt7996_dev *dev = phy->dev; 137198686cd2SShayne Chen int ret = -EINVAL; 137298686cd2SShayne Chen bool running; 137398686cd2SShayne Chen 137498686cd2SShayne Chen mutex_lock(&dev->mt76.mutex); 137598686cd2SShayne Chen 137698686cd2SShayne Chen if (dev->mt76.region == NL80211_DFS_UNSET) 137798686cd2SShayne Chen goto out; 137898686cd2SShayne Chen 137998686cd2SShayne Chen if (dev->rdd2_phy && dev->rdd2_phy != phy) { 138098686cd2SShayne Chen /* rdd2 is already locked */ 138198686cd2SShayne Chen ret = -EBUSY; 138298686cd2SShayne Chen goto out; 138398686cd2SShayne Chen } 138498686cd2SShayne Chen 138598686cd2SShayne Chen /* rdd2 already configured on a radar channel */ 138698686cd2SShayne Chen running = dev->rdd2_phy && 138798686cd2SShayne Chen cfg80211_chandef_valid(&dev->rdd2_chandef) && 138898686cd2SShayne Chen !!(dev->rdd2_chandef.chan->flags & IEEE80211_CHAN_RADAR); 138998686cd2SShayne Chen 139098686cd2SShayne Chen if (!chandef || running || 139198686cd2SShayne Chen !(chandef->chan->flags & IEEE80211_CHAN_RADAR)) { 139298686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, NULL); 139398686cd2SShayne Chen if (ret) 139498686cd2SShayne Chen goto out; 139598686cd2SShayne Chen 139698686cd2SShayne Chen if (!running) 139798686cd2SShayne Chen goto update_phy; 139898686cd2SShayne Chen } 139998686cd2SShayne Chen 140098686cd2SShayne Chen ret = mt7996_mcu_rdd_background_enable(phy, chandef); 140198686cd2SShayne Chen if (ret) 140298686cd2SShayne Chen goto out; 140398686cd2SShayne Chen 140498686cd2SShayne Chen update_phy: 140598686cd2SShayne Chen dev->rdd2_phy = chandef ? phy : NULL; 140698686cd2SShayne Chen if (chandef) 140798686cd2SShayne Chen dev->rdd2_chandef = *chandef; 140898686cd2SShayne Chen out: 140998686cd2SShayne Chen mutex_unlock(&dev->mt76.mutex); 141098686cd2SShayne Chen 141198686cd2SShayne Chen return ret; 141298686cd2SShayne Chen } 141398686cd2SShayne Chen 141483eafc92SSujuan Chen #ifdef CONFIG_NET_MEDIATEK_SOC_WED 141583eafc92SSujuan Chen static int 141683eafc92SSujuan Chen mt7996_net_fill_forward_path(struct ieee80211_hw *hw, 141783eafc92SSujuan Chen struct ieee80211_vif *vif, 141883eafc92SSujuan Chen struct ieee80211_sta *sta, 141983eafc92SSujuan Chen struct net_device_path_ctx *ctx, 142083eafc92SSujuan Chen struct net_device_path *path) 142183eafc92SSujuan Chen { 142283eafc92SSujuan Chen struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; 142383eafc92SSujuan Chen struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; 142483eafc92SSujuan Chen struct mt7996_dev *dev = mt7996_hw_dev(hw); 142583eafc92SSujuan Chen struct mt7996_phy *phy = mt7996_hw_phy(hw); 142683eafc92SSujuan Chen struct mtk_wed_device *wed = &dev->mt76.mmio.wed; 142783eafc92SSujuan Chen 142883eafc92SSujuan Chen if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) 142983eafc92SSujuan Chen wed = &dev->mt76.mmio.wed_hif2; 143083eafc92SSujuan Chen 143183eafc92SSujuan Chen if (!mtk_wed_device_active(wed)) 143283eafc92SSujuan Chen return -ENODEV; 143383eafc92SSujuan Chen 143483eafc92SSujuan Chen if (msta->wcid.idx > MT7996_WTBL_STA) 143583eafc92SSujuan Chen return -EIO; 143683eafc92SSujuan Chen 143783eafc92SSujuan Chen path->type = DEV_PATH_MTK_WDMA; 143883eafc92SSujuan Chen path->dev = ctx->dev; 143983eafc92SSujuan Chen path->mtk_wdma.wdma_idx = wed->wdma_idx; 144083eafc92SSujuan Chen path->mtk_wdma.bss = mvif->mt76.idx; 144183eafc92SSujuan Chen path->mtk_wdma.queue = 0; 144283eafc92SSujuan Chen path->mtk_wdma.wcid = msta->wcid.idx; 144383eafc92SSujuan Chen 144483eafc92SSujuan Chen path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); 144583eafc92SSujuan Chen ctx->dev = NULL; 144683eafc92SSujuan Chen 144783eafc92SSujuan Chen return 0; 144883eafc92SSujuan Chen } 144983eafc92SSujuan Chen 145083eafc92SSujuan Chen #endif 145183eafc92SSujuan Chen 145298686cd2SShayne Chen const struct ieee80211_ops mt7996_ops = { 145398686cd2SShayne Chen .tx = mt7996_tx, 145498686cd2SShayne Chen .start = mt7996_start, 145598686cd2SShayne Chen .stop = mt7996_stop, 145698686cd2SShayne Chen .add_interface = mt7996_add_interface, 145798686cd2SShayne Chen .remove_interface = mt7996_remove_interface, 145898686cd2SShayne Chen .config = mt7996_config, 145998686cd2SShayne Chen .conf_tx = mt7996_conf_tx, 146098686cd2SShayne Chen .configure_filter = mt7996_configure_filter, 146198686cd2SShayne Chen .bss_info_changed = mt7996_bss_info_changed, 146298686cd2SShayne Chen .sta_add = mt7996_sta_add, 146398686cd2SShayne Chen .sta_remove = mt7996_sta_remove, 146498686cd2SShayne Chen .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, 146598686cd2SShayne Chen .sta_rc_update = mt7996_sta_rc_update, 146698686cd2SShayne Chen .set_key = mt7996_set_key, 146798686cd2SShayne Chen .ampdu_action = mt7996_ampdu_action, 146898686cd2SShayne Chen .set_rts_threshold = mt7996_set_rts_threshold, 146998686cd2SShayne Chen .wake_tx_queue = mt76_wake_tx_queue, 147098686cd2SShayne Chen .sw_scan_start = mt76_sw_scan, 147198686cd2SShayne Chen .sw_scan_complete = mt76_sw_scan_complete, 147298686cd2SShayne Chen .release_buffered_frames = mt76_release_buffered_frames, 147398686cd2SShayne Chen .get_txpower = mt76_get_txpower, 147498686cd2SShayne Chen .channel_switch_beacon = mt7996_channel_switch_beacon, 147598686cd2SShayne Chen .get_stats = mt7996_get_stats, 147698686cd2SShayne Chen .get_et_sset_count = mt7996_get_et_sset_count, 147798686cd2SShayne Chen .get_et_stats = mt7996_get_et_stats, 147898686cd2SShayne Chen .get_et_strings = mt7996_get_et_strings, 147998686cd2SShayne Chen .get_tsf = mt7996_get_tsf, 148098686cd2SShayne Chen .set_tsf = mt7996_set_tsf, 148198686cd2SShayne Chen .offset_tsf = mt7996_offset_tsf, 148298686cd2SShayne Chen .get_survey = mt76_get_survey, 148398686cd2SShayne Chen .get_antenna = mt76_get_antenna, 148498686cd2SShayne Chen .set_antenna = mt7996_set_antenna, 148598686cd2SShayne Chen .set_bitrate_mask = mt7996_set_bitrate_mask, 148698686cd2SShayne Chen .set_coverage_class = mt7996_set_coverage_class, 148798686cd2SShayne Chen .sta_statistics = mt7996_sta_statistics, 148898686cd2SShayne Chen .sta_set_4addr = mt7996_sta_set_4addr, 148998686cd2SShayne Chen .sta_set_decap_offload = mt7996_sta_set_decap_offload, 149098686cd2SShayne Chen .add_twt_setup = mt7996_mac_add_twt_setup, 149198686cd2SShayne Chen .twt_teardown_request = mt7996_twt_teardown_request, 149298686cd2SShayne Chen #ifdef CONFIG_MAC80211_DEBUGFS 149398686cd2SShayne Chen .sta_add_debugfs = mt7996_sta_add_debugfs, 149498686cd2SShayne Chen #endif 149598686cd2SShayne Chen .set_radar_background = mt7996_set_radar_background, 149683eafc92SSujuan Chen #ifdef CONFIG_NET_MEDIATEK_SOC_WED 149783eafc92SSujuan Chen .net_fill_forward_path = mt7996_net_fill_forward_path, 149883eafc92SSujuan Chen .net_setup_tc = mt76_net_setup_tc, 149983eafc92SSujuan Chen #endif 150098686cd2SShayne Chen }; 1501