162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 262306a36Sopenharmony_ci/* Copyright(c) 2019-2020 Realtek Corporation 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include "cam.h" 662306a36Sopenharmony_ci#include "chan.h" 762306a36Sopenharmony_ci#include "coex.h" 862306a36Sopenharmony_ci#include "debug.h" 962306a36Sopenharmony_ci#include "fw.h" 1062306a36Sopenharmony_ci#include "mac.h" 1162306a36Sopenharmony_ci#include "phy.h" 1262306a36Sopenharmony_ci#include "ps.h" 1362306a36Sopenharmony_ci#include "reg.h" 1462306a36Sopenharmony_ci#include "sar.h" 1562306a36Sopenharmony_ci#include "ser.h" 1662306a36Sopenharmony_ci#include "util.h" 1762306a36Sopenharmony_ci#include "wow.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic void rtw89_ops_tx(struct ieee80211_hw *hw, 2062306a36Sopenharmony_ci struct ieee80211_tx_control *control, 2162306a36Sopenharmony_ci struct sk_buff *skb) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 2462306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 2562306a36Sopenharmony_ci struct ieee80211_vif *vif = info->control.vif; 2662306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 2762306a36Sopenharmony_ci struct ieee80211_sta *sta = control->sta; 2862306a36Sopenharmony_ci u32 flags = IEEE80211_SKB_CB(skb)->flags; 2962306a36Sopenharmony_ci int ret, qsel; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (rtwvif->offchan && !(flags & IEEE80211_TX_CTL_TX_OFFCHAN) && sta) { 3262306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_TXRX, "ops_tx during offchan\n"); 3562306a36Sopenharmony_ci skb_queue_tail(&rtwsta->roc_queue, skb); 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel); 4062306a36Sopenharmony_ci if (ret) { 4162306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to transmit skb: %d\n", ret); 4262306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 4362306a36Sopenharmony_ci return; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci rtw89_core_tx_kick_off(rtwdev, qsel); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void rtw89_ops_wake_tx_queue(struct ieee80211_hw *hw, 4962306a36Sopenharmony_ci struct ieee80211_txq *txq) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ieee80211_schedule_txq(hw, txq); 5462306a36Sopenharmony_ci queue_work(rtwdev->txq_wq, &rtwdev->txq_work); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int rtw89_ops_start(struct ieee80211_hw *hw) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 6062306a36Sopenharmony_ci int ret; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 6362306a36Sopenharmony_ci ret = rtw89_core_start(rtwdev); 6462306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return ret; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void rtw89_ops_stop(struct ieee80211_hw *hw) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 7462306a36Sopenharmony_ci rtw89_core_stop(rtwdev); 7562306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* let previous ips work finish to ensure we don't leave ips twice */ 8362306a36Sopenharmony_ci cancel_work_sync(&rtwdev->ips_work); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 8662306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if ((changed & IEEE80211_CONF_CHANGE_IDLE) && 8962306a36Sopenharmony_ci !(hw->conf.flags & IEEE80211_CONF_IDLE)) 9062306a36Sopenharmony_ci rtw89_leave_ips(rtwdev); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { 9362306a36Sopenharmony_ci rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0, 9462306a36Sopenharmony_ci &hw->conf.chandef); 9562306a36Sopenharmony_ci rtw89_set_channel(rtwdev); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if ((changed & IEEE80211_CONF_CHANGE_IDLE) && 9962306a36Sopenharmony_ci (hw->conf.flags & IEEE80211_CONF_IDLE) && 10062306a36Sopenharmony_ci !rtwdev->scanning) 10162306a36Sopenharmony_ci rtw89_enter_ips(rtwdev); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int rtw89_ops_add_interface(struct ieee80211_hw *hw, 10962306a36Sopenharmony_ci struct ieee80211_vif *vif) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 11262306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 11362306a36Sopenharmony_ci int ret = 0; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_STATE, "add vif %pM type %d, p2p %d\n", 11662306a36Sopenharmony_ci vif->addr, vif->type, vif->p2p); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci rtw89_leave_ips_by_hwflags(rtwdev); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) 12362306a36Sopenharmony_ci vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | 12462306a36Sopenharmony_ci IEEE80211_VIF_SUPPORTS_CQM_RSSI; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci rtwvif->rtwdev = rtwdev; 12762306a36Sopenharmony_ci rtwvif->roc.state = RTW89_ROC_IDLE; 12862306a36Sopenharmony_ci rtwvif->offchan = false; 12962306a36Sopenharmony_ci list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); 13062306a36Sopenharmony_ci INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); 13162306a36Sopenharmony_ci INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work); 13262306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); 13562306a36Sopenharmony_ci rtw89_vif_type_mapping(vif, false); 13662306a36Sopenharmony_ci rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port, 13762306a36Sopenharmony_ci RTW89_PORT_NUM); 13862306a36Sopenharmony_ci if (rtwvif->port == RTW89_PORT_NUM) { 13962306a36Sopenharmony_ci ret = -ENOSPC; 14062306a36Sopenharmony_ci list_del_init(&rtwvif->list); 14162306a36Sopenharmony_ci goto out; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci rtwvif->bcn_hit_cond = 0; 14562306a36Sopenharmony_ci rtwvif->mac_idx = RTW89_MAC_0; 14662306a36Sopenharmony_ci rtwvif->phy_idx = RTW89_PHY_0; 14762306a36Sopenharmony_ci rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; 14862306a36Sopenharmony_ci rtwvif->hit_rule = 0; 14962306a36Sopenharmony_ci rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; 15062306a36Sopenharmony_ci ether_addr_copy(rtwvif->mac_addr, vif->addr); 15162306a36Sopenharmony_ci INIT_LIST_HEAD(&rtwvif->general_pkt_list); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci ret = rtw89_mac_add_vif(rtwdev, rtwvif); 15462306a36Sopenharmony_ci if (ret) { 15562306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); 15662306a36Sopenharmony_ci list_del_init(&rtwvif->list); 15762306a36Sopenharmony_ci goto out; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci rtw89_core_txq_init(rtwdev, vif->txq); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci rtw89_recalc_lps(rtwdev); 16562306a36Sopenharmony_ciout: 16662306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return ret; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void rtw89_ops_remove_interface(struct ieee80211_hw *hw, 17262306a36Sopenharmony_ci struct ieee80211_vif *vif) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 17562306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_STATE, "remove vif %pM type %d p2p %d\n", 17862306a36Sopenharmony_ci vif->addr, vif->type, vif->p2p); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci cancel_work_sync(&rtwvif->update_beacon_work); 18162306a36Sopenharmony_ci cancel_delayed_work_sync(&rtwvif->roc.roc_work); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 18462306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 18562306a36Sopenharmony_ci rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); 18662306a36Sopenharmony_ci rtw89_mac_remove_vif(rtwdev, rtwvif); 18762306a36Sopenharmony_ci rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); 18862306a36Sopenharmony_ci list_del_init(&rtwvif->list); 18962306a36Sopenharmony_ci rtw89_recalc_lps(rtwdev); 19062306a36Sopenharmony_ci rtw89_enter_ips_by_hwflags(rtwdev); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int rtw89_ops_change_interface(struct ieee80211_hw *hw, 19662306a36Sopenharmony_ci struct ieee80211_vif *vif, 19762306a36Sopenharmony_ci enum nl80211_iftype type, bool p2p) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 20062306a36Sopenharmony_ci int ret; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci set_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rtw89_debug(rtwdev, RTW89_DBG_STATE, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", 20562306a36Sopenharmony_ci vif->addr, vif->type, type, vif->p2p, p2p); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci rtw89_ops_remove_interface(hw, vif); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci vif->type = type; 21062306a36Sopenharmony_ci vif->p2p = p2p; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ret = rtw89_ops_add_interface(hw, vif); 21362306a36Sopenharmony_ci if (ret) 21462306a36Sopenharmony_ci rtw89_warn(rtwdev, "failed to change interface %d\n", ret); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci clear_bit(RTW89_FLAG_CHANGING_INTERFACE, rtwdev->flags); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return ret; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void rtw89_ops_configure_filter(struct ieee80211_hw *hw, 22262306a36Sopenharmony_ci unsigned int changed_flags, 22362306a36Sopenharmony_ci unsigned int *new_flags, 22462306a36Sopenharmony_ci u64 multicast) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 22762306a36Sopenharmony_ci const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 23062306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | 23362306a36Sopenharmony_ci FIF_BCN_PRBRESP_PROMISC | FIF_PROBE_REQ; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (changed_flags & FIF_ALLMULTI) { 23662306a36Sopenharmony_ci if (*new_flags & FIF_ALLMULTI) 23762306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_MC; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_MC; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci if (changed_flags & FIF_FCSFAIL) { 24262306a36Sopenharmony_ci if (*new_flags & FIF_FCSFAIL) 24362306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_CRC32_ERR; 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_CRC32_ERR; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci if (changed_flags & FIF_OTHER_BSS) { 24862306a36Sopenharmony_ci if (*new_flags & FIF_OTHER_BSS) 24962306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; 25062306a36Sopenharmony_ci else 25162306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { 25462306a36Sopenharmony_ci if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { 25562306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_BCN_CHK_EN; 25662306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_BC; 25762306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; 25862306a36Sopenharmony_ci } else { 25962306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_BCN_CHK_EN; 26062306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_BC; 26162306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci if (changed_flags & FIF_PROBE_REQ) { 26562306a36Sopenharmony_ci if (*new_flags & FIF_PROBE_REQ) { 26662306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_BC_CAM_MATCH; 26762306a36Sopenharmony_ci rtwdev->hal.rx_fltr &= ~B_AX_A_UC_CAM_MATCH; 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_BC_CAM_MATCH; 27062306a36Sopenharmony_ci rtwdev->hal.rx_fltr |= B_AX_A_UC_CAM_MATCH; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, 27562306a36Sopenharmony_ci rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0), 27662306a36Sopenharmony_ci B_AX_RX_FLTR_CFG_MASK, 27762306a36Sopenharmony_ci rtwdev->hal.rx_fltr); 27862306a36Sopenharmony_ci if (!rtwdev->dbcc_en) 27962306a36Sopenharmony_ci goto out; 28062306a36Sopenharmony_ci rtw89_write32_mask(rtwdev, 28162306a36Sopenharmony_ci rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1), 28262306a36Sopenharmony_ci B_AX_RX_FLTR_CFG_MASK, 28362306a36Sopenharmony_ci rtwdev->hal.rx_fltr); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciout: 28662306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { 29062306a36Sopenharmony_ci [IEEE80211_AC_VO] = 3, 29162306a36Sopenharmony_ci [IEEE80211_AC_VI] = 2, 29262306a36Sopenharmony_ci [IEEE80211_AC_BE] = 0, 29362306a36Sopenharmony_ci [IEEE80211_AC_BK] = 1, 29462306a36Sopenharmony_ci}; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev, 29762306a36Sopenharmony_ci struct rtw89_vif *rtwvif, u8 aifsn) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); 30062306a36Sopenharmony_ci const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, 30162306a36Sopenharmony_ci rtwvif->sub_entity_idx); 30262306a36Sopenharmony_ci u8 slot_time; 30362306a36Sopenharmony_ci u8 sifs; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci slot_time = vif->bss_conf.use_short_slot ? 9 : 20; 30662306a36Sopenharmony_ci sifs = chan->band_type == RTW89_BAND_5G ? 16 : 10; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return aifsn * slot_time + sifs; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, 31262306a36Sopenharmony_ci struct rtw89_vif *rtwvif, u16 ac) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; 31562306a36Sopenharmony_ci u32 val; 31662306a36Sopenharmony_ci u8 ecw_max, ecw_min; 31762306a36Sopenharmony_ci u8 aifs; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ 32062306a36Sopenharmony_ci ecw_max = ilog2(params->cw_max + 1); 32162306a36Sopenharmony_ci ecw_min = ilog2(params->cw_min + 1); 32262306a36Sopenharmony_ci aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); 32362306a36Sopenharmony_ci val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) | 32462306a36Sopenharmony_ci FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) | 32562306a36Sopenharmony_ci FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) | 32662306a36Sopenharmony_ci FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs); 32762306a36Sopenharmony_ci rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac_to_fw_idx[ac], val); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS] = { 33162306a36Sopenharmony_ci [IEEE80211_AC_VO] = R_AX_MUEDCA_VO_PARAM_0, 33262306a36Sopenharmony_ci [IEEE80211_AC_VI] = R_AX_MUEDCA_VI_PARAM_0, 33362306a36Sopenharmony_ci [IEEE80211_AC_BE] = R_AX_MUEDCA_BE_PARAM_0, 33462306a36Sopenharmony_ci [IEEE80211_AC_BK] = R_AX_MUEDCA_BK_PARAM_0, 33562306a36Sopenharmony_ci}; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, 33862306a36Sopenharmony_ci struct rtw89_vif *rtwvif, u16 ac) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; 34162306a36Sopenharmony_ci struct ieee80211_he_mu_edca_param_ac_rec *mu_edca; 34262306a36Sopenharmony_ci u8 aifs, aifsn; 34362306a36Sopenharmony_ci u16 timer_32us; 34462306a36Sopenharmony_ci u32 reg; 34562306a36Sopenharmony_ci u32 val; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (!params->mu_edca) 34862306a36Sopenharmony_ci return; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci mu_edca = ¶ms->mu_edca_param_rec; 35162306a36Sopenharmony_ci aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn); 35262306a36Sopenharmony_ci aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0; 35362306a36Sopenharmony_ci timer_32us = mu_edca->mu_edca_timer << 8; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) | 35662306a36Sopenharmony_ci FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) | 35762306a36Sopenharmony_ci FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); 35862306a36Sopenharmony_ci reg = rtw89_mac_reg_by_idx(rtwdev, ac_to_mu_edca_param[ac], rtwvif->mac_idx); 35962306a36Sopenharmony_ci rtw89_write32(rtwdev, reg, val); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void __rtw89_conf_tx(struct rtw89_dev *rtwdev, 36562306a36Sopenharmony_ci struct rtw89_vif *rtwvif, u16 ac) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac); 36862306a36Sopenharmony_ci ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void rtw89_conf_tx(struct rtw89_dev *rtwdev, 37262306a36Sopenharmony_ci struct rtw89_vif *rtwvif) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci u16 ac; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) 37762306a36Sopenharmony_ci __rtw89_conf_tx(rtwdev, rtwvif, ac); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, 38162306a36Sopenharmony_ci struct ieee80211_vif *vif, 38262306a36Sopenharmony_ci struct ieee80211_bss_conf *conf) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct ieee80211_sta *sta; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_STATION) 38762306a36Sopenharmony_ci return; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci sta = ieee80211_find_sta(vif, conf->bssid); 39062306a36Sopenharmony_ci if (!sta) { 39162306a36Sopenharmony_ci rtw89_err(rtwdev, "can't find sta to set sta_assoc state\n"); 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci rtw89_vif_type_mapping(vif, true); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci rtw89_core_sta_assoc(rtwdev, vif, sta); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, 40162306a36Sopenharmony_ci struct ieee80211_vif *vif, 40262306a36Sopenharmony_ci struct ieee80211_bss_conf *conf, 40362306a36Sopenharmony_ci u64 changed) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 40662306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 40962306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (changed & BSS_CHANGED_ASSOC) { 41262306a36Sopenharmony_ci if (vif->cfg.assoc) { 41362306a36Sopenharmony_ci rtw89_station_mode_sta_assoc(rtwdev, vif, conf); 41462306a36Sopenharmony_ci rtw89_phy_set_bss_color(rtwdev, vif); 41562306a36Sopenharmony_ci rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); 41662306a36Sopenharmony_ci rtw89_mac_port_update(rtwdev, rtwvif); 41762306a36Sopenharmony_ci rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci rtw89_queue_chanctx_work(rtwdev); 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci /* Abort ongoing scan if cancel_scan isn't issued 42262306a36Sopenharmony_ci * when disconnected by peer 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci if (rtwdev->scanning) 42562306a36Sopenharmony_ci rtw89_hw_scan_abort(rtwdev, vif); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (changed & BSS_CHANGED_BSSID) { 43062306a36Sopenharmony_ci ether_addr_copy(rtwvif->bssid, conf->bssid); 43162306a36Sopenharmony_ci rtw89_cam_bssid_changed(rtwdev, rtwvif); 43262306a36Sopenharmony_ci rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (changed & BSS_CHANGED_BEACON) 43662306a36Sopenharmony_ci rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (changed & BSS_CHANGED_ERP_SLOT) 43962306a36Sopenharmony_ci rtw89_conf_tx(rtwdev, rtwvif); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (changed & BSS_CHANGED_HE_BSS_COLOR) 44262306a36Sopenharmony_ci rtw89_phy_set_bss_color(rtwdev, vif); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (changed & BSS_CHANGED_MU_GROUPS) 44562306a36Sopenharmony_ci rtw89_mac_bf_set_gid_table(rtwdev, vif, conf); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (changed & BSS_CHANGED_P2P_PS) 44862306a36Sopenharmony_ci rtw89_process_p2p_ps(rtwdev, vif); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (changed & BSS_CHANGED_CQM) 45162306a36Sopenharmony_ci rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (changed & BSS_CHANGED_PS) 45462306a36Sopenharmony_ci rtw89_recalc_lps(rtwdev); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int rtw89_ops_start_ap(struct ieee80211_hw *hw, 46062306a36Sopenharmony_ci struct ieee80211_vif *vif, 46162306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 46462306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 46562306a36Sopenharmony_ci const struct rtw89_chan *chan; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); 47062306a36Sopenharmony_ci if (chan->band_type == RTW89_BAND_6G) { 47162306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 47262306a36Sopenharmony_ci return -EOPNOTSUPP; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (rtwdev->scanning) 47662306a36Sopenharmony_ci rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); 47962306a36Sopenharmony_ci rtw89_cam_bssid_changed(rtwdev, rtwvif); 48062306a36Sopenharmony_ci rtw89_mac_port_update(rtwdev, rtwvif); 48162306a36Sopenharmony_ci rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); 48262306a36Sopenharmony_ci rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); 48362306a36Sopenharmony_ci rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); 48462306a36Sopenharmony_ci rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); 48562306a36Sopenharmony_ci rtw89_chip_rfk_channel(rtwdev); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci rtw89_queue_chanctx_work(rtwdev); 48862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return 0; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic 49462306a36Sopenharmony_civoid rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 49562306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 49862306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 50162306a36Sopenharmony_ci rtw89_mac_stop_ap(rtwdev, rtwvif); 50262306a36Sopenharmony_ci rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); 50362306a36Sopenharmony_ci rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); 50462306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 50862306a36Sopenharmony_ci bool set) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 51162306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 51262306a36Sopenharmony_ci struct rtw89_vif *rtwvif = rtwsta->rtwvif; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci ieee80211_queue_work(rtwdev->hw, &rtwvif->update_beacon_work); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int rtw89_ops_conf_tx(struct ieee80211_hw *hw, 52062306a36Sopenharmony_ci struct ieee80211_vif *vif, 52162306a36Sopenharmony_ci unsigned int link_id, u16 ac, 52262306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 52562306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 52862306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 52962306a36Sopenharmony_ci rtwvif->tx_params[ac] = *params; 53062306a36Sopenharmony_ci __rtw89_conf_tx(rtwdev, rtwvif, ac); 53162306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return 0; 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int __rtw89_ops_sta_state(struct ieee80211_hw *hw, 53762306a36Sopenharmony_ci struct ieee80211_vif *vif, 53862306a36Sopenharmony_ci struct ieee80211_sta *sta, 53962306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 54062306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NOTEXIST && 54562306a36Sopenharmony_ci new_state == IEEE80211_STA_NONE) 54662306a36Sopenharmony_ci return rtw89_core_sta_add(rtwdev, vif, sta); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (old_state == IEEE80211_STA_AUTH && 54962306a36Sopenharmony_ci new_state == IEEE80211_STA_ASSOC) { 55062306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) 55162306a36Sopenharmony_ci return 0; /* defer to bss_info_changed to have vif info */ 55262306a36Sopenharmony_ci return rtw89_core_sta_assoc(rtwdev, vif, sta); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (old_state == IEEE80211_STA_ASSOC && 55662306a36Sopenharmony_ci new_state == IEEE80211_STA_AUTH) 55762306a36Sopenharmony_ci return rtw89_core_sta_disassoc(rtwdev, vif, sta); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (old_state == IEEE80211_STA_AUTH && 56062306a36Sopenharmony_ci new_state == IEEE80211_STA_NONE) 56162306a36Sopenharmony_ci return rtw89_core_sta_disconnect(rtwdev, vif, sta); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (old_state == IEEE80211_STA_NONE && 56462306a36Sopenharmony_ci new_state == IEEE80211_STA_NOTEXIST) 56562306a36Sopenharmony_ci return rtw89_core_sta_remove(rtwdev, vif, sta); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int rtw89_ops_sta_state(struct ieee80211_hw *hw, 57162306a36Sopenharmony_ci struct ieee80211_vif *vif, 57262306a36Sopenharmony_ci struct ieee80211_sta *sta, 57362306a36Sopenharmony_ci enum ieee80211_sta_state old_state, 57462306a36Sopenharmony_ci enum ieee80211_sta_state new_state) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 57762306a36Sopenharmony_ci int ret; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 58062306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 58162306a36Sopenharmony_ci ret = __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state); 58262306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return ret; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 58862306a36Sopenharmony_ci struct ieee80211_vif *vif, 58962306a36Sopenharmony_ci struct ieee80211_sta *sta, 59062306a36Sopenharmony_ci struct ieee80211_key_conf *key) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 59362306a36Sopenharmony_ci int ret = 0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 59662306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci switch (cmd) { 59962306a36Sopenharmony_ci case SET_KEY: 60062306a36Sopenharmony_ci rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL_END); 60162306a36Sopenharmony_ci ret = rtw89_cam_sec_key_add(rtwdev, vif, sta, key); 60262306a36Sopenharmony_ci if (ret && ret != -EOPNOTSUPP) { 60362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to add key to sec cam\n"); 60462306a36Sopenharmony_ci goto out; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci case DISABLE_KEY: 60862306a36Sopenharmony_ci rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, 60962306a36Sopenharmony_ci false); 61062306a36Sopenharmony_ci rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, false); 61162306a36Sopenharmony_ci ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key, true); 61262306a36Sopenharmony_ci if (ret) { 61362306a36Sopenharmony_ci rtw89_err(rtwdev, "failed to remove key from sec cam\n"); 61462306a36Sopenharmony_ci goto out; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci break; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ciout: 62062306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return ret; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, 62662306a36Sopenharmony_ci struct ieee80211_vif *vif, 62762306a36Sopenharmony_ci struct ieee80211_ampdu_params *params) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 63062306a36Sopenharmony_ci struct ieee80211_sta *sta = params->sta; 63162306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 63262306a36Sopenharmony_ci u16 tid = params->tid; 63362306a36Sopenharmony_ci struct ieee80211_txq *txq = sta->txq[tid]; 63462306a36Sopenharmony_ci struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci switch (params->action) { 63762306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_START: 63862306a36Sopenharmony_ci return IEEE80211_AMPDU_TX_START_IMMEDIATE; 63962306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_CONT: 64062306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH: 64162306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 64262306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 64362306a36Sopenharmony_ci clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); 64462306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 64562306a36Sopenharmony_ci ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci case IEEE80211_AMPDU_TX_OPERATIONAL: 64862306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 64962306a36Sopenharmony_ci set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); 65062306a36Sopenharmony_ci rtwsta->ampdu_params[tid].agg_num = params->buf_size; 65162306a36Sopenharmony_ci rtwsta->ampdu_params[tid].amsdu = params->amsdu; 65262306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 65362306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_START: 65662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 65762306a36Sopenharmony_ci rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, true, params); 65862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case IEEE80211_AMPDU_RX_STOP: 66162306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 66262306a36Sopenharmony_ci rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, false, params); 66362306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci default: 66662306a36Sopenharmony_ci WARN_ON(1); 66762306a36Sopenharmony_ci return -ENOTSUPP; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 67862306a36Sopenharmony_ci rtw89_leave_ps_mode(rtwdev); 67962306a36Sopenharmony_ci if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) 68062306a36Sopenharmony_ci rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); 68162306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic void rtw89_ops_sta_statistics(struct ieee80211_hw *hw, 68762306a36Sopenharmony_ci struct ieee80211_vif *vif, 68862306a36Sopenharmony_ci struct ieee80211_sta *sta, 68962306a36Sopenharmony_ci struct station_info *sinfo) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci sinfo->txrate = rtwsta->ra_report.txrate; 69462306a36Sopenharmony_ci sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic 69862306a36Sopenharmony_civoid __rtw89_drop_packets(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct rtw89_vif *rtwvif; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (vif) { 70362306a36Sopenharmony_ci rtwvif = (struct rtw89_vif *)vif->drv_priv; 70462306a36Sopenharmony_ci rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); 70562306a36Sopenharmony_ci } else { 70662306a36Sopenharmony_ci rtw89_for_each_rtwvif(rtwdev, rtwvif) 70762306a36Sopenharmony_ci rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 71262306a36Sopenharmony_ci u32 queues, bool drop) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 71762306a36Sopenharmony_ci rtw89_leave_lps(rtwdev); 71862306a36Sopenharmony_ci rtw89_hci_flush_queues(rtwdev, queues, drop); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (drop && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw)) 72162306a36Sopenharmony_ci __rtw89_drop_packets(rtwdev, vif); 72262306a36Sopenharmony_ci else 72362306a36Sopenharmony_ci rtw89_mac_flush_txq(rtwdev, queues, drop); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistruct rtw89_iter_bitrate_mask_data { 72962306a36Sopenharmony_ci struct rtw89_dev *rtwdev; 73062306a36Sopenharmony_ci struct ieee80211_vif *vif; 73162306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask; 73262306a36Sopenharmony_ci}; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci struct rtw89_iter_bitrate_mask_data *br_data = data; 73762306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 73862306a36Sopenharmony_ci struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (vif != br_data->vif || vif->p2p) 74162306a36Sopenharmony_ci return; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci rtwsta->use_cfg_mask = true; 74462306a36Sopenharmony_ci rtwsta->mask = *br_data->mask; 74562306a36Sopenharmony_ci rtw89_phy_ra_updata_sta(br_data->rtwdev, sta, IEEE80211_RC_SUPP_RATES_CHANGED); 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic void rtw89_ra_mask_info_update(struct rtw89_dev *rtwdev, 74962306a36Sopenharmony_ci struct ieee80211_vif *vif, 75062306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct rtw89_iter_bitrate_mask_data br_data = { .rtwdev = rtwdev, 75362306a36Sopenharmony_ci .vif = vif, 75462306a36Sopenharmony_ci .mask = mask}; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_ra_mask_info_update_iter, 75762306a36Sopenharmony_ci &br_data); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw, 76162306a36Sopenharmony_ci struct ieee80211_vif *vif, 76262306a36Sopenharmony_ci const struct cfg80211_bitrate_mask *mask) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 76762306a36Sopenharmony_ci rtw89_phy_rate_pattern_vif(rtwdev, vif, mask); 76862306a36Sopenharmony_ci rtw89_ra_mask_info_update(rtwdev, vif, mask); 76962306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic 77562306a36Sopenharmony_ciint rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 77862306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (hal->ant_diversity) { 78162306a36Sopenharmony_ci if (tx_ant != rx_ant || hweight32(tx_ant) != 1) 78262306a36Sopenharmony_ci return -EINVAL; 78362306a36Sopenharmony_ci } else if (rx_ant != hw->wiphy->available_antennas_rx && rx_ant != hal->antenna_rx) { 78462306a36Sopenharmony_ci return -EINVAL; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 78862306a36Sopenharmony_ci hal->antenna_tx = tx_ant; 78962306a36Sopenharmony_ci hal->antenna_rx = rx_ant; 79062306a36Sopenharmony_ci hal->tx_path_diversity = false; 79162306a36Sopenharmony_ci hal->ant_diversity_fixed = true; 79262306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic 79862306a36Sopenharmony_ciint rtw89_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 80162306a36Sopenharmony_ci struct rtw89_hal *hal = &rtwdev->hal; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci *tx_ant = hal->antenna_tx; 80462306a36Sopenharmony_ci *rx_ant = hal->antenna_rx; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, 81062306a36Sopenharmony_ci struct ieee80211_vif *vif, 81162306a36Sopenharmony_ci const u8 *mac_addr) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 81462306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 81762306a36Sopenharmony_ci rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, false); 81862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, 82262306a36Sopenharmony_ci struct ieee80211_vif *vif) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 82762306a36Sopenharmony_ci rtw89_core_scan_complete(rtwdev, vif, false); 82862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, 83262306a36Sopenharmony_ci enum ieee80211_reconfig_type reconfig_type) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) 83762306a36Sopenharmony_ci rtw89_ser_recfg_done(rtwdev); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 84162306a36Sopenharmony_ci struct ieee80211_scan_request *req) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 84462306a36Sopenharmony_ci struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 84562306a36Sopenharmony_ci int ret = 0; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) 84862306a36Sopenharmony_ci return 1; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (rtwdev->scanning || rtwvif->offchan) 85162306a36Sopenharmony_ci return -EBUSY; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 85462306a36Sopenharmony_ci rtw89_hw_scan_start(rtwdev, vif, req); 85562306a36Sopenharmony_ci ret = rtw89_hw_scan_offload(rtwdev, vif, true); 85662306a36Sopenharmony_ci if (ret) { 85762306a36Sopenharmony_ci rtw89_hw_scan_abort(rtwdev, vif); 85862306a36Sopenharmony_ci rtw89_err(rtwdev, "HW scan failed with status: %d\n", ret); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return ret; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, 86662306a36Sopenharmony_ci struct ieee80211_vif *vif) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) 87162306a36Sopenharmony_ci return; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (!rtwdev->scanning) 87462306a36Sopenharmony_ci return; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 87762306a36Sopenharmony_ci rtw89_hw_scan_abort(rtwdev, vif); 87862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw, 88262306a36Sopenharmony_ci struct ieee80211_vif *vif, 88362306a36Sopenharmony_ci struct ieee80211_sta *sta, u32 changed) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci rtw89_phy_ra_updata_sta(rtwdev, sta, changed); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic int rtw89_ops_add_chanctx(struct ieee80211_hw *hw, 89162306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 89462306a36Sopenharmony_ci int ret; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 89762306a36Sopenharmony_ci ret = rtw89_chanctx_ops_add(rtwdev, ctx); 89862306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return ret; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic void rtw89_ops_remove_chanctx(struct ieee80211_hw *hw, 90462306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 90962306a36Sopenharmony_ci rtw89_chanctx_ops_remove(rtwdev, ctx); 91062306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic void rtw89_ops_change_chanctx(struct ieee80211_hw *hw, 91462306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx, 91562306a36Sopenharmony_ci u32 changed) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 92062306a36Sopenharmony_ci rtw89_chanctx_ops_change(rtwdev, ctx, changed); 92162306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw, 92562306a36Sopenharmony_ci struct ieee80211_vif *vif, 92662306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 92762306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 93062306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 93162306a36Sopenharmony_ci int ret; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 93462306a36Sopenharmony_ci ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif, ctx); 93562306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return ret; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, 94162306a36Sopenharmony_ci struct ieee80211_vif *vif, 94262306a36Sopenharmony_ci struct ieee80211_bss_conf *link_conf, 94362306a36Sopenharmony_ci struct ieee80211_chanctx_conf *ctx) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 94662306a36Sopenharmony_ci struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 94962306a36Sopenharmony_ci rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif, ctx); 95062306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, 95462306a36Sopenharmony_ci struct ieee80211_vif *vif, 95562306a36Sopenharmony_ci struct ieee80211_channel *chan, 95662306a36Sopenharmony_ci int duration, 95762306a36Sopenharmony_ci enum ieee80211_roc_type type) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 96062306a36Sopenharmony_ci struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 96162306a36Sopenharmony_ci struct rtw89_roc *roc = &rtwvif->roc; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (!vif) 96462306a36Sopenharmony_ci return -EINVAL; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (roc->state != RTW89_ROC_IDLE) { 96962306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 97062306a36Sopenharmony_ci return -EBUSY; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (rtwdev->scanning) 97462306a36Sopenharmony_ci rtw89_hw_scan_abort(rtwdev, vif); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (type == IEEE80211_ROC_TYPE_MGMT_TX) 97762306a36Sopenharmony_ci roc->state = RTW89_ROC_MGMT; 97862306a36Sopenharmony_ci else 97962306a36Sopenharmony_ci roc->state = RTW89_ROC_NORMAL; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci roc->duration = duration; 98262306a36Sopenharmony_ci roc->chan = *chan; 98362306a36Sopenharmony_ci roc->type = type; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci rtw89_roc_start(rtwdev, rtwvif); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci return 0; 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw, 99362306a36Sopenharmony_ci struct ieee80211_vif *vif) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 99662306a36Sopenharmony_ci struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (!rtwvif) 99962306a36Sopenharmony_ci return -EINVAL; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci cancel_delayed_work_sync(&rtwvif->roc.roc_work); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 100462306a36Sopenharmony_ci rtw89_roc_end(rtwdev, rtwvif); 100562306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci return 0; 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic void rtw89_set_tid_config_iter(void *data, struct ieee80211_sta *sta) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci struct cfg80211_tid_config *tid_config = data; 101362306a36Sopenharmony_ci struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; 101462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = rtwsta->rtwvif->rtwdev; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci rtw89_core_set_tid_config(rtwdev, sta, tid_config); 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic int rtw89_ops_set_tid_config(struct ieee80211_hw *hw, 102062306a36Sopenharmony_ci struct ieee80211_vif *vif, 102162306a36Sopenharmony_ci struct ieee80211_sta *sta, 102262306a36Sopenharmony_ci struct cfg80211_tid_config *tid_config) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 102762306a36Sopenharmony_ci if (sta) 102862306a36Sopenharmony_ci rtw89_core_set_tid_config(rtwdev, sta, tid_config); 102962306a36Sopenharmony_ci else 103062306a36Sopenharmony_ci ieee80211_iterate_stations_atomic(rtwdev->hw, 103162306a36Sopenharmony_ci rtw89_set_tid_config_iter, 103262306a36Sopenharmony_ci tid_config); 103362306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci return 0; 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci#ifdef CONFIG_PM 103962306a36Sopenharmony_cistatic int rtw89_ops_suspend(struct ieee80211_hw *hw, 104062306a36Sopenharmony_ci struct cfg80211_wowlan *wowlan) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 104362306a36Sopenharmony_ci int ret; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 104662306a36Sopenharmony_ci cancel_delayed_work_sync(&rtwdev->track_work); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 104962306a36Sopenharmony_ci ret = rtw89_wow_suspend(rtwdev, wowlan); 105062306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (ret) { 105362306a36Sopenharmony_ci rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); 105462306a36Sopenharmony_ci clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 105562306a36Sopenharmony_ci return 1; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int rtw89_ops_resume(struct ieee80211_hw *hw) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 106462306a36Sopenharmony_ci int ret; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci mutex_lock(&rtwdev->mutex); 106762306a36Sopenharmony_ci ret = rtw89_wow_resume(rtwdev); 106862306a36Sopenharmony_ci if (ret) 106962306a36Sopenharmony_ci rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); 107062306a36Sopenharmony_ci mutex_unlock(&rtwdev->mutex); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); 107362306a36Sopenharmony_ci ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work, 107462306a36Sopenharmony_ci RTW89_TRACK_WORK_PERIOD); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return ret ? 1 : 0; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic void rtw89_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct rtw89_dev *rtwdev = hw->priv; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci device_set_wakeup_enable(rtwdev->dev, enabled); 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci#endif 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ciconst struct ieee80211_ops rtw89_ops = { 108862306a36Sopenharmony_ci .tx = rtw89_ops_tx, 108962306a36Sopenharmony_ci .wake_tx_queue = rtw89_ops_wake_tx_queue, 109062306a36Sopenharmony_ci .start = rtw89_ops_start, 109162306a36Sopenharmony_ci .stop = rtw89_ops_stop, 109262306a36Sopenharmony_ci .config = rtw89_ops_config, 109362306a36Sopenharmony_ci .add_interface = rtw89_ops_add_interface, 109462306a36Sopenharmony_ci .change_interface = rtw89_ops_change_interface, 109562306a36Sopenharmony_ci .remove_interface = rtw89_ops_remove_interface, 109662306a36Sopenharmony_ci .configure_filter = rtw89_ops_configure_filter, 109762306a36Sopenharmony_ci .bss_info_changed = rtw89_ops_bss_info_changed, 109862306a36Sopenharmony_ci .start_ap = rtw89_ops_start_ap, 109962306a36Sopenharmony_ci .stop_ap = rtw89_ops_stop_ap, 110062306a36Sopenharmony_ci .set_tim = rtw89_ops_set_tim, 110162306a36Sopenharmony_ci .conf_tx = rtw89_ops_conf_tx, 110262306a36Sopenharmony_ci .sta_state = rtw89_ops_sta_state, 110362306a36Sopenharmony_ci .set_key = rtw89_ops_set_key, 110462306a36Sopenharmony_ci .ampdu_action = rtw89_ops_ampdu_action, 110562306a36Sopenharmony_ci .set_rts_threshold = rtw89_ops_set_rts_threshold, 110662306a36Sopenharmony_ci .sta_statistics = rtw89_ops_sta_statistics, 110762306a36Sopenharmony_ci .flush = rtw89_ops_flush, 110862306a36Sopenharmony_ci .set_bitrate_mask = rtw89_ops_set_bitrate_mask, 110962306a36Sopenharmony_ci .set_antenna = rtw89_ops_set_antenna, 111062306a36Sopenharmony_ci .get_antenna = rtw89_ops_get_antenna, 111162306a36Sopenharmony_ci .sw_scan_start = rtw89_ops_sw_scan_start, 111262306a36Sopenharmony_ci .sw_scan_complete = rtw89_ops_sw_scan_complete, 111362306a36Sopenharmony_ci .reconfig_complete = rtw89_ops_reconfig_complete, 111462306a36Sopenharmony_ci .hw_scan = rtw89_ops_hw_scan, 111562306a36Sopenharmony_ci .cancel_hw_scan = rtw89_ops_cancel_hw_scan, 111662306a36Sopenharmony_ci .add_chanctx = rtw89_ops_add_chanctx, 111762306a36Sopenharmony_ci .remove_chanctx = rtw89_ops_remove_chanctx, 111862306a36Sopenharmony_ci .change_chanctx = rtw89_ops_change_chanctx, 111962306a36Sopenharmony_ci .assign_vif_chanctx = rtw89_ops_assign_vif_chanctx, 112062306a36Sopenharmony_ci .unassign_vif_chanctx = rtw89_ops_unassign_vif_chanctx, 112162306a36Sopenharmony_ci .remain_on_channel = rtw89_ops_remain_on_channel, 112262306a36Sopenharmony_ci .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, 112362306a36Sopenharmony_ci .set_sar_specs = rtw89_ops_set_sar_specs, 112462306a36Sopenharmony_ci .sta_rc_update = rtw89_ops_sta_rc_update, 112562306a36Sopenharmony_ci .set_tid_config = rtw89_ops_set_tid_config, 112662306a36Sopenharmony_ci#ifdef CONFIG_PM 112762306a36Sopenharmony_ci .suspend = rtw89_ops_suspend, 112862306a36Sopenharmony_ci .resume = rtw89_ops_resume, 112962306a36Sopenharmony_ci .set_wakeup = rtw89_ops_set_wakeup, 113062306a36Sopenharmony_ci#endif 113162306a36Sopenharmony_ci}; 113262306a36Sopenharmony_ciEXPORT_SYMBOL(rtw89_ops); 1133