Search Linux Wireless

Re: [PATCH 03/24] rtw89: add core and trx files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jun 18, 2021 at 02:46:04PM +0800, Ping-Ke Shih wrote:
> Implement main flows that contains register/unregister mac80211 hw with
> hardware capability, power on/off sequence, STA state actions, and
> TX/RX path.
> 
> The chip info is read from efuse while probing PCI, and then it can be
> used to induce supported channel, band, bitrate, ht/vht/he capability,
> and etc. Then, we register hardware with these capabilities.
> 
> When network interface is up, driver does power-on sequence to enable MAC,
> BB and RF function blocks. Oppositely, do power-off sequence when
> interface is going to down.
> 
> To maintain STA state, five callbacks are implemented -- add, assoc,
> disassoc, disconnect and remove. In which state, driver tells firmware STA
> info via H2C.
> 
> TX flow:
> When a SKB is going to be transmitted, we must know its type first. If
> the type is mgmt or fwcmd made by driver, SKB is queued into corresponding
> DMA channel and PCI ring. The other type is data frame that is more
> complex, because it needs to establish BA session to have better throughput
> with AMPDU and AMSDU.
> In order to have better PCI DMA efficiency, we don't kick off DMA every
> SKB. With wake TX queue, kick off DMA after a bunch of SKBs are written.
> To achieve this, we have two HCI ops -- tx_write and tx_kick_off.
> 
> BA establishment work:
> For data frames, we start to establish BA session if the STA is associated
> with APMDU capability and the TID session isn't established, and then the
> BA work is used to ask mac80211 to start AMPDU actions. Driver implements
> AMPDU action callbacks to know the session is established, so that we can
> set AGG_EN bit in TX descriptor to enable AMPDU.
> 
> RX flow:
> When a RX SKB is delivered from PCI, rtw89_core_rx() process it depneds on
> its type -- WIFI, C2H or PPDU. If type is C2H, it's queued into a C2H
> queue, and wake a work to handle the C2H packet. If type is WIFI, it's a
> normal RX packet. When mgmt or data frame is received, it is queued
> into pending RX SKB queue to wait for corresponding PPDU packet (another
> RX packet with PPDU type) to fill its rx_status, like RSSI. And, then
> indicate this packet to mac80211. When control frame is received, indicate
> it to mac80211 immediately.
> 
> Track work:
> Use track work to monitor PHY status to know the changes of environment,
> and then update RA status or do RFK accordingly.
> 
> Signed-off-by: Ping-Ke Shih <pkshih@xxxxxxxxxxx>
> ---
>  drivers/net/wireless/realtek/rtw89/core.c | 2359 +++++++++++++++
>  drivers/net/wireless/realtek/rtw89/core.h | 3336 +++++++++++++++++++++
>  drivers/net/wireless/realtek/rtw89/txrx.h |  393 +++
>  drivers/net/wireless/realtek/rtw89/util.c |   37 +
>  drivers/net/wireless/realtek/rtw89/util.h |   31 +
>  5 files changed, 6156 insertions(+)
>  create mode 100644 drivers/net/wireless/realtek/rtw89/core.c
>  create mode 100644 drivers/net/wireless/realtek/rtw89/core.h
>  create mode 100644 drivers/net/wireless/realtek/rtw89/txrx.h
>  create mode 100644 drivers/net/wireless/realtek/rtw89/util.c
>  create mode 100644 drivers/net/wireless/realtek/rtw89/util.h
> 
> diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
> new file mode 100644
> index 000000000000..3bd31e669aea
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw89/core.c
> @@ -0,0 +1,2359 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/* Copyright(c) 2019-2020  Realtek Corporation
> + */
> +
> +#include "coex.h"
> +#include "core.h"
> +#include "efuse.h"
> +#include "fw.h"
> +#include "mac.h"
> +#include "phy.h"
> +#include "ps.h"
> +#include "reg.h"
> +#include "sar.h"
> +#include "ser.h"
> +#include "txrx.h"
> +#include "util.h"
> +
> +static bool rtw89_disable_ps_mode;
> +module_param_named(disable_ps_mode, rtw89_disable_ps_mode, bool, 0644);
> +MODULE_PARM_DESC(disable_ps_mode, "Set Y to disable low power mode");
> +
> +static struct ieee80211_channel rtw89_channels_2ghz[] = {
> +	{ .center_freq = 2412, .hw_value = 1, },
> +	{ .center_freq = 2417, .hw_value = 2, },
> +	{ .center_freq = 2422, .hw_value = 3, },
> +	{ .center_freq = 2427, .hw_value = 4, },
> +	{ .center_freq = 2432, .hw_value = 5, },
> +	{ .center_freq = 2437, .hw_value = 6, },
> +	{ .center_freq = 2442, .hw_value = 7, },
> +	{ .center_freq = 2447, .hw_value = 8, },
> +	{ .center_freq = 2452, .hw_value = 9, },
> +	{ .center_freq = 2457, .hw_value = 10, },
> +	{ .center_freq = 2462, .hw_value = 11, },
> +	{ .center_freq = 2467, .hw_value = 12, },
> +	{ .center_freq = 2472, .hw_value = 13, },
> +	{ .center_freq = 2484, .hw_value = 14, },
> +};
> +
> +static struct ieee80211_channel rtw89_channels_5ghz[] = {
> +	{.center_freq = 5180, .hw_value = 36,},
> +	{.center_freq = 5200, .hw_value = 40,},
> +	{.center_freq = 5220, .hw_value = 44,},
> +	{.center_freq = 5240, .hw_value = 48,},
> +	{.center_freq = 5260, .hw_value = 52,},
> +	{.center_freq = 5280, .hw_value = 56,},
> +	{.center_freq = 5300, .hw_value = 60,},
> +	{.center_freq = 5320, .hw_value = 64,},
> +	{.center_freq = 5500, .hw_value = 100,},
> +	{.center_freq = 5520, .hw_value = 104,},
> +	{.center_freq = 5540, .hw_value = 108,},
> +	{.center_freq = 5560, .hw_value = 112,},
> +	{.center_freq = 5580, .hw_value = 116,},
> +	{.center_freq = 5600, .hw_value = 120,},
> +	{.center_freq = 5620, .hw_value = 124,},
> +	{.center_freq = 5640, .hw_value = 128,},
> +	{.center_freq = 5660, .hw_value = 132,},
> +	{.center_freq = 5680, .hw_value = 136,},
> +	{.center_freq = 5700, .hw_value = 140,},
> +	{.center_freq = 5720, .hw_value = 144,},
> +	{.center_freq = 5745, .hw_value = 149,},
> +	{.center_freq = 5765, .hw_value = 153,},
> +	{.center_freq = 5785, .hw_value = 157,},
> +	{.center_freq = 5805, .hw_value = 161,},
> +	{.center_freq = 5825, .hw_value = 165,
> +	 .flags = IEEE80211_CHAN_NO_HT40MINUS},
> +};
> +
> +static struct ieee80211_rate rtw89_bitrates[] = {
> +	{ .bitrate = 10,  .hw_value = 0x00, },
> +	{ .bitrate = 20,  .hw_value = 0x01, },
> +	{ .bitrate = 55,  .hw_value = 0x02, },
> +	{ .bitrate = 110, .hw_value = 0x03, },
> +	{ .bitrate = 60,  .hw_value = 0x04, },
> +	{ .bitrate = 90,  .hw_value = 0x05, },
> +	{ .bitrate = 120, .hw_value = 0x06, },
> +	{ .bitrate = 180, .hw_value = 0x07, },
> +	{ .bitrate = 240, .hw_value = 0x08, },
> +	{ .bitrate = 360, .hw_value = 0x09, },
> +	{ .bitrate = 480, .hw_value = 0x0a, },
> +	{ .bitrate = 540, .hw_value = 0x0b, },
> +};
> +
> +u16 rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate)
> +{
> +	struct ieee80211_rate rate;
> +
> +	if (unlikely(rpt_rate >= ARRAY_SIZE(rtw89_bitrates))) {
> +		rtw89_info(rtwdev, "invalid rpt rate %d\n", rpt_rate);
> +		return 0;
> +	}
> +
> +	rate = rtw89_bitrates[rpt_rate];
> +
> +	return rate.bitrate;
> +}
> +
> +static struct ieee80211_supported_band rtw89_sband_2ghz = {
> +	.band		= NL80211_BAND_2GHZ,
> +	.channels	= rtw89_channels_2ghz,
> +	.n_channels	= ARRAY_SIZE(rtw89_channels_2ghz),
> +	.bitrates	= rtw89_bitrates,
> +	.n_bitrates	= ARRAY_SIZE(rtw89_bitrates),
> +	.ht_cap		= {0},
> +	.vht_cap	= {0},
> +};
> +
> +static struct ieee80211_supported_band rtw89_sband_5ghz = {
> +	.band		= NL80211_BAND_5GHZ,
> +	.channels	= rtw89_channels_5ghz,
> +	.n_channels	= ARRAY_SIZE(rtw89_channels_5ghz),
> +
> +	/* 5G has no CCK rates, 1M/2M/5.5M/11M */
> +	.bitrates	= rtw89_bitrates + 4,
> +	.n_bitrates	= ARRAY_SIZE(rtw89_bitrates) - 4,
> +	.ht_cap		= {0},
> +	.vht_cap	= {0},
> +};
> +
> +static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev,
> +				     struct rtw89_traffic_stats *stats,
> +				     struct sk_buff *skb, bool tx)
> +{
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +
> +	if (!ieee80211_is_data(hdr->frame_control))
> +		return;
> +
> +	if (is_broadcast_ether_addr(hdr->addr1) ||
> +	    is_multicast_ether_addr(hdr->addr1))
> +		return;
> +
> +	if (tx) {
> +		stats->tx_cnt++;
> +		stats->tx_unicast += skb->len;
> +	} else {
> +		stats->rx_cnt++;
> +		stats->rx_unicast += skb->len;
> +	}
> +}
> +
> +static void rtw89_get_channel_params(struct cfg80211_chan_def *chandef,
> +				     struct rtw89_channel_params *chan_param)
> +{
> +	struct ieee80211_channel *channel = chandef->chan;
> +	enum nl80211_chan_width width = chandef->width;
> +	u8 *cch_by_bw = chan_param->cch_by_bw;
> +	u32 primary_freq, center_freq;
> +	u8 center_chan;
> +	u8 bandwidth = RTW89_CHANNEL_WIDTH_20;
> +	u8 primary_chan_idx = 0;
> +	u8 i;
> +
> +	center_chan = channel->hw_value;
> +	primary_freq = channel->center_freq;
> +	center_freq = chandef->center_freq1;
> +
> +	/* assign the center channel used while 20M bw is selected */
> +	cch_by_bw[RTW89_CHANNEL_WIDTH_20] = channel->hw_value;
> +
> +	switch (width) {
> +	case NL80211_CHAN_WIDTH_20_NOHT:
> +	case NL80211_CHAN_WIDTH_20:
> +		bandwidth = RTW89_CHANNEL_WIDTH_20;
> +		primary_chan_idx = RTW89_SC_DONT_CARE;
> +		break;
> +	case NL80211_CHAN_WIDTH_40:
> +		bandwidth = RTW89_CHANNEL_WIDTH_40;
> +		if (primary_freq > center_freq) {
> +			primary_chan_idx = RTW89_SC_20_UPPER;
> +			center_chan -= 2;
> +		} else {
> +			primary_chan_idx = RTW89_SC_20_LOWER;
> +			center_chan += 2;
> +		}
> +		break;
> +	case NL80211_CHAN_WIDTH_80:
> +		bandwidth = RTW89_CHANNEL_WIDTH_80;
> +		if (primary_freq > center_freq) {
> +			if (primary_freq - center_freq == 10) {
> +				primary_chan_idx = RTW89_SC_20_UPPER;
> +				center_chan -= 2;
> +			} else {
> +				primary_chan_idx = RTW89_SC_20_UPMOST;
> +				center_chan -= 6;
> +			}
> +			/* assign the center channel used
> +			 * while 40M bw is selected
> +			 */
> +			cch_by_bw[RTW89_CHANNEL_WIDTH_40] = center_chan + 4;
> +		} else {
> +			if (center_freq - primary_freq == 10) {
> +				primary_chan_idx = RTW89_SC_20_LOWER;
> +				center_chan += 2;
> +			} else {
> +				primary_chan_idx = RTW89_SC_20_LOWEST;
> +				center_chan += 6;
> +			}
> +			/* assign the center channel used
> +			 * while 40M bw is selected
> +			 */
> +			cch_by_bw[RTW89_CHANNEL_WIDTH_40] = center_chan - 4;
> +		}
> +		break;
> +	default:
> +		center_chan = 0;
> +		break;
> +	}
> +
> +	chan_param->center_chan = center_chan;
> +	chan_param->primary_chan = channel->hw_value;
> +	chan_param->bandwidth = bandwidth;
> +	chan_param->pri_ch_idx = primary_chan_idx;
> +
> +	/* assign the center channel used while current bw is selected */
> +	cch_by_bw[bandwidth] = center_chan;
> +
> +	for (i = bandwidth + 1; i <= RTW89_MAX_CHANNEL_WIDTH; i++)
> +		cch_by_bw[i] = 0;
> +}
> +
> +void rtw89_set_channel(struct rtw89_dev *rtwdev)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +	struct rtw89_hal *hal = &rtwdev->hal;
> +	struct rtw89_channel_params ch_param;
> +	struct rtw89_channel_help_params bak;
> +	u8 center_chan, bandwidth;
> +	u8 band_type;
> +	bool band_changed;
> +	u8 i;
> +
> +	rtw89_get_channel_params(&hw->conf.chandef, &ch_param);
> +	if (WARN(ch_param.center_chan == 0, "Invalid channel\n"))
> +		return;
> +
> +	center_chan = ch_param.center_chan;
> +	bandwidth = ch_param.bandwidth;
> +	band_type = center_chan > 14 ? RTW89_BAND_5G : RTW89_BAND_2G;
> +	band_changed = hal->current_band_type != band_type ||
> +		       hal->current_channel == 0;
> +
> +	hal->current_band_width = bandwidth;
> +	hal->current_channel = center_chan;
> +	hal->current_primary_channel = ch_param.primary_chan;
> +	hal->current_band_type = band_type;
> +
> +	switch (center_chan) {
> +	case 1 ... 14:
> +		hal->current_subband = RTW89_CH_2G;
> +		break;
> +	case 36 ... 64:
> +		hal->current_subband = RTW89_CH_5G_BAND_1;
> +		break;
> +	case 100 ... 144:
> +		hal->current_subband = RTW89_CH_5G_BAND_3;
> +		break;
> +	case 149 ... 177:
> +		hal->current_subband = RTW89_CH_5G_BAND_4;
> +		break;
> +	}
> +
> +	for (i = RTW89_CHANNEL_WIDTH_20; i <= RTW89_MAX_CHANNEL_WIDTH; i++)
> +		hal->cch_by_bw[i] = ch_param.cch_by_bw[i];
> +
> +	rtw89_chip_set_channel_prepare(rtwdev, &bak);
> +
> +	chip->ops->set_channel(rtwdev, &ch_param);
> +
> +	rtw89_chip_set_txpwr(rtwdev);
> +
> +	rtw89_chip_set_channel_done(rtwdev, &bak);
> +
> +	if (band_changed) {
> +		rtw89_btc_ntfy_switch_band(rtwdev, RTW89_PHY_0, hal->current_band_type);
> +		rtw89_chip_rfk_band_changed(rtwdev);
> +	}
> +}
> +
> +static enum rtw89_core_tx_type
> +rtw89_core_get_tx_type(struct rtw89_dev *rtwdev,
> +		       struct sk_buff *skb)
> +{
> +	struct ieee80211_hdr *hdr = (void *)skb->data;
> +	__le16 fc = hdr->frame_control;
> +
> +	if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc))
> +		return RTW89_CORE_TX_TYPE_MGMT;
> +
> +	return RTW89_CORE_TX_TYPE_DATA;
> +}
> +
> +static void
> +rtw89_core_tx_update_ampdu_info(struct rtw89_dev *rtwdev,
> +				struct rtw89_core_tx_request *tx_req, u8 tid)
> +{
> +	struct ieee80211_sta *sta = tx_req->sta;
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +	struct rtw89_sta *rtwsta;
> +	u8 ampdu_num;
> +
> +	if (!sta) {
> +		rtw89_warn(rtwdev, "cannot set ampdu info without sta\n");
> +		return;
> +	}
> +
> +	rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +
> +	ampdu_num = (u8)((rtwsta->ampdu_params[tid].agg_num ?
> +			  rtwsta->ampdu_params[tid].agg_num :
> +			  4 << sta->ht_cap.ampdu_factor) - 1);
> +
> +	desc_info->agg_en = true;
> +	desc_info->ampdu_density = sta->ht_cap.ampdu_density;
> +	desc_info->ampdu_num = ampdu_num;
> +}
> +
> +static void
> +rtw89_core_tx_update_sec_key(struct rtw89_dev *rtwdev,
> +			     struct rtw89_core_tx_request *tx_req)
> +{
> +	struct ieee80211_vif *vif = tx_req->vif;
> +	struct ieee80211_tx_info *info;
> +	struct ieee80211_key_conf *key;
> +	struct rtw89_vif *rtwvif;
> +	struct rtw89_addr_cam_entry *addr_cam;
> +	struct rtw89_sec_cam_entry *sec_cam;
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +	struct sk_buff *skb = tx_req->skb;
> +	u8 sec_type = RTW89_SEC_KEY_TYPE_NONE;
> +
> +	if (!vif) {
> +		rtw89_warn(rtwdev, "cannot set sec key without vif\n");
> +		return;
> +	}
> +
> +	rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	addr_cam = &rtwvif->addr_cam;
> +
> +	info = IEEE80211_SKB_CB(skb);
> +	key = info->control.hw_key;
> +	sec_cam = addr_cam->sec_entries[key->hw_key_idx];
> +	if (!sec_cam) {
> +		rtw89_warn(rtwdev, "sec cam entry is empty\n");
> +		return;
> +	}
> +
> +	switch (key->cipher) {
> +	case WLAN_CIPHER_SUITE_WEP40:
> +		sec_type = RTW89_SEC_KEY_TYPE_WEP40;
> +		break;
> +	case WLAN_CIPHER_SUITE_WEP104:
> +		sec_type = RTW89_SEC_KEY_TYPE_WEP104;
> +		break;
> +	case WLAN_CIPHER_SUITE_TKIP:
> +		sec_type = RTW89_SEC_KEY_TYPE_TKIP;
> +		break;
> +	case WLAN_CIPHER_SUITE_CCMP:
> +		sec_type = RTW89_SEC_KEY_TYPE_CCMP128;
> +		break;
> +	case WLAN_CIPHER_SUITE_CCMP_256:
> +		sec_type = RTW89_SEC_KEY_TYPE_CCMP256;
> +		break;
> +	case WLAN_CIPHER_SUITE_GCMP:
> +		sec_type = RTW89_SEC_KEY_TYPE_GCMP128;
> +		break;
> +	case WLAN_CIPHER_SUITE_GCMP_256:
> +		sec_type = RTW89_SEC_KEY_TYPE_GCMP256;
> +		break;
> +	default:
> +		rtw89_warn(rtwdev, "key cipher not supported %d\n", key->cipher);
> +		return;
> +	}
> +
> +	desc_info->sec_en = true;
> +	desc_info->sec_type = sec_type;
> +	desc_info->sec_cam_idx = sec_cam->sec_cam_idx;
> +}
> +
> +static void
> +rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
> +			       struct rtw89_core_tx_request *tx_req)
> +{
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +	u8 qsel, ch_dma;
> +
> +	qsel = RTW89_TX_QSEL_B0_MGMT;
> +	ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
> +
> +	desc_info->qsel = RTW89_TX_QSEL_B0_MGMT;
> +	desc_info->ch_dma = ch_dma;
> +
> +	/* fixed data rate for mgmt frames */
> +	desc_info->en_wd_info = true;
> +	desc_info->use_rate = true;
> +	desc_info->dis_data_fb = true;
> +	desc_info->data_rate = 0x00;
> +}
> +
> +static void
> +rtw89_core_tx_update_h2c_info(struct rtw89_dev *rtwdev,
> +			      struct rtw89_core_tx_request *tx_req)
> +{
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +
> +	desc_info->is_bmc = false;
> +	desc_info->wd_page = false;
> +	desc_info->ch_dma = RTW89_DMA_H2C;
> +}
> +
> +static bool
> +__rtw89_core_tx_check_he_qos_htc(struct rtw89_dev *rtwdev,
> +				 struct rtw89_core_tx_request *tx_req,
> +				 enum btc_pkt_type pkt_type)
> +{
> +	struct ieee80211_sta *sta = tx_req->sta;
> +	struct sk_buff *skb = tx_req->skb;
> +	struct ieee80211_hdr *hdr = (void *)skb->data;
> +	__le16 fc = hdr->frame_control;
> +
> +	/* AP IOT issue with EAPoL, ARP and DHCP */
> +	if (pkt_type < PACKET_MAX)
> +		return false;
> +
> +	if (!sta || !sta->he_cap.has_he)
> +		return false;
> +
> +	if (!ieee80211_is_data_qos(fc))
> +		return false;
> +
> +	if (skb_headroom(skb) < IEEE80211_HT_CTL_LEN)
> +		return false;
> +
> +	return true;
> +}
> +
> +static void
> +__rtw89_core_tx_adjust_he_qos_htc(struct rtw89_dev *rtwdev,
> +				  struct rtw89_core_tx_request *tx_req)
> +{
> +	struct sk_buff *skb = tx_req->skb;
> +	struct ieee80211_hdr *hdr = (void *)skb->data;
> +	__le16 fc = hdr->frame_control;
> +	void *data;
> +	__le32 *htc;
> +	u8 *qc;
> +	int hdr_len;
> +
> +	hdr_len = ieee80211_has_a4(fc) ? 32 : 26;
> +	data = skb_push(skb, IEEE80211_HT_CTL_LEN);
> +	memmove(data, data + IEEE80211_HT_CTL_LEN, hdr_len);
> +
> +	hdr = data;
> +	htc = data + hdr_len;
> +	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_ORDER);
> +	memset(htc, 0, sizeof(*htc));
> +	*htc = le32_encode_bits(RTW89_HTC_VARIANT_HE, RTW89_HTC_MASK_VARIANT) |
> +	       le32_encode_bits(RTW89_HTC_VARIANT_HE_CID_CAS, RTW89_HTC_MASK_CTL_ID);
> +
> +	qc = data + hdr_len - IEEE80211_QOS_CTL_LEN;
> +	qc[0] |= IEEE80211_QOS_CTL_EOSP;
> +}
> +
> +static void
> +rtw89_core_tx_update_he_qos_htc(struct rtw89_dev *rtwdev,
> +				struct rtw89_core_tx_request *tx_req,
> +				enum btc_pkt_type pkt_type)
> +{
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +	struct ieee80211_vif *vif = tx_req->vif;
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +
> +	if (!__rtw89_core_tx_check_he_qos_htc(rtwdev, tx_req, pkt_type))
> +		goto desc_bk;
> +
> +	__rtw89_core_tx_adjust_he_qos_htc(rtwdev, tx_req);
> +
> +	desc_info->pkt_size += IEEE80211_HT_CTL_LEN;
> +	desc_info->a_ctrl_bsr = true;
> +
> +desc_bk:
> +	if (!rtwvif || rtwvif->last_a_ctrl == desc_info->a_ctrl_bsr)
> +		return;
> +
> +	rtwvif->last_a_ctrl = desc_info->a_ctrl_bsr;
> +	desc_info->bk = true;
> +}
> +
> +static void
> +rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev,
> +			       struct rtw89_core_tx_request *tx_req)
> +{
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +	struct sk_buff *skb = tx_req->skb;
> +	u8 tid, tid_indicate;
> +	u8 qsel, ch_dma;
> +
> +	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
> +	tid_indicate = rtw89_core_get_tid_indicate(rtwdev, tid);
> +	qsel = rtw89_core_get_qsel(rtwdev, tid);
> +	ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
> +
> +	desc_info->ch_dma = ch_dma;
> +	desc_info->tid_indicate = tid_indicate;
> +	desc_info->qsel = qsel;
> +
> +	/* enable wd_info for AMPDU */
> +	desc_info->en_wd_info = true;
> +
> +	if (IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU)
> +		rtw89_core_tx_update_ampdu_info(rtwdev, tx_req, tid);
> +	if (IEEE80211_SKB_CB(skb)->control.hw_key)
> +		rtw89_core_tx_update_sec_key(rtwdev, tx_req);
> +}
> +
> +static enum btc_pkt_type
> +rtw89_core_tx_btc_spec_pkt_notify(struct rtw89_dev *rtwdev,
> +				  struct rtw89_core_tx_request *tx_req)
> +{
> +	struct sk_buff *skb = tx_req->skb;
> +	struct udphdr *udphdr;
> +
> +	if (IEEE80211_SKB_CB(skb)->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) {
> +		ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.eapol_notify_work);
> +		return PACKET_EAPOL;
> +	}
> +
> +	if (skb->protocol == htons(ETH_P_ARP)) {
> +		ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.arp_notify_work);
> +		return PACKET_ARP;
> +	}
> +
> +	if (skb->protocol == htons(ETH_P_IP) &&
> +	    ip_hdr(skb)->protocol == IPPROTO_UDP) {
> +		udphdr = udp_hdr(skb);
> +		if (((udphdr->source == htons(67) && udphdr->dest == htons(68)) ||
> +		     (udphdr->source == htons(68) && udphdr->dest == htons(67))) &&
> +		    skb->len > 282) {
> +			ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.dhcp_notify_work);
> +			return PACKET_DHCP;
> +		}
> +	}
> +
> +	return PACKET_MAX;
> +}
> +
> +static void
> +rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev,
> +			       struct rtw89_core_tx_request *tx_req)
> +{
> +	struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
> +	struct sk_buff *skb = tx_req->skb;
> +	struct ieee80211_hdr *hdr = (void *)skb->data;
> +	enum rtw89_core_tx_type tx_type;
> +	enum btc_pkt_type pkt_type;
> +	bool is_bmc;
> +	u16 seq;
> +
> +	seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
> +	if (tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD) {
> +		tx_type = rtw89_core_get_tx_type(rtwdev, skb);
> +		tx_req->tx_type = tx_type;
> +	}
> +	is_bmc = (is_broadcast_ether_addr(hdr->addr1) ||
> +		  is_multicast_ether_addr(hdr->addr1));
> +
> +	desc_info->seq = seq;
> +	desc_info->pkt_size = skb->len;
> +	desc_info->is_bmc = is_bmc;
> +	desc_info->wd_page = true;
> +
> +	switch (tx_req->tx_type) {
> +	case RTW89_CORE_TX_TYPE_MGMT:
> +		rtw89_core_tx_update_mgmt_info(rtwdev, tx_req);
> +		break;
> +	case RTW89_CORE_TX_TYPE_DATA:
> +		rtw89_core_tx_update_data_info(rtwdev, tx_req);
> +		pkt_type = rtw89_core_tx_btc_spec_pkt_notify(rtwdev, tx_req);
> +		rtw89_core_tx_update_he_qos_htc(rtwdev, tx_req, pkt_type);
> +		break;
> +	case RTW89_CORE_TX_TYPE_FWCMD:
> +		rtw89_core_tx_update_h2c_info(rtwdev, tx_req);
> +		break;
> +	}
> +}
> +
> +void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel)
> +{
> +	u8 ch_dma;
> +
> +	ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
> +
> +	rtw89_hci_tx_kick_off(rtwdev, ch_dma);
> +}
> +
> +int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
> +		 struct sk_buff *skb, bool fwdl)
> +{
> +	struct rtw89_core_tx_request tx_req = {0};
> +	int ret;
> +
> +	tx_req.skb = skb;
> +	tx_req.tx_type = RTW89_CORE_TX_TYPE_FWCMD;
> +	if (fwdl)
> +		tx_req.desc_info.fw_dl = true;
> +
> +	rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
> +
> +	if (!fwdl)
> +		rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "H2C: ", skb->data, skb->len);
> +
> +	ret = rtw89_hci_tx_write(rtwdev, &tx_req);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
> +		return ret;
> +	}
> +	rtw89_hci_tx_kick_off(rtwdev, RTW89_TXCH_CH12);
> +
> +	return 0;
> +}
> +
> +int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
> +			struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel)
> +{
> +	struct rtw89_core_tx_request tx_req = {0};
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	int ret;
> +
> +	tx_req.skb = skb;
> +	tx_req.sta = sta;
> +	tx_req.vif = vif;
> +
> +	rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true);
> +	rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true);
> +	rtw89_core_tx_update_desc_info(rtwdev, &tx_req);
> +	ret = rtw89_hci_tx_write(rtwdev, &tx_req);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to transmit skb to HCI\n");
> +		return ret;
> +	}
> +
> +	if (qsel)
> +		*qsel = tx_req.desc_info.qsel;
> +
> +	return 0;
> +}
> +
> +void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
> +			    struct rtw89_tx_desc_info *desc_info,
> +			    void *txdesc)
> +{
> +	RTW89_SET_TXWD_BODY_WP_OFFSET(txdesc, desc_info->wp_offset);
> +	RTW89_SET_TXWD_BODY_WD_INFO_EN(txdesc, desc_info->en_wd_info);
> +	RTW89_SET_TXWD_BODY_CHANNEL_DMA(txdesc, desc_info->ch_dma);
> +	RTW89_SET_TXWD_BODY_HDR_LLC_LEN(txdesc, desc_info->hdr_llc_len);
> +	RTW89_SET_TXWD_BODY_WD_PAGE(txdesc, desc_info->wd_page);
> +	RTW89_SET_TXWD_BODY_FW_DL(txdesc, desc_info->fw_dl);
> +	RTW89_SET_TXWD_BODY_SW_SEQ(txdesc, desc_info->seq);
> +
> +	RTW89_SET_TXWD_BODY_TID_INDICATE(txdesc, desc_info->tid_indicate);
> +	RTW89_SET_TXWD_BODY_QSEL(txdesc, desc_info->qsel);
> +	RTW89_SET_TXWD_BODY_TXPKT_SIZE(txdesc, desc_info->pkt_size);
> +	RTW89_SET_TXWD_BODY_AGG_EN(txdesc, desc_info->agg_en);
> +	RTW89_SET_TXWD_BODY_BK(txdesc, desc_info->bk);
> +
> +	if (!desc_info->en_wd_info)
> +		return;
> +
> +	RTW89_SET_TXWD_INFO_USE_RATE(txdesc, desc_info->use_rate);
> +	RTW89_SET_TXWD_INFO_DATA_RATE(txdesc, desc_info->data_rate);
> +	RTW89_SET_TXWD_INFO_DISDATAFB(txdesc, desc_info->dis_data_fb);
> +	RTW89_SET_TXWD_INFO_MAX_AGGNUM(txdesc, desc_info->ampdu_num);
> +	RTW89_SET_TXWD_INFO_AMPDU_DENSITY(txdesc, desc_info->ampdu_density);
> +	RTW89_SET_TXWD_INFO_SEC_TYPE(txdesc, desc_info->sec_type);
> +	RTW89_SET_TXWD_INFO_SEC_HW_ENC(txdesc, desc_info->sec_en);
> +	RTW89_SET_TXWD_INFO_SEC_CAM_IDX(txdesc, desc_info->sec_cam_idx);
> +	RTW89_SET_TXWD_INFO_RTS_EN(txdesc, 1);
> +	RTW89_SET_TXWD_INFO_HW_RTS_EN(txdesc, 1);
> +	RTW89_SET_TXWD_INFO_A_CTRL_BSR(txdesc, desc_info->a_ctrl_bsr);
> +}
> +EXPORT_SYMBOL(rtw89_core_fill_txdesc);
> +
> +static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev,
> +					  struct sk_buff *skb,
> +					  struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	bool rx_cnt_valid = false;
> +	u8 plcp_size = 0;
> +	u8 usr_num = 0;
> +	u8 *phy_sts;
> +
> +	rx_cnt_valid = RTW89_GET_RXINFO_RX_CNT_VLD(skb->data);
> +	plcp_size = RTW89_GET_RXINFO_PLCP_LEN(skb->data) << 3;
> +	usr_num = RTW89_GET_RXINFO_USR_NUM(skb->data);
> +	if (usr_num > RTW89_PPDU_MAX_USR) {
> +		rtw89_warn(rtwdev, "Invalid user number in mac info\n");
> +		return -EINVAL;
> +	}
> +
> +	phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE;
> +	phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE;
> +	/* 8-byte alignment */
> +	if (usr_num & BIT(0))
> +		phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE;
> +	if (rx_cnt_valid)
> +		phy_sts += RTW89_PPDU_MAC_RX_CNT_SIZE;
> +	phy_sts += plcp_size;
> +
> +	phy_ppdu->buf = phy_sts;
> +	phy_ppdu->len = skb->data + skb->len - phy_sts;
> +
> +	return 0;
> +}
> +
> +static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
> +						struct ieee80211_sta *sta)
> +{
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +	struct rtw89_rx_phy_ppdu *phy_ppdu = (struct rtw89_rx_phy_ppdu *)data;
> +
> +	if (rtwsta->mac_id == phy_ppdu->mac_id && phy_ppdu->to_self)
> +		ewma_rssi_add(&rtwsta->avg_rssi, phy_ppdu->rssi_avg);
> +}
> +
> +#define VAR_LEN 0xff
> +#define VAR_LEN_UNIT 8
> +static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, u8 *addr)
> +{
> +	static const u8 physts_ie_len_tab[32] = {
> +		16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
> +		VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
> +		VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
> +	};
> +	u16 ie_len;
> +	u8 ie;
> +
> +	ie = RTW89_GET_PHY_STS_IE_TYPE(addr);
> +	if (physts_ie_len_tab[ie] != VAR_LEN)
> +		ie_len = physts_ie_len_tab[ie];
> +	else
> +		ie_len = RTW89_GET_PHY_STS_IE_LEN(addr) * VAR_LEN_UNIT;
> +
> +	return ie_len;
> +}
> +
> +static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev, u8 *addr,
> +					     struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	s16 cfo;
> +
> +	/* sign conversion for S(12,2) */
> +	cfo = sign_extend32(RTW89_GET_PHY_STS_IE0_CFO(addr), 11);
> +	rtw89_phy_cfo_parse(rtwdev, cfo, phy_ppdu);
> +}
> +
> +static int rtw89_core_process_phy_status_ie(struct rtw89_dev *rtwdev, u8 *addr,
> +					    struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	u8 ie;
> +
> +	ie = RTW89_GET_PHY_STS_IE_TYPE(addr);
> +	switch (ie) {
> +	case RTW89_PHYSTS_IE01_CMN_OFDM:
> +		rtw89_core_parse_phy_status_ie01(rtwdev, addr, phy_ppdu);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +static void rtw89_core_update_phy_ppdu(struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	s8 *rssi = phy_ppdu->rssi;
> +	u8 *buf = phy_ppdu->buf;
> +
> +	phy_ppdu->rssi_avg = RTW89_GET_PHY_STS_RSSI_AVG(buf);
> +	rssi[RF_PATH_A] = RTW89_RSSI_RAW_TO_DBM(RTW89_GET_PHY_STS_RSSI_A(buf));
> +	rssi[RF_PATH_B] = RTW89_RSSI_RAW_TO_DBM(RTW89_GET_PHY_STS_RSSI_B(buf));
> +	rssi[RF_PATH_C] = RTW89_RSSI_RAW_TO_DBM(RTW89_GET_PHY_STS_RSSI_C(buf));
> +	rssi[RF_PATH_D] = RTW89_RSSI_RAW_TO_DBM(RTW89_GET_PHY_STS_RSSI_D(buf));
> +}
> +
> +static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev,
> +					  struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	if (RTW89_GET_PHY_STS_LEN(phy_ppdu->buf) << 3 != phy_ppdu->len) {
> +		rtw89_warn(rtwdev, "phy ppdu len mismatch\n");
> +		return -EINVAL;
> +	}
> +	rtw89_core_update_phy_ppdu(phy_ppdu);
> +	ieee80211_iterate_stations_atomic(rtwdev->hw,
> +					  rtw89_core_rx_process_phy_ppdu_iter,
> +					  phy_ppdu);
> +
> +	return 0;
> +}
> +
> +static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev,
> +				       struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	u16 ie_len;
> +	u8 *pos, *end;
> +
> +	if (!phy_ppdu->to_self)
> +		return 0;
> +
> +	pos = (u8 *)phy_ppdu->buf + PHY_STS_HDR_LEN;
> +	end = (u8 *)phy_ppdu->buf + phy_ppdu->len;
> +	while (pos < end) {
> +		ie_len = rtw89_core_get_phy_status_ie_len(rtwdev, pos);
> +		rtw89_core_process_phy_status_ie(rtwdev, pos, phy_ppdu);
> +		pos += ie_len;
> +		if (pos > end || ie_len == 0) {
> +			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
> +				    "phy status parse failed\n");
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev,
> +					  struct rtw89_rx_phy_ppdu *phy_ppdu)
> +{
> +	int ret;
> +
> +	ret = rtw89_core_rx_parse_phy_sts(rtwdev, phy_ppdu);
> +	if (ret)
> +		rtw89_debug(rtwdev, RTW89_DBG_TXRX, "parse phy sts failed\n");
> +	else
> +		phy_ppdu->valid = true;
> +}
> +
> +static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev,
> +				   const struct rtw89_rx_desc_info *desc_info,
> +				   bool rx_status)
> +{
> +	switch (desc_info->gi_ltf) {
> +	case RTW89_GILTF_SGI_4XHE08:
> +	case RTW89_GILTF_2XHE08:
> +	case RTW89_GILTF_1XHE08:
> +		return NL80211_RATE_INFO_HE_GI_0_8;
> +	case RTW89_GILTF_2XHE16:
> +	case RTW89_GILTF_1XHE16:
> +		return NL80211_RATE_INFO_HE_GI_1_6;
> +	case RTW89_GILTF_LGI_4XHE32:
> +		return NL80211_RATE_INFO_HE_GI_3_2;
> +	default:
> +		rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info->gi_ltf);
> +		return rx_status ? NL80211_RATE_INFO_HE_GI_3_2 : U8_MAX;
> +	}
> +}
> +
> +static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev,
> +				     struct rtw89_rx_desc_info *desc_info,
> +				     struct ieee80211_rx_status *status)
> +{
> +	u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
> +	u8 data_rate_mode, bw, rate_idx = MASKBYTE0, gi_ltf;
> +	u16 data_rate;
> +	bool ret;
> +
> +	data_rate = desc_info->data_rate;
> +	data_rate_mode = GET_DATA_RATE_MODE(data_rate);
> +	if (data_rate_mode == DATA_RATE_MODE_NON_HT) {
> +		rate_idx = GET_DATA_RATE_NOT_HT_IDX(data_rate);
> +		/* No 4 CCK rates for 5G */
> +		if (status->band == NL80211_BAND_5GHZ)
> +			rate_idx -= 4;
> +	} else if (data_rate_mode == DATA_RATE_MODE_HT) {
> +		rate_idx = GET_DATA_RATE_HT_IDX(data_rate);
> +	} else if (data_rate_mode == DATA_RATE_MODE_VHT) {
> +		rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
> +	} else if (data_rate_mode == DATA_RATE_MODE_HE) {
> +		rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
> +	} else {
> +		rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
> +	}
> +
> +	if (desc_info->bw == RTW89_CHANNEL_WIDTH_80)
> +		bw = RATE_INFO_BW_80;
> +	else if (desc_info->bw == RTW89_CHANNEL_WIDTH_40)
> +		bw = RATE_INFO_BW_40;
> +	else
> +		bw = RATE_INFO_BW_20;
> +
> +	gi_ltf = rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info, false);
> +	ret = rtwdev->ppdu_sts.curr_rx_ppdu_cnt[band] == desc_info->ppdu_cnt &&
> +	      status->rate_idx == rate_idx &&
> +	      status->he_gi == gi_ltf &&
> +	      status->bw == bw;
> +
> +	return ret;
> +}
> +
> +struct rtw89_vif_rx_stats_iter_data {
> +	struct rtw89_dev *rtwdev;
> +	struct rtw89_rx_phy_ppdu *phy_ppdu;
> +	struct rtw89_rx_desc_info *desc_info;
> +	struct sk_buff *skb;
> +	const u8 *bssid;
> +};
> +
> +static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
> +				    struct ieee80211_vif *vif)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	struct rtw89_vif_rx_stats_iter_data *iter_data = data;
> +	struct rtw89_dev *rtwdev = iter_data->rtwdev;
> +	struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat;
> +	struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
> +	struct sk_buff *skb = iter_data->skb;
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +	const u8 *bssid = iter_data->bssid;
> +
> +	if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
> +		return;
> +
> +	if (ieee80211_is_beacon(hdr->frame_control))
> +		pkt_stat->beacon_nr++;
> +
> +	if (!ether_addr_equal(vif->addr, hdr->addr1))
> +		return;
> +
> +	if (desc_info->data_rate < RTW89_HW_RATE_NR)
> +		pkt_stat->rx_rate_cnt[desc_info->data_rate]++;
> +
> +	rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false);
> +}
> +
> +static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev,
> +				struct rtw89_rx_phy_ppdu *phy_ppdu,
> +				struct rtw89_rx_desc_info *desc_info,
> +				struct sk_buff *skb)
> +{
> +	struct rtw89_vif_rx_stats_iter_data iter_data;
> +
> +	rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, false);
> +
> +	iter_data.rtwdev = rtwdev;
> +	iter_data.phy_ppdu = phy_ppdu;
> +	iter_data.desc_info = desc_info;
> +	iter_data.skb = skb;
> +	iter_data.bssid = get_hdr_bssid((struct ieee80211_hdr *)skb->data);
> +	rtw89_iterate_vifs_bh(rtwdev, rtw89_vif_rx_stats_iter, &iter_data);
> +}
> +
> +static void rtw89_core_rx_pending_skb(struct rtw89_dev *rtwdev,
> +				      struct rtw89_rx_phy_ppdu *phy_ppdu,
> +				      struct rtw89_rx_desc_info *desc_info,
> +				      struct sk_buff *skb)
> +{
> +	u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
> +	int curr = rtwdev->ppdu_sts.curr_rx_ppdu_cnt[band];
> +	struct sk_buff *skb_ppdu = NULL, *tmp;
> +	struct ieee80211_rx_status *rx_status;
> +
> +	if (curr > RTW89_MAX_PPDU_CNT)
> +		return;
> +
> +	skb_queue_walk_safe(&rtwdev->ppdu_sts.rx_queue[band], skb_ppdu, tmp) {
> +		skb_unlink(skb_ppdu, &rtwdev->ppdu_sts.rx_queue[band]);
> +		rx_status = IEEE80211_SKB_RXCB(skb_ppdu);
> +		if (rtw89_core_rx_ppdu_match(rtwdev, desc_info, rx_status))
> +			rtw89_chip_query_ppdu(rtwdev, phy_ppdu, rx_status);
> +		rtw89_core_rx_stats(rtwdev, phy_ppdu, desc_info, skb_ppdu);
> +		ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, &rtwdev->napi);
> +		rtwdev->napi_budget_countdown--;
> +	}
> +}
> +
> +static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev,
> +					   struct rtw89_rx_desc_info *desc_info,
> +					   struct sk_buff *skb)
> +{
> +	struct rtw89_rx_phy_ppdu phy_ppdu = {.buf = skb->data, .valid = false,
> +					     .len = skb->len,
> +					     .to_self = desc_info->addr1_match,
> +					     .mac_id = desc_info->mac_id};
> +	int ret;
> +
> +	if (desc_info->mac_info_valid)
> +		rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu);
> +	ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu);
> +	if (ret)
> +		rtw89_debug(rtwdev, RTW89_DBG_TXRX, "process ppdu failed\n");
> +
> +	rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu);
> +	rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb);
> +	dev_kfree_skb_any(skb);
> +}
> +
> +static void rtw89_core_rx_process_report(struct rtw89_dev *rtwdev,
> +					 struct rtw89_rx_desc_info *desc_info,
> +					 struct sk_buff *skb)
> +{
> +	switch (desc_info->pkt_type) {
> +	case RTW89_CORE_RX_TYPE_C2H:
> +		rtw89_fw_c2h_irqsafe(rtwdev, skb);
> +		break;
> +	case RTW89_CORE_RX_TYPE_PPDU_STAT:
> +		rtw89_core_rx_process_ppdu_sts(rtwdev, desc_info, skb);
> +		break;
> +	default:
> +		rtw89_debug(rtwdev, RTW89_DBG_TXRX, "unhandled pkt_type=%d\n",
> +			    desc_info->pkt_type);
> +		dev_kfree_skb_any(skb);
> +		break;
> +	}
> +}
> +
> +void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev,
> +			     struct rtw89_rx_desc_info *desc_info,
> +			     u8 *data, u32 data_offset)
> +{
> +	struct rtw89_rxdesc_short *rxd_s;
> +	struct rtw89_rxdesc_long *rxd_l;
> +	u8 shift_len, drv_info_len;
> +
> +	rxd_s = (struct rtw89_rxdesc_short *)(data + data_offset);
> +	desc_info->pkt_size = RTW89_GET_RXWD_PKT_SIZE(rxd_s);
> +	desc_info->drv_info_size = RTW89_GET_RXWD_DRV_INFO_SIZE(rxd_s);
> +	desc_info->long_rxdesc = RTW89_GET_RXWD_LONG_RXD(rxd_s);
> +	desc_info->pkt_type = RTW89_GET_RXWD_RPKT_TYPE(rxd_s);
> +	desc_info->mac_info_valid = RTW89_GET_RXWD_MAC_INFO_VALID(rxd_s);
> +	desc_info->bw = RTW89_GET_RXWD_BW(rxd_s);
> +	desc_info->data_rate = RTW89_GET_RXWD_DATA_RATE(rxd_s);
> +	desc_info->gi_ltf = RTW89_GET_RXWD_GI_LTF(rxd_s);
> +	desc_info->user_id = RTW89_GET_RXWD_USER_ID(rxd_s);
> +	desc_info->sr_en = RTW89_GET_RXWD_SR_EN(rxd_s);
> +	desc_info->ppdu_cnt = RTW89_GET_RXWD_PPDU_CNT(rxd_s);
> +	desc_info->ppdu_type = RTW89_GET_RXWD_PPDU_TYPE(rxd_s);
> +	desc_info->free_run_cnt = RTW89_GET_RXWD_FREE_RUN_CNT(rxd_s);
> +	desc_info->icv_err = RTW89_GET_RXWD_ICV_ERR(rxd_s);
> +	desc_info->crc32_err = RTW89_GET_RXWD_CRC32_ERR(rxd_s);
> +	desc_info->hw_dec = RTW89_GET_RXWD_HW_DEC(rxd_s);
> +	desc_info->sw_dec = RTW89_GET_RXWD_SW_DEC(rxd_s);
> +	desc_info->addr1_match = RTW89_GET_RXWD_A1_MATCH(rxd_s);
> +
> +	shift_len = desc_info->shift << 1; /* 2-byte unit */
> +	drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */
> +	desc_info->offset = data_offset + shift_len + drv_info_len;
> +	desc_info->ready = true;
> +
> +	if (!desc_info->long_rxdesc)
> +		return;
> +
> +	rxd_l = (struct rtw89_rxdesc_long *)(data + data_offset);
> +	desc_info->frame_type = RTW89_GET_RXWD_TYPE(rxd_l);
> +	desc_info->addr_cam_valid = RTW89_GET_RXWD_ADDR_CAM_VLD(rxd_l);
> +	desc_info->addr_cam_id = RTW89_GET_RXWD_ADDR_CAM_ID(rxd_l);
> +	desc_info->sec_cam_id = RTW89_GET_RXWD_SEC_CAM_ID(rxd_l);
> +	desc_info->mac_id = RTW89_GET_RXWD_MAC_ID(rxd_l);
> +	desc_info->rx_pl_id = RTW89_GET_RXWD_RX_PL_ID(rxd_l);
> +}
> +EXPORT_SYMBOL(rtw89_core_query_rxdesc);
> +
> +struct rtw89_core_iter_rx_status {
> +	struct rtw89_dev *rtwdev;
> +	struct ieee80211_rx_status *rx_status;
> +	struct rtw89_rx_desc_info *desc_info;
> +	u8 mac_id;
> +};
> +
> +static
> +void rtw89_core_stats_sta_rx_status_iter(void *data, struct ieee80211_sta *sta)
> +{
> +	struct rtw89_core_iter_rx_status *iter_data =
> +				(struct rtw89_core_iter_rx_status *)data;
> +	struct ieee80211_rx_status *rx_status = iter_data->rx_status;
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +	struct rtw89_rx_desc_info *desc_info = iter_data->desc_info;
> +	u8 mac_id = iter_data->mac_id;
> +
> +	if (mac_id != rtwsta->mac_id)
> +		return;
> +
> +	rtwsta->rx_status = *rx_status;
> +	rtwsta->rx_hw_rate = desc_info->data_rate;
> +}
> +
> +static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev,
> +					   struct rtw89_rx_desc_info *desc_info,
> +					   struct ieee80211_rx_status *rx_status)
> +{
> +	struct rtw89_core_iter_rx_status iter_data;
> +
> +	if (!desc_info->addr1_match || !desc_info->long_rxdesc)
> +		return;
> +
> +	if (desc_info->frame_type != RTW89_RX_TYPE_DATA)
> +		return;
> +
> +	iter_data.rtwdev = rtwdev;
> +	iter_data.rx_status = rx_status;
> +	iter_data.desc_info = desc_info;
> +	iter_data.mac_id = desc_info->mac_id;
> +	ieee80211_iterate_stations_atomic(rtwdev->hw,
> +					  rtw89_core_stats_sta_rx_status_iter,
> +					  &iter_data);
> +}
> +
> +static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
> +					struct rtw89_rx_desc_info *desc_info,
> +					struct ieee80211_rx_status *rx_status)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +	u16 data_rate;
> +	u8 data_rate_mode;
> +
> +	/* currently using single PHY */
> +	rx_status->freq = hw->conf.chandef.chan->center_freq;
> +	rx_status->band = hw->conf.chandef.chan->band;
> +
> +	if (desc_info->icv_err || desc_info->crc32_err)
> +		rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
> +
> +	if (desc_info->hw_dec &&
> +	    !(desc_info->sw_dec || desc_info->icv_err))
> +		rx_status->flag |= RX_FLAG_DECRYPTED;
> +
> +	if (desc_info->bw == RTW89_CHANNEL_WIDTH_80)
> +		rx_status->bw = RATE_INFO_BW_80;
> +	else if (desc_info->bw == RTW89_CHANNEL_WIDTH_40)
> +		rx_status->bw = RATE_INFO_BW_40;
> +	else
> +		rx_status->bw = RATE_INFO_BW_20;
> +
> +	data_rate = desc_info->data_rate;
> +	data_rate_mode = GET_DATA_RATE_MODE(data_rate);
> +	if (data_rate_mode == DATA_RATE_MODE_NON_HT) {
> +		rx_status->encoding = RX_ENC_LEGACY;
> +		rx_status->rate_idx = GET_DATA_RATE_NOT_HT_IDX(data_rate);
> +		/* No 4 CCK rates for 5G */
> +		if (rx_status->band == NL80211_BAND_5GHZ)
> +			rx_status->rate_idx -= 4;
> +		if (rtwdev->scanning)
> +			rx_status->rate_idx = min_t(u8, rx_status->rate_idx,
> +						    ARRAY_SIZE(rtw89_bitrates) - 5);
> +	} else if (data_rate_mode == DATA_RATE_MODE_HT) {
> +		rx_status->encoding = RX_ENC_HT;
> +		rx_status->rate_idx = GET_DATA_RATE_HT_IDX(data_rate);
> +		if (desc_info->gi_ltf)
> +			rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
> +	} else if (data_rate_mode == DATA_RATE_MODE_VHT) {
> +		rx_status->encoding = RX_ENC_VHT;
> +		rx_status->rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
> +		rx_status->nss = GET_DATA_RATE_NSS(data_rate) + 1;
> +		if (desc_info->gi_ltf)
> +			rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
> +	} else if (data_rate_mode == DATA_RATE_MODE_HE) {
> +		rx_status->encoding = RX_ENC_HE;
> +		rx_status->rate_idx = GET_DATA_RATE_VHT_HE_IDX(data_rate);
> +		rx_status->nss = GET_DATA_RATE_NSS(data_rate) + 1;
> +	} else {
> +		rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
> +	}
> +
> +	/* he_gi is used to match ppdu, so we always fill it. */
> +	rx_status->he_gi = rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info, true);
> +	rx_status->flag |= RX_FLAG_MACTIME_START;
> +	rx_status->mactime = desc_info->free_run_cnt;
> +
> +	rtw89_core_stats_sta_rx_status(rtwdev, desc_info, rx_status);
> +}
> +
> +static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (rtw89_disable_ps_mode || !chip->ps_mode_supported)
> +		return RTW89_PS_MODE_NONE;
> +
> +	if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_PWR_GATED))
> +		return RTW89_PS_MODE_PWR_GATED;

