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 = &params->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