Current driver support only one chip with RTW89_PS_MODE_PWR_GATED,
RTW89_PS_MODE_CLK_GATED and RTW89_PS_MODE_RFOFF.

According to this code, only RTW89_PS_MODE_PWR_GATED will return. Please
remove all other modes to reduce review overhead.

> +	if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_CLK_GATED))
> +		return RTW89_PS_MODE_CLK_GATED;
> +
> +	if (chip->ps_mode_supported & BIT(RTW89_PS_MODE_RFOFF))
> +		return RTW89_PS_MODE_RFOFF;
> +
> +	return RTW89_PS_MODE_NONE;
> +}
> +
> +static void rtw89_core_flush_ppdu_rx_queue(struct rtw89_dev *rtwdev,
> +					   struct rtw89_rx_desc_info *desc_info)
> +{
> +	struct rtw89_ppdu_sts_info *ppdu_sts = &rtwdev->ppdu_sts;
> +	u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
> +	struct sk_buff *skb_ppdu, *tmp;
> +
> +	skb_queue_walk_safe(&ppdu_sts->rx_queue[band], skb_ppdu, tmp) {
> +		skb_unlink(skb_ppdu, &ppdu_sts->rx_queue[band]);
> +		rtw89_core_rx_stats(rtwdev, NULL, desc_info, skb_ppdu);
> +		ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, &rtwdev->napi);
> +		rtwdev->napi_budget_countdown--;
> +	}
> +}
> +
> +void rtw89_core_rx(struct rtw89_dev *rtwdev,
> +		   struct rtw89_rx_desc_info *desc_info,
> +		   struct sk_buff *skb)
> +{
> +	struct ieee80211_rx_status *rx_status;
> +	struct rtw89_ppdu_sts_info *ppdu_sts = &rtwdev->ppdu_sts;
> +	u8 ppdu_cnt = desc_info->ppdu_cnt;
> +	u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
> +
> +	if (desc_info->pkt_type != RTW89_CORE_RX_TYPE_WIFI) {
> +		rtw89_core_rx_process_report(rtwdev, desc_info, skb);
> +		return;
> +	}
> +
> +	if (ppdu_sts->curr_rx_ppdu_cnt[band] != ppdu_cnt) {
> +		rtw89_core_flush_ppdu_rx_queue(rtwdev, desc_info);
> +		ppdu_sts->curr_rx_ppdu_cnt[band] = ppdu_cnt;
> +	}
> +
> +	rx_status = IEEE80211_SKB_RXCB(skb);
> +	memset(rx_status, 0, sizeof(*rx_status));
> +	rtw89_core_update_rx_status(rtwdev, desc_info, rx_status);
> +	if (desc_info->long_rxdesc &&
> +	    BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP) {
> +		skb_queue_tail(&ppdu_sts->rx_queue[band], skb);
> +	} else {
> +		rtw89_core_rx_stats(rtwdev, NULL, desc_info, skb);
> +		ieee80211_rx_napi(rtwdev->hw, NULL, skb, &rtwdev->napi);
> +		rtwdev->napi_budget_countdown--;
> +	}
> +}
> +EXPORT_SYMBOL(rtw89_core_rx);
> +
> +void rtw89_core_napi_start(struct rtw89_dev *rtwdev)
> +{
> +	if (test_and_set_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
> +		return;
> +
> +	napi_enable(&rtwdev->napi);
> +}
> +EXPORT_SYMBOL(rtw89_core_napi_start);
> +
> +void rtw89_core_napi_stop(struct rtw89_dev *rtwdev)
> +{
> +	if (!test_and_clear_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
> +		return;
> +
> +	napi_synchronize(&rtwdev->napi);
> +	napi_disable(&rtwdev->napi);
> +}
> +EXPORT_SYMBOL(rtw89_core_napi_stop);
> +
> +void rtw89_core_napi_init(struct rtw89_dev *rtwdev)
> +{
> +	init_dummy_netdev(&rtwdev->netdev);
> +	netif_napi_add(&rtwdev->netdev, &rtwdev->napi,
> +		       rtwdev->hci.ops->napi_poll, NAPI_POLL_WEIGHT);
> +}
> +EXPORT_SYMBOL(rtw89_core_napi_init);
> +
> +void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev)
> +{
> +	rtw89_core_napi_stop(rtwdev);
> +	netif_napi_del(&rtwdev->napi);
> +}
> +EXPORT_SYMBOL(rtw89_core_napi_deinit);
> +
> +static void rtw89_core_ba_work(struct work_struct *work)
> +{
> +	struct rtw89_dev *rtwdev =
> +		container_of(work, struct rtw89_dev, ba_work);
> +	struct rtw89_txq *rtwtxq, *tmp;
> +	int ret;
> +
> +	spin_lock_bh(&rtwdev->ba_lock);
> +	list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) {
> +		struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
> +		struct ieee80211_sta *sta = txq->sta;
> +		struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +		u8 tid = txq->tid;
> +
> +		if (!sta) {
> +			rtw89_warn(rtwdev, "cannot start BA without sta\n");
> +			goto skip_ba_work;
> +		}
> +
> +		if (rtwsta->disassoc) {
> +			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
> +				    "cannot start BA with disassoc sta\n");
> +			goto skip_ba_work;
> +		}
> +
> +		ret = ieee80211_start_tx_ba_session(sta, tid, 0);
> +		if (ret) {
> +			rtw89_debug(rtwdev, RTW89_DBG_TXRX,
> +				    "failed to setup BA session for %pM:%2d: %d\n",
> +				    sta->addr, tid, ret);
> +			if (ret == -EINVAL)
> +				set_bit(RTW89_TXQ_F_BLOCK_BA, &rtwtxq->flags);
> +		}
> +skip_ba_work:
> +		list_del_init(&rtwtxq->list);
> +	}
> +	spin_unlock_bh(&rtwdev->ba_lock);
> +}
> +
> +static void rtw89_core_free_sta_pending_ba(struct rtw89_dev *rtwdev,
> +					   struct ieee80211_sta *sta)
> +{
> +	struct rtw89_txq *rtwtxq, *tmp;
> +
> +	spin_lock_bh(&rtwdev->ba_lock);
> +	list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->ba_list, list) {
> +		struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
> +
> +		if (sta == txq->sta)
> +			list_del_init(&rtwtxq->list);
> +	}
> +	spin_unlock_bh(&rtwdev->ba_lock);
> +}
> +
> +static void rtw89_core_txq_check_agg(struct rtw89_dev *rtwdev,
> +				     struct rtw89_txq *rtwtxq,
> +				     struct sk_buff *skb)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +	struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
> +	struct ieee80211_sta *sta = txq->sta;
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +
> +	if (unlikely(skb_get_queue_mapping(skb) == IEEE80211_AC_VO))
> +		return;
> +
> +	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
> +		return;
> +
> +	if (unlikely(!sta))
> +		return;
> +
> +	if (unlikely(test_bit(RTW89_TXQ_F_BLOCK_BA, &rtwtxq->flags)))
> +		return;
> +
> +	if (test_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags)) {
> +		IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_AMPDU;
> +		return;
> +	}
> +
> +	spin_lock_bh(&rtwdev->ba_lock);
> +	if (!rtwsta->disassoc && list_empty(&rtwtxq->list)) {
> +		list_add_tail(&rtwtxq->list, &rtwdev->ba_list);
> +		ieee80211_queue_work(hw, &rtwdev->ba_work);
> +	}
> +	spin_unlock_bh(&rtwdev->ba_lock);
> +}
> +
> +static void rtw89_core_txq_push(struct rtw89_dev *rtwdev,
> +				struct rtw89_txq *rtwtxq,
> +				unsigned long frame_cnt,
> +				unsigned long byte_cnt)
> +{
> +	struct ieee80211_txq *txq = rtw89_txq_to_txq(rtwtxq);
> +	struct ieee80211_vif *vif = txq->vif;
> +	struct ieee80211_sta *sta = txq->sta;
> +	struct sk_buff *skb;
> +	unsigned long i;
> +	int ret;
> +
> +	for (i = 0; i < frame_cnt; i++) {
> +		skb = ieee80211_tx_dequeue_ni(rtwdev->hw, txq);
> +		if (!skb) {
> +			rtw89_debug(rtwdev, RTW89_DBG_TXRX, "dequeue a NULL skb\n");
> +			return;
> +		}
> +		rtw89_core_txq_check_agg(rtwdev, rtwtxq, skb);
> +		ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, NULL);
> +		if (ret) {
> +			rtw89_err(rtwdev, "failed to push txq: %d\n", ret);
> +			ieee80211_free_txskb(rtwdev->hw, skb);
> +			break;
> +		}
> +	}
> +}
> +
> +static u32 rtw89_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 tid)
> +{
> +	u8 qsel, ch_dma;
> +
> +	qsel = rtw89_core_get_qsel(rtwdev, tid);
> +	ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel);
> +
> +	return rtw89_hci_check_and_reclaim_tx_resource(rtwdev, ch_dma);
> +}
> +
> +static bool rtw89_core_txq_agg_wait(struct rtw89_dev *rtwdev,
> +				    struct ieee80211_txq *txq,
> +				    unsigned long *frame_cnt,
> +				    bool *sched_txq, bool *reinvoke)
> +{
> +	struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv;
> +	struct ieee80211_sta *sta = txq->sta;
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +
> +	if (!sta || rtwsta->max_agg_wait <= 0)
> +		return false;
> +
> +	if (rtwdev->stats.tx_tfc_lv <= RTW89_TFC_MID)
> +		return false;
> +
> +	if (*frame_cnt > 1) {
> +		*frame_cnt -= 1;
> +		*sched_txq = true;
> +		*reinvoke = true;
> +		rtwtxq->wait_cnt = 1;
> +		return false;
> +	}
> +
> +	if (*frame_cnt == 1 && rtwtxq->wait_cnt < rtwsta->max_agg_wait) {
> +		*reinvoke = true;
> +		rtwtxq->wait_cnt++;
> +		return true;
> +	}
> +
> +	rtwtxq->wait_cnt = 0;
> +	return false;
> +}
> +
> +static void rtw89_core_txq_schedule(struct rtw89_dev *rtwdev, u8 ac, bool *reinvoke)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +	struct ieee80211_txq *txq;
> +	struct rtw89_txq *rtwtxq;
> +	unsigned long frame_cnt;
> +	unsigned long byte_cnt;
> +	u32 tx_resource;
> +	bool sched_txq;
> +
> +	ieee80211_txq_schedule_start(hw, ac);
> +	while ((txq = ieee80211_next_txq(hw, ac))) {
> +		rtwtxq = (struct rtw89_txq *)txq->drv_priv;
> +		tx_resource = rtw89_check_and_reclaim_tx_resource(rtwdev, txq->tid);
> +		sched_txq = false;
> +
> +		ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt);
> +		if (rtw89_core_txq_agg_wait(rtwdev, txq, &frame_cnt, &sched_txq, reinvoke)) {
> +			ieee80211_return_txq(hw, txq, true);
> +			continue;
> +		}
> +		frame_cnt = min_t(unsigned long, frame_cnt, tx_resource);
> +		rtw89_core_txq_push(rtwdev, rtwtxq, frame_cnt, byte_cnt);
> +		ieee80211_return_txq(hw, txq, sched_txq);
> +		if (frame_cnt != 0)
> +			rtw89_core_tx_kick_off(rtwdev, rtw89_core_get_qsel(rtwdev, txq->tid));
> +	}
> +	ieee80211_txq_schedule_end(hw, ac);
> +}
> +
> +static void rtw89_core_txq_work(struct work_struct *w)
> +{
> +	struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev, txq_work);
> +	bool reinvoke = false;
> +	u8 ac;
> +
> +	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
> +		rtw89_core_txq_schedule(rtwdev, ac, &reinvoke);
> +
> +	if (reinvoke) {
> +		/* reinvoke to process the last frame */
> +		mod_delayed_work(rtwdev->txq_wq, &rtwdev->txq_reinvoke_work, 1);
> +	}
> +}
> +
> +static void rtw89_core_txq_reinvoke_work(struct work_struct *w)
> +{
> +	struct rtw89_dev *rtwdev = container_of(w, struct rtw89_dev,
> +						txq_reinvoke_work.work);
> +
> +	queue_work(rtwdev->txq_wq, &rtwdev->txq_work);
> +}
> +
> +static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev,
> +						 u32 throughput, u64 cnt)
> +{
> +	if (cnt < 100)
> +		return RTW89_TFC_IDLE;
> +	if (throughput > 50)
> +		return RTW89_TFC_HIGH;
> +	if (throughput > 10)
> +		return RTW89_TFC_MID;
> +	if (throughput > 2)
> +		return RTW89_TFC_LOW;
> +	return RTW89_TFC_ULTRA_LOW;
> +}
> +
> +static void rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
> +				     struct rtw89_traffic_stats *stats)
> +{
> +	enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
> +	enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
> +
> +	stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT);
> +	stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT);
> +
> +	ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw);
> +	ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw);
> +
> +	stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp);
> +	stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp);
> +	stats->tx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->tx_throughput,
> +						   stats->tx_cnt);
> +	stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput,
> +						   stats->rx_cnt);
> +	stats->tx_avg_len = (u32)(stats->tx_cnt ? stats->tx_unicast / stats->tx_cnt : 0);
> +	stats->rx_avg_len = (u32)(stats->rx_cnt ? stats->rx_unicast / stats->rx_cnt : 0);
> +
> +	stats->tx_unicast = 0;
> +	stats->rx_unicast = 0;
> +	stats->tx_cnt = 0;
> +	stats->rx_cnt = 0;
> +
> +	if (tx_tfc_lv != stats->tx_tfc_lv || rx_tfc_lv != stats->rx_tfc_lv)
> +		ieee80211_queue_work(rtwdev->hw, &rtwdev->btc.wl_sta_notify_work);
> +}
> +
> +static void rtw89_vif_traffic_stats_iter(void *data, u8 *mac,
> +					 struct ieee80211_vif *vif)
> +{
> +	struct rtw89_dev *rtwdev = data;
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +
> +	rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats);
> +}
> +
> +static void rtw89_traffic_stats_track(struct rtw89_dev *rtwdev)
> +{
> +	rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats);
> +
> +	rtw89_iterate_vifs(rtwdev, rtw89_vif_traffic_stats_iter, rtwdev, false);
> +}
> +
> +static void rtw89_vif_enter_lps_iter(void *data, u8 *mac,
> +				     struct ieee80211_vif *vif)
> +{
> +	struct rtw89_dev *rtwdev = data;
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +
> +	if (rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION)
> +		return;
> +
> +	if (rtwvif->stats.tx_tfc_lv == RTW89_TFC_IDLE &&
> +	    rtwvif->stats.rx_tfc_lv == RTW89_TFC_IDLE)
> +		rtw89_enter_lps(rtwdev, rtwvif->mac_id);
> +}
> +
> +static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
> +{
> +	rtw89_iterate_vifs(rtwdev, rtw89_vif_enter_lps_iter, rtwdev, false);
> +}
> +
> +void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
> +			      struct rtw89_traffic_stats *stats)
> +{
> +	stats->tx_unicast = 0;
> +	stats->rx_unicast = 0;
> +	stats->tx_cnt = 0;
> +	stats->rx_cnt = 0;
> +	ewma_tp_init(&stats->tx_ewma_tp);
> +	ewma_tp_init(&stats->rx_ewma_tp);
> +}
> +
> +static void rtw89_track_work(struct work_struct *work)
> +{
> +	struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
> +						track_work.work);
> +
> +	mutex_lock(&rtwdev->mutex);
> +
> +	if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
> +		goto out;
> +
> +	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work,
> +				     RTW89_TRACK_WORK_PERIOD);
> +
> +	rtw89_leave_lps(rtwdev, false);
> +
> +	rtw89_traffic_stats_track(rtwdev);
> +	rtw89_mac_bf_monitor_track(rtwdev);
> +	rtw89_phy_stat_track(rtwdev);
> +	rtw89_phy_env_monitor_track(rtwdev);
> +	rtw89_phy_dig(rtwdev);
> +	rtw89_chip_rfk_track(rtwdev);
> +	rtw89_phy_ra_update(rtwdev);
> +	rtw89_phy_cfo_track(rtwdev);
> +
> +	if (rtwdev->lps_enabled && !rtwdev->btc.lps && !rtwdev->scanning)
> +		rtw89_enter_lps_track(rtwdev);
> +
> +out:
> +	mutex_unlock(&rtwdev->mutex);
> +}
> +
> +int rtw89_core_power_on(struct rtw89_dev *rtwdev)
> +{
> +	int ret;
> +
> +	ret = rtw89_mac_pwr_on(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to start power sequence\n");
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}

rtw89_core_power_on() is not used. please remote it to avoid review
overhead.

> +u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size)
> +{
> +	unsigned long bit;
> +
> +	bit = find_first_zero_bit(addr, size);
> +	if (bit < size)
> +		set_bit(bit, addr);
> +
> +	return bit;
> +}
> +
> +void rtw89_core_release_bit_map(unsigned long *addr, u8 bit)
> +{
> +	clear_bit(bit, addr);
> +}
> +
> +void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits)
> +{
> +	bitmap_zero(addr, nbits);
> +}
> +
> +#define RTW89_TYPE_MAPPING(_type)	\
> +	case NL80211_IFTYPE_ ## _type:	\
> +		rtwvif->wifi_role = RTW89_WIFI_ROLE_ ## _type;	\
> +		break
> +void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +
> +	switch (vif->type) {
> +	RTW89_TYPE_MAPPING(ADHOC);
> +	RTW89_TYPE_MAPPING(STATION);
> +	RTW89_TYPE_MAPPING(AP);
> +	RTW89_TYPE_MAPPING(AP_VLAN);
> +	RTW89_TYPE_MAPPING(MONITOR);
> +	RTW89_TYPE_MAPPING(MESH_POINT);
> +	RTW89_TYPE_MAPPING(P2P_CLIENT);
> +	RTW89_TYPE_MAPPING(P2P_GO);
> +	RTW89_TYPE_MAPPING(P2P_DEVICE);
> +	RTW89_TYPE_MAPPING(NAN);
> +	default:
> +		WARN_ON(1);
> +		break;
> +	}

This switch statement makes no sense. Only NL80211_IFTYPE_AP,
NL80211_IFTYPE_MESH_POINT, NL80211_IFTYPE_ADHOC and
NL80211_IFTYPE_STATION are supported. Please remove this mapping
open code rtwvif->wifi_role in the following switch

> +	switch (vif->type) {
> +	case NL80211_IFTYPE_AP:
> +	case NL80211_IFTYPE_MESH_POINT:
> +		rtwvif->net_type = RTW89_NET_TYPE_AP_MODE;
> +		rtwvif->self_role = RTW89_SELF_ROLE_AP;
> +		break;
> +	case NL80211_IFTYPE_ADHOC:
> +		rtwvif->net_type = RTW89_NET_TYPE_AD_HOC;

Please set rtwvif->self_role here, to make it easy to read.

> +		break;
> +	case NL80211_IFTYPE_STATION:
> +		if (assoc) {
> +			rtwvif->net_type = RTW89_NET_TYPE_INFRA;
> +			rtwvif->trigger = vif->bss_conf.he_support;
> +		} else {
> +			rtwvif->net_type = RTW89_NET_TYPE_NO_LINK;
> +			rtwvif->trigger = false;
> +		}
> +		rtwvif->self_role = RTW89_SELF_ROLE_CLIENT;
> +		rtwvif->addr_cam.sec_ent_mode = RTW89_ADDR_CAM_SEC_NORMAL;
> +		break;
> +	default:
> +		WARN_ON(1);
> +		break;
> +	}
> +}
> +
> +int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
> +		       struct ieee80211_vif *vif,
> +		       struct ieee80211_sta *sta)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +	int i;
> +
> +	rtwsta->rtwvif = rtwvif;
> +	rtwsta->prev_rssi = 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
> +		rtw89_core_txq_init(rtwdev, sta->txq[i]);
> +
> +	ewma_rssi_init(&rtwsta->avg_rssi);
> +
> +	if (vif->type == NL80211_IFTYPE_STATION) {
> +		rtwvif->mgd.ap = sta;
> +		rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
> +					 BTC_ROLE_MSTS_STA_CONN_START);
> +		rtw89_chip_rfk_channel(rtwdev);
> +	}
> +
> +	return 0;
> +}
> +
> +int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev,
> +			    struct ieee80211_vif *vif,
> +			    struct ieee80211_sta *sta)
> +{
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +
> +	rtwdev->total_sta_assoc--;
> +	rtwsta->disassoc = true;
> +
> +	return 0;
> +}
> +
> +int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
> +			      struct ieee80211_vif *vif,
> +			      struct ieee80211_sta *sta)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	int ret;
> +
> +	rtw89_mac_bf_monitor_calc(rtwdev, sta, true);
> +	rtw89_mac_bf_disassoc(rtwdev, vif, sta);
> +	rtw89_core_free_sta_pending_ba(rtwdev, sta);
> +
> +	rtw89_vif_type_mapping(vif, false);
> +
> +	ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
> +		return ret;
> +	}
> +
> +	ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, 1);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c join info\n");
> +		return ret;
> +	}
> +
> +	/* update cam aid mac_id net_type */
> +	rtw89_fw_h2c_cam(rtwdev, rtwvif);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c cam\n");
> +		return ret;
> +	}
> +
> +	return ret;
> +}
> +
> +int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
> +			 struct ieee80211_vif *vif,
> +			 struct ieee80211_sta *sta)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +	int ret;
> +
> +	rtw89_vif_type_mapping(vif, true);
> +
> +	ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
> +		return ret;
> +	}
> +
> +	/* for station mode, assign the mac_id from itself */
> +	if (vif->type == NL80211_IFTYPE_STATION)
> +		rtwsta->mac_id = rtwvif->mac_id;
> +
> +	ret = rtw89_fw_h2c_join_info(rtwdev, rtwvif, 0);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c join info\n");
> +		return ret;
> +	}
> +
> +	/* update cam aid mac_id net_type */
> +	rtw89_fw_h2c_cam(rtwdev, rtwvif);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c cam\n");
> +		return ret;
> +	}
> +
> +	ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwsta->mac_id);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "failed to send h2c general packet\n");
> +		return ret;
> +	}
> +
> +	rtwdev->total_sta_assoc++;
> +	rtw89_phy_ra_assoc(rtwdev, sta);
> +	rtw89_mac_bf_assoc(rtwdev, vif, sta);
> +	rtw89_mac_bf_monitor_calc(rtwdev, sta, false);
> +
> +	if (vif->type == NL80211_IFTYPE_STATION)
> +		rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
> +					 BTC_ROLE_MSTS_STA_CONN_END);
> +
> +	return ret;
> +}
> +
> +int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
> +			  struct ieee80211_vif *vif,
> +			  struct ieee80211_sta *sta)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
> +
> +	if (vif->type == NL80211_IFTYPE_STATION)
> +		rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
> +					 BTC_ROLE_MSTS_STA_DIS_CONN);
> +
> +	return 0;
> +}
> +
> +static void rtw89_init_ht_cap(struct rtw89_dev *rtwdev,
> +			      struct ieee80211_sta_ht_cap *ht_cap)
> +{
> +	ht_cap->ht_supported = true;
> +	ht_cap->cap = 0;
> +	ht_cap->cap |= IEEE80211_HT_CAP_SGI_20 |
> +		       IEEE80211_HT_CAP_MAX_AMSDU |
> +		       IEEE80211_HT_CAP_TX_STBC |
> +		       (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
> +
> +	ht_cap->cap |= IEEE80211_HT_CAP_LDPC_CODING;
> +
> +	ht_cap->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
> +		       IEEE80211_HT_CAP_DSSSCCK40 |
> +		       IEEE80211_HT_CAP_SGI_40;
> +	ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
> +	ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
> +	ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
> +	ht_cap->mcs.rx_mask[0] = 0xFF;
> +	ht_cap->mcs.rx_mask[1] = 0xFF;
> +	ht_cap->mcs.rx_mask[4] = 0x01;
> +	ht_cap->mcs.rx_highest = cpu_to_le16(300);
> +}
> +
> +static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev,
> +			       struct ieee80211_sta_vht_cap *vht_cap)
> +{
> +	u16 mcs_map;
> +	__le16 highest;
> +	u8 sts_cap = 3;
> +
> +	vht_cap->vht_supported = true;
> +	vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
> +		       IEEE80211_VHT_CAP_SHORT_GI_80 |
> +		       IEEE80211_VHT_CAP_RXSTBC_1 |
> +		       IEEE80211_VHT_CAP_HTC_VHT |
> +		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
> +		       0;
> +	vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC;
> +	vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
> +	vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
> +			IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
> +	vht_cap->cap |= sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
> +
> +	mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
> +		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
> +		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
> +		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
> +		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
> +		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
> +		  IEEE80211_VHT_MCS_NOT_SUPPORTED << 14;
> +	highest = cpu_to_le16(867);
> +	mcs_map |= IEEE80211_VHT_MCS_SUPPORT_0_9 << 2;
> +	vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
> +	vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
> +	vht_cap->vht_mcs.rx_highest = highest;
> +	vht_cap->vht_mcs.tx_highest = highest;
> +}
> +
> +#define RTW89_SBAND_IFTYPES_NR 2
> +
> +static void rtw89_init_he_cap(struct rtw89_dev *rtwdev,
> +			      enum nl80211_band band,
> +			      struct ieee80211_supported_band *sband)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +	struct rtw89_hal *hal = &rtwdev->hal;
> +	struct ieee80211_sband_iftype_data *iftype_data;
> +	bool no_ng16 = (chip->chip_id == RTL8852A && hal->cv == CHIP_CBV) ||
> +		       (chip->chip_id == RTL8852B && hal->cv == CHIP_CAV);
> +	u16 mcs_map = 0;
> +	int i;
> +	int nss = chip->rx_nss;
> +	int idx = 0;
> +
> +	iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL);
> +	if (!iftype_data)
> +		return;
> +
> +	for (i = 0; i < 8; i++) {
> +		if (i < nss)
> +			mcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2);
> +		else
> +			mcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
> +	}
> +
> +	for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
> +		struct ieee80211_sta_he_cap *he_cap;
> +		u8 *mac_cap_info;
> +		u8 *phy_cap_info;
> +
> +		switch (i) {
> +		case NL80211_IFTYPE_STATION:
> +		case NL80211_IFTYPE_AP:
> +			break;
> +		default:
> +			continue;
> +		}
> +
> +		if (idx >= RTW89_SBAND_IFTYPES_NR) {
> +			rtw89_warn(rtwdev, "run out of iftype_data\n");
> +			break;
> +		}
> +
> +		iftype_data[idx].types_mask = BIT(i);
> +		he_cap = &iftype_data[idx].he_cap;
> +		mac_cap_info = he_cap->he_cap_elem.mac_cap_info;
> +		phy_cap_info = he_cap->he_cap_elem.phy_cap_info;
> +
> +		he_cap->has_he = true;
> +		if (i == NL80211_IFTYPE_AP)
> +			mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE;
> +		if (i == NL80211_IFTYPE_STATION)
> +			mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
> +		mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK |
> +				  IEEE80211_HE_MAC_CAP2_BSR;
> +		mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2;
> +		if (i == NL80211_IFTYPE_AP)
> +			mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
> +		mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS |
> +				  IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
> +		if (i == NL80211_IFTYPE_STATION)
> +			mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX;
> +		phy_cap_info[0] = IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
> +				  IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
> +		phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
> +				  IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
> +				  IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
> +		phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
> +				  IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
> +				  IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
> +				  IEEE80211_HE_PHY_CAP2_DOPPLER_TX;
> +		phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM;
> +		if (i == NL80211_IFTYPE_STATION)
> +			phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM |
> +					   IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2;
> +		if (i == NL80211_IFTYPE_AP)
> +			phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
> +		phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
> +				  IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
> +		phy_cap_info[5] = no_ng16 ? 0 :
> +				  IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
> +				  IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
> +		phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
> +				  IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
> +				  IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
> +				  IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE;
> +		phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
> +				  IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
> +				  IEEE80211_HE_PHY_CAP7_MAX_NC_1;
> +		phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
> +				  IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
> +				  IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996;
> +		phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
> +				  IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
> +				  IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
> +				  IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
> +				  IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
> +		if (i == NL80211_IFTYPE_STATION)
> +			phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
> +		he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map);
> +		he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map);
> +
> +		idx++;
> +	}
> +
> +	sband->iftype_data = iftype_data;
> +	sband->n_iftype_data = idx;
> +}
> +
> +static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +	struct ieee80211_supported_band *sband_2ghz = NULL, *sband_5ghz = NULL;
> +	u32 size = sizeof(struct ieee80211_supported_band);
> +
> +	sband_2ghz = kmemdup(&rtw89_sband_2ghz, size, GFP_KERNEL);
> +	if (!sband_2ghz)
> +		goto err;
> +	rtw89_init_ht_cap(rtwdev, &sband_2ghz->ht_cap);
> +	rtw89_init_he_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz);
> +	hw->wiphy->bands[NL80211_BAND_2GHZ] = sband_2ghz;
> +
> +	sband_5ghz = kmemdup(&rtw89_sband_5ghz, size, GFP_KERNEL);
> +	if (!sband_5ghz)
> +		goto err;
> +	rtw89_init_ht_cap(rtwdev, &sband_5ghz->ht_cap);
> +	rtw89_init_vht_cap(rtwdev, &sband_5ghz->vht_cap);
> +	rtw89_init_he_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz);
> +	hw->wiphy->bands[NL80211_BAND_5GHZ] = sband_5ghz;
> +
> +	return 0;
> +
> +err:
> +	hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
> +	hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
> +	if (sband_2ghz)
> +		kfree(sband_2ghz->iftype_data);
> +	if (sband_5ghz)
> +		kfree(sband_5ghz->iftype_data);
> +	kfree(sband_2ghz);
> +	kfree(sband_5ghz);
> +	return -ENOMEM;
> +}
> +
> +static void rtw89_core_clr_supported_band(struct rtw89_dev *rtwdev)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +
> +	kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
> +	kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
> +	kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
> +	kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
> +	hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
> +	hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
> +}
> +
> +static void rtw89_core_ppdu_sts_init(struct rtw89_dev *rtwdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < RTW89_PHY_MAX; i++)
> +		skb_queue_head_init(&rtwdev->ppdu_sts.rx_queue[i]);
> +	for (i = 0; i < RTW89_PHY_MAX; i++)
> +		rtwdev->ppdu_sts.curr_rx_ppdu_cnt[i] = U8_MAX;
> +}
> +
> +int rtw89_core_start(struct rtw89_dev *rtwdev)
> +{
> +	int ret;
> +
> +	rtwdev->mac.qta_mode = RTW89_QTA_SCC;
> +	ret = rtw89_mac_init(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret);
> +		return ret;
> +	}
> +
> +	rtw89_btc_ntfy_poweron(rtwdev);
> +
> +	/* efuse process */
> +
> +	/* pre-config BB/RF, BB reset/RFC reset */
> +	rtw89_mac_disable_bb_rf(rtwdev);
> +	rtw89_mac_enable_bb_rf(rtwdev);
> +	rtw89_phy_init_bb_reg(rtwdev);
> +	rtw89_phy_init_rf_reg(rtwdev);
> +
> +	rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL);
> +
> +	rtw89_phy_dm_init(rtwdev);
> +
> +	rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
> +	rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
> +
> +	ret = rtw89_hci_start(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to start hci\n");
> +		return ret;
> +	}
> +
> +	ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->track_work,
> +				     RTW89_TRACK_WORK_PERIOD);
> +
> +	set_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
> +
> +	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
> +	rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.fw_log_enable);
> +
> +	return 0;
> +}
> +
> +void rtw89_core_stop(struct rtw89_dev *rtwdev)
> +{
> +	struct rtw89_btc *btc = &rtwdev->btc;
> +
> +	/* Prvent to stop twice; enter_ips and ops_stop */
> +	if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags))
> +		return;
> +
> +	rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_OFF);
> +
> +	clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
> +
> +	mutex_unlock(&rtwdev->mutex);
> +
> +	cancel_work_sync(&rtwdev->c2h_work);
> +	cancel_work_sync(&btc->eapol_notify_work);
> +	cancel_work_sync(&btc->arp_notify_work);
> +	cancel_work_sync(&btc->dhcp_notify_work);
> +	cancel_work_sync(&btc->wl_sta_notify_work);
> +	cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
> +	cancel_delayed_work_sync(&rtwdev->track_work);
> +	cancel_delayed_work_sync(&rtwdev->coex_act1_work);
> +	cancel_delayed_work_sync(&rtwdev->cfo_track_work);
> +
> +	mutex_lock(&rtwdev->mutex);
> +
> +	rtw89_btc_ntfy_poweroff(rtwdev);
> +	rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, true);
> +	rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, true);
> +	rtw89_hci_stop(rtwdev);
> +	rtw89_hci_deinit(rtwdev);
> +	rtw89_mac_pwr_off(rtwdev);
> +	rtw89_hci_reset(rtwdev);
> +}
> +
> +int rtw89_core_init(struct rtw89_dev *rtwdev)
> +{
> +	struct rtw89_btc *btc = &rtwdev->btc;
> +	int ret;
> +
> +	INIT_LIST_HEAD(&rtwdev->ba_list);
> +	INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work);
> +	INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
> +	INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
> +	INIT_DELAYED_WORK(&rtwdev->track_work, rtw89_track_work);
> +	INIT_DELAYED_WORK(&rtwdev->coex_act1_work, rtw89_coex_act1_work);
> +	INIT_DELAYED_WORK(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work);
> +	rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0);
> +	spin_lock_init(&rtwdev->ba_lock);
> +	mutex_init(&rtwdev->mutex);
> +	mutex_init(&rtwdev->rf_mutex);
> +	rtwdev->total_sta_assoc = 0;
> +
> +	INIT_WORK(&rtwdev->c2h_work, rtw89_fw_c2h_work);
> +	skb_queue_head_init(&rtwdev->c2h_queue);
> +	rtw89_core_ppdu_sts_init(rtwdev);
> +	rtw89_traffic_stats_init(rtwdev, &rtwdev->stats);
> +
> +	rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev);
> +	rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR;
> +
> +	INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work);
> +	INIT_WORK(&btc->arp_notify_work, rtw89_btc_ntfy_arp_packet_work);
> +	INIT_WORK(&btc->dhcp_notify_work, rtw89_btc_ntfy_dhcp_packet_work);
> +	INIT_WORK(&btc->wl_sta_notify_work, rtw89_btc_ntfy_wl_sta_work);
> +
> +	ret = rtw89_load_firmware(rtwdev);
> +	if (ret) {
> +		rtw89_warn(rtwdev, "no firmware loaded\n");
> +		return ret;
> +	}
> +	rtw89_ser_init(rtwdev);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(rtw89_core_init);
> +
> +void rtw89_core_deinit(struct rtw89_dev *rtwdev)
> +{
> +	rtw89_ser_deinit(rtwdev);
> +	rtw89_unload_firmware(rtwdev);
> +
> +	destroy_workqueue(rtwdev->txq_wq);
> +	mutex_destroy(&rtwdev->rf_mutex);
> +	mutex_destroy(&rtwdev->mutex);
> +}
> +EXPORT_SYMBOL(rtw89_core_deinit);
> +
> +static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev)
> +{
> +	u8 cv;
> +
> +	cv = rtw89_read32_mask(rtwdev, R_AX_SYS_CFG1, B_AX_CHIP_VER_MSK);
> +	if (cv <= CHIP_CBV) {
> +		if (rtw89_read32(rtwdev, R_AX_GPIO0_7_FUNC_SEL) == RTW89_R32_DEAD)
> +			cv = CHIP_CAV;
> +		else
> +			cv = CHIP_CBV;
> +	}
> +
> +	rtwdev->hal.cv = cv;
> +}
> +
> +static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
> +{
> +	int ret;
> +
> +	ret = rtw89_mac_partial_init(rtwdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = rtw89_parse_efuse_map(rtwdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = rtw89_parse_phycap_map(rtwdev);
> +	if (ret)
> +		return ret;
> +
> +	rtw89_mac_pwr_off(rtwdev);
> +
> +	return 0;
> +}
> +
> +static int rtw89_chip_board_info_setup(struct rtw89_dev *rtwdev)
> +{
> +	rtw89_chip_fem_setup(rtwdev);
> +
> +	return 0;
> +}
> +
> +int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
> +{
> +	int ret;
> +
> +	rtw89_read_chip_ver(rtwdev);
> +
> +	ret = rtw89_wait_firmware_completion(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to wait firmware completion\n");
> +		return ret;
> +	}
> +
> +	ret = rtw89_fw_recognize(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to recognize firmware\n");
> +		return ret;
> +	}
> +
> +	ret = rtw89_chip_efuse_info_setup(rtwdev);
> +	if (ret)
> +		return ret;
> +
> +	ret = rtw89_chip_board_info_setup(rtwdev);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(rtw89_chip_info_setup);
> +
> +static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +	struct rtw89_efuse *efuse = &rtwdev->efuse;
> +	int ret;
> +	int tx_headroom = IEEE80211_HT_CTL_LEN;
> +
> +	hw->vif_data_size = sizeof(struct rtw89_vif);
> +	hw->sta_data_size = sizeof(struct rtw89_sta);
> +	hw->txq_data_size = sizeof(struct rtw89_txq);
> +
> +	SET_IEEE80211_PERM_ADDR(hw, efuse->addr);
> +
> +	hw->extra_tx_headroom = tx_headroom;
> +	hw->queues = IEEE80211_NUM_ACS;
> +	hw->max_rx_aggregation_subframes = RTW89_MAX_RX_AGG_NUM;
> +	hw->max_tx_aggregation_subframes = RTW89_MAX_TX_AGG_NUM;
> +
> +	ieee80211_hw_set(hw, SIGNAL_DBM);
> +	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
> +	ieee80211_hw_set(hw, MFP_CAPABLE);
> +	ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
> +	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
> +	ieee80211_hw_set(hw, RX_INCLUDES_FCS);
> +	ieee80211_hw_set(hw, TX_AMSDU);
> +	ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
> +	ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
> +	ieee80211_hw_set(hw, SUPPORTS_PS);
> +	ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
> +
> +	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
> +	hw->wiphy->available_antennas_tx = BIT(rtwdev->chip->rf_path_num) - 1;
> +	hw->wiphy->available_antennas_rx = BIT(rtwdev->chip->rf_path_num) - 1;
> +
> +	hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
> +
> +	wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
> +
> +	ret = rtw89_core_set_supported_band(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to set supported band\n");
> +		return ret;
> +	}
> +
> +	hw->wiphy->reg_notifier = rtw89_regd_notifier;
> +	hw->wiphy->sar_capa = &rtw89_sar_capa;
> +
> +	ret = ieee80211_register_hw(hw);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to register hw\n");
> +		goto err;
> +	}
> +
> +	ret = rtw89_regd_init(rtwdev, rtw89_regd_notifier);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to init regd\n");
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}
> +
> +static void rtw89_core_unregister_hw(struct rtw89_dev *rtwdev)
> +{
> +	struct ieee80211_hw *hw = rtwdev->hw;
> +
> +	ieee80211_unregister_hw(hw);
> +	rtw89_core_clr_supported_band(rtwdev);
> +}
> +
> +int rtw89_core_register(struct rtw89_dev *rtwdev)
> +{
> +	int ret;
> +
> +	ret = rtw89_core_register_hw(rtwdev);
> +	if (ret) {
> +		rtw89_err(rtwdev, "failed to register core hw\n");
> +		return ret;
> +	}
> +
> +	rtw89_debugfs_init(rtwdev);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(rtw89_core_register);
> +
> +void rtw89_core_unregister(struct rtw89_dev *rtwdev)
> +{
> +	rtw89_core_unregister_hw(rtwdev);
> +}
> +EXPORT_SYMBOL(rtw89_core_unregister);
> +
> +MODULE_AUTHOR("Realtek Corporation");
> +MODULE_DESCRIPTION("Realtek 802.11ax wireless core module");
> +MODULE_LICENSE("Dual BSD/GPL");
> diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
> new file mode 100644
> index 000000000000..d535b9293911
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw89/core.h
> @@ -0,0 +1,3336 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
> +/* Copyright(c) 2019-2020  Realtek Corporation
> + */
> +
> +#ifndef __RTW89_CORE_H__
> +#define __RTW89_CORE_H__
> +
> +#include <linux/average.h>
> +#include <linux/bitfield.h>
> +#include <linux/firmware.h>
> +#include <linux/iopoll.h>
> +#include <linux/workqueue.h>
> +#include <net/mac80211.h>
> +
> +struct rtw89_dev;
> +
> +extern const struct ieee80211_ops rtw89_ops;
> +extern const struct rtw89_chip_info rtw8852a_chip_info;
> +
> +#define MASKBYTE0 0xff
> +#define MASKBYTE1 0xff00
> +#define MASKBYTE2 0xff0000
> +#define MASKBYTE3 0xff000000
> +#define MASKBYTE4 0xff00000000ULL
> +#define MASKHWORD 0xffff0000
> +#define MASKLWORD 0x0000ffff
> +#define MASKDWORD 0xffffffff
> +#define RFREG_MASK 0xfffff
> +#define INV_RF_DATA 0xffffffff
> +
> +#define RTW89_TRACK_WORK_PERIOD	round_jiffies_relative(HZ * 2)
> +#define CFO_TRACK_MAX_USER 64
> +#define MAX_RSSI 110
> +#define RSSI_FACTOR 1
> +#define RTW89_RSSI_RAW_TO_DBM(rssi) ((s8)((rssi) >> RSSI_FACTOR) - MAX_RSSI)
> +#define RTW89_MAX_HW_PORT_NUM 5
> +
> +#define RTW89_HTC_MASK_VARIANT GENMASK(1, 0)
> +#define RTW89_HTC_VARIANT_HE 3
> +#define RTW89_HTC_MASK_CTL_ID GENMASK(5, 2)
> +#define RTW89_HTC_VARIANT_HE_CID_CAS 6
> +#define RTW89_HTC_MASK_CTL_INFO GENMASK(31, 6)
> +
> +enum rtw89_subband {
> +	RTW89_CH_2G = 0,
> +	RTW89_CH_5G_BAND_1 = 1,
> +	/* RTW89_CH_5G_BAND_2 = 2, unused */
> +	RTW89_CH_5G_BAND_3 = 3,
> +	RTW89_CH_5G_BAND_4 = 4,
> +
> +	RTW89_SUBBAND_NR,
> +};
> +
> +enum rtw89_hci_type {
> +	RTW89_HCI_TYPE_PCIE,
> +	RTW89_HCI_TYPE_USB,
> +	RTW89_HCI_TYPE_SDIO,
> +};
> +
> +enum rtw89_core_chip_id {
> +	RTL8852A,
> +	RTL8852B,
> +	RTL8852C,
> +};
> +
> +enum rtw89_cv {
> +	CHIP_CAV,
> +	CHIP_CBV,
> +	CHIP_CCV,
> +	CHIP_CDV,
> +	CHIP_CEV,
> +	CHIP_CFV,
> +	CHIP_CV_MAX,
> +	CHIP_CV_INVALID = CHIP_CV_MAX,
> +};
> +
> +enum rtw89_core_tx_type {
> +	RTW89_CORE_TX_TYPE_DATA,
> +	RTW89_CORE_TX_TYPE_MGMT,
> +	RTW89_CORE_TX_TYPE_FWCMD,
> +};
> +
> +enum rtw89_core_rx_type {
> +	RTW89_CORE_RX_TYPE_WIFI		= 0,
> +	RTW89_CORE_RX_TYPE_PPDU_STAT	= 1,
> +	RTW89_CORE_RX_TYPE_CHAN_INFO	= 2,
> +	RTW89_CORE_RX_TYPE_BB_SCOPE	= 3,
> +	RTW89_CORE_RX_TYPE_F2P_TXCMD	= 4,
> +	RTW89_CORE_RX_TYPE_SS2FW	= 5,
> +	RTW89_CORE_RX_TYPE_TX_REPORT	= 6,
> +	RTW89_CORE_RX_TYPE_TX_REL_HOST	= 7,
> +	RTW89_CORE_RX_TYPE_DFS_REPORT	= 8,
> +	RTW89_CORE_RX_TYPE_TX_REL_CPU	= 9,
> +	RTW89_CORE_RX_TYPE_C2H		= 10,
> +	RTW89_CORE_RX_TYPE_CSI		= 11,
> +	RTW89_CORE_RX_TYPE_CQI		= 12,
> +};
> +
> +enum rtw89_txq_flags {
> +	RTW89_TXQ_F_AMPDU		= 0,
> +	RTW89_TXQ_F_BLOCK_BA		= 1,
> +};
> +
> +enum rtw89_net_type {
> +	RTW89_NET_TYPE_NO_LINK		= 0,
> +	RTW89_NET_TYPE_AD_HOC		= 1,
> +	RTW89_NET_TYPE_INFRA		= 2,
> +	RTW89_NET_TYPE_AP_MODE		= 3,
> +};
> +
> +enum rtw89_wifi_role {
> +	RTW89_WIFI_ROLE_NONE,
> +	RTW89_WIFI_ROLE_STATION,
> +	RTW89_WIFI_ROLE_AP,
> +	RTW89_WIFI_ROLE_AP_VLAN,
> +	RTW89_WIFI_ROLE_ADHOC,
> +	RTW89_WIFI_ROLE_ADHOC_MASTER,
> +	RTW89_WIFI_ROLE_MESH_POINT,
> +	RTW89_WIFI_ROLE_MONITOR,
> +	RTW89_WIFI_ROLE_P2P_DEVICE,
> +	RTW89_WIFI_ROLE_P2P_CLIENT,
> +	RTW89_WIFI_ROLE_P2P_GO,
> +	RTW89_WIFI_ROLE_NAN,
> +	RTW89_WIFI_ROLE_MLME_MAX
> +};
> +
> +enum rtw89_upd_mode {
> +	RTW89_VIF_CREATE,
> +	RTW89_VIF_REMOVE,
> +	RTW89_VIF_TYPE_CHANGE,
> +	RTW89_VIF_INFO_CHANGE,
> +	RTW89_VIF_CON_DISCONN
> +};
> +
> +enum rtw89_self_role {
> +	RTW89_SELF_ROLE_CLIENT,
> +	RTW89_SELF_ROLE_AP,
> +	RTW89_SELF_ROLE_AP_CLIENT
> +};
> +
> +enum rtw89_msk_sO_el {
> +	RTW89_NO_MSK,
> +	RTW89_SMA,
> +	RTW89_TMA,
> +	RTW89_BSSID
> +};
> +
> +enum rtw89_sch_tx_sel {
> +	RTW89_SCH_TX_SEL_ALL,
> +	RTW89_SCH_TX_SEL_HIQ,
> +	RTW89_SCH_TX_SEL_MG0,
> +	RTW89_SCH_TX_SEL_MACID,
> +};
> +
> +/* RTW89_ADDR_CAM_SEC_NONE	: not enabled
> + * RTW89_ADDR_CAM_SEC_ALL_UNI	: 0 - 6 unicast
> + * RTW89_ADDR_CAM_SEC_NORMAL	: 0 - 1 unicast, 2 - 4 group, 5 - 6 BIP
> + * RTW89_ADDR_CAM_SEC_4GROUP	: 0 - 1 unicast, 2 - 5 group, 6 BIP
> + */
> +enum rtw89_add_cam_sec_mode {
> +	RTW89_ADDR_CAM_SEC_NONE		= 0,
> +	RTW89_ADDR_CAM_SEC_ALL_UNI	= 1,
> +	RTW89_ADDR_CAM_SEC_NORMAL	= 2,
> +	RTW89_ADDR_CAM_SEC_4GROUP	= 3,
> +};
> +
> +enum rtw89_sec_key_type {
> +	RTW89_SEC_KEY_TYPE_NONE		= 0,
> +	RTW89_SEC_KEY_TYPE_WEP40	= 1,
> +	RTW89_SEC_KEY_TYPE_WEP104	= 2,
> +	RTW89_SEC_KEY_TYPE_TKIP		= 3,
> +	RTW89_SEC_KEY_TYPE_WAPI		= 4,
> +	RTW89_SEC_KEY_TYPE_GCMSMS4	= 5,
> +	RTW89_SEC_KEY_TYPE_CCMP128	= 6,
> +	RTW89_SEC_KEY_TYPE_CCMP256	= 7,
> +	RTW89_SEC_KEY_TYPE_GCMP128	= 8,
> +	RTW89_SEC_KEY_TYPE_GCMP256	= 9,
> +	RTW89_SEC_KEY_TYPE_BIP_CCMP128	= 10,
> +};
> +
> +enum rtw89_port {
> +	RTW89_PORT_0 = 0,
> +	RTW89_PORT_1 = 1,
> +	RTW89_PORT_2 = 2,
> +	RTW89_PORT_3 = 3,
> +	RTW89_PORT_4 = 4,
> +	RTW89_PORT_NUM
> +};
> +
> +enum rtw89_band {
> +	RTW89_BAND_2G = 0,
> +	RTW89_BAND_5G = 1,
> +	RTW89_BAND_MAX,
> +};
> +
> +enum rtw89_hw_rate {
> +	RTW89_HW_RATE_CCK1	= 0x0,
> +	RTW89_HW_RATE_CCK2	= 0x1,
> +	RTW89_HW_RATE_CCK5_5	= 0x2,
> +	RTW89_HW_RATE_CCK11	= 0x3,
> +	RTW89_HW_RATE_OFDM6	= 0x4,
> +	RTW89_HW_RATE_OFDM9	= 0x5,
> +	RTW89_HW_RATE_OFDM12	= 0x6,
> +	RTW89_HW_RATE_OFDM18	= 0x7,
> +	RTW89_HW_RATE_OFDM24	= 0x8,
> +	RTW89_HW_RATE_OFDM36	= 0x9,
> +	RTW89_HW_RATE_OFDM48	= 0xA,
> +	RTW89_HW_RATE_OFDM54	= 0xB,
> +	RTW89_HW_RATE_MCS0	= 0x80,
> +	RTW89_HW_RATE_MCS1	= 0x81,
> +	RTW89_HW_RATE_MCS2	= 0x82,
> +	RTW89_HW_RATE_MCS3	= 0x83,
> +	RTW89_HW_RATE_MCS4	= 0x84,
> +	RTW89_HW_RATE_MCS5	= 0x85,
> +	RTW89_HW_RATE_MCS6	= 0x86,
> +	RTW89_HW_RATE_MCS7	= 0x87,
> +	RTW89_HW_RATE_MCS8	= 0x88,
> +	RTW89_HW_RATE_MCS9	= 0x89,
> +	RTW89_HW_RATE_MCS10	= 0x8A,
> +	RTW89_HW_RATE_MCS11	= 0x8B,
> +	RTW89_HW_RATE_MCS12	= 0x8C,
> +	RTW89_HW_RATE_MCS13	= 0x8D,
> +	RTW89_HW_RATE_MCS14	= 0x8E,
> +	RTW89_HW_RATE_MCS15	= 0x8F,
> +	RTW89_HW_RATE_MCS16	= 0x90,
> +	RTW89_HW_RATE_MCS17	= 0x91,
> +	RTW89_HW_RATE_MCS18	= 0x92,
> +	RTW89_HW_RATE_MCS19	= 0x93,
> +	RTW89_HW_RATE_MCS20	= 0x94,
> +	RTW89_HW_RATE_MCS21	= 0x95,
> +	RTW89_HW_RATE_MCS22	= 0x96,
> +	RTW89_HW_RATE_MCS23	= 0x97,
> +	RTW89_HW_RATE_MCS24	= 0x98,
> +	RTW89_HW_RATE_MCS25	= 0x99,
> +	RTW89_HW_RATE_MCS26	= 0x9A,
> +	RTW89_HW_RATE_MCS27	= 0x9B,
> +	RTW89_HW_RATE_MCS28	= 0x9C,
> +	RTW89_HW_RATE_MCS29	= 0x9D,
> +	RTW89_HW_RATE_MCS30	= 0x9E,
> +	RTW89_HW_RATE_MCS31	= 0x9F,
> +	RTW89_HW_RATE_VHT_NSS1_MCS0	= 0x100,
> +	RTW89_HW_RATE_VHT_NSS1_MCS1	= 0x101,
> +	RTW89_HW_RATE_VHT_NSS1_MCS2	= 0x102,
> +	RTW89_HW_RATE_VHT_NSS1_MCS3	= 0x103,
> +	RTW89_HW_RATE_VHT_NSS1_MCS4	= 0x104,
> +	RTW89_HW_RATE_VHT_NSS1_MCS5	= 0x105,
> +	RTW89_HW_RATE_VHT_NSS1_MCS6	= 0x106,
> +	RTW89_HW_RATE_VHT_NSS1_MCS7	= 0x107,
> +	RTW89_HW_RATE_VHT_NSS1_MCS8	= 0x108,
> +	RTW89_HW_RATE_VHT_NSS1_MCS9	= 0x109,
> +	RTW89_HW_RATE_VHT_NSS2_MCS0	= 0x110,
> +	RTW89_HW_RATE_VHT_NSS2_MCS1	= 0x111,
> +	RTW89_HW_RATE_VHT_NSS2_MCS2	= 0x112,
> +	RTW89_HW_RATE_VHT_NSS2_MCS3	= 0x113,
> +	RTW89_HW_RATE_VHT_NSS2_MCS4	= 0x114,
> +	RTW89_HW_RATE_VHT_NSS2_MCS5	= 0x115,
> +	RTW89_HW_RATE_VHT_NSS2_MCS6	= 0x116,
> +	RTW89_HW_RATE_VHT_NSS2_MCS7	= 0x117,
> +	RTW89_HW_RATE_VHT_NSS2_MCS8	= 0x118,
> +	RTW89_HW_RATE_VHT_NSS2_MCS9	= 0x119,
> +	RTW89_HW_RATE_VHT_NSS3_MCS0	= 0x120,
> +	RTW89_HW_RATE_VHT_NSS3_MCS1	= 0x121,
> +	RTW89_HW_RATE_VHT_NSS3_MCS2	= 0x122,
> +	RTW89_HW_RATE_VHT_NSS3_MCS3	= 0x123,
> +	RTW89_HW_RATE_VHT_NSS3_MCS4	= 0x124,
> +	RTW89_HW_RATE_VHT_NSS3_MCS5	= 0x125,
> +	RTW89_HW_RATE_VHT_NSS3_MCS6	= 0x126,
> +	RTW89_HW_RATE_VHT_NSS3_MCS7	= 0x127,
> +	RTW89_HW_RATE_VHT_NSS3_MCS8	= 0x128,
> +	RTW89_HW_RATE_VHT_NSS3_MCS9	= 0x129,
> +	RTW89_HW_RATE_VHT_NSS4_MCS0	= 0x130,
> +	RTW89_HW_RATE_VHT_NSS4_MCS1	= 0x131,
> +	RTW89_HW_RATE_VHT_NSS4_MCS2	= 0x132,
> +	RTW89_HW_RATE_VHT_NSS4_MCS3	= 0x133,
> +	RTW89_HW_RATE_VHT_NSS4_MCS4	= 0x134,
> +	RTW89_HW_RATE_VHT_NSS4_MCS5	= 0x135,
> +	RTW89_HW_RATE_VHT_NSS4_MCS6	= 0x136,
> +	RTW89_HW_RATE_VHT_NSS4_MCS7	= 0x137,
> +	RTW89_HW_RATE_VHT_NSS4_MCS8	= 0x138,
> +	RTW89_HW_RATE_VHT_NSS4_MCS9	= 0x139,
> +	RTW89_HW_RATE_HE_NSS1_MCS0	= 0x180,
> +	RTW89_HW_RATE_HE_NSS1_MCS1	= 0x181,
> +	RTW89_HW_RATE_HE_NSS1_MCS2	= 0x182,
> +	RTW89_HW_RATE_HE_NSS1_MCS3	= 0x183,
> +	RTW89_HW_RATE_HE_NSS1_MCS4	= 0x184,
> +	RTW89_HW_RATE_HE_NSS1_MCS5	= 0x185,
> +	RTW89_HW_RATE_HE_NSS1_MCS6	= 0x186,
> +	RTW89_HW_RATE_HE_NSS1_MCS7	= 0x187,
> +	RTW89_HW_RATE_HE_NSS1_MCS8	= 0x188,
> +	RTW89_HW_RATE_HE_NSS1_MCS9	= 0x189,
> +	RTW89_HW_RATE_HE_NSS1_MCS10	= 0x18A,
> +	RTW89_HW_RATE_HE_NSS1_MCS11	= 0x18B,
> +	RTW89_HW_RATE_HE_NSS2_MCS0	= 0x190,
> +	RTW89_HW_RATE_HE_NSS2_MCS1	= 0x191,
> +	RTW89_HW_RATE_HE_NSS2_MCS2	= 0x192,
> +	RTW89_HW_RATE_HE_NSS2_MCS3	= 0x193,
> +	RTW89_HW_RATE_HE_NSS2_MCS4	= 0x194,
> +	RTW89_HW_RATE_HE_NSS2_MCS5	= 0x195,
> +	RTW89_HW_RATE_HE_NSS2_MCS6	= 0x196,
> +	RTW89_HW_RATE_HE_NSS2_MCS7	= 0x197,
> +	RTW89_HW_RATE_HE_NSS2_MCS8	= 0x198,
> +	RTW89_HW_RATE_HE_NSS2_MCS9	= 0x199,
> +	RTW89_HW_RATE_HE_NSS2_MCS10	= 0x19A,
> +	RTW89_HW_RATE_HE_NSS2_MCS11	= 0x19B,
> +	RTW89_HW_RATE_HE_NSS3_MCS0	= 0x1A0,
> +	RTW89_HW_RATE_HE_NSS3_MCS1	= 0x1A1,
> +	RTW89_HW_RATE_HE_NSS3_MCS2	= 0x1A2,
> +	RTW89_HW_RATE_HE_NSS3_MCS3	= 0x1A3,
> +	RTW89_HW_RATE_HE_NSS3_MCS4	= 0x1A4,
> +	RTW89_HW_RATE_HE_NSS3_MCS5	= 0x1A5,
> +	RTW89_HW_RATE_HE_NSS3_MCS6	= 0x1A6,
> +	RTW89_HW_RATE_HE_NSS3_MCS7	= 0x1A7,
> +	RTW89_HW_RATE_HE_NSS3_MCS8	= 0x1A8,
> +	RTW89_HW_RATE_HE_NSS3_MCS9	= 0x1A9,
> +	RTW89_HW_RATE_HE_NSS3_MCS10	= 0x1AA,
> +	RTW89_HW_RATE_HE_NSS3_MCS11	= 0x1AB,
> +	RTW89_HW_RATE_HE_NSS4_MCS0	= 0x1B0,
> +	RTW89_HW_RATE_HE_NSS4_MCS1	= 0x1B1,
> +	RTW89_HW_RATE_HE_NSS4_MCS2	= 0x1B2,
> +	RTW89_HW_RATE_HE_NSS4_MCS3	= 0x1B3,
> +	RTW89_HW_RATE_HE_NSS4_MCS4	= 0x1B4,
> +	RTW89_HW_RATE_HE_NSS4_MCS5	= 0x1B5,
> +	RTW89_HW_RATE_HE_NSS4_MCS6	= 0x1B6,
> +	RTW89_HW_RATE_HE_NSS4_MCS7	= 0x1B7,
> +	RTW89_HW_RATE_HE_NSS4_MCS8	= 0x1B8,
> +	RTW89_HW_RATE_HE_NSS4_MCS9	= 0x1B9,
> +	RTW89_HW_RATE_HE_NSS4_MCS10	= 0x1BA,
> +	RTW89_HW_RATE_HE_NSS4_MCS11	= 0x1BB,
> +	RTW89_HW_RATE_NR,
> +
> +	RTW89_HW_RATE_MASK_MOD = GENMASK(8, 7),
> +	RTW89_HW_RATE_MASK_VAL = GENMASK(6, 0),
> +};
> +
> +/* 2G channels,
> + * 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
> + */
> +#define RTW89_2G_CH_NUM 14
> +
> +/* 5G channels,
> + * 36, 38, 40, 42, 44, 46, 48, 50,
> + * 52, 54, 56, 58, 60, 62, 64,
> + * 100, 102, 104, 106, 108, 110, 112, 114,
> + * 116, 118, 120, 122, 124, 126, 128, 130,
> + * 132, 134, 136, 138, 140, 142, 144,
> + * 149, 151, 153, 155, 157, 159, 161, 163,
> + * 165, 167, 169, 171, 173, 175, 177
> + */
> +#define RTW89_5G_CH_NUM 53
> +
> +enum rtw89_rate_section {
> +	RTW89_RS_CCK,
> +	RTW89_RS_OFDM,
> +	RTW89_RS_MCS, /* for HT/VHT/HE */
> +	RTW89_RS_HEDCM,
> +	RTW89_RS_OFFSET,
> +	RTW89_RS_MAX,
> +	RTW89_RS_LMT_NUM = RTW89_RS_MCS + 1,
> +};
> +
> +enum rtw89_rate_max {
> +	RTW89_RATE_CCK_MAX	= 4,
> +	RTW89_RATE_OFDM_MAX	= 8,
> +	RTW89_RATE_MCS_MAX	= 12,
> +	RTW89_RATE_HEDCM_MAX	= 4, /* for HEDCM MCS0/1/3/4 */
> +	RTW89_RATE_OFFSET_MAX	= 5, /* for HE(HEDCM)/VHT/HT/OFDM/CCK offset */
> +};
> +
> +enum rtw89_nss {
> +	RTW89_NSS_1		= 0,
> +	RTW89_NSS_2		= 1,
> +	/* HE DCM only support 1ss and 2ss */
> +	RTW89_NSS_HEDCM_MAX	= RTW89_NSS_2 + 1,
> +	RTW89_NSS_3		= 2,
> +	RTW89_NSS_4		= 3,
> +	RTW89_NSS_MAX,
> +};
> +
> +enum rtw89_ntx {
> +	RTW89_1TX	= 0,
> +	RTW89_2TX	= 1,
> +	RTW89_NTX_NUM,
> +};
> +
> +enum rtw89_beamforming_type {
> +	RTW89_NONBF	= 0,
> +	RTW89_BF	= 1,
> +	RTW89_BF_NUM,
> +};
> +
> +enum rtw89_regulation_type {
> +	RTW89_WW	= 0,
> +	RTW89_ETSI	= 1,
> +	RTW89_FCC	= 2,
> +	RTW89_MKK	= 3,
> +	RTW89_NA	= 4,
> +	RTW89_IC	= 5,
> +	RTW89_KCC	= 6,
> +	RTW89_NCC	= 7,
> +	RTW89_CHILE	= 8,
> +	RTW89_ACMA	= 9,
> +	RTW89_MEXICO	= 10,
> +	RTW89_UKRAINE	= 11,
> +	RTW89_CN	= 12,
> +	RTW89_REGD_NUM,
> +};
> +
> +extern const u8 rtw89_rs_idx_max[RTW89_RS_MAX];
> +extern const u8 rtw89_rs_nss_max[RTW89_RS_MAX];
> +
> +struct rtw89_txpwr_byrate {
> +	s8 cck[RTW89_RATE_CCK_MAX];
> +	s8 ofdm[RTW89_RATE_OFDM_MAX];
> +	s8 mcs[RTW89_NSS_MAX][RTW89_RATE_MCS_MAX];
> +	s8 hedcm[RTW89_NSS_HEDCM_MAX][RTW89_RATE_HEDCM_MAX];
> +	s8 offset[RTW89_RATE_OFFSET_MAX];
> +};
> +
> +enum rtw89_bandwidth_section_num {
> +	RTW89_BW20_SEC_NUM = 8,
> +	RTW89_BW40_SEC_NUM = 4,
> +	RTW89_BW80_SEC_NUM = 2,
> +};
> +
> +struct rtw89_txpwr_limit {
> +	s8 cck_20m[RTW89_BF_NUM];
> +	s8 cck_40m[RTW89_BF_NUM];
> +	s8 ofdm[RTW89_BF_NUM];
> +	s8 mcs_20m[RTW89_BW20_SEC_NUM][RTW89_BF_NUM];
> +	s8 mcs_40m[RTW89_BW40_SEC_NUM][RTW89_BF_NUM];
> +	s8 mcs_80m[RTW89_BW80_SEC_NUM][RTW89_BF_NUM];
> +	s8 mcs_160m[RTW89_BF_NUM];
> +	s8 mcs_40m_0p5[RTW89_BF_NUM];
> +	s8 mcs_40m_2p5[RTW89_BF_NUM];
> +};
> +
> +#define RTW89_RU_SEC_NUM 8
> +
> +struct rtw89_txpwr_limit_ru {
> +	s8 ru26[RTW89_RU_SEC_NUM];
> +	s8 ru52[RTW89_RU_SEC_NUM];
> +	s8 ru106[RTW89_RU_SEC_NUM];
> +};
> +
> +struct rtw89_rate_desc {
> +	enum rtw89_nss nss;
> +	enum rtw89_rate_section rs;
> +	u8 idx;
> +};
> +
> +#define PHY_STS_HDR_LEN 8
> +#define RF_PATH_MAX 4
> +#define RTW89_MAX_PPDU_CNT 8
> +struct rtw89_rx_phy_ppdu {
> +	u8 *buf;
> +	u32 len;
> +	u8 rssi_avg;
> +	s8 rssi[RF_PATH_MAX];
> +	u8 mac_id;
> +	bool to_self;
> +	bool valid;
> +};
> +
> +enum rtw89_mac_idx {
> +	RTW89_MAC_0 = 0,
> +	RTW89_MAC_1 = 1,
> +};
> +
> +enum rtw89_phy_idx {
> +	RTW89_PHY_0 = 0,
> +	RTW89_PHY_1 = 1,
> +	RTW89_PHY_MAX
> +};
> +
> +enum rtw89_rf_path {
> +	RF_PATH_A = 0,
> +	RF_PATH_B = 1,
> +	RF_PATH_C = 2,
> +	RF_PATH_D = 3,
> +	RF_PATH_AB,
> +	RF_PATH_AC,
> +	RF_PATH_AD,
> +	RF_PATH_BC,
> +	RF_PATH_BD,
> +	RF_PATH_CD,
> +	RF_PATH_ABC,
> +	RF_PATH_ABD,
> +	RF_PATH_ACD,
> +	RF_PATH_BCD,
> +	RF_PATH_ABCD,
> +};
> +
> +enum rtw89_rf_path_bit {
> +	RF_A	= BIT(0),
> +	RF_B	= BIT(1),
> +	RF_C	= BIT(2),
> +	RF_D	= BIT(3),
> +
> +	RF_AB	= (RF_A | RF_B),
> +	RF_AC	= (RF_A | RF_C),
> +	RF_AD	= (RF_A | RF_D),
> +	RF_BC	= (RF_B | RF_C),
> +	RF_BD	= (RF_B | RF_D),
> +	RF_CD	= (RF_C | RF_D),
> +
> +	RF_ABC	= (RF_A | RF_B | RF_C),
> +	RF_ABD	= (RF_A | RF_B | RF_D),
> +	RF_ACD	= (RF_A | RF_C | RF_D),
> +	RF_BCD	= (RF_B | RF_C | RF_D),
> +
> +	RF_ABCD	= (RF_A | RF_B | RF_C | RF_D),
> +};
> +
> +enum rtw89_bandwidth {
> +	RTW89_CHANNEL_WIDTH_20	= 0,
> +	RTW89_CHANNEL_WIDTH_40	= 1,
> +	RTW89_CHANNEL_WIDTH_80	= 2,
> +	RTW89_CHANNEL_WIDTH_160	= 3,
> +	RTW89_CHANNEL_WIDTH_80_80	= 4,
> +	RTW89_CHANNEL_WIDTH_5	= 5,
> +	RTW89_CHANNEL_WIDTH_10	= 6,
> +};
> +
> +enum rtw89_ps_mode {
> +	RTW89_PS_MODE_NONE	= 0,
> +	RTW89_PS_MODE_RFOFF	= 1,
> +	RTW89_PS_MODE_CLK_GATED	= 2,
> +	RTW89_PS_MODE_PWR_GATED	= 3,
> +};
> +
> +#define RTW89_MAX_CHANNEL_WIDTH RTW89_CHANNEL_WIDTH_80
> +#define RTW89_2G_BW_NUM (RTW89_CHANNEL_WIDTH_40 + 1)
> +#define RTW89_5G_BW_NUM (RTW89_CHANNEL_WIDTH_80 + 1)
> +#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_80 + 1)
> +
> +enum rtw89_ru_bandwidth {
> +	RTW89_RU26 = 0,
> +	RTW89_RU52 = 1,
> +	RTW89_RU106 = 2,
> +	RTW89_RU_NUM,
> +};
> +
> +enum rtw89_sc_offset {
> +	RTW89_SC_DONT_CARE	= 0,
> +	RTW89_SC_20_UPPER	= 1,
> +	RTW89_SC_20_LOWER	= 2,
> +	RTW89_SC_20_UPMOST	= 3,
> +	RTW89_SC_20_LOWEST	= 4,
> +	RTW89_SC_40_UPPER	= 9,
> +	RTW89_SC_40_LOWER	= 10,
> +};
> +
> +struct rtw89_channel_params {
> +	u8 center_chan;
> +	u8 primary_chan;
> +	u8 bandwidth;
> +	u8 pri_ch_idx;
> +	u8 cch_by_bw[RTW89_MAX_CHANNEL_WIDTH + 1];
> +};
> +
> +struct rtw89_channel_help_params {
> +	u16 tx_en;
> +};
> +
> +struct rtw89_port_reg {
> +	u32 port_cfg;
> +	u32 tbtt_prohib;
> +	u32 bcn_area;
> +	u32 bcn_early;
> +	u32 tbtt_early;
> +	u32 tbtt_agg;
> +	u32 bcn_space;
> +	u32 bcn_forcetx;
> +	u32 bcn_err_cnt;
> +	u32 bcn_err_flag;
> +	u32 dtim_ctrl;
> +	u32 tbtt_shift;
> +	u32 bcn_cnt_tmr;
> +	u32 tsftr_l;
> +	u32 tsftr_h;
> +};
> +
> +struct rtw89_txwd_body {
> +	__le32 dword0;
> +	__le32 dword1;
> +	__le32 dword2;
> +	__le32 dword3;
> +	__le32 dword4;
> +	__le32 dword5;
> +} __packed;
> +
> +struct rtw89_txwd_info {
> +	__le32 dword0;
> +	__le32 dword1;
> +	__le32 dword2;
> +	__le32 dword3;
> +	__le32 dword4;
> +	__le32 dword5;
> +} __packed;
> +
> +struct rtw89_rx_desc_info {
> +	u16 pkt_size;
> +	u8 pkt_type;
> +	u8 drv_info_size;
> +	u8 shift;
> +	u8 wl_hd_iv_len;
> +	bool long_rxdesc;
> +	bool bb_sel;
> +	bool mac_info_valid;
> +	u16 data_rate;
> +	u8 gi_ltf;
> +	u8 bw;
> +	u32 free_run_cnt;
> +	u8 user_id;
> +	bool sr_en;
> +	u8 ppdu_cnt;
> +	u8 ppdu_type;
> +	bool icv_err;
> +	bool crc32_err;
> +	bool hw_dec;
> +	bool sw_dec;
> +	bool addr1_match;
> +	u8 frag;
> +	u16 seq;
> +	u8 frame_type;
> +	u8 rx_pl_id;
> +	bool addr_cam_valid;
> +	u8 addr_cam_id;
> +	u8 sec_cam_id;
> +	u8 mac_id;
> +	u16 offset;
> +	bool ready;
> +};
> +
> +struct rtw89_rxdesc_short {
> +	__le32 dword0;
> +	__le32 dword1;
> +	__le32 dword2;
> +	__le32 dword3;
> +} __packed;
> +
> +struct rtw89_rxdesc_long {
> +	__le32 dword0;
> +	__le32 dword1;
> +	__le32 dword2;
> +	__le32 dword3;
> +	__le32 dword4;
> +	__le32 dword5;
> +	__le32 dword6;
> +	__le32 dword7;
> +} __packed;
> +
> +struct rtw89_tx_desc_info {
> +	u16 pkt_size;
> +	u8 wp_offset;
> +	u8 qsel;
> +	u8 ch_dma;
> +	u8 hdr_llc_len;
> +	bool is_bmc;
> +	bool en_wd_info;
> +	bool wd_page;
> +	bool use_rate;
> +	bool dis_data_fb;
> +	bool tid_indicate;
> +	bool agg_en;
> +	bool bk;
> +	u8 ampdu_density;
> +	u8 ampdu_num;
> +	bool sec_en;
> +	u8 sec_type;
> +	u8 sec_cam_idx;
> +	u16 data_rate;
> +	bool fw_dl;
> +	u16 seq;
> +	bool a_ctrl_bsr;
> +};
> +
> +struct rtw89_core_tx_request {
> +	enum rtw89_core_tx_type tx_type;
> +
> +	struct sk_buff *skb;
> +	struct ieee80211_vif *vif;
> +	struct ieee80211_sta *sta;
> +	struct rtw89_tx_desc_info desc_info;
> +};
> +
> +struct rtw89_txq {
> +	struct list_head list;
> +	unsigned long flags;
> +	int wait_cnt;
> +};
> +
> +struct rtw89_mac_ax_gnt {
> +	u8 gnt_bt_sw_en;
> +	u8 gnt_bt;
> +	u8 gnt_wl_sw_en;
> +	u8 gnt_wl;
> +};
> +
> +#define RTW89_MAC_AX_COEX_GNT_NR 2
> +struct rtw89_mac_ax_coex_gnt {
> +	struct rtw89_mac_ax_gnt band[RTW89_MAC_AX_COEX_GNT_NR];
> +};
> +
> +enum rtw89_btc_ncnt {
> +	BTC_NCNT_POWER_ON = 0x0,
> +	BTC_NCNT_POWER_OFF,
> +	BTC_NCNT_INIT_COEX,
> +	BTC_NCNT_SCAN_START,
> +	BTC_NCNT_SCAN_FINISH,
> +	BTC_NCNT_SPECIAL_PACKET,
> +	BTC_NCNT_SWITCH_BAND,
> +	BTC_NCNT_RFK_TIMEOUT,
> +	BTC_NCNT_SHOW_COEX_INFO,
> +	BTC_NCNT_ROLE_INFO,
> +	BTC_NCNT_CONTROL,
> +	BTC_NCNT_RADIO_STATE,
> +	BTC_NCNT_CUSTOMERIZE,
> +	BTC_NCNT_WL_RFK,
> +	BTC_NCNT_WL_STA,
> +	BTC_NCNT_FWINFO,
> +	BTC_NCNT_TIMER,
> +	BTC_NCNT_NUM
> +};
> +
> +enum rtw89_btc_btinfo {
> +	BTC_BTINFO_L0 = 0,
> +	BTC_BTINFO_L1,
> +	BTC_BTINFO_L2,
> +	BTC_BTINFO_L3,
> +	BTC_BTINFO_H0,
> +	BTC_BTINFO_H1,
> +	BTC_BTINFO_H2,
> +	BTC_BTINFO_H3,
> +	BTC_BTINFO_MAX
> +};
> +
> +enum rtw89_btc_dcnt {
> +	BTC_DCNT_RUN = 0x0,
> +	BTC_DCNT_CX_RUNINFO,
> +	BTC_DCNT_RPT,
> +	BTC_DCNT_RPT_FREEZE,
> +	BTC_DCNT_CYCLE,
> +	BTC_DCNT_CYCLE_FREEZE,
> +	BTC_DCNT_W1,
> +	BTC_DCNT_W1_FREEZE,
> +	BTC_DCNT_B1,
> +	BTC_DCNT_B1_FREEZE,
> +	BTC_DCNT_TDMA_NONSYNC,
> +	BTC_DCNT_SLOT_NONSYNC,
> +	BTC_DCNT_BTCNT_FREEZE,
> +	BTC_DCNT_WL_SLOT_DRIFT,
> +	BTC_DCNT_WL_STA_LAST,
> +	BTC_DCNT_NUM,
> +};
> +
> +enum rtw89_btc_wl_state_cnt {
> +	BTC_WCNT_SCANAP = 0x0,
> +	BTC_WCNT_DHCP,
> +	BTC_WCNT_EAPOL,
> +	BTC_WCNT_ARP,
> +	BTC_WCNT_SCBDUPDATE,
> +	BTC_WCNT_RFK_REQ,
> +	BTC_WCNT_RFK_GO,
> +	BTC_WCNT_RFK_REJECT,
> +	BTC_WCNT_RFK_TIMEOUT,
> +	BTC_WCNT_CH_UPDATE,
> +	BTC_WCNT_NUM
> +};
> +
> +enum rtw89_btc_bt_state_cnt {
> +	BTC_BCNT_RETRY = 0x0,
> +	BTC_BCNT_REINIT,
> +	BTC_BCNT_REENABLE,
> +	BTC_BCNT_SCBDREAD,
> +	BTC_BCNT_RELINK,
> +	BTC_BCNT_IGNOWL,
> +	BTC_BCNT_INQPAG,
> +	BTC_BCNT_INQ,
> +	BTC_BCNT_PAGE,
> +	BTC_BCNT_ROLESW,
> +	BTC_BCNT_AFH,
> +	BTC_BCNT_INFOUPDATE,
> +	BTC_BCNT_INFOSAME,
> +	BTC_BCNT_SCBDUPDATE,
> +	BTC_BCNT_HIPRI_TX,
> +	BTC_BCNT_HIPRI_RX,
> +	BTC_BCNT_LOPRI_TX,
> +	BTC_BCNT_LOPRI_RX,
> +	BTC_BCNT_RATECHG,
> +	BTC_BCNT_NUM
> +};
> +
> +enum rtw89_btc_bt_profile {
> +	BTC_BT_NOPROFILE = 0,
> +	BTC_BT_HFP = BIT(0),
> +	BTC_BT_HID = BIT(1),
> +	BTC_BT_A2DP = BIT(2),
> +	BTC_BT_PAN = BIT(3),
> +	BTC_PROFILE_MAX = 4,
> +};
> +
> +struct rtw89_btc_ant_info {
> +	u8 type;  /* shared, dedicated */
> +	u8 num;
> +	u8 isolation;
> +
> +	u8 single_pos: 1;/* Single antenna at S0 or S1 */
> +	u8 diversity: 1;
> +};
> +
> +enum rtw89_tfc_dir {
> +	RTW89_TFC_UL,
> +	RTW89_TFC_DL,
> +};
> +
> +struct rtw89_btc_wl_smap {
> +	u32 busy: 1;
> +	u32 scan: 1;
> +	u32 connecting: 1;
> +	u32 roaming: 1;
> +	u32 _4way: 1;
> +	u32 rf_off: 1;
> +	u32 lps: 1;
> +	u32 ips: 1;
> +	u32 init_ok: 1;
> +	u32 traffic_dir : 2;
> +	u32 rf_off_pre: 1;
> +	u32 lps_pre: 1;
> +};
> +
> +enum rtw89_tfc_lv {
> +	RTW89_TFC_IDLE,
> +	RTW89_TFC_ULTRA_LOW,
> +	RTW89_TFC_LOW,
> +	RTW89_TFC_MID,
> +	RTW89_TFC_HIGH,
> +};
> +
> +#define RTW89_TP_SHIFT 18 /* bytes/2s --> Mbps */
> +DECLARE_EWMA(tp, 10, 2);
> +
> +struct rtw89_traffic_stats {
> +	/* units in bytes */
> +	u64 tx_unicast;
> +	u64 rx_unicast;
> +	u32 tx_avg_len;
> +	u32 rx_avg_len;
> +
> +	/* count for packets */
> +	u64 tx_cnt;
> +	u64 rx_cnt;
> +
> +	/* units in Mbps */
> +	u32 tx_throughput;
> +	u32 rx_throughput;
> +	u32 tx_throughput_raw;
> +	u32 rx_throughput_raw;
> +	enum rtw89_tfc_lv tx_tfc_lv;
> +	enum rtw89_tfc_lv rx_tfc_lv;
> +	struct ewma_tp tx_ewma_tp;
> +	struct ewma_tp rx_ewma_tp;
> +
> +	u16 tx_rate;
> +	u16 rx_rate;
> +};
> +
> +struct rtw89_btc_statistic {
> +	u8 rssi; /* 0%~110% (dBm = rssi -110) */
> +	struct rtw89_traffic_stats traffic;
> +};
> +
> +#define BTC_WL_RSSI_THMAX 4
> +
> +struct rtw89_btc_wl_link_info {
> +	struct rtw89_btc_statistic stat;
> +	enum rtw89_tfc_dir dir;
> +	u8 rssi_state[BTC_WL_RSSI_THMAX];
> +	u8 mac_addr[ETH_ALEN];
> +	u8 busy;
> +	u8 ch;
> +	u8 bw;
> +	u8 band;
> +	u8 role;
> +	u8 pid;
> +	u8 phy;
> +	u8 dtim_period;
> +	u8 mode;
> +
> +	u8 mac_id;
> +	u8 tx_retry;
> +
> +	u32 bcn_period;
> +	u32 busy_t;
> +	u32 tx_time;
> +	u32 client_cnt;
> +	u32 rx_rate_drop_cnt;
> +
> +	u32 active: 1;
> +	u32 noa: 1;
> +	u32 client_ps: 1;
> +	u32 connected: 2;
> +};
> +
> +union rtw89_btc_wl_state_map {
> +	u32 val;
> +	struct rtw89_btc_wl_smap map;
> +};
> +
> +struct rtw89_btc_bt_hfp_desc {
> +	u32 exist: 1;
> +	u32 type: 2;
> +	u32 rsvd: 29;
> +};
> +
> +struct rtw89_btc_bt_hid_desc {
> +	u32 exist: 1;
> +	u32 slot_info: 2;
> +	u32 pair_cnt: 2;
> +	u32 type: 8;
> +	u32 rsvd: 19;
> +};
> +
> +struct rtw89_btc_bt_a2dp_desc {
> +	u8 exist: 1;
> +	u8 exist_last: 1;
> +	u8 play_latency: 1;
> +	u8 type: 3;
> +	u8 active: 1;
> +	u8 sink: 1;
> +
> +	u8 bitpool;
> +	u16 vendor_id;
> +	u32 device_name;
> +	u32 flush_time;
> +};
> +
> +struct rtw89_btc_bt_pan_desc {
> +	u32 exist: 1;
> +	u32 type: 1;
> +	u32 active: 1;
> +	u32 rsvd: 29;
> +};
> +
> +struct rtw89_btc_bt_rfk_info {
> +	u32 run: 1;
> +	u32 req: 1;
> +	u32 timeout: 1;
> +	u32 rsvd: 29;
> +};
> +
> +union rtw89_btc_bt_rfk_info_map {
> +	u32 val;
> +	struct rtw89_btc_bt_rfk_info map;
> +};
> +
> +struct rtw89_btc_bt_ver_info {
> +	u32 fw_coex; /* match with which coex_ver */
> +	u32 fw;
> +};
> +
> +struct rtw89_btc_bool_sta_chg {
> +	u32 now: 1;
> +	u32 last: 1;
> +	u32 remain: 1;
> +	u32 srvd: 29;
> +};
> +
> +struct rtw89_btc_u8_sta_chg {
> +	u8 now;
> +	u8 last;
> +	u8 remain;
> +	u8 rsvd;
> +};
> +
> +struct rtw89_btc_wl_scan_info {
> +	u8 band[RTW89_PHY_MAX];
> +	u8 phy_map;
> +	u8 rsvd;
> +};
> +
> +struct rtw89_btc_wl_dbcc_info {
> +	u8 op_band[RTW89_PHY_MAX]; /* op band in each phy */
> +	u8 scan_band[RTW89_PHY_MAX]; /* scan band in  each phy */
> +	u8 real_band[RTW89_PHY_MAX];
> +	u8 role[RTW89_PHY_MAX]; /* role in each phy */
> +};
> +
> +struct rtw89_btc_wl_active_role {
> +	u8 connected: 1;
> +	u8 pid: 3;
> +	u8 phy: 1;
> +	u8 noa: 1;
> +	u8 band: 2;
> +
> +	u8 client_ps: 1;
> +	u8 bw: 7;
> +
> +	u8 role;
> +	u8 ch;
> +
> +	u16 tx_lvl;
> +	u16 rx_lvl;
> +	u16 tx_rate;
> +	u16 rx_rate;
> +};
> +
> +struct rtw89_btc_wl_role_info_bpos {
> +	u16 none: 1;
> +	u16 station: 1;
> +	u16 ap: 1;
> +	u16 vap: 1;
> +	u16 adhoc: 1;
> +	u16 adhoc_master: 1;
> +	u16 mesh: 1;
> +	u16 moniter: 1;
> +	u16 p2p_device: 1;
> +	u16 p2p_gc: 1;
> +	u16 p2p_go: 1;
> +	u16 nan: 1;
> +};
> +
> +union rtw89_btc_wl_role_info_map {
> +	u16 val;
> +	struct rtw89_btc_wl_role_info_bpos role;
> +};
> +
> +struct rtw89_btc_wl_role_info { /* struct size must be n*4 bytes */
> +	u8 connect_cnt;
> +	u8 link_mode;
> +	union rtw89_btc_wl_role_info_map role_map;
> +	struct rtw89_btc_wl_active_role active_role[RTW89_MAX_HW_PORT_NUM];
> +};
> +
> +struct rtw89_btc_wl_ver_info {
> +	u32 fw_coex; /* match with which coex_ver */
> +	u32 fw;
> +	u32 mac;
> +	u32 bb;
> +	u32 rf;
> +};
> +
> +struct rtw89_btc_wl_afh_info {
> +	u8 en;
> +	u8 ch;
> +	u8 bw;
> +	u8 rsvd;
> +} __packed;
> +
> +struct rtw89_btc_wl_rfk_info {
> +	u32 state: 2;
> +	u32 path_map: 4;
> +	u32 phy_map: 2;
> +	u32 band: 2;
> +	u32 type: 8;
> +	u32 rsvd: 14;
> +};
> +
> +struct rtw89_btc_bt_smap {
> +	u32 connect: 1;
> +	u32 ble_connect: 1;
> +	u32 acl_busy: 1;
> +	u32 sco_busy: 1;
> +	u32 mesh_busy: 1;
> +	u32 inq_pag: 1;
> +};
> +
> +union rtw89_btc_bt_state_map {
> +	u32 val;
> +	struct rtw89_btc_bt_smap map;
> +};
> +
> +#define BTC_BT_RSSI_THMAX 4
> +#define BTC_BT_AFH_GROUP 12
> +
> +struct rtw89_btc_bt_link_info {
> +	struct rtw89_btc_u8_sta_chg profile_cnt;
> +	struct rtw89_btc_bool_sta_chg multi_link;
> +	struct rtw89_btc_bool_sta_chg relink;
> +	struct rtw89_btc_bt_hfp_desc hfp_desc;
> +	struct rtw89_btc_bt_hid_desc hid_desc;
> +	struct rtw89_btc_bt_a2dp_desc a2dp_desc;
> +	struct rtw89_btc_bt_pan_desc pan_desc;
> +	union rtw89_btc_bt_state_map status;
> +
> +	u8 sut_pwr_level[BTC_PROFILE_MAX];
> +	u8 golden_rx_shift[BTC_PROFILE_MAX];
> +	u8 rssi_state[BTC_BT_RSSI_THMAX];
> +	u8 afh_map[BTC_BT_AFH_GROUP];
> +
> +	u32 role_sw: 1;
> +	u32 slave_role: 1;
> +	u32 afh_update: 1;
> +	u32 cqddr: 1;
> +	u32 rssi: 8;
> +	u32 tx_3m: 1;
> +	u32 rsvd: 19;
> +};
> +
> +struct rtw89_btc_3rdcx_info {
> +	u8 type;   /* 0: none, 1:zigbee, 2:LTE  */
> +	u8 hw_coex;
> +	u16 rsvd;
> +};
> +
> +struct rtw89_btc_dm_emap {
> +	u32 init: 1;
> +	u32 pta_owner: 1;
> +	u32 wl_rfk_timeout: 1;
> +	u32 bt_rfk_timeout: 1;
> +
> +	u32 wl_fw_hang: 1;
> +	u32 offload_mismatch: 1;
> +	u32 cycle_hang: 1;
> +	u32 w1_hang: 1;
> +
> +	u32 b1_hang: 1;
> +	u32 tdma_no_sync: 1;
> +	u32 wl_slot_drift: 1;
> +};
> +
> +union rtw89_btc_dm_error_map {
> +	u32 val;
> +	struct rtw89_btc_dm_emap map;
> +};
> +
> +struct rtw89_btc_rf_para {
> +	u32 tx_pwr_freerun;
> +	u32 rx_gain_freerun;
> +	u32 tx_pwr_perpkt;
> +	u32 rx_gain_perpkt;
> +};
> +
> +struct rtw89_btc_wl_info {
> +	struct rtw89_btc_wl_link_info link_info[RTW89_MAX_HW_PORT_NUM];
> +	struct rtw89_btc_wl_rfk_info rfk_info;
> +	struct rtw89_btc_wl_ver_info  ver_info;
> +	struct rtw89_btc_wl_afh_info afh_info;
> +	struct rtw89_btc_wl_role_info role_info;
> +	struct rtw89_btc_wl_scan_info scan_info;
> +	struct rtw89_btc_wl_dbcc_info dbcc_info;
> +	struct rtw89_btc_rf_para rf_para;
> +	union rtw89_btc_wl_state_map status;
> +
> +	u8 port_id[RTW89_WIFI_ROLE_MLME_MAX];
> +	u8 rssi_level;
> +
> +	u32 scbd;
> +};
> +
> +struct rtw89_btc_module {
> +	struct rtw89_btc_ant_info ant;
> +	u8 rfe_type;
> +	u8 cv;
> +
> +	u8 bt_solo: 1;
> +	u8 bt_pos: 1;
> +	u8 switch_type: 1;
> +
> +	u8 rsvd;
> +};
> +
> +#define RTW89_BTC_DM_MAXSTEP 30
> +#define RTW89_BTC_DM_CNT_MAX (RTW89_BTC_DM_MAXSTEP * 8)
> +
> +struct rtw89_btc_dm_step {
> +	u16 step[RTW89_BTC_DM_MAXSTEP];
> +	u8 step_pos;
> +	bool step_ov;
> +};
> +
> +struct rtw89_btc_init_info {
> +	struct rtw89_btc_module module;
> +	u8 wl_guard_ch;
> +
> +	u8 wl_only: 1;
> +	u8 wl_init_ok: 1;
> +	u8 dbcc_en: 1;
> +	u8 cx_other: 1;
> +	u8 bt_only: 1;
> +
> +	u16 rsvd;
> +};
> +
> +struct rtw89_btc_wl_tx_limit_para {
> +	u16 enable;
> +	u32 tx_time;	/* unit: us */
> +	u16 tx_retry;
> +};
> +
> +struct rtw89_btc_bt_scan_info {
> +	u16 win;
> +	u16 intvl;
> +	u32 enable: 1;
> +	u32 interlace: 1;
> +	u32 rsvd: 30;
> +};
> +
> +enum rtw89_btc_bt_scan_type {
> +	BTC_SCAN_INQ	= 0,
> +	BTC_SCAN_PAGE,
> +	BTC_SCAN_BLE,
> +	BTC_SCAN_INIT,
> +	BTC_SCAN_TV,
> +	BTC_SCAN_ADV,
> +	BTC_SCAN_MAX1,
> +};
> +
> +struct rtw89_btc_bt_info {
> +	struct rtw89_btc_bt_link_info link_info;
> +	struct rtw89_btc_bt_scan_info scan_info[BTC_SCAN_MAX1];
> +	struct rtw89_btc_bt_ver_info ver_info;
> +	struct rtw89_btc_bool_sta_chg enable;
> +	struct rtw89_btc_bool_sta_chg inq_pag;
> +	struct rtw89_btc_rf_para rf_para;
> +	union rtw89_btc_bt_rfk_info_map rfk_info;
> +
> +	u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
> +
> +	u32 scbd;
> +	u32 feature;
> +
> +	u32 mbx_avl: 1;
> +	u32 whql_test: 1;
> +	u32 igno_wl: 1;
> +	u32 reinit: 1;
> +	u32 ble_scan_en: 1;
> +	u32 btg_type: 1;
> +	u32 inq: 1;
> +	u32 pag: 1;
> +	u32 run_patch_code: 1;
> +	u32 hi_lna_rx: 1;
> +	u32 rsvd: 22;
> +};
> +
> +struct rtw89_btc_cx {
> +	struct rtw89_btc_wl_info wl;
> +	struct rtw89_btc_bt_info bt;
> +	struct rtw89_btc_3rdcx_info other;
> +	u32 state_map;
> +	u32 cnt_bt[BTC_BCNT_NUM];
> +	u32 cnt_wl[BTC_WCNT_NUM];
> +};
> +
> +struct rtw89_btc_fbtc_tdma {
> +	u8 type;
> +	u8 rxflctrl;
> +	u8 txpause;
> +	u8 wtgle_n;
> +	u8 leak_n;
> +	u8 ext_ctrl;
> +	u8 rsvd0;
> +	u8 rsvd1;
> +} __packed;
> +
> +#define CXMREG_MAX 30
> +#define FCXMAX_STEP 255 /*STEP trace record cnt, Max:65535, default:255*/
> +#define BTCRPT_VER 1
> +#define BTC_CYCLE_SLOT_MAX 48 /* must be even number, non-zero */
> +
> +enum rtw89_btc_bt_rfk_counter {
> +	BTC_BCNT_RFK_REQ = 0,
> +	BTC_BCNT_RFK_GO = 1,
> +	BTC_BCNT_RFK_REJECT = 2,
> +	BTC_BCNT_RFK_FAIL = 3,
> +	BTC_BCNT_RFK_TIMEOUT = 4,
> +	BTC_BCNT_RFK_MAX
> +};
> +
> +struct rtw89_btc_fbtc_rpt_ctrl {
> +	u16 fver;
> +	u16 rpt_cnt; /* tmr counters */
> +	u32 wl_fw_coex_ver; /* match which driver's coex version */
> +	u32 wl_fw_cx_offload;
> +	u32 wl_fw_ver;
> +	u32 rpt_enable;
> +	u32 rpt_para; /* ms */
> +	u32 mb_send_fail_cnt; /* fw send mailbox fail counter */
> +	u32 mb_send_ok_cnt; /* fw send mailbox ok counter */
> +	u32 mb_recv_cnt; /* fw recv mailbox counter */
> +	u32 mb_a2dp_empty_cnt; /* a2dp empty count */
> +	u32 mb_a2dp_flct_cnt; /* a2dp empty flow control counter */
> +	u32 mb_a2dp_full_cnt; /* a2dp empty full counter */
> +	u32 bt_rfk_cnt[BTC_BCNT_RFK_MAX];
> +	u32 c2h_cnt; /* fw send c2h counter  */
> +	u32 h2c_cnt; /* fw recv h2c counter */
> +} __packed;
> +
> +enum rtw89_fbtc_ext_ctrl_type {
> +	CXECTL_OFF = 0x0, /* tdma off */
> +	CXECTL_B2 = 0x1, /* allow B2 (beacon-early) */
> +	CXECTL_EXT = 0x2,
> +	CXECTL_MAX
> +};
> +
> +union rtw89_btc_fbtc_rxflct {
> +	u8 val;
> +	u8 type: 3;
> +	u8 tgln_n: 5;
> +};
> +
> +enum rtw89_btc_cxst_state {
> +	CXST_OFF = 0x0,
> +	CXST_B2W = 0x1,
> +	CXST_W1 = 0x2,
> +	CXST_W2 = 0x3,
> +	CXST_W2B = 0x4,
> +	CXST_B1 = 0x5,
> +	CXST_B2 = 0x6,
> +	CXST_B3 = 0x7,
> +	CXST_B4 = 0x8,
> +	CXST_LK = 0x9,
> +	CXST_BLK = 0xa,
> +	CXST_E2G = 0xb,
> +	CXST_E5G = 0xc,
> +	CXST_EBT = 0xd,
> +	CXST_ENULL = 0xe,
> +	CXST_WLK = 0xf,
> +	CXST_W1FDD = 0x10,
> +	CXST_B1FDD = 0x11,
> +	CXST_MAX = 0x12,
> +};
> +
> +enum {
> +	CXBCN_ALL = 0x0,
> +	CXBCN_ALL_OK,
> +	CXBCN_BT_SLOT,
> +	CXBCN_BT_OK,
> +	CXBCN_MAX
> +};
> +
> +enum btc_slot_type {
> +	SLOT_MIX = 0x0, /* accept BT Lower-Pri Tx/Rx request 0x778 = 1 */
> +	SLOT_ISO = 0x1, /* no accept BT Lower-Pri Tx/Rx request 0x778 = d*/
> +	CXSTYPE_NUM,
> +};
> +
> +enum { /* TIME */
> +	CXT_BT = 0x0,
> +	CXT_WL = 0x1,
> +	CXT_MAX
> +};
> +
> +enum { /* TIME-A2DP */
> +	CXT_FLCTRL_OFF = 0x0,
> +	CXT_FLCTRL_ON = 0x1,
> +	CXT_FLCTRL_MAX
> +};
> +
> +enum { /* STEP TYPE */
> +	CXSTEP_NONE = 0x0,
> +	CXSTEP_EVNT = 0x1,
> +	CXSTEP_SLOT = 0x2,
> +	CXSTEP_MAX,
> +};
> +
> +#define FCXGPIODBG_VER 1
> +#define BTC_DBG_MAX1  32
> +struct rtw89_btc_fbtc_gpio_dbg {
> +	u8 fver;
> +	u8 rsvd;
> +	u16 rsvd2;
> +	u32 en_map; /* which debug signal (see btc_wl_gpio_debug) is enable */
> +	u32 pre_state; /* the debug signal is 1 or 0  */
> +	u8 gpio_map[BTC_DBG_MAX1]; /*the debug signals to GPIO-Position */
> +} __packed;
> +
> +#define FCXMREG_VER 1
> +struct rtw89_btc_fbtc_mreg_val {
> +	u8 fver;
> +	u8 reg_num;
> +	__le16 rsvd;
> +	__le32 mreg_val[CXMREG_MAX];
> +} __packed;
> +
> +#define RTW89_DEF_FBTC_MREG(__type, __bytes, __offset) \
> +	{ .type = cpu_to_le16(__type), .bytes = cpu_to_le16(__bytes), \
> +	  .offset = cpu_to_le32(__offset), }
> +
> +struct rtw89_btc_fbtc_mreg {
> +	__le16 type;
> +	__le16 bytes;
> +	__le32 offset;
> +} __packed;
> +
> +struct rtw89_btc_fbtc_slot {
> +	__le16 dur;
> +	__le32 cxtbl;
> +	__le16 cxtype;
> +} __packed;
> +
> +#define FCXSLOTS_VER 1
> +struct rtw89_btc_fbtc_slots {
> +	u8 fver;
> +	u8 tbl_num;
> +	__le16 rsvd;
> +	__le32 update_map;
> +	struct rtw89_btc_fbtc_slot slot[CXST_MAX];
> +} __packed;
> +
> +#define FCXSTEP_VER 2
> +struct rtw89_btc_fbtc_step {
> +	u8 type;
> +	u8 val;
> +	__le16 difft;
> +} __packed;
> +
> +struct rtw89_btc_fbtc_steps {
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 cnt;
> +	__le16 pos_old;
> +	__le16 pos_new;
> +	struct rtw89_btc_fbtc_step step[FCXMAX_STEP];
> +} __packed;
> +
> +#define FCXCYSTA_VER 2
> +struct rtw89_btc_fbtc_cysta { /* statistics for cycles */
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 cycles; /* total cycle number */
> +	__le16 cycles_a2dp[CXT_FLCTRL_MAX];
> +	__le16 a2dpept; /* a2dp empty cnt */
> +	__le16 a2dpeptto; /* a2dp empty timeout cnt*/
> +	__le16 tavg_cycle[CXT_MAX]; /* avg wl/bt cycle time */
> +	__le16 tmax_cycle[CXT_MAX]; /* max wl/bt cycle time */
> +	__le16 tmaxdiff_cycle[CXT_MAX]; /* max wl-wl bt-bt cycle diff time */
> +	__le16 tavg_a2dp[CXT_FLCTRL_MAX]; /* avg a2dp PSTDMA/TDMA time */
> +	__le16 tmax_a2dp[CXT_FLCTRL_MAX]; /* max a2dp PSTDMA/TDMA time */
> +	__le16 tavg_a2dpept; /* avg a2dp empty time */
> +	__le16 tmax_a2dpept; /* max a2dp empty time */
> +	__le16 tavg_lk; /* avg leak-slot time */
> +	__le16 tmax_lk; /* max leak-slot time */
> +	__le32 slot_cnt[CXST_MAX]; /* slot count */
> +	__le32 bcn_cnt[CXBCN_MAX];
> +	__le32 leakrx_cnt; /* the rximr occur at leak slot  */
> +	__le32 collision_cnt; /* counter for event/timer occur at same time */
> +	__le32 skip_cnt;
> +	__le32 exception;
> +	__le32 except_cnt;
> +#if (FCXCYSTA_VER > 1)
> +	__le16 tslot_cycle[BTC_CYCLE_SLOT_MAX];
> +#endif
> +} __packed;
> +
> +#define FCXNULLSTA_VER 1
> +struct rtw89_btc_fbtc_cynullsta { /* cycle null statistics */
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 rsvd2;
> +	__le32 max_t[2]; /* max_t for 0:null0/1:null1 */
> +	__le32 avg_t[2]; /* avg_t for 0:null0/1:null1 */
> +	__le32 result[2][4]; /* 0:fail, 1:ok, 2:on_time, 3:retry */
> +} __packed;
> +
> +#define FCX_BTVER_VER 1
> +struct rtw89_btc_fbtc_btver {
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 rsvd2;
> +	__le32 coex_ver; /*bit[15:8]->shared, bit[7:0]->non-shared */
> +	__le32 fw_ver;
> +	__le32 feature;
> +} __packed;
> +
> +#define FCX_BTSCAN_VER 1
> +struct rtw89_btc_fbtc_btscan {
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 rsvd2;
> +	u8 scan[6];
> +} __packed;
> +
> +#define FCX_BTAFH_VER 1
> +struct rtw89_btc_fbtc_btafh {
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 rsvd2;
> +	u8 afh_l[4]; /*bit0:2402, bit1: 2403.... bit31:2433 */
> +	u8 afh_m[4]; /*bit0:2434, bit1: 2435.... bit31:2465 */
> +	u8 afh_h[4]; /*bit0:2466, bit1:2467......bit14:2480 */
> +} __packed;
> +
> +#define FCX_BTDEVINFO_VER 1
> +struct rtw89_btc_fbtc_btdevinfo {
> +	u8 fver;
> +	u8 rsvd;
> +	__le16 vendor_id;
> +	__le32 dev_name; /* only 24 bits valid */
> +	__le32 flush_time;
> +} __packed;
> +
> +#define RTW89_BTC_WL_DEF_TX_PWR GENMASK(7, 0)
> +struct rtw89_btc_rf_trx_para {
> +	u32 wl_tx_power; /* absolute Tx power (dBm), 0xff-> no BTC control */
> +	u32 wl_rx_gain;  /* rx gain table index (TBD.) */
> +	u8 bt_tx_power; /* decrease Tx power (dB) */
> +	u8 bt_rx_gain;  /* LNA constrain level */
> +};
> +
> +struct rtw89_btc_dm {
> +	struct rtw89_btc_fbtc_slot slot[CXST_MAX];
> +	struct rtw89_btc_fbtc_slot slot_now[CXST_MAX];
> +	struct rtw89_btc_fbtc_tdma tdma;
> +	struct rtw89_btc_fbtc_tdma tdma_now;
> +	struct rtw89_mac_ax_coex_gnt gnt;
> +	struct rtw89_btc_init_info init_info; /* pass to wl_fw if offload */
> +	struct rtw89_btc_rf_trx_para rf_trx_para;
> +	struct rtw89_btc_wl_tx_limit_para wl_tx_limit;
> +	struct rtw89_btc_dm_step dm_step;
> +	union rtw89_btc_dm_error_map error;
> +	u32 cnt_dm[BTC_DCNT_NUM];
> +	u32 cnt_notify[BTC_NCNT_NUM];
> +
> +	u32 update_slot_map;
> +	u32 set_ant_path;
> +
> +	u32 wl_only: 1;
> +	u32 wl_fw_cx_offload: 1;
> +	u32 freerun: 1;
> +	u32 wl_ps_ctrl: 2;
> +	u32 wl_mimo_ps: 1;
> +	u32 leak_ap: 1;
> +	u32 noisy_level: 3;
> +	u32 coex_info_map: 8;
> +	u32 bt_only: 1;
> +	u32 wl_btg_rx: 1;
> +	u32 trx_para_level: 8;
> +	u32 rsvd: 4;
> +
> +	u16 slot_dur[CXST_MAX];
> +
> +	u8 run_reason;
> +	u8 run_action;
> +};
> +
> +struct rtw89_btc_ctrl {
> +	u32 manual: 1;
> +	u32 igno_bt: 1;
> +	u32 always_freerun: 1;
> +	u32 trace_step: 16;
> +	u32 rsvd: 12;
> +};
> +
> +struct rtw89_btc_dbg {
> +	/* cmd "rb" */
> +	bool rb_done;
> +	u32 rb_val;
> +};
> +
> +#define FCXTDMA_VER 1
> +
> +enum rtw89_btc_btf_fw_event {
> +	BTF_EVNT_RPT = 0,
> +	BTF_EVNT_BT_INFO = 1,
> +	BTF_EVNT_BT_SCBD = 2,
> +	BTF_EVNT_BT_REG = 3,
> +	BTF_EVNT_CX_RUNINFO = 4,
> +	BTF_EVNT_BT_PSD = 5,
> +	BTF_EVNT_BUF_OVERFLOW,
> +	BTF_EVNT_C2H_LOOPBACK,
> +	BTF_EVNT_MAX,
> +};
> +
> +enum btf_fw_event_report {
> +	BTC_RPT_TYPE_CTRL = 0x0,
> +	BTC_RPT_TYPE_TDMA,
> +	BTC_RPT_TYPE_SLOT,
> +	BTC_RPT_TYPE_CYSTA,
> +	BTC_RPT_TYPE_STEP,
> +	BTC_RPT_TYPE_NULLSTA,
> +	BTC_RPT_TYPE_MREG,
> +	BTC_RPT_TYPE_GPIO_DBG,
> +	BTC_RPT_TYPE_BT_VER,
> +	BTC_RPT_TYPE_BT_SCAN,
> +	BTC_RPT_TYPE_BT_AFH,
> +	BTC_RPT_TYPE_BT_DEVICE,
> +	BTC_RPT_TYPE_TEST,
> +	BTC_RPT_TYPE_MAX = 31
> +};
> +
> +enum rtw_btc_btf_reg_type {
> +	REG_MAC = 0x0,
> +	REG_BB = 0x1,
> +	REG_RF = 0x2,
> +	REG_BT_RF = 0x3,
> +	REG_BT_MODEM = 0x4,
> +	REG_BT_BLUEWIZE = 0x5,
> +	REG_BT_VENDOR = 0x6,
> +	REG_BT_LE = 0x7,
> +	REG_MAX_TYPE,
> +};
> +
> +struct rtw89_btc_rpt_cmn_info {
> +	u32 rx_cnt;
> +	u32 rx_len;
> +	u32 req_len; /* expected rsp len */
> +	u8 req_fver; /* expected rsp fver */
> +	u8 rsp_fver; /* fver from fw */
> +	u8 valid;
> +} __packed;
> +
> +struct rtw89_btc_report_ctrl_state {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_rpt_ctrl finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_tdma {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_tdma finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_slots {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_slots finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_cysta {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_cysta finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_step {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_steps finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_nullsta {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_cynullsta finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_mreg {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_mreg_val finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_gpio_dbg {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_gpio_dbg finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_btver {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_btver finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_btscan {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_btscan finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_btafh {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_btafh finfo; /* info from fw */
> +};
> +
> +struct rtw89_btc_rpt_fbtc_btdev {
> +	struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
> +	struct rtw89_btc_fbtc_btdevinfo finfo; /* info from fw */
> +};
> +
> +enum rtw89_btc_btfre_type {
> +	BTFRE_INVALID_INPUT = 0x0, /* invalid input parameters */
> +	BTFRE_UNDEF_TYPE,
> +	BTFRE_EXCEPTION,
> +	BTFRE_MAX,
> +};
> +
> +struct rtw89_btc_btf_fwinfo {
> +	u32 cnt_c2h;
> +	u32 cnt_h2c;
> +	u32 cnt_h2c_fail;
> +	u32 event[BTF_EVNT_MAX];
> +
> +	u32 err[BTFRE_MAX];
> +	u32 len_mismch;
> +	u32 fver_mismch;
> +	u32 rpt_en_map;
> +
> +	struct rtw89_btc_report_ctrl_state rpt_ctrl;
> +	struct rtw89_btc_rpt_fbtc_tdma rpt_fbtc_tdma;
> +	struct rtw89_btc_rpt_fbtc_slots rpt_fbtc_slots;
> +	struct rtw89_btc_rpt_fbtc_cysta rpt_fbtc_cysta;
> +	struct rtw89_btc_rpt_fbtc_step rpt_fbtc_step;
> +	struct rtw89_btc_rpt_fbtc_nullsta rpt_fbtc_nullsta;
> +	struct rtw89_btc_rpt_fbtc_mreg rpt_fbtc_mregval;
> +	struct rtw89_btc_rpt_fbtc_gpio_dbg rpt_fbtc_gpio_dbg;
> +	struct rtw89_btc_rpt_fbtc_btver rpt_fbtc_btver;
> +	struct rtw89_btc_rpt_fbtc_btscan rpt_fbtc_btscan;
> +	struct rtw89_btc_rpt_fbtc_btafh rpt_fbtc_btafh;
> +	struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev;
> +};
> +
> +#define RTW89_BTC_POLICY_MAXLEN 512
> +
> +struct rtw89_btc {
> +	struct rtw89_btc_cx cx;
> +	struct rtw89_btc_dm dm;
> +	struct rtw89_btc_ctrl ctrl;
> +	struct rtw89_btc_module mdinfo;
> +	struct rtw89_btc_btf_fwinfo fwinfo;
> +	struct rtw89_btc_dbg dbg;
> +
> +	struct work_struct eapol_notify_work;
> +	struct work_struct arp_notify_work;
> +	struct work_struct dhcp_notify_work;
> +	struct work_struct wl_sta_notify_work;
> +
> +	u32 bt_req_len;
> +
> +	u8 policy[RTW89_BTC_POLICY_MAXLEN];
> +	u16 policy_len;
> +	u16 policy_type;
> +	bool bt_req_en;
> +	bool update_policy_force;
> +	bool lps;
> +};
> +
> +enum rtw89_ra_mode {
> +	RTW89_RA_MODE_CCK = BIT(0),
> +	RTW89_RA_MODE_OFDM = BIT(1),
> +	RTW89_RA_MODE_HT = BIT(2),
> +	RTW89_RA_MODE_VHT = BIT(3),
> +	RTW89_RA_MODE_HE = BIT(4),
> +};
> +
> +enum rtw89_ra_report_mode {
> +	RTW89_RA_RPT_MODE_LEGACY,
> +	RTW89_RA_RPT_MODE_HT,
> +	RTW89_RA_RPT_MODE_VHT,
> +	RTW89_RA_RPT_MODE_HE,
> +};
> +
> +enum rtw89_dig_noisy_level {
> +	RTW89_DIG_NOISY_LEVEL0 = -1,
> +	RTW89_DIG_NOISY_LEVEL1 = 0,
> +	RTW89_DIG_NOISY_LEVEL2 = 1,
> +	RTW89_DIG_NOISY_LEVEL3 = 2,
> +	RTW89_DIG_NOISY_LEVEL_MAX = 3,
> +};
> +
> +enum rtw89_gi_ltf {
> +	RTW89_GILTF_LGI_4XHE32 = 0,
> +	RTW89_GILTF_SGI_4XHE08 = 1,
> +	RTW89_GILTF_2XHE16 = 2,
> +	RTW89_GILTF_2XHE08 = 3,
> +	RTW89_GILTF_1XHE16 = 4,
> +	RTW89_GILTF_1XHE08 = 5,
> +	RTW89_GILTF_MAX
> +};
> +
> +enum rtw89_rx_frame_type {
> +	RTW89_RX_TYPE_MGNT = 0,
> +	RTW89_RX_TYPE_CTRL = 1,
> +	RTW89_RX_TYPE_DATA = 2,
> +	RTW89_RX_TYPE_RSVD = 3,
> +};
> +
> +struct rtw89_ra_info {
> +	u8 is_dis_ra:1;
> +	/* Bit0 : CCK
> +	 * Bit1 : OFDM
> +	 * Bit2 : HT
> +	 * Bit3 : VHT
> +	 * Bit4 : HE
> +	 */
> +	u8 mode_ctrl:5;
> +	u8 bw_cap:2;
> +	u8 macid;
> +	u8 dcm_cap:1;
> +	u8 er_cap:1;
> +	u8 init_rate_lv:2;
> +	u8 upd_all:1;
> +	u8 en_sgi:1;
> +	u8 ldpc_cap:1;
> +	u8 stbc_cap:1;
> +	u8 ss_num:3;
> +	u8 giltf:3;
> +	u8 upd_bw_nss_mask:1;
> +	u8 upd_mask:1;
> +	u64 ra_mask; /* 63 bits ra_mask + 1 bit CSI ctrl */
> +	/* BFee CSI */
> +	u8 band_num;
> +	u8 ra_csi_rate_en:1;
> +	u8 fixed_csi_rate_en:1;
> +	u8 cr_tbl_sel:1;
> +	u8 rsvd2:5;
> +	u8 csi_mcs_ss_idx;
> +	u8 csi_mode:2;
> +	u8 csi_gi_ltf:3;
> +	u8 csi_bw:3;
> +};
> +
> +#define RTW89_PPDU_MAX_USR 4
> +#define RTW89_PPDU_MAC_INFO_USR_SIZE 4
> +#define RTW89_PPDU_MAC_INFO_SIZE 8
> +#define RTW89_PPDU_MAC_RX_CNT_SIZE 96
> +
> +#define RTW89_MAX_RX_AGG_NUM 64
> +#define RTW89_MAX_TX_AGG_NUM 128
> +
> +struct rtw89_ampdu_params {
> +	u16 agg_num;
> +	bool amsdu;
> +};
> +
> +struct rtw89_ra_report {
> +	struct rate_info txrate;
> +	u32 bit_rate;
> +	u16 hw_rate;
> +};
> +
> +DECLARE_EWMA(rssi, 10, 16);
> +
> +struct rtw89_sta {
> +	u8 mac_id;
> +	bool disassoc;
> +	struct rtw89_vif *rtwvif;
> +	struct rtw89_ra_info ra;
> +	struct rtw89_ra_report ra_report;
> +	int max_agg_wait;
> +	u8 prev_rssi;
> +	struct ewma_rssi avg_rssi;
> +	struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS];
> +	struct ieee80211_rx_status rx_status;
> +	u16 rx_hw_rate;
> +
> +	bool use_cfg_mask;
> +	struct cfg80211_bitrate_mask mask;
> +
> +	bool cctl_tx_time;
> +	u32 ampdu_max_time:4;
> +	bool cctl_tx_retry_limit;
> +	u32 data_tx_cnt_lmt:6;
> +};
> +
> +#define RTW89_MAX_ADDR_CAM_NUM		128
> +#define RTW89_MAX_BSSID_CAM_NUM		20
> +#define RTW89_MAX_SEC_CAM_NUM		128
> +#define RTW89_SEC_CAM_IN_ADDR_CAM	7
> +
> +struct rtw89_addr_cam_entry {
> +	u8 addr_cam_idx;
> +	u8 offset;
> +	u8 len;
> +	u8 valid	: 1;
> +	u8 addr_mask	: 6;
> +	u8 wapi		: 1;
> +	u8 mask_sel	: 2;
> +	u8 bssid_cam_idx: 6;
> +	u8 tma[ETH_ALEN];
> +	u8 sma[ETH_ALEN];
> +
> +	u8 sec_ent_mode;
> +	DECLARE_BITMAP(sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM);
> +	u8 sec_ent_keyid[RTW89_SEC_CAM_IN_ADDR_CAM];
> +	u8 sec_ent[RTW89_SEC_CAM_IN_ADDR_CAM];
> +	struct rtw89_sec_cam_entry *sec_entries[RTW89_SEC_CAM_IN_ADDR_CAM];
> +};
> +
> +struct rtw89_bssid_cam_entry {
> +	u8 bssid[ETH_ALEN];
> +	u8 phy_idx;
> +	u8 bssid_cam_idx;
> +	u8 offset;
> +	u8 len;
> +	u8 valid : 1;
> +	u8 num;
> +};
> +
> +struct rtw89_sec_cam_entry {
> +	u8 sec_cam_idx;
> +	u8 offset;
> +	u8 len;
> +	u8 type : 4;
> +	u8 ext_key : 1;
> +	u8 spp_mode : 1;
> +	/* 256 bits */
> +	u8 key[32];
> +};
> +
> +struct rtw89_efuse {
> +	bool valid;
> +	u8 xtal_cap;
> +	u8 addr[ETH_ALEN];
> +	u8 rfe_type;
> +	char country_code[2];
> +};
> +
> +struct rtw89_vif {
> +	struct list_head list;
> +	u8 mac_id;
> +	u8 port;
> +	u8 mac_addr[ETH_ALEN];
> +	u8 bssid[ETH_ALEN];
> +	u8 phy_idx;
> +	u8 mac_idx;
> +	u8 net_type;
> +	u8 wifi_role;
> +	u8 self_role;
> +	u8 wmm;
> +	u8 bcn_hit_cond;
> +	u8 hit_rule;
> +	bool trigger;
> +	bool lsig_txop;
> +	u8 tgt_ind;
> +	u8 frm_tgt_ind;
> +	bool wowlan_pattern;
> +	bool wowlan_uc;
> +	bool wowlan_magic;
> +	bool is_hesta;
> +	bool last_a_ctrl;
> +	union {
> +		struct {
> +			struct ieee80211_sta *ap;
> +		} mgd;
> +		struct {
> +			struct list_head sta_list;
> +		} ap;
> +	};
> +	struct rtw89_addr_cam_entry addr_cam;
> +	struct rtw89_bssid_cam_entry bssid_cam;
> +	struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS];
> +	struct rtw89_traffic_stats stats;
> +};
> +
> +enum rtw89_lv1_rcvy_step {
> +	RTW89_LV1_RCVY_STEP_1,
> +	RTW89_LV1_RCVY_STEP_2,
> +};
> +
> +struct rtw89_hci_ops {
> +	int (*tx_write)(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req);
> +	void (*tx_kick_off)(struct rtw89_dev *rtwdev, u8 txch);
> +	void (*flush_queues)(struct rtw89_dev *rtwdev, u32 queues, bool drop);
> +	void (*reset)(struct rtw89_dev *rtwdev);
> +	int (*start)(struct rtw89_dev *rtwdev);
> +	void (*stop)(struct rtw89_dev *rtwdev);
> +	void (*link_ps)(struct rtw89_dev *rtwdev, bool enter);
> +
> +	u8 (*read8)(struct rtw89_dev *rtwdev, u32 addr);
> +	u16 (*read16)(struct rtw89_dev *rtwdev, u32 addr);
> +	u32 (*read32)(struct rtw89_dev *rtwdev, u32 addr);
> +	void (*write8)(struct rtw89_dev *rtwdev, u32 addr, u8 data);
> +	void (*write16)(struct rtw89_dev *rtwdev, u32 addr, u16 data);
> +	void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data);
> +
> +	int (*mac_pre_init)(struct rtw89_dev *rtwdev);
> +	int (*mac_post_init)(struct rtw89_dev *rtwdev);
> +	int (*deinit)(struct rtw89_dev *rtwdev);
> +
> +	u32 (*check_and_reclaim_tx_resource)(struct rtw89_dev *rtwdev, u8 txch);
> +	int (*mac_lv1_rcvy)(struct rtw89_dev *rtwdev, enum rtw89_lv1_rcvy_step step);
> +	void (*dump_err_status)(struct rtw89_dev *rtwdev);
> +	int (*napi_poll)(struct napi_struct *napi, int budget);
> +};
> +
> +struct rtw89_hci_info {
> +	const struct rtw89_hci_ops *ops;
> +	enum rtw89_hci_type type;
> +	u32 rpwm_addr;
> +	u32 cpwm_addr;
> +};
> +
> +struct rtw89_chip_ops {
> +	void (*bb_reset)(struct rtw89_dev *rtwdev,
> +			 enum rtw89_phy_idx phy_idx);
> +	void (*bb_sethw)(struct rtw89_dev *rtwdev);
> +	u32 (*read_rf)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
> +		       u32 addr, u32 mask);
> +	bool (*write_rf)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
> +			 u32 addr, u32 mask, u32 data);
> +	void (*set_channel)(struct rtw89_dev *rtwdev,
> +			    struct rtw89_channel_params *param);
> +	void (*set_channel_help)(struct rtw89_dev *rtwdev, bool enter,
> +				 struct rtw89_channel_help_params *p);
> +	int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map);
> +	int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map);
> +	void (*fem_setup)(struct rtw89_dev *rtwdev);
> +	void (*rfk_init)(struct rtw89_dev *rtwdev);
> +	void (*rfk_channel)(struct rtw89_dev *rtwdev);
> +	void (*rfk_band_changed)(struct rtw89_dev *rtwdev);
> +	void (*rfk_track)(struct rtw89_dev *rtwdev);
> +	void (*power_trim)(struct rtw89_dev *rtwdev);
> +	void (*set_txpwr)(struct rtw89_dev *rtwdev);
> +	void (*set_txpwr_ctrl)(struct rtw89_dev *rtwdev);
> +	int (*init_txpwr_unit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
> +	u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path);
> +	void (*ctrl_btg)(struct rtw89_dev *rtwdev, bool btg);
> +	void (*query_ppdu)(struct rtw89_dev *rtwdev,
> +			   struct rtw89_rx_phy_ppdu *phy_ppdu,
> +			   struct ieee80211_rx_status *status);
> +	void (*bb_ctrl_btc_preagc)(struct rtw89_dev *rtwdev, bool bt_en);
> +	void (*set_txpwr_ul_tb_offset)(struct rtw89_dev *rtwdev,
> +				       s16 pw_ofst, enum rtw89_mac_idx mac_idx);
> +
> +	void (*btc_set_rfe)(struct rtw89_dev *rtwdev);
> +	void (*btc_init_cfg)(struct rtw89_dev *rtwdev);
> +	void (*btc_set_wl_pri)(struct rtw89_dev *rtwdev, u8 map, bool state);
> +	void (*btc_set_wl_txpwr_ctrl)(struct rtw89_dev *rtwdev, u32 txpwr_val);
> +	s8 (*btc_get_bt_rssi)(struct rtw89_dev *rtwdev, s8 val);
> +	void (*btc_bt_aci_imp)(struct rtw89_dev *rtwdev);
> +	void (*btc_update_bt_cnt)(struct rtw89_dev *rtwdev);
> +};
> +
> +enum rtw89_dma_ch {
> +	RTW89_DMA_ACH0 = 0,
> +	RTW89_DMA_ACH1 = 1,
> +	RTW89_DMA_ACH2 = 2,
> +	RTW89_DMA_ACH3 = 3,
> +	RTW89_DMA_ACH4 = 4,
> +	RTW89_DMA_ACH5 = 5,
> +	RTW89_DMA_ACH6 = 6,
> +	RTW89_DMA_ACH7 = 7,
> +	RTW89_DMA_B0MG = 8,
> +	RTW89_DMA_B0HI = 9,
> +	RTW89_DMA_B1MG = 10,
> +	RTW89_DMA_B1HI = 11,
> +	RTW89_DMA_H2C = 12,
> +	RTW89_DMA_CH_NUM = 13
> +};
> +
> +enum rtw89_qta_mode {
> +	RTW89_QTA_SCC,
> +	RTW89_QTA_DBCC,
> +	RTW89_QTA_SCC_WD128,
> +	RTW89_QTA_DBCC_WD128,
> +	RTW89_QTA_SCC_STF,
> +	RTW89_QTA_DBCC_STF,
> +	RTW89_QTA_SU_TP,
> +	RTW89_QTA_DLFW,
> +	RTW89_QTA_BCN_TEST,
> +	RTW89_QTA_LAMODE,
> +
> +	/* keep last */
> +	RTW89_QTA_INVALID,
> +};
> +
> +struct rtw89_hfc_ch_cfg {
> +	u16 min;
> +	u16 max;
> +#define grp_0 0
> +#define grp_1 1
> +#define grp_num 2
> +	u8 grp;
> +};
> +
> +struct rtw89_hfc_ch_info {
> +	u16 aval;
> +	u16 used;
> +};
> +
> +struct rtw89_hfc_pub_cfg {
> +	u16 grp0;
> +	u16 grp1;
> +	u16 pub_max;
> +	u16 wp_thrd;
> +};
> +
> +struct rtw89_hfc_pub_info {
> +	u16 g0_used;
> +	u16 g1_used;
> +	u16 g0_aval;
> +	u16 g1_aval;
> +	u16 pub_aval;
> +	u16 wp_aval;
> +};
> +
> +struct rtw89_hfc_prec_cfg {
> +	u16 ch011_prec;
> +	u16 h2c_prec;
> +	u16 wp_ch07_prec;
> +	u16 wp_ch811_prec;
> +	u8 ch011_full_cond;
> +	u8 h2c_full_cond;
> +	u8 wp_ch07_full_cond;
> +	u8 wp_ch811_full_cond;
> +};
> +
> +struct rtw89_hfc_param {
> +	bool en;
> +	bool h2c_en;
> +	u8 mode;
> +	struct rtw89_hfc_ch_cfg *ch_cfg;
> +	struct rtw89_hfc_ch_info ch_info[RTW89_DMA_CH_NUM];
> +	struct rtw89_hfc_pub_cfg *pub_cfg;
> +	struct rtw89_hfc_pub_info pub_info;
> +	struct rtw89_hfc_prec_cfg *prec_cfg;
> +};
> +
> +struct rtw89_hfc_param_ini {
> +	struct rtw89_hfc_ch_cfg *ch_cfg;
> +	struct rtw89_hfc_pub_cfg *pub_cfg;
> +	struct rtw89_hfc_prec_cfg *prec_cfg;
> +	u8 mode;
> +};
> +
> +struct rtw89_dle_size {
> +	u16 pge_size;
> +	u16 lnk_pge_num;
> +	u16 unlnk_pge_num;
> +};
> +
> +struct rtw89_wde_quota {
> +	u16 hif;
> +	u16 wcpu;
> +	u16 pkt_in;
> +	u16 cpu_io;
> +};
> +
> +struct rtw89_ple_quota {
> +	u16 cma0_tx;
> +	u16 cma1_tx;
> +	u16 c2h;
> +	u16 h2c;
> +	u16 wcpu;
> +	u16 mpdu_proc;
> +	u16 cma0_dma;
> +	u16 cma1_dma;
> +	u16 bb_rpt;
> +	u16 wd_rel;
> +	u16 cpu_io;
> +};
> +
> +struct rtw89_dle_mem {
> +	enum rtw89_qta_mode mode;
> +	struct rtw89_dle_size *wde_size;
> +	struct rtw89_dle_size *ple_size;
> +	struct rtw89_wde_quota *wde_min_qt;
> +	struct rtw89_wde_quota *wde_max_qt;
> +	struct rtw89_ple_quota *ple_min_qt;
> +	struct rtw89_ple_quota *ple_max_qt;
> +};
> +
> +struct rtw89_reg_def {
> +	u32 addr;
> +	u32 mask;
> +};
> +
> +struct rtw89_reg2_def {
> +	u32 addr;
> +	u32 data;
> +};
> +
> +struct rtw89_reg3_def {
> +	u32 addr;
> +	u32 mask;
> +	u32 data;
> +};
> +
> +struct rtw89_reg5_def {
> +	u8 flag; /* recognized by parsers */
> +	u8 path;
> +	u32 addr;
> +	u32 mask;
> +	u32 data;
> +};
> +
> +struct rtw89_phy_table {
> +	const struct rtw89_reg2_def *regs;
> +	u32 n_regs;
> +	enum rtw89_rf_path rf_path;
> +};
> +
> +struct rtw89_txpwr_table {
> +	const void *data;
> +	u32 size;
> +	void (*load)(struct rtw89_dev *rtwdev,
> +		     const struct rtw89_txpwr_table *tbl);
> +};
> +
> +struct rtw89_chip_info {
> +	enum rtw89_core_chip_id chip_id;
> +	const struct rtw89_chip_ops *ops;
> +	const char *fw_name;
> +	u32 fifo_size;
> +	u32 dle_lamode_size;
> +	u16 max_amsdu_limit;
> +	struct rtw89_hfc_param_ini *hfc_param_ini;
> +	struct rtw89_dle_mem *dle_mem;
> +	u32 rf_base_addr[2];
> +	u8 rf_path_num;
> +	u8 tx_nss;
> +	u8 rx_nss;
> +	u8 acam_num;
> +	u8 bcam_num;
> +	u8 scam_num;
> +
> +	u8 sec_ctrl_efuse_size;
> +	u32 physical_efuse_size;
> +	u32 logical_efuse_size;
> +	u32 limit_efuse_size;
> +	u32 phycap_addr;
> +	u32 phycap_size;
> +
> +	const struct rtw89_pwr_cfg * const *pwr_on_seq;
> +	const struct rtw89_pwr_cfg * const *pwr_off_seq;
> +	const struct rtw89_phy_table *bb_table;
> +	const struct rtw89_phy_table *rf_table[RF_PATH_MAX];
> +	const struct rtw89_phy_table *nctl_table;
> +	const struct rtw89_txpwr_table *byr_table;
> +	const struct rtw89_phy_dig_gain_table *dig_table;
> +	const s8 (*txpwr_lmt_2g)[RTW89_2G_BW_NUM][RTW89_NTX_NUM]
> +				[RTW89_RS_LMT_NUM][RTW89_BF_NUM]
> +				[RTW89_REGD_NUM][RTW89_2G_CH_NUM];
> +	const s8 (*txpwr_lmt_5g)[RTW89_5G_BW_NUM][RTW89_NTX_NUM]
> +				[RTW89_RS_LMT_NUM][RTW89_BF_NUM]
> +				[RTW89_REGD_NUM][RTW89_5G_CH_NUM];
> +	const s8 (*txpwr_lmt_ru_2g)[RTW89_RU_NUM][RTW89_NTX_NUM]
> +				   [RTW89_REGD_NUM][RTW89_2G_CH_NUM];
> +	const s8 (*txpwr_lmt_ru_5g)[RTW89_RU_NUM][RTW89_NTX_NUM]
> +				   [RTW89_REGD_NUM][RTW89_5G_CH_NUM];
> +
> +	u8 txpwr_factor_rf;
> +	u8 txpwr_factor_mac;
> +
> +	u32 para_ver;
> +	u32 wlcx_desired;
> +	u8 btcx_desired;
> +	u8 scbd;
> +	u8 mailbox;
> +
> +	u8 afh_guard_ch;
> +
> +	u8 mon_reg_num;
> +	const struct rtw89_btc_fbtc_mreg *mon_reg;
> +	u8 rf_para_ulink_num;
> +	const struct rtw89_btc_rf_trx_para *rf_para_ulink;
> +	u8 rf_para_dlink_num;
> +	const struct rtw89_btc_rf_trx_para *rf_para_dlink;
> +	u8 ps_mode_supported;
> +};
> +
> +enum rtw89_hcifc_mode {
> +	RTW89_HCIFC_POH = 0,
> +	RTW89_HCIFC_STF = 1,
> +	RTW89_HCIFC_SDIO = 2,
> +
> +	/* keep last */
> +	RTW89_HCIFC_MODE_INVALID,
> +};
> +
> +struct rtw89_dle_info {
> +	enum rtw89_qta_mode qta_mode;
> +	u16 wde_pg_size;
> +	u16 ple_pg_size;
> +	u16 c0_rx_qta;
> +	u16 c1_rx_qta;
> +};
> +
> +enum rtw89_host_rpr_mode {
> +	RTW89_RPR_MODE_POH = 0,
> +	RTW89_RPR_MODE_STF
> +};
> +
> +struct rtw89_mac_info {
> +	struct rtw89_dle_info dle_info;
> +	struct rtw89_hfc_param hfc_param;
> +	enum rtw89_qta_mode qta_mode;
> +	u8 rpwm_seq_num;
> +	u8 cpwm_seq_num;
> +};
> +
> +enum rtw89_fw_type {
> +	RTW89_FW_NORMAL = 1,
> +	RTW89_FW_WOWLAN = 3,
> +};
> +
> +struct rtw89_fw_suit {
> +	const u8 *data;
> +	u32 size;
> +	u8 major_ver;
> +	u8 minor_ver;
> +	u8 sub_ver;
> +	u8 sub_idex;
> +	u16 build_year;
> +	u16 build_mon;
> +	u16 build_date;
> +	u16 build_hour;
> +	u16 build_min;
> +	u8 cmd_ver;
> +};
> +
> +struct rtw89_fw_info {
> +	const struct firmware *firmware;
> +	struct rtw89_dev *rtwdev;
> +	struct completion completion;
> +	u8 h2c_seq;
> +	u8 rec_seq;
> +	struct rtw89_fw_suit normal;
> +	struct rtw89_fw_suit wowlan;
> +	bool fw_log_enable;
> +};
> +
> +struct rtw89_cam_info {
> +	DECLARE_BITMAP(addr_cam_map, RTW89_MAX_ADDR_CAM_NUM);
> +	DECLARE_BITMAP(bssid_cam_map, RTW89_MAX_BSSID_CAM_NUM);
> +	DECLARE_BITMAP(sec_cam_map, RTW89_MAX_SEC_CAM_NUM);
> +};
> +
> +enum rtw89_sar_sources {
> +	RTW89_SAR_SOURCE_NONE,
> +	RTW89_SAR_SOURCE_COMMON,
> +
> +	RTW89_SAR_SOURCE_NR,
> +};
> +
> +struct rtw89_sar_cfg_common {
> +	bool set[RTW89_SUBBAND_NR];
> +	s32 cfg[RTW89_SUBBAND_NR];
> +};
> +
> +struct rtw89_sar_info {
> +	/* used to decide how to acces SAR cfg union */
> +	enum rtw89_sar_sources src;
> +
> +	/* reserved for different knids of SAR cfg struct.
> +	 * supposed that a single cfg struct cannot handle various SAR sources.
> +	 */
> +	union {
> +		struct rtw89_sar_cfg_common cfg_common;
> +	};
> +};
> +
> +struct rtw89_hal {
> +	u32 rx_fltr;
> +	u8 cv;
> +	u8 current_channel;
> +	u8 current_primary_channel;
> +	enum rtw89_subband current_subband;
> +	u8 current_band_width;
> +	u8 current_band_type;
> +	/* center channel for different available bandwidth,
> +	 * val of (bw > current_band_width) is invalid
> +	 */
> +	u8 cch_by_bw[RTW89_MAX_CHANNEL_WIDTH + 1];
> +	u32 sw_amsdu_max_size;
> +	u32 antenna_tx;
> +	u32 antenna_rx;
> +};
> +
> +#define RTW89_MAX_MAC_ID_NUM 128
> +
> +enum rtw89_flags {
> +	RTW89_FLAG_POWERON,
> +	RTW89_FLAG_FW_RDY,
> +	RTW89_FLAG_RUNNING,
> +	RTW89_FLAG_BFEE_MON,
> +	RTW89_FLAG_BFEE_EN,
> +	RTW89_FLAG_NAPI_RUNNING,
> +	RTW89_FLAG_LEISURE_PS,
> +	RTW89_FLAG_LOW_POWER_MODE,
> +	RTW89_FLAG_INACTIVE_PS,
> +
> +	NUM_OF_RTW89_FLAGS,
> +};
> +
> +struct rtw89_pkt_stat {
> +	u16 beacon_nr;
> +	u32 rx_rate_cnt[RTW89_HW_RATE_NR];
> +};
> +
> +DECLARE_EWMA(thermal, 4, 4);
> +
> +struct rtw89_phy_stat {
> +	struct ewma_thermal avg_thermal[RF_PATH_MAX];
> +	struct rtw89_pkt_stat cur_pkt_stat;
> +	struct rtw89_pkt_stat last_pkt_stat;
> +};
> +
> +#define RTW89_DACK_PATH_NR 2
> +#define RTW89_DACK_IDX_NR 2
> +#define RTW89_DACK_MSBK_NR 16
> +struct rtw89_dack_info {
> +	bool dack_done;
> +	u8 msbk_d[RTW89_DACK_PATH_NR][RTW89_DACK_IDX_NR][RTW89_DACK_MSBK_NR];
> +	u8 dadck_d[RTW89_DACK_PATH_NR][RTW89_DACK_IDX_NR];
> +	u16 addck_d[RTW89_DACK_PATH_NR][RTW89_DACK_IDX_NR];
> +	u16 biask_d[RTW89_DACK_PATH_NR][RTW89_DACK_IDX_NR];
> +	u32 dack_cnt;
> +	bool addck_timeout[RTW89_DACK_PATH_NR];
> +	bool dadck_timeout[RTW89_DACK_PATH_NR];
> +	bool msbk_timeout[RTW89_DACK_PATH_NR];
> +};
> +
> +#define RTW89_IQK_CHS_NR 2
> +#define RTW89_IQK_PATH_NR 4
> +struct rtw89_iqk_info {
> +	bool lok_cor_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
> +	bool lok_fin_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
> +	bool iqk_tx_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
> +	bool iqk_rx_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
> +	u32 iqk_fail_cnt;
> +	bool is_iqk_init;
> +	u32 iqk_channel[RTW89_IQK_CHS_NR];
> +	u8 iqk_band[RTW89_IQK_PATH_NR];
> +	u8 iqk_ch[RTW89_IQK_PATH_NR];
> +	u8 iqk_bw[RTW89_IQK_PATH_NR];
> +	u8 kcount;
> +	u8 iqk_times;
> +	u8 version;
> +	u32 nb_txcfir[RTW89_IQK_PATH_NR];
> +	u32 nb_rxcfir[RTW89_IQK_PATH_NR];
> +	u32 bp_txkresult[RTW89_IQK_PATH_NR];
> +	u32 bp_rxkresult[RTW89_IQK_PATH_NR];
> +	u32 bp_iqkenable[RTW89_IQK_PATH_NR];
> +	bool is_wb_txiqk[RTW89_IQK_PATH_NR];
> +	bool is_wb_rxiqk[RTW89_IQK_PATH_NR];
> +	bool is_nbiqk;
> +	bool iqk_fft_en;
> +	bool iqk_xym_en;
> +	bool iqk_sram_en;
> +	bool iqk_cfir_en;
> +	u8 thermal[RTW89_IQK_PATH_NR];
> +	bool thermal_rek_en;
> +	u32 syn1to2;
> +	u8 iqk_mcc_ch[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
> +	u8 iqk_table_idx[RTW89_IQK_PATH_NR];
> +};
> +
> +#define RTW89_DPK_RF_PATH 2
> +#define RTW89_DPK_AVG_THERMAL_NUM 8
> +#define RTW89_DPK_BKUP_NUM 2
> +struct rtw89_dpk_bkup_para {
> +	enum rtw89_band band;
> +	enum rtw89_bandwidth bw;
> +	u8 ch;
> +	bool path_ok;
> +	u8 txagc_dpk;
> +	u8 ther_dpk;
> +	u8 gs;
> +	u16 pwsf;
> +};
> +
> +struct rtw89_dpk_info {
> +	bool is_dpk_enable;
> +	bool is_dpk_reload_en;
> +	u16 dc_i[RTW89_DPK_RF_PATH];
> +	u16 dc_q[RTW89_DPK_RF_PATH];
> +	u8 corr_val[RTW89_DPK_RF_PATH];
> +	u8 corr_idx[RTW89_DPK_RF_PATH];
> +	u8 cur_idx[RTW89_DPK_RF_PATH];
> +	struct rtw89_dpk_bkup_para bp[RTW89_DPK_RF_PATH][RTW89_DPK_BKUP_NUM];
> +};
> +
> +struct rtw89_fem_info {
> +	bool elna_2g;
> +	bool elna_5g;
> +	bool epa_2g;
> +	bool epa_5g;
> +};
> +
> +struct rtw89_phy_ch_info {
> +	u8 rssi_min;
> +	u16 rssi_min_macid;
> +	u8 pre_rssi_min;
> +	u8 rssi_max;
> +	u16 rssi_max_macid;
> +	u8 rxsc_160;
> +	u8 rxsc_80;
> +	u8 rxsc_40;
> +	u8 rxsc_20;
> +	u8 rxsc_l;
> +	u8 is_noisy;
> +};
> +
> +struct rtw89_agc_gaincode_set {
> +	u8 lna_idx;
> +	u8 tia_idx;
> +	u8 rxb_idx;
> +};
> +
> +#define IGI_RSSI_TH_NUM 5
> +#define FA_TH_NUM 4
> +#define LNA_GAIN_NUM 7
> +#define TIA_GAIN_NUM 2
> +struct rtw89_dig_info {
> +	struct rtw89_agc_gaincode_set cur_gaincode;
> +	bool force_gaincode_idx_en;
> +	struct rtw89_agc_gaincode_set force_gaincode;
> +	u8 igi_rssi_th[IGI_RSSI_TH_NUM];
> +	u16 fa_th[FA_TH_NUM];
> +	u8 igi_rssi;
> +	u8 igi_fa_rssi;
> +	u8 fa_rssi_ofst;
> +	u8 dyn_igi_max;
> +	u8 dyn_igi_min;
> +	bool dyn_pd_th_en;
> +	u8 dyn_pd_th_max;
> +	u8 pd_low_th_ofst;
> +	u8 ib_pbk;
> +	s8 ib_pkpwr;
> +	s8 lna_gain_a[LNA_GAIN_NUM];
> +	s8 lna_gain_g[LNA_GAIN_NUM];
> +	s8 *lna_gain;
> +	s8 tia_gain_a[TIA_GAIN_NUM];
> +	s8 tia_gain_g[TIA_GAIN_NUM];
> +	s8 *tia_gain;
> +	bool is_linked_pre;
> +};
> +
> +enum rtw89_multi_cfo_mode {
> +	RTW89_PKT_BASED_AVG_MODE = 0,
> +	RTW89_ENTRY_BASED_AVG_MODE = 1,
> +	RTW89_TP_BASED_AVG_MODE = 2,
> +};
> +
> +enum rtw89_phy_cfo_status {
> +	RTW89_PHY_DCFO_STATE_NORMAL = 0,
> +	RTW89_PHY_DCFO_STATE_ENHANCE = 1,
> +	RTW89_PHY_DCFO_STATE_MAX
> +};
> +
> +struct rtw89_cfo_tracking_info {
> +	u16 cfo_timer_ms;
> +	bool cfo_trig_by_timer_en;
> +	enum rtw89_phy_cfo_status phy_cfo_status;
> +	u8 phy_cfo_trk_cnt;
> +	bool is_adjust;
> +	enum rtw89_multi_cfo_mode rtw89_multi_cfo_mode;
> +	bool apply_compensation;
> +	u8 crystal_cap;
> +	u8 crystal_cap_default;
> +	u8 def_x_cap;
> +	s8 x_cap_ofst;
> +	u32 sta_cfo_tolerance;
> +	s32 cfo_tail[CFO_TRACK_MAX_USER];
> +	u16 cfo_cnt[CFO_TRACK_MAX_USER];
> +	s32 cfo_avg_pre;
> +	s32 cfo_avg[CFO_TRACK_MAX_USER];
> +	s32 pre_cfo_avg[CFO_TRACK_MAX_USER];
> +	u32 packet_count;
> +	u32 packet_count_pre;
> +	s32 residual_cfo_acc;
> +	u8 phy_cfotrk_state;
> +	u8 phy_cfotrk_cnt;
> +};
> +
> +/* 2GL, 2GH, 5GL1, 5GH1, 5GM1, 5GM2, 5GH1, 5GH2 */
> +#define TSSI_TRIM_CH_GROUP_NUM 8
> +
> +#define TSSI_CCK_CH_GROUP_NUM 6
> +#define TSSI_MCS_2G_CH_GROUP_NUM 5
> +#define TSSI_MCS_5G_CH_GROUP_NUM 14
> +#define TSSI_MCS_CH_GROUP_NUM \
> +	(TSSI_MCS_2G_CH_GROUP_NUM + TSSI_MCS_5G_CH_GROUP_NUM)
> +
> +struct rtw89_tssi_info {
> +	u8 thermal[RF_PATH_MAX];
> +	s8 tssi_trim[RF_PATH_MAX][TSSI_TRIM_CH_GROUP_NUM];
> +	s8 tssi_cck[RF_PATH_MAX][TSSI_CCK_CH_GROUP_NUM];
> +	s8 tssi_mcs[RF_PATH_MAX][TSSI_MCS_CH_GROUP_NUM];
> +	s8 extra_ofst[RF_PATH_MAX];
> +	bool tssi_tracking_check[RF_PATH_MAX];
> +	u8 default_txagc_offset[RF_PATH_MAX];
> +	u32 base_thermal[RF_PATH_MAX];
> +};
> +
> +struct rtw89_power_trim_info {
> +	bool pg_thermal_trim;
> +	bool pg_pa_bias_trim;
> +	u8 thermal_trim[RF_PATH_MAX];
> +	u8 pa_bias_trim[RF_PATH_MAX];
> +};
> +
> +struct rtw89_regulatory {
> +	char alpha2[3];
> +	u8 txpwr_regd[RTW89_BAND_MAX];
> +};
> +
> +enum rtw89_ifs_clm_application {
> +	RTW89_IFS_CLM_INIT = 0,
> +	RTW89_IFS_CLM_BACKGROUND = 1,
> +	RTW89_IFS_CLM_ACS = 2,
> +	RTW89_IFS_CLM_DIG = 3,
> +	RTW89_IFS_CLM_TDMA_DIG = 4,
> +	RTW89_IFS_CLM_DBG = 5,
> +	RTW89_IFS_CLM_DBG_MANUAL = 6
> +};
> +
> +enum rtw89_env_racing_lv {
> +	RTW89_RAC_RELEASE = 0,
> +	RTW89_RAC_LV_1 = 1,
> +	RTW89_RAC_LV_2 = 2,
> +	RTW89_RAC_LV_3 = 3,
> +	RTW89_RAC_LV_4 = 4,
> +	RTW89_RAC_MAX_NUM = 5
> +};
> +
> +struct rtw89_ccx_para_info {
> +	enum rtw89_env_racing_lv rac_lv;
> +	u16 mntr_time;
> +	u8 nhm_manual_th_ofst;
> +	u8 nhm_manual_th0;
> +	enum rtw89_ifs_clm_application ifs_clm_app;
> +	u32 ifs_clm_manual_th_times;
> +	u32 ifs_clm_manual_th0;
> +	u8 fahm_manual_th_ofst;
> +	u8 fahm_manual_th0;
> +	u8 fahm_numer_opt;
> +	u8 fahm_denom_opt;
> +};
> +
> +enum rtw89_ccx_edcca_opt_sc_idx {
> +	RTW89_CCX_EDCCA_SEG0_P0 = 0,
> +	RTW89_CCX_EDCCA_SEG0_S1 = 1,
> +	RTW89_CCX_EDCCA_SEG0_S2 = 2,
> +	RTW89_CCX_EDCCA_SEG0_S3 = 3,
> +	RTW89_CCX_EDCCA_SEG1_P0 = 4,
> +	RTW89_CCX_EDCCA_SEG1_S1 = 5,
> +	RTW89_CCX_EDCCA_SEG1_S2 = 6,
> +	RTW89_CCX_EDCCA_SEG1_S3 = 7
> +};
> +
> +enum rtw89_ccx_edcca_opt_bw_idx {
> +	RTW89_CCX_EDCCA_BW20_0 = 0,
> +	RTW89_CCX_EDCCA_BW20_1 = 1,
> +	RTW89_CCX_EDCCA_BW20_2 = 2,
> +	RTW89_CCX_EDCCA_BW20_3 = 3,
> +	RTW89_CCX_EDCCA_BW20_4 = 4,
> +	RTW89_CCX_EDCCA_BW20_5 = 5,
> +	RTW89_CCX_EDCCA_BW20_6 = 6,
> +	RTW89_CCX_EDCCA_BW20_7 = 7
> +};
> +
> +#define RTW89_NHM_TH_NUM 11
> +#define RTW89_FAHM_TH_NUM 11
> +#define RTW89_NHM_RPT_NUM 12
> +#define RTW89_FAHM_RPT_NUM 12
> +#define RTW89_IFS_CLM_NUM 4
> +struct rtw89_env_monitor_info {
> +	u32 ccx_trigger_time;
> +	u64 start_time;
> +	u8 ccx_rpt_stamp;
> +	u8 ccx_watchdog_result;
> +	bool ccx_ongoing;
> +	u8 ccx_rac_lv;
> +	bool ccx_manual_ctrl;
> +	u8 ccx_pre_rssi;
> +	u16 clm_mntr_time;
> +	u16 nhm_mntr_time;
> +	u16 ifs_clm_mntr_time;
> +	enum rtw89_ifs_clm_application ifs_clm_app;
> +	u16 fahm_mntr_time;
> +	u16 edcca_clm_mntr_time;
> +	u16 ccx_period;
> +	u8 ccx_unit_idx;
> +	enum rtw89_ccx_edcca_opt_bw_idx ccx_edcca_opt_bw_idx;
> +	u8 nhm_th[RTW89_NHM_TH_NUM];
> +	u16 ifs_clm_th_l[RTW89_IFS_CLM_NUM];
> +	u16 ifs_clm_th_h[RTW89_IFS_CLM_NUM];
> +	u8 fahm_numer_opt;
> +	u8 fahm_denom_opt;
> +	u8 fahm_th[RTW89_FAHM_TH_NUM];
> +	u16 clm_result;
> +	u16 nhm_result[RTW89_NHM_RPT_NUM];
> +	u8 nhm_wgt[RTW89_NHM_RPT_NUM];
> +	u16 nhm_tx_cnt;
> +	u16 nhm_cca_cnt;
> +	u16 nhm_idle_cnt;
> +	u16 ifs_clm_tx;
> +	u16 ifs_clm_edcca_excl_cca;
> +	u16 ifs_clm_ofdmfa;
> +	u16 ifs_clm_ofdmcca_excl_fa;
> +	u16 ifs_clm_cckfa;
> +	u16 ifs_clm_cckcca_excl_fa;
> +	u16 ifs_clm_total_ifs;
> +	u8 ifs_clm_his[RTW89_IFS_CLM_NUM];
> +	u16 ifs_clm_avg[RTW89_IFS_CLM_NUM];
> +	u16 ifs_clm_cca[RTW89_IFS_CLM_NUM];
> +	u16 fahm_result[RTW89_FAHM_RPT_NUM];
> +	u16 fahm_denom_result;
> +	u16 edcca_clm_result;
> +	u8 clm_ratio;
> +	u8 nhm_rpt[RTW89_NHM_RPT_NUM];
> +	u8 nhm_tx_ratio;
> +	u8 nhm_cca_ratio;
> +	u8 nhm_idle_ratio;
> +	u8 nhm_ratio;
> +	u16 nhm_result_sum;
> +	u8 nhm_pwr;
> +	u8 ifs_clm_tx_ratio;
> +	u8 ifs_clm_edcca_excl_cca_ratio;
> +	u8 ifs_clm_cck_fa_ratio;
> +	u8 ifs_clm_ofdm_fa_ratio;
> +	u8 ifs_clm_cck_cca_excl_fa_ratio;
> +	u8 ifs_clm_ofdm_cca_excl_fa_ratio;
> +	u16 ifs_clm_cck_fa_permil;
> +	u16 ifs_clm_ofdm_fa_permil;
> +	u32 ifs_clm_ifs_avg[RTW89_IFS_CLM_NUM];
> +	u32 ifs_clm_cca_avg[RTW89_IFS_CLM_NUM];
> +	u8 fahm_rpt[RTW89_FAHM_RPT_NUM];
> +	u16 fahm_result_sum;
> +	u8 fahm_ratio;
> +	u8 fahm_denom_ratio;
> +	u8 fahm_pwr;
> +	u8 edcca_clm_ratio;
> +};
> +
> +enum rtw89_ser_rcvy_step {
> +	RTW89_SER_DRV_STOP_TX,
> +	RTW89_SER_DRV_STOP_RX,
> +	RTW89_SER_DRV_STOP_RUN,
> +	RTW89_SER_HAL_STOP_DMA,
> +	RTW89_NUM_OF_SER_FLAGS
> +};
> +
> +struct rtw89_ser {
> +	u8 state;
> +	u8 alarm_event;
> +
> +	struct work_struct ser_hdl_work;
> +	struct delayed_work ser_alarm_work;
> +	struct state_ent *st_tbl;
> +	struct event_ent *ev_tbl;
> +	struct list_head msg_q;
> +	spinlock_t msg_q_lock; /* lock when read/write ser msg */
> +	DECLARE_BITMAP(flags, RTW89_NUM_OF_SER_FLAGS);
> +};
> +
> +enum rtw89_mac_ax_ps_mode {
> +	RTW89_MAC_AX_PS_MODE_ACTIVE = 0,
> +	RTW89_MAC_AX_PS_MODE_LEGACY = 1,
> +	RTW89_MAC_AX_PS_MODE_WMMPS  = 2,
> +	RTW89_MAC_AX_PS_MODE_MAX    = 3,
> +};
> +
> +enum rtw89_last_rpwm_mode {
> +	RTW89_LAST_RPWM_PS        = 0x0,
> +	RTW89_LAST_RPWM_ACTIVE    = 0x6,
> +};
> +
> +struct rtw89_lps_parm {
> +	u8 macid;
> +	u8 psmode; /* enum rtw89_mac_ax_ps_mode */
> +	u8 lastrpwm; /* enum rtw89_last_rpwm_mode */
> +};
> +
> +struct rtw89_ppdu_sts_info {
> +	struct sk_buff_head rx_queue[RTW89_PHY_MAX];
> +	u8 curr_rx_ppdu_cnt[RTW89_PHY_MAX];
> +};
> +
> +struct rtw89_dev {
> +	struct ieee80211_hw *hw;
> +	struct device *dev;
> +
> +	bool dbcc_en;
> +	const struct rtw89_chip_info *chip;
> +	struct rtw89_hal hal;
> +	struct rtw89_mac_info mac;
> +	struct rtw89_fw_info fw;
> +	struct rtw89_hci_info hci;
> +	struct rtw89_efuse efuse;
> +	struct rtw89_traffic_stats stats;
> +
> +	/* ensures exclusive access from mac80211 callbacks */
> +	struct mutex mutex;
> +	/* used to protect rf read write */
> +	struct mutex rf_mutex;
> +	struct workqueue_struct *txq_wq;
> +	struct work_struct txq_work;
> +	struct delayed_work txq_reinvoke_work;
> +	/* used to protect ba_list */
> +	spinlock_t ba_lock;
> +	/* txqs to setup ba session */
> +	struct list_head ba_list;
> +	struct work_struct ba_work;
> +
> +	struct rtw89_cam_info cam_info;
> +
> +	struct sk_buff_head c2h_queue;
> +	struct work_struct c2h_work;
> +
> +	struct rtw89_ser ser;
> +
> +	DECLARE_BITMAP(hw_port, RTW89_MAX_HW_PORT_NUM);
> +	DECLARE_BITMAP(mac_id_map, RTW89_MAX_MAC_ID_NUM);
> +	DECLARE_BITMAP(flags, NUM_OF_RTW89_FLAGS);
> +
> +	struct rtw89_phy_stat phystat;
> +	struct rtw89_dack_info dack;
> +	struct rtw89_iqk_info iqk;
> +	struct rtw89_dpk_info dpk;
> +	bool is_tssi_mode[RF_PATH_MAX];
> +	bool is_bt_iqk_timeout;
> +
> +	struct rtw89_fem_info fem;
> +	struct rtw89_txpwr_byrate byr[RTW89_BAND_MAX];
> +	struct rtw89_tssi_info tssi;
> +	struct rtw89_power_trim_info pwr_trim;
> +
> +	struct rtw89_cfo_tracking_info cfo_tracking;
> +	struct rtw89_env_monitor_info env_monitor;
> +	struct rtw89_dig_info dig;
> +	struct rtw89_phy_ch_info ch_info;
> +	struct delayed_work track_work;
> +	struct delayed_work coex_act1_work;
> +	struct delayed_work cfo_track_work;
> +	struct rtw89_ppdu_sts_info ppdu_sts;
> +	u8 total_sta_assoc;
> +	bool scanning;
> +
> +	const struct rtw89_regulatory *regd;
> +	struct rtw89_sar_info sar;
> +
> +	struct rtw89_btc btc;
> +	enum rtw89_ps_mode ps_mode;
> +	bool lps_enabled;
> +
> +	/* napi structure */
> +	struct net_device netdev;
> +	struct napi_struct napi;
> +	int napi_budget_countdown;
> +
> +	/* HCI related data, keep last */
> +	u8 priv[0] __aligned(sizeof(void *));
> +};
> +
> +static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev,
> +				     struct rtw89_core_tx_request *tx_req)
> +{
> +	return rtwdev->hci.ops->tx_write(rtwdev, tx_req);
> +}
> +
> +static inline void rtw89_hci_reset(struct rtw89_dev *rtwdev)
> +{
> +	rtwdev->hci.ops->reset(rtwdev);
> +}
> +
> +static inline int rtw89_hci_start(struct rtw89_dev *rtwdev)
> +{
> +	return rtwdev->hci.ops->start(rtwdev);
> +}
> +
> +static inline void rtw89_hci_stop(struct rtw89_dev *rtwdev)
> +{
> +	rtwdev->hci.ops->stop(rtwdev);
> +}
> +
> +static inline int rtw89_hci_deinit(struct rtw89_dev *rtwdev)
> +{
> +	return rtwdev->hci.ops->deinit(rtwdev);
> +}
> +
> +static inline void rtw89_hci_link_ps(struct rtw89_dev *rtwdev, bool enter)
> +{
> +	rtwdev->hci.ops->link_ps(rtwdev, enter);
> +}
> +
> +static inline u32 rtw89_hci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 txch)
> +{
> +	return rtwdev->hci.ops->check_and_reclaim_tx_resource(rtwdev, txch);
> +}
> +
> +static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
> +{
> +	return rtwdev->hci.ops->tx_kick_off(rtwdev, txch);
> +}
> +
> +static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues,
> +					  bool drop)
> +{
> +	if (rtwdev->hci.ops->flush_queues)
> +		return rtwdev->hci.ops->flush_queues(rtwdev, queues, drop);
> +}
> +
> +static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr)
> +{
> +	return rtwdev->hci.ops->read8(rtwdev, addr);
> +}
> +
> +static inline u16 rtw89_read16(struct rtw89_dev *rtwdev, u32 addr)
> +{
> +	return rtwdev->hci.ops->read16(rtwdev, addr);
> +}
> +
> +static inline u32 rtw89_read32(struct rtw89_dev *rtwdev, u32 addr)
> +{
> +	return rtwdev->hci.ops->read32(rtwdev, addr);
> +}
> +
> +static inline void rtw89_write8(struct rtw89_dev *rtwdev, u32 addr, u8 data)
> +{
> +	rtwdev->hci.ops->write8(rtwdev, addr, data);
> +}
> +
> +static inline void rtw89_write16(struct rtw89_dev *rtwdev, u32 addr, u16 data)
> +{
> +	rtwdev->hci.ops->write16(rtwdev, addr, data);
> +}
> +
> +static inline void rtw89_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data)
> +{
> +	rtwdev->hci.ops->write32(rtwdev, addr, data);
> +}
> +
> +static inline void
> +rtw89_write8_set(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
> +{
> +	u8 val;
> +
> +	val = rtw89_read8(rtwdev, addr);
> +	rtw89_write8(rtwdev, addr, val | bit);
> +}
> +
> +static inline void
> +rtw89_write16_set(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
> +{
> +	u16 val;
> +
> +	val = rtw89_read16(rtwdev, addr);
> +	rtw89_write16(rtwdev, addr, val | bit);
> +}
> +
> +static inline void
> +rtw89_write32_set(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
> +{
> +	u32 val;
> +
> +	val = rtw89_read32(rtwdev, addr);
> +	rtw89_write32(rtwdev, addr, val | bit);
> +}
> +
> +static inline void
> +rtw89_write8_clr(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
> +{
> +	u8 val;
> +
> +	val = rtw89_read8(rtwdev, addr);
> +	rtw89_write8(rtwdev, addr, val & ~bit);
> +}
> +
> +static inline void
> +rtw89_write16_clr(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
> +{
> +	u16 val;
> +
> +	val = rtw89_read16(rtwdev, addr);
> +	rtw89_write16(rtwdev, addr, val & ~bit);
> +}
> +
> +static inline void
> +rtw89_write32_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
> +{
> +	u32 val;
> +
> +	val = rtw89_read32(rtwdev, addr);
> +	rtw89_write32(rtwdev, addr, val & ~bit);
> +}
> +
> +static inline u32
> +rtw89_read32_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask)
> +{
> +	u32 shift = __ffs(mask);
> +	u32 orig;
> +	u32 ret;
> +
> +	orig = rtw89_read32(rtwdev, addr);
> +	ret = (orig & mask) >> shift;
> +
> +	return ret;
> +}
> +
> +static inline u16
> +rtw89_read16_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask)
> +{
> +	u32 shift = __ffs(mask);
> +	u32 orig;
> +	u32 ret;
> +
> +	orig = rtw89_read16(rtwdev, addr);
> +	ret = (orig & mask) >> shift;
> +
> +	return ret;
> +}
> +
> +static inline u8
> +rtw89_read8_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask)
> +{
> +	u32 shift = __ffs(mask);
> +	u32 orig;
> +	u32 ret;
> +
> +	orig = rtw89_read8(rtwdev, addr);
> +	ret = (orig & mask) >> shift;
> +
> +	return ret;
> +}
> +
> +static inline void
> +rtw89_write32_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data)
> +{
> +	u32 shift = __ffs(mask);
> +	u32 orig;
> +	u32 set;
> +
> +	WARN(addr & 0x3, "should be 4-byte aligned, addr = 0x%08x\n", addr);
> +
> +	orig = rtw89_read32(rtwdev, addr);
> +	set = (orig & ~mask) | ((data << shift) & mask);
> +	rtw89_write32(rtwdev, addr, set);
> +}
> +
> +static inline void
> +rtw89_write16_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u16 data)
> +{
> +	u32 shift;
> +	u16 orig, set;
> +
> +	mask &= 0xffff;
> +	shift = __ffs(mask);
> +
> +	orig = rtw89_read16(rtwdev, addr);
> +	set = (orig & ~mask) | ((data << shift) & mask);
> +	rtw89_write16(rtwdev, addr, set);
> +}
> +
> +static inline void
> +rtw89_write8_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u8 data)
> +{
> +	u32 shift;
> +	u8 orig, set;
> +
> +	mask &= 0xff;
> +	shift = __ffs(mask);
> +
> +	orig = rtw89_read8(rtwdev, addr);
> +	set = (orig & ~mask) | ((data << shift) & mask);
> +	rtw89_write8(rtwdev, addr, set);
> +}
> +
> +static inline u32
> +rtw89_read_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
> +	      u32 addr, u32 mask)
> +{
> +	u32 val;
> +
> +	mutex_lock(&rtwdev->rf_mutex);
> +	val = rtwdev->chip->ops->read_rf(rtwdev, rf_path, addr, mask);
> +	mutex_unlock(&rtwdev->rf_mutex);
> +
> +	return val;
> +}
> +
> +static inline void
> +rtw89_write_rf(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
> +	       u32 addr, u32 mask, u32 data)
> +{
> +	mutex_lock(&rtwdev->rf_mutex);
> +	rtwdev->chip->ops->write_rf(rtwdev, rf_path, addr, mask, data);
> +	mutex_unlock(&rtwdev->rf_mutex);
> +}
> +
> +static inline struct ieee80211_txq *rtw89_txq_to_txq(struct rtw89_txq *rtwtxq)
> +{
> +	void *p = rtwtxq;
> +
> +	return container_of(p, struct ieee80211_txq, drv_priv);
> +}
> +
> +static inline void rtw89_core_txq_init(struct rtw89_dev *rtwdev,
> +				       struct ieee80211_txq *txq)
> +{
> +	struct rtw89_txq *rtwtxq;
> +
> +	if (!txq)
> +		return;
> +
> +	rtwtxq = (struct rtw89_txq *)txq->drv_priv;
> +	INIT_LIST_HEAD(&rtwtxq->list);
> +}
> +
> +static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw89_vif *rtwvif)
> +{
> +	void *p = rtwvif;
> +
> +	return container_of(p, struct ieee80211_vif, drv_priv);
> +}
> +
> +static inline struct ieee80211_sta *rtwsta_to_sta(struct rtw89_sta *rtwsta)
> +{
> +	void *p = rtwsta;
> +
> +	return container_of(p, struct ieee80211_sta, drv_priv);
> +}
> +
> +static inline
> +void rtw89_chip_set_channel_prepare(struct rtw89_dev *rtwdev,
> +				    struct rtw89_channel_help_params *p)
> +{
> +	rtwdev->chip->ops->set_channel_help(rtwdev, true, p);
> +}
> +
> +static inline
> +void rtw89_chip_set_channel_done(struct rtw89_dev *rtwdev,
> +				 struct rtw89_channel_help_params *p)
> +{
> +	rtwdev->chip->ops->set_channel_help(rtwdev, false, p);
> +}
> +
> +static inline void rtw89_chip_fem_setup(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->fem_setup)
> +		chip->ops->fem_setup(rtwdev);
> +}
> +
> +static inline void rtw89_chip_bb_sethw(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->bb_sethw)
> +		chip->ops->bb_sethw(rtwdev);
> +}
> +
> +static inline void rtw89_chip_rfk_init(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->rfk_init)
> +		chip->ops->rfk_init(rtwdev);
> +}
> +
> +static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->rfk_channel)
> +		chip->ops->rfk_channel(rtwdev);
> +}
> +
> +static inline void rtw89_chip_rfk_band_changed(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->rfk_band_changed)
> +		chip->ops->rfk_band_changed(rtwdev);
> +}
> +
> +static inline void rtw89_chip_rfk_track(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->rfk_track)
> +		chip->ops->rfk_track(rtwdev);
> +}
> +
> +static inline void rtw89_chip_set_txpwr_ctrl(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->set_txpwr_ctrl)
> +		chip->ops->set_txpwr_ctrl(rtwdev);
> +}
> +
> +static inline void rtw89_chip_set_txpwr(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +	u8 ch = rtwdev->hal.current_channel;
> +
> +	if (!ch)
> +		return;
> +
> +	if (chip->ops->set_txpwr)
> +		chip->ops->set_txpwr(rtwdev);
> +}
> +
> +static inline void rtw89_chip_power_trim(struct rtw89_dev *rtwdev)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->power_trim)
> +		chip->ops->power_trim(rtwdev);
> +}
> +
> +static inline void rtw89_chip_init_txpwr_unit(struct rtw89_dev *rtwdev,
> +					      enum rtw89_phy_idx phy_idx)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->init_txpwr_unit)
> +		chip->ops->init_txpwr_unit(rtwdev, phy_idx);
> +}
> +
> +static inline u8 rtw89_chip_get_thermal(struct rtw89_dev *rtwdev,
> +					enum rtw89_rf_path rf_path)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (!chip->ops->get_thermal)
> +		return 0x10;
> +
> +	return chip->ops->get_thermal(rtwdev, rf_path);
> +}
> +
> +static inline void rtw89_chip_query_ppdu(struct rtw89_dev *rtwdev,
> +					 struct rtw89_rx_phy_ppdu *phy_ppdu,
> +					 struct ieee80211_rx_status *status)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->query_ppdu)
> +		chip->ops->query_ppdu(rtwdev, phy_ppdu, status);
> +}
> +
> +static inline void rtw89_chip_bb_ctrl_btc_preagc(struct rtw89_dev *rtwdev,
> +						 bool bt_en)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->bb_ctrl_btc_preagc)
> +		chip->ops->bb_ctrl_btc_preagc(rtwdev, bt_en);
> +}
> +
> +static inline
> +void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
> +				       struct ieee80211_vif *vif)
> +{
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (!vif->bss_conf.he_support || !vif->bss_conf.assoc)
> +		return;
> +
> +	if (chip->ops->set_txpwr_ul_tb_offset)
> +		chip->ops->set_txpwr_ul_tb_offset(rtwdev, 0, rtwvif->mac_idx);
> +}
> +
> +static inline void rtw89_load_txpwr_table(struct rtw89_dev *rtwdev,
> +					  const struct rtw89_txpwr_table *tbl)
> +{
> +	tbl->load(rtwdev, tbl);
> +}
> +
> +static inline u8 rtw89_regd_get(struct rtw89_dev *rtwdev, u8 band)
> +{
> +	return rtwdev->regd->txpwr_regd[band];
> +}
> +
> +static inline void rtw89_ctrl_btg(struct rtw89_dev *rtwdev, bool btg)
> +{
> +	const struct rtw89_chip_info *chip = rtwdev->chip;
> +
> +	if (chip->ops->ctrl_btg)
> +		chip->ops->ctrl_btg(rtwdev, btg);
> +}
> +
> +static inline u8 *get_hdr_bssid(struct ieee80211_hdr *hdr)
> +{
> +	__le16 fc = hdr->frame_control;
> +
> +	if (ieee80211_has_tods(fc))
> +		return hdr->addr1;
> +	else if (ieee80211_has_fromds(fc))
> +		return hdr->addr2;
> +	else
> +		return hdr->addr3;
> +}
> +
> +static inline bool rtw89_sta_has_beamformer_cap(struct ieee80211_sta *sta)
> +{
> +	if ((sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) ||
> +	    (sta->vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) ||
> +	    (sta->he_cap.he_cap_elem.phy_cap_info[3] & IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) ||
> +	    (sta->he_cap.he_cap_elem.phy_cap_info[4] & IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER))
> +		return true;
> +	return false;
> +}
> +
> +static inline struct rtw89_fw_suit *rtw89_fw_suit_get(struct rtw89_dev *rtwdev,
> +						      enum rtw89_fw_type type)
> +{
> +	struct rtw89_fw_info *fw_info = &rtwdev->fw;
> +
> +	if (type == RTW89_FW_WOWLAN)
> +		return &fw_info->wowlan;
> +	return &fw_info->normal;
> +}
> +
> +int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
> +			struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel);
> +int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
> +		 struct sk_buff *skb, bool fwdl);
> +void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel);
> +void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
> +			    struct rtw89_tx_desc_info *desc_info,
> +			    void *txdesc);
> +void rtw89_core_rx(struct rtw89_dev *rtwdev,
> +		   struct rtw89_rx_desc_info *desc_info,
> +		   struct sk_buff *skb);
> +void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev,
> +			     struct rtw89_rx_desc_info *desc_info,
> +			     u8 *data, u32 data_offset);
> +void rtw89_core_napi_start(struct rtw89_dev *rtwdev);
> +void rtw89_core_napi_stop(struct rtw89_dev *rtwdev);
> +void rtw89_core_napi_init(struct rtw89_dev *rtwdev);
> +void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev);
> +int rtw89_core_power_on(struct rtw89_dev *rtwdev);
> +int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
> +		       struct ieee80211_vif *vif,
> +		       struct ieee80211_sta *sta);
> +int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
> +			 struct ieee80211_vif *vif,
> +			 struct ieee80211_sta *sta);
> +int rtw89_core_sta_disassoc(struct rtw89_dev *rtwdev,
> +			    struct ieee80211_vif *vif,
> +			    struct ieee80211_sta *sta);
> +int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
> +			      struct ieee80211_vif *vif,
> +			      struct ieee80211_sta *sta);
> +int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
> +			  struct ieee80211_vif *vif,
> +			  struct ieee80211_sta *sta);
> +int rtw89_core_init(struct rtw89_dev *rtwdev);
> +void rtw89_core_deinit(struct rtw89_dev *rtwdev);
> +int rtw89_core_register(struct rtw89_dev *rtwdev);
> +void rtw89_core_unregister(struct rtw89_dev *rtwdev);
> +void rtw89_set_channel(struct rtw89_dev *rtwdev);
> +u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size);
> +void rtw89_core_release_bit_map(unsigned long *addr, u8 bit);
> +void rtw89_core_release_all_bits_map(unsigned long *addr, unsigned int nbits);
> +void rtw89_vif_type_mapping(struct ieee80211_vif *vif, bool assoc);
> +int rtw89_chip_info_setup(struct rtw89_dev *rtwdev);
> +u16 rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate);
> +int rtw89_regd_init(struct rtw89_dev *rtwdev,
> +		    void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request));
> +void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request);
> +void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
> +			      struct rtw89_traffic_stats *stats);
> +int rtw89_core_start(struct rtw89_dev *rtwdev);
> +void rtw89_core_stop(struct rtw89_dev *rtwdev);
> +
> +#endif
> diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h
> new file mode 100644
> index 000000000000..0dc99cbc6761
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw89/txrx.h
> @@ -0,0 +1,393 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
> +/* Copyright(c) 2020  Realtek Corporation
> + */
> +
> +#ifndef __RTW89_TXRX_H__
> +#define __RTW89_TXRX_H__
> +
> +#include "debug.h"
> +
> +#define DATA_RATE_MODE_CTRL_MASK	GENMASK(8, 7)
> +#define DATA_RATE_NOT_HT_IDX_MASK	GENMASK(3, 0)
> +#define DATA_RATE_MODE_NON_HT		0x0
> +#define DATA_RATE_HT_IDX_MASK		GENMASK(4, 0)
> +#define DATA_RATE_MODE_HT		0x1
> +#define DATA_RATE_VHT_HE_NSS_MASK	GENMASK(6, 4)
> +#define DATA_RATE_VHT_HE_IDX_MASK	GENMASK(3, 0)
> +#define DATA_RATE_MODE_VHT		0x2
> +#define DATA_RATE_MODE_HE		0x3
> +#define GET_DATA_RATE_MODE(r)		FIELD_GET(DATA_RATE_MODE_CTRL_MASK, r)
> +#define GET_DATA_RATE_NOT_HT_IDX(r)	FIELD_GET(DATA_RATE_NOT_HT_IDX_MASK, r)
> +#define GET_DATA_RATE_HT_IDX(r)		FIELD_GET(DATA_RATE_HT_IDX_MASK, r)
> +#define GET_DATA_RATE_VHT_HE_IDX(r)	FIELD_GET(DATA_RATE_VHT_HE_IDX_MASK, r)
> +#define GET_DATA_RATE_NSS(r)		FIELD_GET(DATA_RATE_VHT_HE_NSS_MASK, r)
> +
> +/* TX WD BODY DWORD 0 */
> +#define RTW89_SET_TXWD_BODY_WP_OFFSET(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, GENMASK(31, 24))
> +#define RTW89_SET_TXWD_BODY_MORE_DATA(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, BIT(23))
> +#define RTW89_SET_TXWD_BODY_WD_INFO_EN(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, BIT(22))
> +#define RTW89_SET_TXWD_BODY_FW_DL(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, BIT(20))
> +#define RTW89_SET_TXWD_BODY_CHANNEL_DMA(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, GENMASK(19, 16))
> +#define RTW89_SET_TXWD_BODY_HDR_LLC_LEN(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, GENMASK(15, 11))
> +#define RTW89_SET_TXWD_BODY_WD_PAGE(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, BIT(7))
> +#define RTW89_SET_TXWD_BODY_HW_AMSDU(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x00, BIT(5))
> +
> +/* TX WD BODY DWORD 1 */
> +#define RTW89_SET_TXWD_BODY_PAYLOAD_ID(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x01, GENMASK(31, 16))
> +
> +/* TX WD BODY DWORD 2 */
> +#define RTW89_SET_TXWD_BODY_MACID(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x02, GENMASK(30, 24))
> +#define RTW89_SET_TXWD_BODY_TID_INDICATE(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x02, BIT(23))
> +#define RTW89_SET_TXWD_BODY_QSEL(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x02, GENMASK(22, 17))
> +#define RTW89_SET_TXWD_BODY_TXPKT_SIZE(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x02, GENMASK(13, 0))
> +
> +/* TX WD BODY DWORD 3 */
> +#define RTW89_SET_TXWD_BODY_BK(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x03, BIT(13))
> +#define RTW89_SET_TXWD_BODY_AGG_EN(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x03, BIT(12))
> +#define RTW89_SET_TXWD_BODY_SW_SEQ(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x03, GENMASK(11, 0))
> +
> +/* TX WD BODY DWORD 4 */
> +
> +/* TX WD BODY DWORD 5 */
> +
> +/* TX WD INFO DWORD 0 */
> +#define RTW89_SET_TXWD_INFO_USE_RATE(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x6, BIT(30))
> +#define RTW89_SET_TXWD_INFO_DATA_BW(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x6, GENMASK(29, 28))
> +#define RTW89_SET_TXWD_INFO_GI_LTF(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x6, GENMASK(27, 25))
> +#define RTW89_SET_TXWD_INFO_DATA_RATE(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x6, GENMASK(24, 16))
> +#define RTW89_SET_TXWD_INFO_DISDATAFB(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x6, BIT(10))
> +
> +/* TX WD INFO DWORD 1 */
> +#define RTW89_SET_TXWD_INFO_A_CTRL_BSR(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x7, BIT(14))
> +#define RTW89_SET_TXWD_INFO_MAX_AGGNUM(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x7, GENMASK(7, 0))
> +
> +/* TX WD INFO DWORD 2 */
> +#define RTW89_SET_TXWD_INFO_AMPDU_DENSITY(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x8, GENMASK(20, 18))
> +#define RTW89_SET_TXWD_INFO_SEC_TYPE(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x8, GENMASK(12, 9))
> +#define RTW89_SET_TXWD_INFO_SEC_HW_ENC(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x8, BIT(8))
> +#define RTW89_SET_TXWD_INFO_SEC_CAM_IDX(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0x8, GENMASK(7, 0))
> +
> +/* TX WD INFO DWORD 3 */
> +
> +/* TX WD INFO DWORD 4 */
> +#define RTW89_SET_TXWD_INFO_RTS_EN(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0xA, BIT(27))
> +#define RTW89_SET_TXWD_INFO_HW_RTS_EN(txdesc, val) \
> +	RTW89_SET_TXWD(txdesc, val, 0xA, BIT(31))
> +
> +/* TX WD INFO DWORD 5 */
> +
> +/* RX DESC helpers */
> +/* Short Descriptor */
> +#define RTW89_GET_RXWD_LONG_RXD(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, BIT(31))
> +#define RTW89_GET_RXWD_DRV_INFO_SIZE(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, GENMASK(30, 28))
> +#define RTW89_GET_RXWD_RPKT_TYPE(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, GENMASK(27, 24))
> +#define RTW89_GET_RXWD_MAC_INFO_VALID(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, BIT(23))
> +#define RTW89_GET_RXWD_BB_SEL(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, BIT(22))
> +#define RTW89_GET_RXWD_HD_IV_LEN(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, GENMASK(21, 16))
> +#define RTW89_GET_RXWD_SHIFT(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, GENMASK(15, 14))
> +#define RTW89_GET_RXWD_PKT_SIZE(rxdesc) \
> +	le32_get_bits((rxdesc)->dword0, GENMASK(13, 0))
> +#define RTW89_GET_RXWD_BW(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, GENMASK(31, 30))
> +#define RTW89_GET_RXWD_GI_LTF(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, GENMASK(27, 25))
> +#define RTW89_GET_RXWD_DATA_RATE(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, GENMASK(24, 16))
> +#define RTW89_GET_RXWD_USER_ID(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, GENMASK(15, 8))
> +#define RTW89_GET_RXWD_SR_EN(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, BIT(7))
> +#define RTW89_GET_RXWD_PPDU_CNT(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, GENMASK(6, 4))
> +#define RTW89_GET_RXWD_PPDU_TYPE(rxdesc) \
> +	le32_get_bits((rxdesc)->dword1, GENMASK(3, 0))
> +#define RTW89_GET_RXWD_FREE_RUN_CNT(rxdesc) \
> +	le32_get_bits((rxdesc)->dword2, GENMASK(31, 0))
> +#define RTW89_GET_RXWD_ICV_ERR(rxdesc) \
> +	le32_get_bits((rxdesc)->dword3, BIT(10))
> +#define RTW89_GET_RXWD_CRC32_ERR(rxdesc) \
> +	le32_get_bits((rxdesc)->dword3, BIT(9))
> +#define RTW89_GET_RXWD_HW_DEC(rxdesc) \
> +	le32_get_bits((rxdesc)->dword3, BIT(2))
> +#define RTW89_GET_RXWD_SW_DEC(rxdesc) \
> +	le32_get_bits((rxdesc)->dword3, BIT(1))
> +#define RTW89_GET_RXWD_A1_MATCH(rxdesc) \
> +	le32_get_bits((rxdesc)->dword3, BIT(0))
> +
> +/* Long Descriptor */
> +#define RTW89_GET_RXWD_FRAG(rxdesc) \
> +	le32_get_bits((rxdesc)->dword4, GENMASK(31, 28))
> +#define RTW89_GET_RXWD_SEQ(rxdesc) \
> +	le32_get_bits((rxdesc)->dword4, GENMASK(27, 16))
> +#define RTW89_GET_RXWD_TYPE(rxdesc) \
> +	le32_get_bits((rxdesc)->dword4, GENMASK(1, 0))
> +#define RTW89_GET_RXWD_ADDR_CAM_VLD(rxdesc) \
> +	le32_get_bits((rxdesc)->dword5, BIT(28))
> +#define RTW89_GET_RXWD_RX_PL_ID(rxdesc) \
> +	le32_get_bits((rxdesc)->dword5, GENMASK(27, 24))
> +#define RTW89_GET_RXWD_MAC_ID(rxdesc) \
> +	le32_get_bits((rxdesc)->dword5, GENMASK(23, 16))
> +#define RTW89_GET_RXWD_ADDR_CAM_ID(rxdesc) \
> +	le32_get_bits((rxdesc)->dword5, GENMASK(15, 8))
> +#define RTW89_GET_RXWD_SEC_CAM_ID(rxdesc) \
> +	le32_get_bits((rxdesc)->dword5, GENMASK(7, 0))
> +
> +#define RTW89_GET_RXINFO_USR_NUM(rpt) \
> +	le32_get_bits(*((__le32 *)rpt), GENMASK(3, 0))
> +#define RTW89_GET_RXINFO_FW_DEFINE(rpt) \
> +	le32_get_bits(*((__le32 *)rpt), GENMASK(15, 8))
> +#define RTW89_GET_RXINFO_LSIG_LEN(rpt) \
> +	le32_get_bits(*((__le32 *)rpt), GENMASK(27, 16))
> +#define RTW89_GET_RXINFO_IS_TO_SELF(rpt) \
> +	le32_get_bits(*((__le32 *)rpt), BIT(28))
> +#define RTW89_GET_RXINFO_RX_CNT_VLD(rpt) \
> +	le32_get_bits(*((__le32 *)rpt), BIT(29))
> +#define RTW89_GET_RXINFO_LONG_RXD(rpt) \
> +	le32_get_bits(*((__le32 *)rpt), GENMASK(31, 30))
> +#define RTW89_GET_RXINFO_SERVICE(rpt) \
> +	le32_get_bits(*((__le32 *)(rpt) + 1), GENMASK(15, 0))
> +#define RTW89_GET_RXINFO_PLCP_LEN(rpt) \
> +	le32_get_bits(*((__le32 *)(rpt) + 1), GENMASK(23, 16))
> +#define RTW89_GET_RXINFO_MAC_ID_VALID(rpt, usr) \
> +	le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(0))
> +#define RTW89_GET_RXINFO_DATA(rpt, usr) \
> +	le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(1))
> +#define RTW89_GET_RXINFO_CTRL(rpt, usr) \
> +	le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(2))
> +#define RTW89_GET_RXINFO_MGMT(rpt, usr) \
> +	le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(3))
> +#define RTW89_GET_RXINFO_BCM(rpt, usr) \
> +	le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), BIT(4))
> +#define RTW89_GET_RXINFO_MACID(rpt, usr) \
> +	le32_get_bits(*((__le32 *)(rpt) + (usr) + 2), GENMASK(15, 8))
> +
> +#define RTW89_GET_PHY_STS_RSSI_A(sts) \
> +	le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(7, 0))
> +#define RTW89_GET_PHY_STS_RSSI_B(sts) \
> +	le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(15, 8))
> +#define RTW89_GET_PHY_STS_RSSI_C(sts) \
> +	le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(23, 16))
> +#define RTW89_GET_PHY_STS_RSSI_D(sts) \
> +	le32_get_bits(*((__le32 *)(sts) + 1), GENMASK(31, 24))
> +#define RTW89_GET_PHY_STS_LEN(sts) \
> +	le32_get_bits(*((__le32 *)sts), GENMASK(15, 8))
> +#define RTW89_GET_PHY_STS_RSSI_AVG(sts) \
> +	le32_get_bits(*((__le32 *)sts), GENMASK(31, 24))
> +#define RTW89_GET_PHY_STS_IE_TYPE(ie) \
> +	le32_get_bits(*((__le32 *)ie), GENMASK(4, 0))
> +#define RTW89_GET_PHY_STS_IE_LEN(ie) \
> +	le32_get_bits(*((__le32 *)ie), GENMASK(11, 5))
> +#define RTW89_GET_PHY_STS_IE0_CFO(ie) \
> +	le32_get_bits(*((__le32 *)(ie) + 1), GENMASK(31, 20))
> +
> +enum rtw89_tx_channel {
> +	RTW89_TXCH_ACH0	= 0,
> +	RTW89_TXCH_ACH1	= 1,
> +	RTW89_TXCH_ACH2	= 2,
> +	RTW89_TXCH_ACH3	= 3,
> +	RTW89_TXCH_ACH4	= 4,
> +	RTW89_TXCH_ACH5	= 5,
> +	RTW89_TXCH_ACH6	= 6,
> +	RTW89_TXCH_ACH7	= 7,
> +	RTW89_TXCH_CH8	= 8,  /* MGMT Band 0 */
> +	RTW89_TXCH_CH9	= 9,  /* HI Band 0 */
> +	RTW89_TXCH_CH10	= 10, /* MGMT Band 1 */
> +	RTW89_TXCH_CH11	= 11, /* HI Band 1 */
> +	RTW89_TXCH_CH12	= 12, /* FW CMD */
> +
> +	/* keep last */
> +	RTW89_TXCH_NUM,
> +	RTW89_TXCH_MAX = RTW89_TXCH_NUM - 1
> +};
> +
> +enum rtw89_rx_channel {
> +	RTW89_RXCH_RXQ	= 0,
> +	RTW89_RXCH_RPQ	= 1,
> +
> +	/* keep last */
> +	RTW89_RXCH_NUM,
> +	RTW89_RXCH_MAX = RTW89_RXCH_NUM - 1
> +};
> +
> +enum rtw89_tx_qsel {
> +	RTW89_TX_QSEL_BE_0		= 0x00,
> +	RTW89_TX_QSEL_BK_0		= 0x01,
> +	RTW89_TX_QSEL_VI_0		= 0x02,
> +	RTW89_TX_QSEL_VO_0		= 0x03,
> +	RTW89_TX_QSEL_BE_1		= 0x04,
> +	RTW89_TX_QSEL_BK_1		= 0x05,
> +	RTW89_TX_QSEL_VI_1		= 0x06,
> +	RTW89_TX_QSEL_VO_1		= 0x07,
> +	RTW89_TX_QSEL_BE_2		= 0x08,
> +	RTW89_TX_QSEL_BK_2		= 0x09,
> +	RTW89_TX_QSEL_VI_2		= 0x0a,
> +	RTW89_TX_QSEL_VO_2		= 0x0b,
> +	RTW89_TX_QSEL_BE_3		= 0x0c,
> +	RTW89_TX_QSEL_BK_3		= 0x0d,
> +	RTW89_TX_QSEL_VI_3		= 0x0e,
> +	RTW89_TX_QSEL_VO_3		= 0x0f,
> +	RTW89_TX_QSEL_B0_BCN		= 0x10,
> +	RTW89_TX_QSEL_B0_HI		= 0x11,
> +	RTW89_TX_QSEL_B0_MGMT		= 0x12,
> +	RTW89_TX_QSEL_B0_NOPS		= 0x13,
> +	RTW89_TX_QSEL_B0_MGMT_FAST	= 0x14,
> +	/* reserved */
> +	/* reserved */
> +	/* reserved */
> +	RTW89_TX_QSEL_B1_BCN		= 0x18,
> +	RTW89_TX_QSEL_B1_HI		= 0x19,
> +	RTW89_TX_QSEL_B1_MGMT		= 0x1a,
> +	RTW89_TX_QSEL_B1_NOPS		= 0x1b,
> +	RTW89_TX_QSEL_B1_MGMT_FAST	= 0x1c,
> +	/* reserved */
> +	/* reserved */
> +	/* reserved */
> +};
> +
> +enum rtw89_phy_status_ie_type {
> +	RTW89_PHYSTS_IE00_CMN_CCK			= 0,
> +	RTW89_PHYSTS_IE01_CMN_OFDM			= 1,
> +	RTW89_PHYSTS_IE02_CMN_EXT_AX			= 2,
> +	RTW89_PHYSTS_IE03_CMN_EXT_SEG_1			= 3,
> +	RTW89_PHYSTS_IE04_CMN_EXT_PATH_A		= 4,
> +	RTW89_PHYSTS_IE05_CMN_EXT_PATH_B		= 5,
> +	RTW89_PHYSTS_IE06_CMN_EXT_PATH_C		= 6,
> +	RTW89_PHYSTS_IE07_CMN_EXT_PATH_D		= 7,
> +	RTW89_PHYSTS_IE08_FTR_CH			= 8,
> +	RTW89_PHYSTS_IE09_FTR_PLCP_0			= 9,
> +	RTW89_PHYSTS_IE10_FTR_PLCP_EXT			= 10,
> +	RTW89_PHYSTS_IE11_FTR_PLCP_HISTOGRAM		= 11,
> +	RTW89_PHYSTS_IE12_MU_EIGEN_INFO			= 12,
> +	RTW89_PHYSTS_IE13_DL_MU_DEF			= 13,
> +	RTW89_PHYSTS_IE14_TB_UL_CQI			= 14,
> +	RTW89_PHYSTS_IE15_TB_UL_DEF			= 15,
> +	RTW89_PHYSTS_IE16_RSVD16			= 16,
> +	RTW89_PHYSTS_IE17_TB_UL_CTRL			= 17,
> +	RTW89_PHYSTS_IE18_DBG_OFDM_FD_CMN		= 18,
> +	RTW89_PHYSTS_IE19_DBG_OFDM_TD_CMN		= 19,
> +	RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0	= 20,
> +	RTW89_PHYSTS_IE21_DBG_OFDM_FD_USER_SEG_1	= 21,
> +	RTW89_PHYSTS_IE22_DBG_OFDM_FD_USER_AGC		= 22,
> +	RTW89_PHYSTS_IE23_RSVD23			= 23,
> +	RTW89_PHYSTS_IE24_DBG_OFDM_TD_PATH_A		= 24,
> +	RTW89_PHYSTS_IE25_DBG_OFDM_TD_PATH_B		= 25,
> +	RTW89_PHYSTS_IE26_DBG_OFDM_TD_PATH_C		= 26,
> +	RTW89_PHYSTS_IE27_DBG_OFDM_TD_PATH_D		= 27,
> +	RTW89_PHYSTS_IE28_DBG_CCK_PATH_A		= 28,
> +	RTW89_PHYSTS_IE29_DBG_CCK_PATH_B		= 29,
> +	RTW89_PHYSTS_IE30_DBG_CCK_PATH_C		= 30,
> +	RTW89_PHYSTS_IE31_DBG_CCK_PATH_D		= 31,
> +
> +	/* keep last */
> +	RTW89_PHYSTS_IE_NUM,
> +	RTW89_PHYSTS_IE_MAX = RTW89_PHYSTS_IE_NUM - 1
> +};
> +
> +static inline u8 rtw89_core_get_qsel(struct rtw89_dev *rtwdev, u8 tid)
> +{
> +	switch (tid) {
> +	default:
> +		rtw89_warn(rtwdev, "Should use tag 1d: %d\n", tid);
> +		fallthrough;
> +	case 0:
> +	case 3:
> +		return RTW89_TX_QSEL_BE_0;
> +	case 1:
> +	case 2:
> +		return RTW89_TX_QSEL_BK_0;
> +	case 4:
> +	case 5:
> +		return RTW89_TX_QSEL_VI_0;
> +	case 6:
> +	case 7:
> +		return RTW89_TX_QSEL_VO_0;
> +	}
> +}
> +
> +static inline u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel)
> +{
> +	switch (qsel) {
> +	default:
> +		rtw89_warn(rtwdev, "Cannot map qsel to dma: %d\n", qsel);
> +		fallthrough;
> +	case RTW89_TX_QSEL_BE_0:
> +		return RTW89_TXCH_ACH0;
> +	case RTW89_TX_QSEL_BK_0:
> +		return RTW89_TXCH_ACH1;
> +	case RTW89_TX_QSEL_VI_0:
> +		return RTW89_TXCH_ACH2;
> +	case RTW89_TX_QSEL_VO_0:
> +		return RTW89_TXCH_ACH3;
> +	case RTW89_TX_QSEL_B0_MGMT:
> +		return RTW89_TXCH_CH8;
> +	case RTW89_TX_QSEL_B0_HI:
> +		return RTW89_TXCH_CH9;
> +	case RTW89_TX_QSEL_B1_MGMT:
> +		return RTW89_TXCH_CH10;
> +	case RTW89_TX_QSEL_B1_HI:
> +		return RTW89_TXCH_CH11;
> +	}
> +}
> +
> +static inline u8 rtw89_core_get_tid_indicate(struct rtw89_dev *rtwdev, u8 tid)
> +{
> +	switch (tid) {
> +	case 3:
> +	case 2:
> +	case 5:
> +	case 7:
> +		return 1;
> +	default:
> +		rtw89_warn(rtwdev, "Should use tag 1d: %d\n", tid);
> +		fallthrough;
> +	case 0:
> +	case 1:
> +	case 4:
> +	case 6:
> +		return 0;
> +	}
> +}
> +
> +static __always_inline void RTW89_SET_TXWD(u8 *txdesc, u32 val, u8 offset, u32 mask)
> +{
> +	u32 *txd32 = (u32 *)txdesc;
> +
> +	le32p_replace_bits((__le32 *)(txd32 + offset), val, mask);
> +}
> +
> +#endif
> diff --git a/drivers/net/wireless/realtek/rtw89/util.c b/drivers/net/wireless/realtek/rtw89/util.c
> new file mode 100644
> index 000000000000..a0650bb88d0c
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw89/util.c
> @@ -0,0 +1,37 @@
> +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> +/* Copyright(c) 2019-2020  Realtek Corporation
> + */
> +
> +#include "util.h"
> +
> +static void
> +__rtw89_vifs_collect_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
> +{
> +	struct list_head *vif_list = (struct list_head *)data;
> +	struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
> +
> +	list_add_tail(&rtwvif->list, vif_list);
> +}
> +
> +void __rtw89_iterate_vifs(struct rtw89_dev *rtwdev,
> +			  void (*iterator)(void *data, u8 *mac,
> +					   struct ieee80211_vif *vif),
> +			  void *data)
> +{
> +	struct ieee80211_vif *vif;
> +	struct rtw89_vif *rtwvif;
> +	LIST_HEAD(vif_list);
> +
> +	/* iflist_mtx & mutex are held */
> +	lockdep_assert_held(&rtwdev->mutex);
> +
> +	/* Since iflist_mtx is held, we can use vif outside of iterator */
> +	ieee80211_iterate_active_interfaces_atomic(rtwdev->hw,
> +			IEEE80211_IFACE_ITER_NORMAL, __rtw89_vifs_collect_iter,
> +			&vif_list);
> +
> +	list_for_each_entry(rtwvif, &vif_list, list) {
> +		vif = rtwvif_to_vif(rtwvif);
> +		iterator(data, vif->addr, vif);
> +	}
> +}
> diff --git a/drivers/net/wireless/realtek/rtw89/util.h b/drivers/net/wireless/realtek/rtw89/util.h
> new file mode 100644
> index 000000000000..935ceecdbb75
> --- /dev/null
> +++ b/drivers/net/wireless/realtek/rtw89/util.h
> @@ -0,0 +1,31 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
> + * Copyright(c) 2019-2020  Realtek Corporation
> + */
> +#ifndef __RTW89_UTIL_H__
> +#define __RTW89_UTIL_H__
> +
> +#include "core.h"
> +
> +#define rtw89_iterate_vifs_bh(rtwdev, iterator, data)                          \
> +	ieee80211_iterate_active_interfaces_atomic((rtwdev)->hw,               \
> +			IEEE80211_IFACE_ITER_NORMAL, iterator, data)
> +void __rtw89_iterate_vifs(struct rtw89_dev *rtwdev,
> +			  void (*iterator)(void *data, u8 *mac,
> +					   struct ieee80211_vif *vif),
> +			  void *data);
> +static inline
> +void rtw89_iterate_vifs(struct rtw89_dev *rtwdev,
> +			void (*iterator)(void *data, u8 *mac,
> +					 struct ieee80211_vif *vif),
> +			void *data, bool held_vifmtx)
> +{
> +	if (!held_vifmtx) {
> +		ieee80211_iterate_active_interfaces((rtwdev)->hw,
> +				IEEE80211_IFACE_ITER_NORMAL, iterator, data);
> +		return;
> +	}
> +
> +	__rtw89_iterate_vifs(rtwdev, iterator, data);
> +}
> +
> +#endif
> -- 
> 2.25.1

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux