162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2022 MediaTek Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/firmware.h>
762306a36Sopenharmony_ci#include <linux/fs.h>
862306a36Sopenharmony_ci#include "mt7996.h"
962306a36Sopenharmony_ci#include "mcu.h"
1062306a36Sopenharmony_ci#include "mac.h"
1162306a36Sopenharmony_ci#include "eeprom.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct mt7996_patch_hdr {
1462306a36Sopenharmony_ci	char build_date[16];
1562306a36Sopenharmony_ci	char platform[4];
1662306a36Sopenharmony_ci	__be32 hw_sw_ver;
1762306a36Sopenharmony_ci	__be32 patch_ver;
1862306a36Sopenharmony_ci	__be16 checksum;
1962306a36Sopenharmony_ci	u16 reserved;
2062306a36Sopenharmony_ci	struct {
2162306a36Sopenharmony_ci		__be32 patch_ver;
2262306a36Sopenharmony_ci		__be32 subsys;
2362306a36Sopenharmony_ci		__be32 feature;
2462306a36Sopenharmony_ci		__be32 n_region;
2562306a36Sopenharmony_ci		__be32 crc;
2662306a36Sopenharmony_ci		u32 reserved[11];
2762306a36Sopenharmony_ci	} desc;
2862306a36Sopenharmony_ci} __packed;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct mt7996_patch_sec {
3162306a36Sopenharmony_ci	__be32 type;
3262306a36Sopenharmony_ci	__be32 offs;
3362306a36Sopenharmony_ci	__be32 size;
3462306a36Sopenharmony_ci	union {
3562306a36Sopenharmony_ci		__be32 spec[13];
3662306a36Sopenharmony_ci		struct {
3762306a36Sopenharmony_ci			__be32 addr;
3862306a36Sopenharmony_ci			__be32 len;
3962306a36Sopenharmony_ci			__be32 sec_key_idx;
4062306a36Sopenharmony_ci			__be32 align_len;
4162306a36Sopenharmony_ci			u32 reserved[9];
4262306a36Sopenharmony_ci		} info;
4362306a36Sopenharmony_ci	};
4462306a36Sopenharmony_ci} __packed;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistruct mt7996_fw_trailer {
4762306a36Sopenharmony_ci	u8 chip_id;
4862306a36Sopenharmony_ci	u8 eco_code;
4962306a36Sopenharmony_ci	u8 n_region;
5062306a36Sopenharmony_ci	u8 format_ver;
5162306a36Sopenharmony_ci	u8 format_flag;
5262306a36Sopenharmony_ci	u8 reserved[2];
5362306a36Sopenharmony_ci	char fw_ver[10];
5462306a36Sopenharmony_ci	char build_date[15];
5562306a36Sopenharmony_ci	u32 crc;
5662306a36Sopenharmony_ci} __packed;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct mt7996_fw_region {
5962306a36Sopenharmony_ci	__le32 decomp_crc;
6062306a36Sopenharmony_ci	__le32 decomp_len;
6162306a36Sopenharmony_ci	__le32 decomp_blk_sz;
6262306a36Sopenharmony_ci	u8 reserved[4];
6362306a36Sopenharmony_ci	__le32 addr;
6462306a36Sopenharmony_ci	__le32 len;
6562306a36Sopenharmony_ci	u8 feature_set;
6662306a36Sopenharmony_ci	u8 reserved1[15];
6762306a36Sopenharmony_ci} __packed;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define MCU_PATCH_ADDRESS		0x200000
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define HE_PHY(p, c)			u8_get_bits(c, IEEE80211_HE_PHY_##p)
7262306a36Sopenharmony_ci#define HE_MAC(m, c)			u8_get_bits(c, IEEE80211_HE_MAC_##m)
7362306a36Sopenharmony_ci#define EHT_PHY(p, c)			u8_get_bits(c, IEEE80211_EHT_PHY_##p)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic bool sr_scene_detect = true;
7662306a36Sopenharmony_cimodule_param(sr_scene_detect, bool, 0644);
7762306a36Sopenharmony_ciMODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic u8
8062306a36Sopenharmony_cimt7996_mcu_get_sta_nss(u16 mcs_map)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	u8 nss;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	for (nss = 8; nss > 0; nss--) {
8562306a36Sopenharmony_ci		u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED)
8862306a36Sopenharmony_ci			break;
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return nss - 1;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic void
9562306a36Sopenharmony_cimt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
9662306a36Sopenharmony_ci			  u16 mcs_map)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
9962306a36Sopenharmony_ci	enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
10062306a36Sopenharmony_ci	const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs;
10162306a36Sopenharmony_ci	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	for (nss = 0; nss < max_nss; nss++) {
10462306a36Sopenharmony_ci		int mcs;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		switch ((mcs_map >> (2 * nss)) & 0x3) {
10762306a36Sopenharmony_ci		case IEEE80211_HE_MCS_SUPPORT_0_11:
10862306a36Sopenharmony_ci			mcs = GENMASK(11, 0);
10962306a36Sopenharmony_ci			break;
11062306a36Sopenharmony_ci		case IEEE80211_HE_MCS_SUPPORT_0_9:
11162306a36Sopenharmony_ci			mcs = GENMASK(9, 0);
11262306a36Sopenharmony_ci			break;
11362306a36Sopenharmony_ci		case IEEE80211_HE_MCS_SUPPORT_0_7:
11462306a36Sopenharmony_ci			mcs = GENMASK(7, 0);
11562306a36Sopenharmony_ci			break;
11662306a36Sopenharmony_ci		default:
11762306a36Sopenharmony_ci			mcs = 0;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		switch (mcs) {
12362306a36Sopenharmony_ci		case 0 ... 7:
12462306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
12562306a36Sopenharmony_ci			break;
12662306a36Sopenharmony_ci		case 8 ... 9:
12762306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
12862306a36Sopenharmony_ci			break;
12962306a36Sopenharmony_ci		case 10 ... 11:
13062306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
13162306a36Sopenharmony_ci			break;
13262306a36Sopenharmony_ci		default:
13362306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
13462306a36Sopenharmony_ci			break;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci		mcs_map &= ~(0x3 << (nss * 2));
13762306a36Sopenharmony_ci		mcs_map |= mcs << (nss * 2);
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	*he_mcs = cpu_to_le16(mcs_map);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void
14462306a36Sopenharmony_cimt7996_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
14562306a36Sopenharmony_ci			   const u16 *mask)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	u16 mcs, mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
14862306a36Sopenharmony_ci	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
15162306a36Sopenharmony_ci		switch (mcs_map & 0x3) {
15262306a36Sopenharmony_ci		case IEEE80211_VHT_MCS_SUPPORT_0_9:
15362306a36Sopenharmony_ci			mcs = GENMASK(9, 0);
15462306a36Sopenharmony_ci			break;
15562306a36Sopenharmony_ci		case IEEE80211_VHT_MCS_SUPPORT_0_8:
15662306a36Sopenharmony_ci			mcs = GENMASK(8, 0);
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		case IEEE80211_VHT_MCS_SUPPORT_0_7:
15962306a36Sopenharmony_ci			mcs = GENMASK(7, 0);
16062306a36Sopenharmony_ci			break;
16162306a36Sopenharmony_ci		default:
16262306a36Sopenharmony_ci			mcs = 0;
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]);
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void
17062306a36Sopenharmony_cimt7996_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
17162306a36Sopenharmony_ci			  const u8 *mask)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	for (nss = 0; nss < max_nss; nss++)
17662306a36Sopenharmony_ci		ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss];
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int
18062306a36Sopenharmony_cimt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd,
18162306a36Sopenharmony_ci			  struct sk_buff *skb, int seq)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd;
18462306a36Sopenharmony_ci	struct mt7996_mcu_uni_event *event;
18562306a36Sopenharmony_ci	int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
18662306a36Sopenharmony_ci	int ret = 0;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (!skb) {
18962306a36Sopenharmony_ci		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
19062306a36Sopenharmony_ci			cmd, seq);
19162306a36Sopenharmony_ci		return -ETIMEDOUT;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	rxd = (struct mt7996_mcu_rxd *)skb->data;
19562306a36Sopenharmony_ci	if (seq != rxd->seq)
19662306a36Sopenharmony_ci		return -EAGAIN;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
19962306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd) - 4);
20062306a36Sopenharmony_ci		ret = *skb->data;
20162306a36Sopenharmony_ci	} else if ((rxd->option & MCU_UNI_CMD_EVENT) &&
20262306a36Sopenharmony_ci		    rxd->eid == MCU_UNI_EVENT_RESULT) {
20362306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd));
20462306a36Sopenharmony_ci		event = (struct mt7996_mcu_uni_event *)skb->data;
20562306a36Sopenharmony_ci		ret = le32_to_cpu(event->status);
20662306a36Sopenharmony_ci		/* skip invalid event */
20762306a36Sopenharmony_ci		if (mcu_cmd != event->cid)
20862306a36Sopenharmony_ci			ret = -EAGAIN;
20962306a36Sopenharmony_ci	} else {
21062306a36Sopenharmony_ci		skb_pull(skb, sizeof(struct mt7996_mcu_rxd));
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return ret;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic int
21762306a36Sopenharmony_cimt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
21862306a36Sopenharmony_ci			int cmd, int *wait_seq)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
22162306a36Sopenharmony_ci	int txd_len, mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
22262306a36Sopenharmony_ci	struct mt76_connac2_mcu_uni_txd *uni_txd;
22362306a36Sopenharmony_ci	struct mt76_connac2_mcu_txd *mcu_txd;
22462306a36Sopenharmony_ci	enum mt76_mcuq_id qid;
22562306a36Sopenharmony_ci	__le32 *txd;
22662306a36Sopenharmony_ci	u32 val;
22762306a36Sopenharmony_ci	u8 seq;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	mdev->mcu.timeout = 20 * HZ;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	seq = ++dev->mt76.mcu.msg_seq & 0xf;
23262306a36Sopenharmony_ci	if (!seq)
23362306a36Sopenharmony_ci		seq = ++dev->mt76.mcu.msg_seq & 0xf;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (cmd == MCU_CMD(FW_SCATTER)) {
23662306a36Sopenharmony_ci		qid = MT_MCUQ_FWDL;
23762306a36Sopenharmony_ci		goto exit;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	txd_len = cmd & __MCU_CMD_FIELD_UNI ? sizeof(*uni_txd) : sizeof(*mcu_txd);
24162306a36Sopenharmony_ci	txd = (__le32 *)skb_push(skb, txd_len);
24262306a36Sopenharmony_ci	if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
24362306a36Sopenharmony_ci		qid = MT_MCUQ_WA;
24462306a36Sopenharmony_ci	else
24562306a36Sopenharmony_ci		qid = MT_MCUQ_WM;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
24862306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) |
24962306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0);
25062306a36Sopenharmony_ci	txd[0] = cpu_to_le32(val);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD);
25362306a36Sopenharmony_ci	txd[1] = cpu_to_le32(val);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (cmd & __MCU_CMD_FIELD_UNI) {
25662306a36Sopenharmony_ci		uni_txd = (struct mt76_connac2_mcu_uni_txd *)txd;
25762306a36Sopenharmony_ci		uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
25862306a36Sopenharmony_ci		uni_txd->cid = cpu_to_le16(mcu_cmd);
25962306a36Sopenharmony_ci		uni_txd->s2d_index = MCU_S2D_H2CN;
26062306a36Sopenharmony_ci		uni_txd->pkt_type = MCU_PKT_ID;
26162306a36Sopenharmony_ci		uni_txd->seq = seq;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (cmd & __MCU_CMD_FIELD_QUERY)
26462306a36Sopenharmony_ci			uni_txd->option = MCU_CMD_UNI_QUERY_ACK;
26562306a36Sopenharmony_ci		else
26662306a36Sopenharmony_ci			uni_txd->option = MCU_CMD_UNI_EXT_ACK;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM))
26962306a36Sopenharmony_ci			uni_txd->s2d_index = MCU_S2D_H2CN;
27062306a36Sopenharmony_ci		else if (cmd & __MCU_CMD_FIELD_WA)
27162306a36Sopenharmony_ci			uni_txd->s2d_index = MCU_S2D_H2C;
27262306a36Sopenharmony_ci		else if (cmd & __MCU_CMD_FIELD_WM)
27362306a36Sopenharmony_ci			uni_txd->s2d_index = MCU_S2D_H2N;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		goto exit;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	mcu_txd = (struct mt76_connac2_mcu_txd *)txd;
27962306a36Sopenharmony_ci	mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
28062306a36Sopenharmony_ci	mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU,
28162306a36Sopenharmony_ci					       MT_TX_MCU_PORT_RX_Q0));
28262306a36Sopenharmony_ci	mcu_txd->pkt_type = MCU_PKT_ID;
28362306a36Sopenharmony_ci	mcu_txd->seq = seq;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	mcu_txd->cid = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
28662306a36Sopenharmony_ci	mcu_txd->set_query = MCU_Q_NA;
28762306a36Sopenharmony_ci	mcu_txd->ext_cid = FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd);
28862306a36Sopenharmony_ci	if (mcu_txd->ext_cid) {
28962306a36Sopenharmony_ci		mcu_txd->ext_cid_ack = 1;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		if (cmd & __MCU_CMD_FIELD_QUERY)
29262306a36Sopenharmony_ci			mcu_txd->set_query = MCU_Q_QUERY;
29362306a36Sopenharmony_ci		else
29462306a36Sopenharmony_ci			mcu_txd->set_query = MCU_Q_SET;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (cmd & __MCU_CMD_FIELD_WA)
29862306a36Sopenharmony_ci		mcu_txd->s2d_index = MCU_S2D_H2C;
29962306a36Sopenharmony_ci	else
30062306a36Sopenharmony_ci		mcu_txd->s2d_index = MCU_S2D_H2N;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ciexit:
30362306a36Sopenharmony_ci	if (wait_seq)
30462306a36Sopenharmony_ci		*wait_seq = seq;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciint mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct {
31262306a36Sopenharmony_ci		__le32 args[3];
31362306a36Sopenharmony_ci	} req = {
31462306a36Sopenharmony_ci		.args = {
31562306a36Sopenharmony_ci			cpu_to_le32(a1),
31662306a36Sopenharmony_ci			cpu_to_le32(a2),
31762306a36Sopenharmony_ci			cpu_to_le32(a3),
31862306a36Sopenharmony_ci		},
31962306a36Sopenharmony_ci	};
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic void
32562306a36Sopenharmony_cimt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	if (vif->bss_conf.csa_active)
32862306a36Sopenharmony_ci		ieee80211_csa_finish(vif);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic void
33262306a36Sopenharmony_cimt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
33562306a36Sopenharmony_ci	struct mt7996_mcu_rdd_report *r;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	r = (struct mt7996_mcu_rdd_report *)skb->data;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys))
34062306a36Sopenharmony_ci		return;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (dev->rdd2_phy && r->band_idx == MT_RX_SEL2)
34362306a36Sopenharmony_ci		mphy = dev->rdd2_phy->mt76;
34462306a36Sopenharmony_ci	else
34562306a36Sopenharmony_ci		mphy = dev->mt76.phys[r->band_idx];
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (!mphy)
34862306a36Sopenharmony_ci		return;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (r->band_idx == MT_RX_SEL2)
35162306a36Sopenharmony_ci		cfg80211_background_radar_event(mphy->hw->wiphy,
35262306a36Sopenharmony_ci						&dev->rdd2_chandef,
35362306a36Sopenharmony_ci						GFP_ATOMIC);
35462306a36Sopenharmony_ci	else
35562306a36Sopenharmony_ci		ieee80211_radar_detected(mphy->hw);
35662306a36Sopenharmony_ci	dev->hw_pattern++;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic void
36062306a36Sopenharmony_cimt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci#define UNI_EVENT_FW_LOG_FORMAT 0
36362306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
36462306a36Sopenharmony_ci	const char *data = (char *)&rxd[1] + 4, *type;
36562306a36Sopenharmony_ci	struct tlv *tlv = (struct tlv *)data;
36662306a36Sopenharmony_ci	int len;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (!(rxd->option & MCU_UNI_CMD_EVENT)) {
36962306a36Sopenharmony_ci		len = skb->len - sizeof(*rxd);
37062306a36Sopenharmony_ci		data = (char *)&rxd[1];
37162306a36Sopenharmony_ci		goto out;
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT)
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	data += sizeof(*tlv) + 4;
37862306a36Sopenharmony_ci	len = le16_to_cpu(tlv->len) - sizeof(*tlv) - 4;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciout:
38162306a36Sopenharmony_ci	switch (rxd->s2d_index) {
38262306a36Sopenharmony_ci	case 0:
38362306a36Sopenharmony_ci		if (mt7996_debugfs_rx_log(dev, data, len))
38462306a36Sopenharmony_ci			return;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		type = "WM";
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci	case 2:
38962306a36Sopenharmony_ci		type = "WA";
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	default:
39262306a36Sopenharmony_ci		type = "unknown";
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void
40062306a36Sopenharmony_cimt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	if (!vif->bss_conf.color_change_active)
40362306a36Sopenharmony_ci		return;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ieee80211_color_change_finish(vif);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void
40962306a36Sopenharmony_cimt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci#define UNI_EVENT_IE_COUNTDOWN_CSA 0
41262306a36Sopenharmony_ci#define UNI_EVENT_IE_COUNTDOWN_BCC 1
41362306a36Sopenharmony_ci	struct header {
41462306a36Sopenharmony_ci		u8 band;
41562306a36Sopenharmony_ci		u8 rsv[3];
41662306a36Sopenharmony_ci	};
41762306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
41862306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
41962306a36Sopenharmony_ci	const char *data = (char *)&rxd[1], *tail;
42062306a36Sopenharmony_ci	struct header *hdr = (struct header *)data;
42162306a36Sopenharmony_ci	struct tlv *tlv = (struct tlv *)(data + 4);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (hdr->band >= ARRAY_SIZE(dev->mt76.phys))
42462306a36Sopenharmony_ci		return;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (hdr->band && dev->mt76.phys[hdr->band])
42762306a36Sopenharmony_ci		mphy = dev->mt76.phys[hdr->band];
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	tail = skb->data + skb->len;
43062306a36Sopenharmony_ci	data += sizeof(struct header);
43162306a36Sopenharmony_ci	while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) {
43262306a36Sopenharmony_ci		switch (le16_to_cpu(tlv->tag)) {
43362306a36Sopenharmony_ci		case UNI_EVENT_IE_COUNTDOWN_CSA:
43462306a36Sopenharmony_ci			ieee80211_iterate_active_interfaces_atomic(mphy->hw,
43562306a36Sopenharmony_ci					IEEE80211_IFACE_ITER_RESUME_ALL,
43662306a36Sopenharmony_ci					mt7996_mcu_csa_finish, mphy->hw);
43762306a36Sopenharmony_ci			break;
43862306a36Sopenharmony_ci		case UNI_EVENT_IE_COUNTDOWN_BCC:
43962306a36Sopenharmony_ci			ieee80211_iterate_active_interfaces_atomic(mphy->hw,
44062306a36Sopenharmony_ci					IEEE80211_IFACE_ITER_RESUME_ALL,
44162306a36Sopenharmony_ci					mt7996_mcu_cca_finish, mphy->hw);
44262306a36Sopenharmony_ci			break;
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		data += le16_to_cpu(tlv->len);
44662306a36Sopenharmony_ci		tlv = (struct tlv *)data;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void
45162306a36Sopenharmony_cimt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	switch (rxd->ext_eid) {
45662306a36Sopenharmony_ci	case MCU_EXT_EVENT_FW_LOG_2_HOST:
45762306a36Sopenharmony_ci		mt7996_mcu_rx_log_message(dev, skb);
45862306a36Sopenharmony_ci		break;
45962306a36Sopenharmony_ci	default:
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic void
46562306a36Sopenharmony_cimt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	switch (rxd->eid) {
47062306a36Sopenharmony_ci	case MCU_EVENT_EXT:
47162306a36Sopenharmony_ci		mt7996_mcu_rx_ext_event(dev, skb);
47262306a36Sopenharmony_ci		break;
47362306a36Sopenharmony_ci	default:
47462306a36Sopenharmony_ci		break;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	dev_kfree_skb(skb);
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic void
48062306a36Sopenharmony_cimt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	switch (rxd->eid) {
48562306a36Sopenharmony_ci	case MCU_UNI_EVENT_FW_LOG_2_HOST:
48662306a36Sopenharmony_ci		mt7996_mcu_rx_log_message(dev, skb);
48762306a36Sopenharmony_ci		break;
48862306a36Sopenharmony_ci	case MCU_UNI_EVENT_IE_COUNTDOWN:
48962306a36Sopenharmony_ci		mt7996_mcu_ie_countdown(dev, skb);
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	case MCU_UNI_EVENT_RDD_REPORT:
49262306a36Sopenharmony_ci		mt7996_mcu_rx_radar_detected(dev, skb);
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	default:
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci	dev_kfree_skb(skb);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_civoid mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) {
50562306a36Sopenharmony_ci		mt7996_mcu_uni_rx_unsolicited_event(dev, skb);
50662306a36Sopenharmony_ci		return;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/* WA still uses legacy event*/
51062306a36Sopenharmony_ci	if (rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
51162306a36Sopenharmony_ci	    !rxd->seq)
51262306a36Sopenharmony_ci		mt7996_mcu_rx_unsolicited_event(dev, skb);
51362306a36Sopenharmony_ci	else
51462306a36Sopenharmony_ci		mt76_mcu_rx_event(&dev->mt76, skb);
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic struct tlv *
51862306a36Sopenharmony_cimt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct tlv *ptlv, tlv = {
52162306a36Sopenharmony_ci		.tag = cpu_to_le16(tag),
52262306a36Sopenharmony_ci		.len = cpu_to_le16(len),
52362306a36Sopenharmony_ci	};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	ptlv = skb_put(skb, len);
52662306a36Sopenharmony_ci	memcpy(ptlv, &tlv, sizeof(tlv));
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return ptlv;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic void
53262306a36Sopenharmony_cimt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
53362306a36Sopenharmony_ci			struct mt7996_phy *phy)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	static const u8 rlm_ch_band[] = {
53662306a36Sopenharmony_ci		[NL80211_BAND_2GHZ] = 1,
53762306a36Sopenharmony_ci		[NL80211_BAND_5GHZ] = 2,
53862306a36Sopenharmony_ci		[NL80211_BAND_6GHZ] = 3,
53962306a36Sopenharmony_ci	};
54062306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
54162306a36Sopenharmony_ci	struct bss_rlm_tlv *ch;
54262306a36Sopenharmony_ci	struct tlv *tlv;
54362306a36Sopenharmony_ci	int freq1 = chandef->center_freq1;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*ch));
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	ch = (struct bss_rlm_tlv *)tlv;
54862306a36Sopenharmony_ci	ch->control_channel = chandef->chan->hw_value;
54962306a36Sopenharmony_ci	ch->center_chan = ieee80211_frequency_to_channel(freq1);
55062306a36Sopenharmony_ci	ch->bw = mt76_connac_chan_bw(chandef);
55162306a36Sopenharmony_ci	ch->tx_streams = hweight8(phy->mt76->antenna_mask);
55262306a36Sopenharmony_ci	ch->rx_streams = hweight8(phy->mt76->antenna_mask);
55362306a36Sopenharmony_ci	ch->band = rlm_ch_band[chandef->chan->band];
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
55662306a36Sopenharmony_ci		int freq2 = chandef->center_freq2;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci		ch->center_chan2 = ieee80211_frequency_to_channel(freq2);
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void
56362306a36Sopenharmony_cimt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
56462306a36Sopenharmony_ci		      struct mt7996_phy *phy)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct bss_ra_tlv *ra;
56762306a36Sopenharmony_ci	struct tlv *tlv;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RA, sizeof(*ra));
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	ra = (struct bss_ra_tlv *)tlv;
57262306a36Sopenharmony_ci	ra->short_preamble = true;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic void
57662306a36Sopenharmony_cimt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
57762306a36Sopenharmony_ci		      struct mt7996_phy *phy)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci#define DEFAULT_HE_PE_DURATION		4
58062306a36Sopenharmony_ci#define DEFAULT_HE_DURATION_RTS_THRES	1023
58162306a36Sopenharmony_ci	const struct ieee80211_sta_he_cap *cap;
58262306a36Sopenharmony_ci	struct bss_info_uni_he *he;
58362306a36Sopenharmony_ci	struct tlv *tlv;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	he = (struct bss_info_uni_he *)tlv;
59062306a36Sopenharmony_ci	he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
59162306a36Sopenharmony_ci	if (!he->he_pe_duration)
59262306a36Sopenharmony_ci		he->he_pe_duration = DEFAULT_HE_PE_DURATION;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
59562306a36Sopenharmony_ci	if (!he->he_rts_thres)
59662306a36Sopenharmony_ci		he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;
59962306a36Sopenharmony_ci	he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;
60062306a36Sopenharmony_ci	he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic void
60462306a36Sopenharmony_cimt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
60562306a36Sopenharmony_ci		       struct mt7996_phy *phy)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
60862306a36Sopenharmony_ci	struct bss_rate_tlv *bmc;
60962306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
61062306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
61162306a36Sopenharmony_ci	struct tlv *tlv;
61262306a36Sopenharmony_ci	u8 idx = mvif->mcast_rates_idx ?
61362306a36Sopenharmony_ci		 mvif->mcast_rates_idx : mvif->basic_rates_idx;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc));
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	bmc = (struct bss_rate_tlv *)tlv;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	bmc->short_preamble = (band == NL80211_BAND_2GHZ);
62062306a36Sopenharmony_ci	bmc->bc_fixed_rate = idx;
62162306a36Sopenharmony_ci	bmc->mc_fixed_rate = idx;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void
62562306a36Sopenharmony_cimt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	struct bss_txcmd_tlv *txcmd;
62862306a36Sopenharmony_ci	struct tlv *tlv;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_TXCMD, sizeof(*txcmd));
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	txcmd = (struct bss_txcmd_tlv *)tlv;
63362306a36Sopenharmony_ci	txcmd->txcmd_mode = en;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic void
63762306a36Sopenharmony_cimt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
63862306a36Sopenharmony_ci{
63962306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
64062306a36Sopenharmony_ci	struct bss_mld_tlv *mld;
64162306a36Sopenharmony_ci	struct tlv *tlv;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld));
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	mld = (struct bss_mld_tlv *)tlv;
64662306a36Sopenharmony_ci	mld->group_mld_id = 0xff;
64762306a36Sopenharmony_ci	mld->own_mld_id = mvif->mt76.idx;
64862306a36Sopenharmony_ci	mld->remap_idx = 0xff;
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic void
65262306a36Sopenharmony_cimt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
65562306a36Sopenharmony_ci	struct bss_sec_tlv *sec;
65662306a36Sopenharmony_ci	struct tlv *tlv;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec));
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	sec = (struct bss_sec_tlv *)tlv;
66162306a36Sopenharmony_ci	sec->cipher = mvif->cipher;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic int
66562306a36Sopenharmony_cimt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
66662306a36Sopenharmony_ci		       bool bssid, bool enable)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci#define UNI_MUAR_ENTRY 2
66962306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
67062306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
67162306a36Sopenharmony_ci	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
67262306a36Sopenharmony_ci	const u8 *addr = vif->addr;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	struct {
67562306a36Sopenharmony_ci		struct {
67662306a36Sopenharmony_ci			u8 band;
67762306a36Sopenharmony_ci			u8 __rsv[3];
67862306a36Sopenharmony_ci		} hdr;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		__le16 tag;
68162306a36Sopenharmony_ci		__le16 len;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		bool smesh;
68462306a36Sopenharmony_ci		u8 bssid;
68562306a36Sopenharmony_ci		u8 index;
68662306a36Sopenharmony_ci		u8 entry_add;
68762306a36Sopenharmony_ci		u8 addr[ETH_ALEN];
68862306a36Sopenharmony_ci		u8 __rsv[2];
68962306a36Sopenharmony_ci	} __packed req = {
69062306a36Sopenharmony_ci		.hdr.band = phy->mt76->band_idx,
69162306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_MUAR_ENTRY),
69262306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - sizeof(req.hdr)),
69362306a36Sopenharmony_ci		.smesh = false,
69462306a36Sopenharmony_ci		.index = idx * 2 + bssid,
69562306a36Sopenharmony_ci		.entry_add = true,
69662306a36Sopenharmony_ci	};
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	if (bssid)
69962306a36Sopenharmony_ci		addr = vif->bss_conf.bssid;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	if (enable)
70262306a36Sopenharmony_ci		memcpy(req.addr, addr, ETH_ALEN);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REPT_MUAR), &req,
70562306a36Sopenharmony_ci				 sizeof(req), true);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic void
70962306a36Sopenharmony_cimt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
71262306a36Sopenharmony_ci	struct mt7996_phy *phy = mvif->phy;
71362306a36Sopenharmony_ci	struct bss_ifs_time_tlv *ifs_time;
71462306a36Sopenharmony_ci	struct tlv *tlv;
71562306a36Sopenharmony_ci	bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time));
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	ifs_time = (struct bss_ifs_time_tlv *)tlv;
72062306a36Sopenharmony_ci	ifs_time->slot_valid = true;
72162306a36Sopenharmony_ci	ifs_time->sifs_valid = true;
72262306a36Sopenharmony_ci	ifs_time->rifs_valid = true;
72362306a36Sopenharmony_ci	ifs_time->eifs_valid = true;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	ifs_time->slot_time = cpu_to_le16(phy->slottime);
72662306a36Sopenharmony_ci	ifs_time->sifs_time = cpu_to_le16(10);
72762306a36Sopenharmony_ci	ifs_time->rifs_time = cpu_to_le16(2);
72862306a36Sopenharmony_ci	ifs_time->eifs_time = cpu_to_le16(is_2ghz ? 78 : 84);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (is_2ghz) {
73162306a36Sopenharmony_ci		ifs_time->eifs_cck_valid = true;
73262306a36Sopenharmony_ci		ifs_time->eifs_cck_time = cpu_to_le16(314);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int
73762306a36Sopenharmony_cimt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
73862306a36Sopenharmony_ci			 struct ieee80211_vif *vif,
73962306a36Sopenharmony_ci			 struct ieee80211_sta *sta,
74062306a36Sopenharmony_ci			 struct mt76_phy *phy, u16 wlan_idx,
74162306a36Sopenharmony_ci			 bool enable)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
74462306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->chandef;
74562306a36Sopenharmony_ci	struct mt76_connac_bss_basic_tlv *bss;
74662306a36Sopenharmony_ci	u32 type = CONNECTION_INFRA_AP;
74762306a36Sopenharmony_ci	u16 sta_wlan_idx = wlan_idx;
74862306a36Sopenharmony_ci	struct tlv *tlv;
74962306a36Sopenharmony_ci	int idx;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	switch (vif->type) {
75262306a36Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
75362306a36Sopenharmony_ci	case NL80211_IFTYPE_AP:
75462306a36Sopenharmony_ci	case NL80211_IFTYPE_MONITOR:
75562306a36Sopenharmony_ci		break;
75662306a36Sopenharmony_ci	case NL80211_IFTYPE_STATION:
75762306a36Sopenharmony_ci		if (enable) {
75862306a36Sopenharmony_ci			rcu_read_lock();
75962306a36Sopenharmony_ci			if (!sta)
76062306a36Sopenharmony_ci				sta = ieee80211_find_sta(vif,
76162306a36Sopenharmony_ci							 vif->bss_conf.bssid);
76262306a36Sopenharmony_ci			/* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
76362306a36Sopenharmony_ci			if (sta) {
76462306a36Sopenharmony_ci				struct mt76_wcid *wcid;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci				wcid = (struct mt76_wcid *)sta->drv_priv;
76762306a36Sopenharmony_ci				sta_wlan_idx = wcid->idx;
76862306a36Sopenharmony_ci			}
76962306a36Sopenharmony_ci			rcu_read_unlock();
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci		type = CONNECTION_INFRA_STA;
77262306a36Sopenharmony_ci		break;
77362306a36Sopenharmony_ci	case NL80211_IFTYPE_ADHOC:
77462306a36Sopenharmony_ci		type = CONNECTION_IBSS_ADHOC;
77562306a36Sopenharmony_ci		break;
77662306a36Sopenharmony_ci	default:
77762306a36Sopenharmony_ci		WARN_ON(1);
77862306a36Sopenharmony_ci		break;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*bss));
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	bss = (struct mt76_connac_bss_basic_tlv *)tlv;
78462306a36Sopenharmony_ci	bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
78562306a36Sopenharmony_ci	bss->dtim_period = vif->bss_conf.dtim_period;
78662306a36Sopenharmony_ci	bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
78762306a36Sopenharmony_ci	bss->sta_idx = cpu_to_le16(sta_wlan_idx);
78862306a36Sopenharmony_ci	bss->conn_type = cpu_to_le32(type);
78962306a36Sopenharmony_ci	bss->omac_idx = mvif->omac_idx;
79062306a36Sopenharmony_ci	bss->band_idx = mvif->band_idx;
79162306a36Sopenharmony_ci	bss->wmm_idx = mvif->wmm_idx;
79262306a36Sopenharmony_ci	bss->conn_state = !enable;
79362306a36Sopenharmony_ci	bss->active = enable;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
79662306a36Sopenharmony_ci	bss->hw_bss_idx = idx;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_MONITOR) {
79962306a36Sopenharmony_ci		memcpy(bss->bssid, phy->macaddr, ETH_ALEN);
80062306a36Sopenharmony_ci		return 0;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
80462306a36Sopenharmony_ci	bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
80562306a36Sopenharmony_ci	bss->dtim_period = vif->bss_conf.dtim_period;
80662306a36Sopenharmony_ci	bss->phymode = mt76_connac_get_phy_mode(phy, vif,
80762306a36Sopenharmony_ci						chandef->chan->band, NULL);
80862306a36Sopenharmony_ci	bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, vif,
80962306a36Sopenharmony_ci							chandef->chan->band);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return 0;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic struct sk_buff *
81562306a36Sopenharmony_ci__mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	struct bss_req_hdr hdr = {
81862306a36Sopenharmony_ci		.bss_idx = mvif->idx,
81962306a36Sopenharmony_ci	};
82062306a36Sopenharmony_ci	struct sk_buff *skb;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(dev, NULL, len);
82362306a36Sopenharmony_ci	if (!skb)
82462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	skb_put_data(skb, &hdr, sizeof(hdr));
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	return skb;
82962306a36Sopenharmony_ci}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ciint mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
83262306a36Sopenharmony_ci			    struct ieee80211_vif *vif, int enable)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
83562306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
83662306a36Sopenharmony_ci	struct sk_buff *skb;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) {
83962306a36Sopenharmony_ci		mt7996_mcu_muar_config(phy, vif, false, enable);
84062306a36Sopenharmony_ci		mt7996_mcu_muar_config(phy, vif, true, enable);
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
84462306a36Sopenharmony_ci					 MT7996_BSS_UPDATE_MAX_SIZE);
84562306a36Sopenharmony_ci	if (IS_ERR(skb))
84662306a36Sopenharmony_ci		return PTR_ERR(skb);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* bss_basic must be first */
84962306a36Sopenharmony_ci	mt7996_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76,
85062306a36Sopenharmony_ci				 mvif->sta.wcid.idx, enable);
85162306a36Sopenharmony_ci	mt7996_mcu_bss_sec_tlv(skb, vif);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_MONITOR)
85462306a36Sopenharmony_ci		goto out;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	if (enable) {
85762306a36Sopenharmony_ci		mt7996_mcu_bss_rfch_tlv(skb, vif, phy);
85862306a36Sopenharmony_ci		mt7996_mcu_bss_bmc_tlv(skb, vif, phy);
85962306a36Sopenharmony_ci		mt7996_mcu_bss_ra_tlv(skb, vif, phy);
86062306a36Sopenharmony_ci		mt7996_mcu_bss_txcmd_tlv(skb, true);
86162306a36Sopenharmony_ci		mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		if (vif->bss_conf.he_support)
86462306a36Sopenharmony_ci			mt7996_mcu_bss_he_tlv(skb, vif, phy);
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		/* this tag is necessary no matter if the vif is MLD */
86762306a36Sopenharmony_ci		mt7996_mcu_bss_mld_tlv(skb, vif);
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ciout:
87062306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
87162306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ciint mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
87762306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
87862306a36Sopenharmony_ci	struct sk_buff *skb;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
88162306a36Sopenharmony_ci					 MT7996_BSS_UPDATE_MAX_SIZE);
88262306a36Sopenharmony_ci	if (IS_ERR(skb))
88362306a36Sopenharmony_ci		return PTR_ERR(skb);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
88862306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic int
89262306a36Sopenharmony_cimt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
89362306a36Sopenharmony_ci		  struct ieee80211_ampdu_params *params,
89462306a36Sopenharmony_ci		  bool enable, bool tx)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv;
89762306a36Sopenharmony_ci	struct sta_rec_ba_uni *ba;
89862306a36Sopenharmony_ci	struct sk_buff *skb;
89962306a36Sopenharmony_ci	struct tlv *tlv;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,
90262306a36Sopenharmony_ci					      MT7996_STA_UPDATE_MAX_SIZE);
90362306a36Sopenharmony_ci	if (IS_ERR(skb))
90462306a36Sopenharmony_ci		return PTR_ERR(skb);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	ba = (struct sta_rec_ba_uni *)tlv;
90962306a36Sopenharmony_ci	ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT;
91062306a36Sopenharmony_ci	ba->winsize = cpu_to_le16(params->buf_size);
91162306a36Sopenharmony_ci	ba->ssn = cpu_to_le16(params->ssn);
91262306a36Sopenharmony_ci	ba->ba_en = enable << params->tid;
91362306a36Sopenharmony_ci	ba->amsdu = params->amsdu;
91462306a36Sopenharmony_ci	ba->tid = params->tid;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(dev, skb,
91762306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci/** starec & wtbl **/
92162306a36Sopenharmony_ciint mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
92262306a36Sopenharmony_ci			 struct ieee80211_ampdu_params *params,
92362306a36Sopenharmony_ci			 bool enable)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
92662306a36Sopenharmony_ci	struct mt7996_vif *mvif = msta->vif;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	if (enable && !params->amsdu)
92962306a36Sopenharmony_ci		msta->wcid.amsdu = false;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
93262306a36Sopenharmony_ci				 enable, true);
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ciint mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
93662306a36Sopenharmony_ci			 struct ieee80211_ampdu_params *params,
93762306a36Sopenharmony_ci			 bool enable)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
94062306a36Sopenharmony_ci	struct mt7996_vif *mvif = msta->vif;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
94362306a36Sopenharmony_ci				 enable, false);
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic void
94762306a36Sopenharmony_cimt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
95062306a36Sopenharmony_ci	struct ieee80211_he_mcs_nss_supp mcs_map;
95162306a36Sopenharmony_ci	struct sta_rec_he_v2 *he;
95262306a36Sopenharmony_ci	struct tlv *tlv;
95362306a36Sopenharmony_ci	int i = 0;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!sta->deflink.he_cap.has_he)
95662306a36Sopenharmony_ci		return;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he));
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	he = (struct sta_rec_he_v2 *)tlv;
96162306a36Sopenharmony_ci	for (i = 0; i < 11; i++) {
96262306a36Sopenharmony_ci		if (i < 6)
96362306a36Sopenharmony_ci			he->he_mac_cap[i] = elem->mac_cap_info[i];
96462306a36Sopenharmony_ci		he->he_phy_cap[i] = elem->phy_cap_info[i];
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
96862306a36Sopenharmony_ci	switch (sta->deflink.bandwidth) {
96962306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
97062306a36Sopenharmony_ci		if (elem->phy_cap_info[0] &
97162306a36Sopenharmony_ci		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
97262306a36Sopenharmony_ci			mt7996_mcu_set_sta_he_mcs(sta,
97362306a36Sopenharmony_ci						  &he->max_nss_mcs[CMD_HE_MCS_BW8080],
97462306a36Sopenharmony_ci						  le16_to_cpu(mcs_map.rx_mcs_80p80));
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci		mt7996_mcu_set_sta_he_mcs(sta,
97762306a36Sopenharmony_ci					  &he->max_nss_mcs[CMD_HE_MCS_BW160],
97862306a36Sopenharmony_ci					  le16_to_cpu(mcs_map.rx_mcs_160));
97962306a36Sopenharmony_ci		fallthrough;
98062306a36Sopenharmony_ci	default:
98162306a36Sopenharmony_ci		mt7996_mcu_set_sta_he_mcs(sta,
98262306a36Sopenharmony_ci					  &he->max_nss_mcs[CMD_HE_MCS_BW80],
98362306a36Sopenharmony_ci					  le16_to_cpu(mcs_map.rx_mcs_80));
98462306a36Sopenharmony_ci		break;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	he->pkt_ext = 2;
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic void
99162306a36Sopenharmony_cimt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	struct sta_rec_he_6g_capa *he_6g;
99462306a36Sopenharmony_ci	struct tlv *tlv;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	if (!sta->deflink.he_6ghz_capa.capa)
99762306a36Sopenharmony_ci		return;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g));
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	he_6g = (struct sta_rec_he_6g_capa *)tlv;
100262306a36Sopenharmony_ci	he_6g->capa = sta->deflink.he_6ghz_capa.capa;
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic void
100662306a36Sopenharmony_cimt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
100962306a36Sopenharmony_ci	struct ieee80211_vif *vif = container_of((void *)msta->vif,
101062306a36Sopenharmony_ci						 struct ieee80211_vif, drv_priv);
101162306a36Sopenharmony_ci	struct ieee80211_eht_mcs_nss_supp *mcs_map;
101262306a36Sopenharmony_ci	struct ieee80211_eht_cap_elem_fixed *elem;
101362306a36Sopenharmony_ci	struct sta_rec_eht *eht;
101462306a36Sopenharmony_ci	struct tlv *tlv;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (!sta->deflink.eht_cap.has_eht)
101762306a36Sopenharmony_ci		return;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	mcs_map = &sta->deflink.eht_cap.eht_mcs_nss_supp;
102062306a36Sopenharmony_ci	elem = &sta->deflink.eht_cap.eht_cap_elem;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht));
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	eht = (struct sta_rec_eht *)tlv;
102562306a36Sopenharmony_ci	eht->tid_bitmap = 0xff;
102662306a36Sopenharmony_ci	eht->mac_cap = cpu_to_le16(*(u16 *)elem->mac_cap_info);
102762306a36Sopenharmony_ci	eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info);
102862306a36Sopenharmony_ci	eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
103162306a36Sopenharmony_ci	    (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
103262306a36Sopenharmony_ci	     (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
103362306a36Sopenharmony_ci	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
103462306a36Sopenharmony_ci	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
103562306a36Sopenharmony_ci	      IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) {
103662306a36Sopenharmony_ci		memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz,
103762306a36Sopenharmony_ci		       sizeof(eht->mcs_map_bw20));
103862306a36Sopenharmony_ci		return;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80));
104262306a36Sopenharmony_ci	memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160));
104362306a36Sopenharmony_ci	memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320));
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic void
104762306a36Sopenharmony_cimt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct sta_rec_ht *ht;
105062306a36Sopenharmony_ci	struct tlv *tlv;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (!sta->deflink.ht_cap.ht_supported)
105362306a36Sopenharmony_ci		return;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	ht = (struct sta_rec_ht *)tlv;
105862306a36Sopenharmony_ci	ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic void
106262306a36Sopenharmony_cimt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct sta_rec_vht *vht;
106562306a36Sopenharmony_ci	struct tlv *tlv;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* For 6G band, this tlv is necessary to let hw work normally */
106862306a36Sopenharmony_ci	if (!sta->deflink.he_6ghz_capa.capa && !sta->deflink.vht_cap.vht_supported)
106962306a36Sopenharmony_ci		return;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	vht = (struct sta_rec_vht *)tlv;
107462306a36Sopenharmony_ci	vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
107562306a36Sopenharmony_ci	vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
107662306a36Sopenharmony_ci	vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic void
108062306a36Sopenharmony_cimt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
108162306a36Sopenharmony_ci			 struct ieee80211_vif *vif, struct ieee80211_sta *sta)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
108462306a36Sopenharmony_ci	struct sta_rec_amsdu *amsdu;
108562306a36Sopenharmony_ci	struct tlv *tlv;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
108862306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_MESH_POINT &&
108962306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP)
109062306a36Sopenharmony_ci		return;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (!sta->deflink.agg.max_amsdu_len)
109362306a36Sopenharmony_ci		return;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
109662306a36Sopenharmony_ci	amsdu = (struct sta_rec_amsdu *)tlv;
109762306a36Sopenharmony_ci	amsdu->max_amsdu_num = 8;
109862306a36Sopenharmony_ci	amsdu->amsdu_en = true;
109962306a36Sopenharmony_ci	msta->wcid.amsdu = true;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	switch (sta->deflink.agg.max_amsdu_len) {
110262306a36Sopenharmony_ci	case IEEE80211_MAX_MPDU_LEN_VHT_11454:
110362306a36Sopenharmony_ci		amsdu->max_mpdu_size =
110462306a36Sopenharmony_ci			IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
110562306a36Sopenharmony_ci		return;
110662306a36Sopenharmony_ci	case IEEE80211_MAX_MPDU_LEN_HT_7935:
110762306a36Sopenharmony_ci	case IEEE80211_MAX_MPDU_LEN_VHT_7991:
110862306a36Sopenharmony_ci		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
110962306a36Sopenharmony_ci		return;
111062306a36Sopenharmony_ci	default:
111162306a36Sopenharmony_ci		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
111262306a36Sopenharmony_ci		return;
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic void
111762306a36Sopenharmony_cimt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
111862306a36Sopenharmony_ci			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
112162306a36Sopenharmony_ci	struct sta_rec_muru *muru;
112262306a36Sopenharmony_ci	struct tlv *tlv;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
112562306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP)
112662306a36Sopenharmony_ci		return;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	muru = (struct sta_rec_muru *)tlv;
113162306a36Sopenharmony_ci	muru->cfg.mimo_dl_en = vif->bss_conf.eht_mu_beamformer ||
113262306a36Sopenharmony_ci			       vif->bss_conf.he_mu_beamformer ||
113362306a36Sopenharmony_ci			       vif->bss_conf.vht_mu_beamformer ||
113462306a36Sopenharmony_ci			       vif->bss_conf.vht_mu_beamformee;
113562306a36Sopenharmony_ci	muru->cfg.ofdma_dl_en = true;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported)
113862306a36Sopenharmony_ci		muru->mimo_dl.vht_mu_bfee =
113962306a36Sopenharmony_ci			!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (!sta->deflink.he_cap.has_he)
114262306a36Sopenharmony_ci		return;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	muru->mimo_dl.partial_bw_dl_mimo =
114562306a36Sopenharmony_ci		HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	muru->mimo_ul.full_ul_mimo =
114862306a36Sopenharmony_ci		HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
114962306a36Sopenharmony_ci	muru->mimo_ul.partial_ul_mimo =
115062306a36Sopenharmony_ci		HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	muru->ofdma_dl.punc_pream_rx =
115362306a36Sopenharmony_ci		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
115462306a36Sopenharmony_ci	muru->ofdma_dl.he_20m_in_40m_2g =
115562306a36Sopenharmony_ci		HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
115662306a36Sopenharmony_ci	muru->ofdma_dl.he_20m_in_160m =
115762306a36Sopenharmony_ci		HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
115862306a36Sopenharmony_ci	muru->ofdma_dl.he_80m_in_160m =
115962306a36Sopenharmony_ci		HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	muru->ofdma_ul.t_frame_dur =
116262306a36Sopenharmony_ci		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
116362306a36Sopenharmony_ci	muru->ofdma_ul.mu_cascading =
116462306a36Sopenharmony_ci		HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
116562306a36Sopenharmony_ci	muru->ofdma_ul.uo_ra =
116662306a36Sopenharmony_ci		HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic inline bool
117062306a36Sopenharmony_cimt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
117162306a36Sopenharmony_ci			struct ieee80211_sta *sta, bool bfee)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	int sts = hweight16(phy->mt76->chainmask);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
117662306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP)
117762306a36Sopenharmony_ci		return false;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	if (!bfee && sts < 2)
118062306a36Sopenharmony_ci		return false;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (sta->deflink.eht_cap.has_eht) {
118362306a36Sopenharmony_ci		struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
118462306a36Sopenharmony_ci		struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci		if (bfee)
118762306a36Sopenharmony_ci			return vif->bss_conf.eht_su_beamformee &&
118862306a36Sopenharmony_ci			       EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
118962306a36Sopenharmony_ci		else
119062306a36Sopenharmony_ci			return vif->bss_conf.eht_su_beamformer &&
119162306a36Sopenharmony_ci			       EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
119562306a36Sopenharmony_ci		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci		if (bfee)
119862306a36Sopenharmony_ci			return vif->bss_conf.he_su_beamformee &&
119962306a36Sopenharmony_ci			       HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
120062306a36Sopenharmony_ci		else
120162306a36Sopenharmony_ci			return vif->bss_conf.he_su_beamformer &&
120262306a36Sopenharmony_ci			       HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported) {
120662306a36Sopenharmony_ci		u32 cap = sta->deflink.vht_cap.cap;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci		if (bfee)
120962306a36Sopenharmony_ci			return vif->bss_conf.vht_su_beamformee &&
121062306a36Sopenharmony_ci			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
121162306a36Sopenharmony_ci		else
121262306a36Sopenharmony_ci			return vif->bss_conf.vht_su_beamformer &&
121362306a36Sopenharmony_ci			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
121462306a36Sopenharmony_ci	}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	return false;
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic void
122062306a36Sopenharmony_cimt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	bf->sounding_phy = MT_PHY_TYPE_OFDM;
122362306a36Sopenharmony_ci	bf->ndp_rate = 0;				/* mcs0 */
122462306a36Sopenharmony_ci	bf->ndpa_rate = MT7996_CFEND_RATE_DEFAULT;	/* ofdm 24m */
122562306a36Sopenharmony_ci	bf->rept_poll_rate = MT7996_CFEND_RATE_DEFAULT;	/* ofdm 24m */
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic void
122962306a36Sopenharmony_cimt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
123062306a36Sopenharmony_ci		       struct sta_rec_bf *bf)
123162306a36Sopenharmony_ci{
123262306a36Sopenharmony_ci	struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
123362306a36Sopenharmony_ci	u8 n = 0;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_HT;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) &&
123862306a36Sopenharmony_ci	    (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED))
123962306a36Sopenharmony_ci		n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK,
124062306a36Sopenharmony_ci			      mcs->tx_params);
124162306a36Sopenharmony_ci	else if (mcs->rx_mask[3])
124262306a36Sopenharmony_ci		n = 3;
124362306a36Sopenharmony_ci	else if (mcs->rx_mask[2])
124462306a36Sopenharmony_ci		n = 2;
124562306a36Sopenharmony_ci	else if (mcs->rx_mask[1])
124662306a36Sopenharmony_ci		n = 1;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	bf->nrow = hweight8(phy->mt76->antenna_mask) - 1;
124962306a36Sopenharmony_ci	bf->ncol = min_t(u8, bf->nrow, n);
125062306a36Sopenharmony_ci	bf->ibf_ncol = n;
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic void
125462306a36Sopenharmony_cimt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
125562306a36Sopenharmony_ci			struct sta_rec_bf *bf, bool explicit)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
125862306a36Sopenharmony_ci	struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
125962306a36Sopenharmony_ci	u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
126062306a36Sopenharmony_ci	u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
126162306a36Sopenharmony_ci	u8 tx_ant = hweight8(phy->mt76->antenna_mask) - 1;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_VHT;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (explicit) {
126662306a36Sopenharmony_ci		u8 sts, snd_dim;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		mt7996_mcu_sta_sounding_rate(bf);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
127162306a36Sopenharmony_ci				pc->cap);
127262306a36Sopenharmony_ci		snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
127362306a36Sopenharmony_ci				    vc->cap);
127462306a36Sopenharmony_ci		bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
127562306a36Sopenharmony_ci		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
127662306a36Sopenharmony_ci		bf->ibf_ncol = bf->ncol;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
127962306a36Sopenharmony_ci			bf->nrow = 1;
128062306a36Sopenharmony_ci	} else {
128162306a36Sopenharmony_ci		bf->nrow = tx_ant;
128262306a36Sopenharmony_ci		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
128362306a36Sopenharmony_ci		bf->ibf_ncol = nss_mcs;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
128662306a36Sopenharmony_ci			bf->ibf_nrow = 1;
128762306a36Sopenharmony_ci	}
128862306a36Sopenharmony_ci}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cistatic void
129162306a36Sopenharmony_cimt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
129262306a36Sopenharmony_ci		       struct mt7996_phy *phy, struct sta_rec_bf *bf)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
129562306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
129662306a36Sopenharmony_ci	const struct ieee80211_sta_he_cap *vc =
129762306a36Sopenharmony_ci		mt76_connac_get_he_phy_cap(phy->mt76, vif);
129862306a36Sopenharmony_ci	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
129962306a36Sopenharmony_ci	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
130062306a36Sopenharmony_ci	u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
130162306a36Sopenharmony_ci	u8 snd_dim, sts;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_HE_SU;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	mt7996_mcu_sta_sounding_rate(bf);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
130862306a36Sopenharmony_ci				pe->phy_cap_info[6]);
130962306a36Sopenharmony_ci	bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
131062306a36Sopenharmony_ci				pe->phy_cap_info[6]);
131162306a36Sopenharmony_ci	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
131262306a36Sopenharmony_ci			 ve->phy_cap_info[5]);
131362306a36Sopenharmony_ci	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
131462306a36Sopenharmony_ci		     pe->phy_cap_info[4]);
131562306a36Sopenharmony_ci	bf->nrow = min_t(u8, snd_dim, sts);
131662306a36Sopenharmony_ci	bf->ncol = min_t(u8, nss_mcs, bf->nrow);
131762306a36Sopenharmony_ci	bf->ibf_ncol = bf->ncol;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
132062306a36Sopenharmony_ci		return;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	/* go over for 160MHz and 80p80 */
132362306a36Sopenharmony_ci	if (pe->phy_cap_info[0] &
132462306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
132562306a36Sopenharmony_ci		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160);
132662306a36Sopenharmony_ci		nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci		bf->ncol_gt_bw80 = nss_mcs;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (pe->phy_cap_info[0] &
133262306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
133362306a36Sopenharmony_ci		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80);
133462306a36Sopenharmony_ci		nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		if (bf->ncol_gt_bw80)
133762306a36Sopenharmony_ci			bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs);
133862306a36Sopenharmony_ci		else
133962306a36Sopenharmony_ci			bf->ncol_gt_bw80 = nss_mcs;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
134362306a36Sopenharmony_ci			 ve->phy_cap_info[5]);
134462306a36Sopenharmony_ci	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
134562306a36Sopenharmony_ci		     pe->phy_cap_info[4]);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	bf->nrow_gt_bw80 = min_t(int, snd_dim, sts);
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic void
135162306a36Sopenharmony_cimt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
135262306a36Sopenharmony_ci			struct mt7996_phy *phy, struct sta_rec_bf *bf)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
135562306a36Sopenharmony_ci	struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
135662306a36Sopenharmony_ci	struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;
135762306a36Sopenharmony_ci	const struct ieee80211_sta_eht_cap *vc =
135862306a36Sopenharmony_ci		mt76_connac_get_eht_phy_cap(phy->mt76, vif);
135962306a36Sopenharmony_ci	const struct ieee80211_eht_cap_elem_fixed *ve = &vc->eht_cap_elem;
136062306a36Sopenharmony_ci	u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss,
136162306a36Sopenharmony_ci				 IEEE80211_EHT_MCS_NSS_RX) - 1;
136262306a36Sopenharmony_ci	u8 snd_dim, sts;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_EHT_MU;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	mt7996_mcu_sta_sounding_rate(bf);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	bf->trigger_su = EHT_PHY(CAP3_TRIG_SU_BF_FDBK, pe->phy_cap_info[3]);
136962306a36Sopenharmony_ci	bf->trigger_mu = EHT_PHY(CAP3_TRIG_MU_BF_PART_BW_FDBK, pe->phy_cap_info[3]);
137062306a36Sopenharmony_ci	snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_80MHZ_MASK, ve->phy_cap_info[2]);
137162306a36Sopenharmony_ci	sts = EHT_PHY(CAP0_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[0]) +
137262306a36Sopenharmony_ci	      (EHT_PHY(CAP1_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[1]) << 1);
137362306a36Sopenharmony_ci	bf->nrow = min_t(u8, snd_dim, sts);
137462306a36Sopenharmony_ci	bf->ncol = min_t(u8, nss_mcs, bf->nrow);
137562306a36Sopenharmony_ci	bf->ibf_ncol = bf->ncol;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_160)
137862306a36Sopenharmony_ci		return;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	switch (sta->deflink.bandwidth) {
138162306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
138262306a36Sopenharmony_ci		snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_160MHZ_MASK, ve->phy_cap_info[2]);
138362306a36Sopenharmony_ci		sts = EHT_PHY(CAP1_BEAMFORMEE_SS_160MHZ_MASK, pe->phy_cap_info[1]);
138462306a36Sopenharmony_ci		nss_mcs = u8_get_bits(eht_nss->bw._160.rx_tx_mcs9_max_nss,
138562306a36Sopenharmony_ci				      IEEE80211_EHT_MCS_NSS_RX) - 1;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci		bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts);
138862306a36Sopenharmony_ci		bf->ncol_gt_bw80 = nss_mcs;
138962306a36Sopenharmony_ci		break;
139062306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_320:
139162306a36Sopenharmony_ci		snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_320MHZ_MASK, ve->phy_cap_info[2]) +
139262306a36Sopenharmony_ci			  (EHT_PHY(CAP3_SOUNDING_DIM_320MHZ_MASK,
139362306a36Sopenharmony_ci				   ve->phy_cap_info[3]) << 1);
139462306a36Sopenharmony_ci		sts = EHT_PHY(CAP1_BEAMFORMEE_SS_320MHZ_MASK, pe->phy_cap_info[1]);
139562306a36Sopenharmony_ci		nss_mcs = u8_get_bits(eht_nss->bw._320.rx_tx_mcs9_max_nss,
139662306a36Sopenharmony_ci				      IEEE80211_EHT_MCS_NSS_RX) - 1;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci		bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts) << 4;
139962306a36Sopenharmony_ci		bf->ncol_gt_bw80 = nss_mcs << 4;
140062306a36Sopenharmony_ci		break;
140162306a36Sopenharmony_ci	default:
140262306a36Sopenharmony_ci		break;
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cistatic void
140762306a36Sopenharmony_cimt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
140862306a36Sopenharmony_ci			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
141162306a36Sopenharmony_ci	struct mt7996_phy *phy = mvif->phy;
141262306a36Sopenharmony_ci	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
141362306a36Sopenharmony_ci	struct sta_rec_bf *bf;
141462306a36Sopenharmony_ci	struct tlv *tlv;
141562306a36Sopenharmony_ci	const u8 matrix[4][4] = {
141662306a36Sopenharmony_ci		{0, 0, 0, 0},
141762306a36Sopenharmony_ci		{1, 1, 0, 0},	/* 2x1, 2x2, 2x3, 2x4 */
141862306a36Sopenharmony_ci		{2, 4, 4, 0},	/* 3x1, 3x2, 3x3, 3x4 */
141962306a36Sopenharmony_ci		{3, 5, 6, 0}	/* 4x1, 4x2, 4x3, 4x4 */
142062306a36Sopenharmony_ci	};
142162306a36Sopenharmony_ci	bool ebf;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
142462306a36Sopenharmony_ci		return;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	ebf = mt7996_is_ebf_supported(phy, vif, sta, false);
142762306a36Sopenharmony_ci	if (!ebf && !dev->ibf)
142862306a36Sopenharmony_ci		return;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
143162306a36Sopenharmony_ci	bf = (struct sta_rec_bf *)tlv;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	/* he/eht: eBF only, in accordance with spec
143462306a36Sopenharmony_ci	 * vht: support eBF and iBF
143562306a36Sopenharmony_ci	 * ht: iBF only, since mac80211 lacks of eBF support
143662306a36Sopenharmony_ci	 */
143762306a36Sopenharmony_ci	if (sta->deflink.eht_cap.has_eht && ebf)
143862306a36Sopenharmony_ci		mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf);
143962306a36Sopenharmony_ci	else if (sta->deflink.he_cap.has_he && ebf)
144062306a36Sopenharmony_ci		mt7996_mcu_sta_bfer_he(sta, vif, phy, bf);
144162306a36Sopenharmony_ci	else if (sta->deflink.vht_cap.vht_supported)
144262306a36Sopenharmony_ci		mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf);
144362306a36Sopenharmony_ci	else if (sta->deflink.ht_cap.ht_supported)
144462306a36Sopenharmony_ci		mt7996_mcu_sta_bfer_ht(sta, phy, bf);
144562306a36Sopenharmony_ci	else
144662306a36Sopenharmony_ci		return;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	bf->bf_cap = ebf ? ebf : dev->ibf << 1;
144962306a36Sopenharmony_ci	bf->bw = sta->deflink.bandwidth;
145062306a36Sopenharmony_ci	bf->ibf_dbw = sta->deflink.bandwidth;
145162306a36Sopenharmony_ci	bf->ibf_nrow = tx_ant;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
145462306a36Sopenharmony_ci		bf->ibf_timeout = 0x48;
145562306a36Sopenharmony_ci	else
145662306a36Sopenharmony_ci		bf->ibf_timeout = 0x18;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	if (ebf && bf->nrow != tx_ant)
145962306a36Sopenharmony_ci		bf->mem_20m = matrix[tx_ant][bf->ncol];
146062306a36Sopenharmony_ci	else
146162306a36Sopenharmony_ci		bf->mem_20m = matrix[bf->nrow][bf->ncol];
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	switch (sta->deflink.bandwidth) {
146462306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
146562306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_80:
146662306a36Sopenharmony_ci		bf->mem_total = bf->mem_20m * 2;
146762306a36Sopenharmony_ci		break;
146862306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_40:
146962306a36Sopenharmony_ci		bf->mem_total = bf->mem_20m;
147062306a36Sopenharmony_ci		break;
147162306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_20:
147262306a36Sopenharmony_ci	default:
147362306a36Sopenharmony_ci		break;
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_cistatic void
147862306a36Sopenharmony_cimt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
147962306a36Sopenharmony_ci			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
148262306a36Sopenharmony_ci	struct mt7996_phy *phy = mvif->phy;
148362306a36Sopenharmony_ci	int tx_ant = hweight8(phy->mt76->antenna_mask) - 1;
148462306a36Sopenharmony_ci	struct sta_rec_bfee *bfee;
148562306a36Sopenharmony_ci	struct tlv *tlv;
148662306a36Sopenharmony_ci	u8 nrow = 0;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
148962306a36Sopenharmony_ci		return;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	if (!mt7996_is_ebf_supported(phy, vif, sta, true))
149262306a36Sopenharmony_ci		return;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
149562306a36Sopenharmony_ci	bfee = (struct sta_rec_bfee *)tlv;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
149862306a36Sopenharmony_ci		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
150162306a36Sopenharmony_ci			      pe->phy_cap_info[5]);
150262306a36Sopenharmony_ci	} else if (sta->deflink.vht_cap.vht_supported) {
150362306a36Sopenharmony_ci		struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
150662306a36Sopenharmony_ci				 pc->cap);
150762306a36Sopenharmony_ci	}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	/* reply with identity matrix to avoid 2x2 BF negative gain */
151062306a36Sopenharmony_ci	bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic void
151462306a36Sopenharmony_cimt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
151562306a36Sopenharmony_ci		       struct ieee80211_vif *vif, struct ieee80211_sta *sta)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	struct sta_rec_phy *phy;
151862306a36Sopenharmony_ci	struct tlv *tlv;
151962306a36Sopenharmony_ci	u8 af = 0, mm = 0;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa)
152262306a36Sopenharmony_ci		return;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	phy = (struct sta_rec_phy *)tlv;
152762306a36Sopenharmony_ci	if (sta->deflink.ht_cap.ht_supported) {
152862306a36Sopenharmony_ci		af = sta->deflink.ht_cap.ampdu_factor;
152962306a36Sopenharmony_ci		mm = sta->deflink.ht_cap.ampdu_density;
153062306a36Sopenharmony_ci	}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported) {
153362306a36Sopenharmony_ci		u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
153462306a36Sopenharmony_ci				      sta->deflink.vht_cap.cap);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		af = max_t(u8, af, vht_af);
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (sta->deflink.he_6ghz_capa.capa) {
154062306a36Sopenharmony_ci		af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
154162306a36Sopenharmony_ci				   IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
154262306a36Sopenharmony_ci		mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
154362306a36Sopenharmony_ci				   IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
154462306a36Sopenharmony_ci	}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) |
154762306a36Sopenharmony_ci		     FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm);
154862306a36Sopenharmony_ci	phy->max_ampdu_len = af;
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_cistatic void
155262306a36Sopenharmony_cimt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb)
155362306a36Sopenharmony_ci{
155462306a36Sopenharmony_ci	struct sta_rec_hdrt *hdrt;
155562306a36Sopenharmony_ci	struct tlv *tlv;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDRT, sizeof(*hdrt));
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	hdrt = (struct sta_rec_hdrt *)tlv;
156062306a36Sopenharmony_ci	hdrt->hdrt_mode = 1;
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic void
156462306a36Sopenharmony_cimt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
156562306a36Sopenharmony_ci			     struct ieee80211_vif *vif,
156662306a36Sopenharmony_ci			     struct ieee80211_sta *sta)
156762306a36Sopenharmony_ci{
156862306a36Sopenharmony_ci	struct sta_rec_hdr_trans *hdr_trans;
156962306a36Sopenharmony_ci	struct mt76_wcid *wcid;
157062306a36Sopenharmony_ci	struct tlv *tlv;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans));
157362306a36Sopenharmony_ci	hdr_trans = (struct sta_rec_hdr_trans *)tlv;
157462306a36Sopenharmony_ci	hdr_trans->dis_rx_hdr_tran = true;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_STATION)
157762306a36Sopenharmony_ci		hdr_trans->to_ds = true;
157862306a36Sopenharmony_ci	else
157962306a36Sopenharmony_ci		hdr_trans->from_ds = true;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	wcid = (struct mt76_wcid *)sta->drv_priv;
158262306a36Sopenharmony_ci	if (!wcid)
158362306a36Sopenharmony_ci		return;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);
158662306a36Sopenharmony_ci	if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {
158762306a36Sopenharmony_ci		hdr_trans->to_ds = true;
158862306a36Sopenharmony_ci		hdr_trans->from_ds = true;
158962306a36Sopenharmony_ci	}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_MESH_POINT) {
159262306a36Sopenharmony_ci		hdr_trans->to_ds = true;
159362306a36Sopenharmony_ci		hdr_trans->from_ds = true;
159462306a36Sopenharmony_ci		hdr_trans->mesh = true;
159562306a36Sopenharmony_ci	}
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistatic enum mcu_mmps_mode
159962306a36Sopenharmony_cimt7996_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	switch (smps) {
160262306a36Sopenharmony_ci	case IEEE80211_SMPS_OFF:
160362306a36Sopenharmony_ci		return MCU_MMPS_DISABLE;
160462306a36Sopenharmony_ci	case IEEE80211_SMPS_STATIC:
160562306a36Sopenharmony_ci		return MCU_MMPS_STATIC;
160662306a36Sopenharmony_ci	case IEEE80211_SMPS_DYNAMIC:
160762306a36Sopenharmony_ci		return MCU_MMPS_DYNAMIC;
160862306a36Sopenharmony_ci	default:
160962306a36Sopenharmony_ci		return MCU_MMPS_DISABLE;
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ciint mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
161462306a36Sopenharmony_ci				   void *data, u16 version)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	struct ra_fixed_rate *req;
161762306a36Sopenharmony_ci	struct uni_header hdr;
161862306a36Sopenharmony_ci	struct sk_buff *skb;
161962306a36Sopenharmony_ci	struct tlv *tlv;
162062306a36Sopenharmony_ci	int len;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	len = sizeof(hdr) + sizeof(*req);
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
162562306a36Sopenharmony_ci	if (!skb)
162662306a36Sopenharmony_ci		return -ENOMEM;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	skb_put_data(skb, &hdr, sizeof(hdr));
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_RA_FIXED_RATE, sizeof(*req));
163162306a36Sopenharmony_ci	req = (struct ra_fixed_rate *)tlv;
163262306a36Sopenharmony_ci	req->version = cpu_to_le16(version);
163362306a36Sopenharmony_ci	memcpy(&req->rate, data, sizeof(req->rate));
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
163662306a36Sopenharmony_ci				     MCU_WM_UNI_CMD(RA), true);
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_cistatic void
164062306a36Sopenharmony_cimt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
164162306a36Sopenharmony_ci			     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
164462306a36Sopenharmony_ci	struct mt76_phy *mphy = mvif->phy->mt76;
164562306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &mphy->chandef;
164662306a36Sopenharmony_ci	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
164762306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
164862306a36Sopenharmony_ci	struct sta_rec_ra *ra;
164962306a36Sopenharmony_ci	struct tlv *tlv;
165062306a36Sopenharmony_ci	u32 supp_rate = sta->deflink.supp_rates[band];
165162306a36Sopenharmony_ci	u32 cap = sta->wme ? STA_CAP_WMM : 0;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
165462306a36Sopenharmony_ci	ra = (struct sta_rec_ra *)tlv;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	ra->valid = true;
165762306a36Sopenharmony_ci	ra->auto_rate = true;
165862306a36Sopenharmony_ci	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
165962306a36Sopenharmony_ci	ra->channel = chandef->chan->hw_value;
166062306a36Sopenharmony_ci	ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ?
166162306a36Sopenharmony_ci		 CMD_CBW_320MHZ : sta->deflink.bandwidth;
166262306a36Sopenharmony_ci	ra->phy.bw = ra->bw;
166362306a36Sopenharmony_ci	ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (supp_rate) {
166662306a36Sopenharmony_ci		supp_rate &= mask->control[band].legacy;
166762306a36Sopenharmony_ci		ra->rate_len = hweight32(supp_rate);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci		if (band == NL80211_BAND_2GHZ) {
167062306a36Sopenharmony_ci			ra->supp_mode = MODE_CCK;
167162306a36Sopenharmony_ci			ra->supp_cck_rate = supp_rate & GENMASK(3, 0);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci			if (ra->rate_len > 4) {
167462306a36Sopenharmony_ci				ra->supp_mode |= MODE_OFDM;
167562306a36Sopenharmony_ci				ra->supp_ofdm_rate = supp_rate >> 4;
167662306a36Sopenharmony_ci			}
167762306a36Sopenharmony_ci		} else {
167862306a36Sopenharmony_ci			ra->supp_mode = MODE_OFDM;
167962306a36Sopenharmony_ci			ra->supp_ofdm_rate = supp_rate;
168062306a36Sopenharmony_ci		}
168162306a36Sopenharmony_ci	}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (sta->deflink.ht_cap.ht_supported) {
168462306a36Sopenharmony_ci		ra->supp_mode |= MODE_HT;
168562306a36Sopenharmony_ci		ra->af = sta->deflink.ht_cap.ampdu_factor;
168662306a36Sopenharmony_ci		ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci		cap |= STA_CAP_HT;
168962306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
169062306a36Sopenharmony_ci			cap |= STA_CAP_SGI_20;
169162306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
169262306a36Sopenharmony_ci			cap |= STA_CAP_SGI_40;
169362306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
169462306a36Sopenharmony_ci			cap |= STA_CAP_TX_STBC;
169562306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
169662306a36Sopenharmony_ci			cap |= STA_CAP_RX_STBC;
169762306a36Sopenharmony_ci		if (vif->bss_conf.ht_ldpc &&
169862306a36Sopenharmony_ci		    (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
169962306a36Sopenharmony_ci			cap |= STA_CAP_LDPC;
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci		mt7996_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
170262306a36Sopenharmony_ci					  mask->control[band].ht_mcs);
170362306a36Sopenharmony_ci		ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
170462306a36Sopenharmony_ci	}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported) {
170762306a36Sopenharmony_ci		u8 af;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci		ra->supp_mode |= MODE_VHT;
171062306a36Sopenharmony_ci		af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
171162306a36Sopenharmony_ci			       sta->deflink.vht_cap.cap);
171262306a36Sopenharmony_ci		ra->af = max_t(u8, ra->af, af);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci		cap |= STA_CAP_VHT;
171562306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
171662306a36Sopenharmony_ci			cap |= STA_CAP_VHT_SGI_80;
171762306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
171862306a36Sopenharmony_ci			cap |= STA_CAP_VHT_SGI_160;
171962306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
172062306a36Sopenharmony_ci			cap |= STA_CAP_VHT_TX_STBC;
172162306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
172262306a36Sopenharmony_ci			cap |= STA_CAP_VHT_RX_STBC;
172362306a36Sopenharmony_ci		if (vif->bss_conf.vht_ldpc &&
172462306a36Sopenharmony_ci		    (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
172562306a36Sopenharmony_ci			cap |= STA_CAP_VHT_LDPC;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci		mt7996_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
172862306a36Sopenharmony_ci					   mask->control[band].vht_mcs);
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
173262306a36Sopenharmony_ci		ra->supp_mode |= MODE_HE;
173362306a36Sopenharmony_ci		cap |= STA_CAP_HE;
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci		if (sta->deflink.he_6ghz_capa.capa)
173662306a36Sopenharmony_ci			ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
173762306a36Sopenharmony_ci					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
173862306a36Sopenharmony_ci	}
173962306a36Sopenharmony_ci	ra->sta_cap = cpu_to_le32(cap);
174062306a36Sopenharmony_ci}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ciint mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
174362306a36Sopenharmony_ci			     struct ieee80211_sta *sta, bool changed)
174462306a36Sopenharmony_ci{
174562306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
174662306a36Sopenharmony_ci	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
174762306a36Sopenharmony_ci	struct sk_buff *skb;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
175062306a36Sopenharmony_ci					      &msta->wcid,
175162306a36Sopenharmony_ci					      MT7996_STA_UPDATE_MAX_SIZE);
175262306a36Sopenharmony_ci	if (IS_ERR(skb))
175362306a36Sopenharmony_ci		return PTR_ERR(skb);
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	/* firmware rc algorithm refers to sta_rec_he for HE control.
175662306a36Sopenharmony_ci	 * once dev->rc_work changes the settings driver should also
175762306a36Sopenharmony_ci	 * update sta_rec_he here.
175862306a36Sopenharmony_ci	 */
175962306a36Sopenharmony_ci	if (changed)
176062306a36Sopenharmony_ci		mt7996_mcu_sta_he_tlv(skb, sta);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* sta_rec_ra accommodates BW, NSS and only MCS range format
176362306a36Sopenharmony_ci	 * i.e 0-{7,8,9} for VHT.
176462306a36Sopenharmony_ci	 */
176562306a36Sopenharmony_ci	mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
176862306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
176962306a36Sopenharmony_ci}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cistatic int
177262306a36Sopenharmony_cimt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif,
177362306a36Sopenharmony_ci		     struct ieee80211_sta *sta)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci#define MT_STA_BSS_GROUP		1
177662306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
177762306a36Sopenharmony_ci	struct mt7996_sta *msta;
177862306a36Sopenharmony_ci	struct {
177962306a36Sopenharmony_ci		u8 __rsv1[4];
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci		__le16 tag;
178262306a36Sopenharmony_ci		__le16 len;
178362306a36Sopenharmony_ci		__le16 wlan_idx;
178462306a36Sopenharmony_ci		u8 __rsv2[2];
178562306a36Sopenharmony_ci		__le32 action;
178662306a36Sopenharmony_ci		__le32 val;
178762306a36Sopenharmony_ci		u8 __rsv3[8];
178862306a36Sopenharmony_ci	} __packed req = {
178962306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_VOW_DRR_CTRL),
179062306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
179162306a36Sopenharmony_ci		.action = cpu_to_le32(MT_STA_BSS_GROUP),
179262306a36Sopenharmony_ci		.val = cpu_to_le32(mvif->mt76.idx % 16),
179362306a36Sopenharmony_ci	};
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
179662306a36Sopenharmony_ci	req.wlan_idx = cpu_to_le16(msta->wcid.idx);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(VOW), &req,
179962306a36Sopenharmony_ci				 sizeof(req), true);
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ciint mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
180362306a36Sopenharmony_ci		       struct ieee80211_sta *sta, bool enable)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
180662306a36Sopenharmony_ci	struct mt7996_sta *msta;
180762306a36Sopenharmony_ci	struct sk_buff *skb;
180862306a36Sopenharmony_ci	int ret;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
181362306a36Sopenharmony_ci					      &msta->wcid,
181462306a36Sopenharmony_ci					      MT7996_STA_UPDATE_MAX_SIZE);
181562306a36Sopenharmony_ci	if (IS_ERR(skb))
181662306a36Sopenharmony_ci		return PTR_ERR(skb);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	/* starec basic */
181962306a36Sopenharmony_ci	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable,
182062306a36Sopenharmony_ci				      !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
182162306a36Sopenharmony_ci	if (!enable)
182262306a36Sopenharmony_ci		goto out;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* tag order is in accordance with firmware dependency. */
182562306a36Sopenharmony_ci	if (sta) {
182662306a36Sopenharmony_ci		/* starec phy */
182762306a36Sopenharmony_ci		mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta);
182862306a36Sopenharmony_ci		/* starec hdrt mode */
182962306a36Sopenharmony_ci		mt7996_mcu_sta_hdrt_tlv(dev, skb);
183062306a36Sopenharmony_ci		/* starec bfer */
183162306a36Sopenharmony_ci		mt7996_mcu_sta_bfer_tlv(dev, skb, vif, sta);
183262306a36Sopenharmony_ci		/* starec ht */
183362306a36Sopenharmony_ci		mt7996_mcu_sta_ht_tlv(skb, sta);
183462306a36Sopenharmony_ci		/* starec vht */
183562306a36Sopenharmony_ci		mt7996_mcu_sta_vht_tlv(skb, sta);
183662306a36Sopenharmony_ci		/* starec uapsd */
183762306a36Sopenharmony_ci		mt76_connac_mcu_sta_uapsd(skb, vif, sta);
183862306a36Sopenharmony_ci		/* starec amsdu */
183962306a36Sopenharmony_ci		mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
184062306a36Sopenharmony_ci		/* starec he */
184162306a36Sopenharmony_ci		mt7996_mcu_sta_he_tlv(skb, sta);
184262306a36Sopenharmony_ci		/* starec he 6g*/
184362306a36Sopenharmony_ci		mt7996_mcu_sta_he_6g_tlv(skb, sta);
184462306a36Sopenharmony_ci		/* starec eht */
184562306a36Sopenharmony_ci		mt7996_mcu_sta_eht_tlv(skb, sta);
184662306a36Sopenharmony_ci		/* starec muru */
184762306a36Sopenharmony_ci		mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta);
184862306a36Sopenharmony_ci		/* starec bfee */
184962306a36Sopenharmony_ci		mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
185062306a36Sopenharmony_ci		/* starec hdr trans */
185162306a36Sopenharmony_ci		mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
185262306a36Sopenharmony_ci	}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	ret = mt7996_mcu_add_group(dev, vif, sta);
185562306a36Sopenharmony_ci	if (ret) {
185662306a36Sopenharmony_ci		dev_kfree_skb(skb);
185762306a36Sopenharmony_ci		return ret;
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ciout:
186062306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
186162306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
186262306a36Sopenharmony_ci}
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_cistatic int
186562306a36Sopenharmony_cimt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
186662306a36Sopenharmony_ci		       struct mt76_connac_sta_key_conf *sta_key_conf,
186762306a36Sopenharmony_ci		       struct sk_buff *skb,
186862306a36Sopenharmony_ci		       struct ieee80211_key_conf *key,
186962306a36Sopenharmony_ci		       enum set_key_cmd cmd)
187062306a36Sopenharmony_ci{
187162306a36Sopenharmony_ci	struct sta_rec_sec_uni *sec;
187262306a36Sopenharmony_ci	struct tlv *tlv;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));
187562306a36Sopenharmony_ci	sec = (struct sta_rec_sec_uni *)tlv;
187662306a36Sopenharmony_ci	sec->add = cmd;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	if (cmd == SET_KEY) {
187962306a36Sopenharmony_ci		struct sec_key_uni *sec_key;
188062306a36Sopenharmony_ci		u8 cipher;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci		cipher = mt76_connac_mcu_get_cipher(key->cipher);
188362306a36Sopenharmony_ci		if (cipher == MCU_CIPHER_NONE)
188462306a36Sopenharmony_ci			return -EOPNOTSUPP;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci		sec_key = &sec->key[0];
188762306a36Sopenharmony_ci		sec_key->cipher_len = sizeof(*sec_key);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci		if (cipher == MCU_CIPHER_BIP_CMAC_128) {
189062306a36Sopenharmony_ci			sec_key->wlan_idx = cpu_to_le16(wcid->idx);
189162306a36Sopenharmony_ci			sec_key->cipher_id = MCU_CIPHER_AES_CCMP;
189262306a36Sopenharmony_ci			sec_key->key_id = sta_key_conf->keyidx;
189362306a36Sopenharmony_ci			sec_key->key_len = 16;
189462306a36Sopenharmony_ci			memcpy(sec_key->key, sta_key_conf->key, 16);
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci			sec_key = &sec->key[1];
189762306a36Sopenharmony_ci			sec_key->wlan_idx = cpu_to_le16(wcid->idx);
189862306a36Sopenharmony_ci			sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128;
189962306a36Sopenharmony_ci			sec_key->cipher_len = sizeof(*sec_key);
190062306a36Sopenharmony_ci			sec_key->key_len = 16;
190162306a36Sopenharmony_ci			memcpy(sec_key->key, key->key, 16);
190262306a36Sopenharmony_ci			sec->n_cipher = 2;
190362306a36Sopenharmony_ci		} else {
190462306a36Sopenharmony_ci			sec_key->wlan_idx = cpu_to_le16(wcid->idx);
190562306a36Sopenharmony_ci			sec_key->cipher_id = cipher;
190662306a36Sopenharmony_ci			sec_key->key_id = key->keyidx;
190762306a36Sopenharmony_ci			sec_key->key_len = key->keylen;
190862306a36Sopenharmony_ci			memcpy(sec_key->key, key->key, key->keylen);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci			if (cipher == MCU_CIPHER_TKIP) {
191162306a36Sopenharmony_ci				/* Rx/Tx MIC keys are swapped */
191262306a36Sopenharmony_ci				memcpy(sec_key->key + 16, key->key + 24, 8);
191362306a36Sopenharmony_ci				memcpy(sec_key->key + 24, key->key + 16, 8);
191462306a36Sopenharmony_ci			}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci			/* store key_conf for BIP batch update */
191762306a36Sopenharmony_ci			if (cipher == MCU_CIPHER_AES_CCMP) {
191862306a36Sopenharmony_ci				memcpy(sta_key_conf->key, key->key, key->keylen);
191962306a36Sopenharmony_ci				sta_key_conf->keyidx = key->keyidx;
192062306a36Sopenharmony_ci			}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci			sec->n_cipher = 1;
192362306a36Sopenharmony_ci		}
192462306a36Sopenharmony_ci	} else {
192562306a36Sopenharmony_ci		sec->n_cipher = 0;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	return 0;
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ciint mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
193262306a36Sopenharmony_ci		       struct mt76_connac_sta_key_conf *sta_key_conf,
193362306a36Sopenharmony_ci		       struct ieee80211_key_conf *key, int mcu_cmd,
193462306a36Sopenharmony_ci		       struct mt76_wcid *wcid, enum set_key_cmd cmd)
193562306a36Sopenharmony_ci{
193662306a36Sopenharmony_ci	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
193762306a36Sopenharmony_ci	struct sk_buff *skb;
193862306a36Sopenharmony_ci	int ret;
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,
194162306a36Sopenharmony_ci					      MT7996_STA_UPDATE_MAX_SIZE);
194262306a36Sopenharmony_ci	if (IS_ERR(skb))
194362306a36Sopenharmony_ci		return PTR_ERR(skb);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	ret = mt7996_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd);
194662306a36Sopenharmony_ci	if (ret)
194762306a36Sopenharmony_ci		return ret;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
195062306a36Sopenharmony_ci}
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ciint mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
195362306a36Sopenharmony_ci			    struct ieee80211_vif *vif, bool enable)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
195662306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
195762306a36Sopenharmony_ci	struct {
195862306a36Sopenharmony_ci		struct req_hdr {
195962306a36Sopenharmony_ci			u8 omac_idx;
196062306a36Sopenharmony_ci			u8 band_idx;
196162306a36Sopenharmony_ci			u8 __rsv[2];
196262306a36Sopenharmony_ci		} __packed hdr;
196362306a36Sopenharmony_ci		struct req_tlv {
196462306a36Sopenharmony_ci			__le16 tag;
196562306a36Sopenharmony_ci			__le16 len;
196662306a36Sopenharmony_ci			u8 active;
196762306a36Sopenharmony_ci			u8 __rsv;
196862306a36Sopenharmony_ci			u8 omac_addr[ETH_ALEN];
196962306a36Sopenharmony_ci		} __packed tlv;
197062306a36Sopenharmony_ci	} data = {
197162306a36Sopenharmony_ci		.hdr = {
197262306a36Sopenharmony_ci			.omac_idx = mvif->mt76.omac_idx,
197362306a36Sopenharmony_ci			.band_idx = mvif->mt76.band_idx,
197462306a36Sopenharmony_ci		},
197562306a36Sopenharmony_ci		.tlv = {
197662306a36Sopenharmony_ci			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
197762306a36Sopenharmony_ci			.len = cpu_to_le16(sizeof(struct req_tlv)),
197862306a36Sopenharmony_ci			.active = enable,
197962306a36Sopenharmony_ci		},
198062306a36Sopenharmony_ci	};
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
198362306a36Sopenharmony_ci		return mt7996_mcu_muar_config(phy, vif, false, enable);
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
198662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(DEV_INFO_UPDATE),
198762306a36Sopenharmony_ci				 &data, sizeof(data), true);
198862306a36Sopenharmony_ci}
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_cistatic void
199162306a36Sopenharmony_cimt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
199262306a36Sopenharmony_ci			 struct sk_buff *skb,
199362306a36Sopenharmony_ci			 struct ieee80211_mutable_offsets *offs)
199462306a36Sopenharmony_ci{
199562306a36Sopenharmony_ci	struct bss_bcn_cntdwn_tlv *info;
199662306a36Sopenharmony_ci	struct tlv *tlv;
199762306a36Sopenharmony_ci	u16 tag;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	if (!offs->cntdwn_counter_offs[0])
200062306a36Sopenharmony_ci		return;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	tag = vif->bss_conf.csa_active ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(rskb, tag, sizeof(*info));
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	info = (struct bss_bcn_cntdwn_tlv *)tlv;
200762306a36Sopenharmony_ci	info->cnt = skb->data[offs->cntdwn_counter_offs[0]];
200862306a36Sopenharmony_ci}
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_cistatic void
201162306a36Sopenharmony_cimt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
201262306a36Sopenharmony_ci		       struct sk_buff *rskb, struct sk_buff *skb,
201362306a36Sopenharmony_ci		       struct bss_bcn_content_tlv *bcn,
201462306a36Sopenharmony_ci		       struct ieee80211_mutable_offsets *offs)
201562306a36Sopenharmony_ci{
201662306a36Sopenharmony_ci	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
201762306a36Sopenharmony_ci	u8 *buf;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	bcn->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
202062306a36Sopenharmony_ci	bcn->tim_ie_pos = cpu_to_le16(offs->tim_offset);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	if (offs->cntdwn_counter_offs[0]) {
202362306a36Sopenharmony_ci		u16 offset = offs->cntdwn_counter_offs[0];
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci		if (vif->bss_conf.csa_active)
202662306a36Sopenharmony_ci			bcn->csa_ie_pos = cpu_to_le16(offset - 4);
202762306a36Sopenharmony_ci		if (vif->bss_conf.color_change_active)
202862306a36Sopenharmony_ci			bcn->bcc_ie_pos = cpu_to_le16(offset - 3);
202962306a36Sopenharmony_ci	}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	buf = (u8 *)bcn + sizeof(*bcn);
203262306a36Sopenharmony_ci	mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0,
203362306a36Sopenharmony_ci			      BSS_CHANGED_BEACON);
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
203662306a36Sopenharmony_ci}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ciint mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
203962306a36Sopenharmony_ci			  struct ieee80211_vif *vif, int en)
204062306a36Sopenharmony_ci{
204162306a36Sopenharmony_ci	struct mt7996_dev *dev = mt7996_hw_dev(hw);
204262306a36Sopenharmony_ci	struct mt7996_phy *phy = mt7996_hw_phy(hw);
204362306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
204462306a36Sopenharmony_ci	struct ieee80211_mutable_offsets offs;
204562306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
204662306a36Sopenharmony_ci	struct sk_buff *skb, *rskb;
204762306a36Sopenharmony_ci	struct tlv *tlv;
204862306a36Sopenharmony_ci	struct bss_bcn_content_tlv *bcn;
204962306a36Sopenharmony_ci	int len;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
205262306a36Sopenharmony_ci					  MT7996_MAX_BSS_OFFLOAD_SIZE);
205362306a36Sopenharmony_ci	if (IS_ERR(rskb))
205462306a36Sopenharmony_ci		return PTR_ERR(rskb);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
205762306a36Sopenharmony_ci	if (!skb) {
205862306a36Sopenharmony_ci		dev_kfree_skb(rskb);
205962306a36Sopenharmony_ci		return -EINVAL;
206062306a36Sopenharmony_ci	}
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	if (skb->len > MT7996_MAX_BEACON_SIZE) {
206362306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
206462306a36Sopenharmony_ci		dev_kfree_skb(rskb);
206562306a36Sopenharmony_ci		dev_kfree_skb(skb);
206662306a36Sopenharmony_ci		return -EINVAL;
206762306a36Sopenharmony_ci	}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
207062306a36Sopenharmony_ci	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx);
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	len = sizeof(*bcn) + MT_TXD_SIZE + skb->len;
207362306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len);
207462306a36Sopenharmony_ci	bcn = (struct bss_bcn_content_tlv *)tlv;
207562306a36Sopenharmony_ci	bcn->enable = en;
207662306a36Sopenharmony_ci	if (!en)
207762306a36Sopenharmony_ci		goto out;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	mt7996_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
208062306a36Sopenharmony_ci	/* TODO: subtag - 11v MBSSID */
208162306a36Sopenharmony_ci	mt7996_mcu_beacon_cntdwn(vif, rskb, skb, &offs);
208262306a36Sopenharmony_ciout:
208362306a36Sopenharmony_ci	dev_kfree_skb(skb);
208462306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
208562306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
208662306a36Sopenharmony_ci}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ciint mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
208962306a36Sopenharmony_ci				    struct ieee80211_vif *vif, u32 changed)
209062306a36Sopenharmony_ci{
209162306a36Sopenharmony_ci#define OFFLOAD_TX_MODE_SU	BIT(0)
209262306a36Sopenharmony_ci#define OFFLOAD_TX_MODE_MU	BIT(1)
209362306a36Sopenharmony_ci	struct ieee80211_hw *hw = mt76_hw(dev);
209462306a36Sopenharmony_ci	struct mt7996_phy *phy = mt7996_hw_phy(hw);
209562306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
209662306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
209762306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
209862306a36Sopenharmony_ci	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
209962306a36Sopenharmony_ci	struct bss_inband_discovery_tlv *discov;
210062306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
210162306a36Sopenharmony_ci	struct sk_buff *rskb, *skb = NULL;
210262306a36Sopenharmony_ci	struct tlv *tlv;
210362306a36Sopenharmony_ci	u8 *buf, interval;
210462306a36Sopenharmony_ci	int len;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	if (vif->bss_conf.nontransmitted)
210762306a36Sopenharmony_ci		return 0;
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
211062306a36Sopenharmony_ci					  MT7996_MAX_BSS_OFFLOAD_SIZE);
211162306a36Sopenharmony_ci	if (IS_ERR(rskb))
211262306a36Sopenharmony_ci		return PTR_ERR(rskb);
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	if (changed & BSS_CHANGED_FILS_DISCOVERY &&
211562306a36Sopenharmony_ci	    vif->bss_conf.fils_discovery.max_interval) {
211662306a36Sopenharmony_ci		interval = vif->bss_conf.fils_discovery.max_interval;
211762306a36Sopenharmony_ci		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
211862306a36Sopenharmony_ci	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
211962306a36Sopenharmony_ci		   vif->bss_conf.unsol_bcast_probe_resp_interval) {
212062306a36Sopenharmony_ci		interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
212162306a36Sopenharmony_ci		skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
212262306a36Sopenharmony_ci	}
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	if (!skb) {
212562306a36Sopenharmony_ci		dev_kfree_skb(rskb);
212662306a36Sopenharmony_ci		return -EINVAL;
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	if (skb->len > MT7996_MAX_BEACON_SIZE) {
213062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "inband discovery size limit exceed\n");
213162306a36Sopenharmony_ci		dev_kfree_skb(rskb);
213262306a36Sopenharmony_ci		dev_kfree_skb(skb);
213362306a36Sopenharmony_ci		return -EINVAL;
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
213762306a36Sopenharmony_ci	info->control.vif = vif;
213862306a36Sopenharmony_ci	info->band = band;
213962306a36Sopenharmony_ci	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx);
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, len);
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	discov = (struct bss_inband_discovery_tlv *)tlv;
214662306a36Sopenharmony_ci	discov->tx_mode = OFFLOAD_TX_MODE_SU;
214762306a36Sopenharmony_ci	/* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
214862306a36Sopenharmony_ci	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
214962306a36Sopenharmony_ci	discov->tx_interval = interval;
215062306a36Sopenharmony_ci	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
215162306a36Sopenharmony_ci	discov->enable = true;
215262306a36Sopenharmony_ci	discov->wcid = cpu_to_le16(MT7996_WTBL_RESERVED);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	buf = (u8 *)tlv + sizeof(*discov);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, changed);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	dev_kfree_skb(skb);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, rskb,
216362306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
216462306a36Sopenharmony_ci}
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_cistatic int mt7996_driver_own(struct mt7996_dev *dev, u8 band)
216762306a36Sopenharmony_ci{
216862306a36Sopenharmony_ci	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN);
216962306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band),
217062306a36Sopenharmony_ci			    MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) {
217162306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for driver own\n");
217262306a36Sopenharmony_ci		return -EIO;
217362306a36Sopenharmony_ci	}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	/* clear irq when the driver own success */
217662306a36Sopenharmony_ci	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band),
217762306a36Sopenharmony_ci		MT_TOP_LPCR_HOST_BAND_STAT);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	return 0;
218062306a36Sopenharmony_ci}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_cistatic u32 mt7996_patch_sec_mode(u32 key_info)
218362306a36Sopenharmony_ci{
218462306a36Sopenharmony_ci	u32 sec = u32_get_bits(key_info, MT7996_PATCH_SEC), key = 0;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	if (key_info == GENMASK(31, 0) || sec == MT7996_SEC_MODE_PLAIN)
218762306a36Sopenharmony_ci		return 0;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	if (sec == MT7996_SEC_MODE_AES)
219062306a36Sopenharmony_ci		key = u32_get_bits(key_info, MT7996_PATCH_AES_KEY);
219162306a36Sopenharmony_ci	else
219262306a36Sopenharmony_ci		key = u32_get_bits(key_info, MT7996_PATCH_SCRAMBLE_KEY);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return MT7996_SEC_ENCRYPT | MT7996_SEC_IV |
219562306a36Sopenharmony_ci	       u32_encode_bits(key, MT7996_SEC_KEY_IDX);
219662306a36Sopenharmony_ci}
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_cistatic int mt7996_load_patch(struct mt7996_dev *dev)
219962306a36Sopenharmony_ci{
220062306a36Sopenharmony_ci	const struct mt7996_patch_hdr *hdr;
220162306a36Sopenharmony_ci	const struct firmware *fw = NULL;
220262306a36Sopenharmony_ci	int i, ret, sem;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, 1);
220562306a36Sopenharmony_ci	switch (sem) {
220662306a36Sopenharmony_ci	case PATCH_IS_DL:
220762306a36Sopenharmony_ci		return 0;
220862306a36Sopenharmony_ci	case PATCH_NOT_DL_SEM_SUCCESS:
220962306a36Sopenharmony_ci		break;
221062306a36Sopenharmony_ci	default:
221162306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
221262306a36Sopenharmony_ci		return -EAGAIN;
221362306a36Sopenharmony_ci	}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev);
221662306a36Sopenharmony_ci	if (ret)
221762306a36Sopenharmony_ci		goto out;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
222062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
222162306a36Sopenharmony_ci		ret = -EINVAL;
222262306a36Sopenharmony_ci		goto out;
222362306a36Sopenharmony_ci	}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	hdr = (const struct mt7996_patch_hdr *)(fw->data);
222662306a36Sopenharmony_ci
222762306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
222862306a36Sopenharmony_ci		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
223162306a36Sopenharmony_ci		struct mt7996_patch_sec *sec;
223262306a36Sopenharmony_ci		const u8 *dl;
223362306a36Sopenharmony_ci		u32 len, addr, sec_key_idx, mode = DL_MODE_NEED_RSP;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci		sec = (struct mt7996_patch_sec *)(fw->data + sizeof(*hdr) +
223662306a36Sopenharmony_ci						  i * sizeof(*sec));
223762306a36Sopenharmony_ci		if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) !=
223862306a36Sopenharmony_ci		    PATCH_SEC_TYPE_INFO) {
223962306a36Sopenharmony_ci			ret = -EINVAL;
224062306a36Sopenharmony_ci			goto out;
224162306a36Sopenharmony_ci		}
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci		addr = be32_to_cpu(sec->info.addr);
224462306a36Sopenharmony_ci		len = be32_to_cpu(sec->info.len);
224562306a36Sopenharmony_ci		sec_key_idx = be32_to_cpu(sec->info.sec_key_idx);
224662306a36Sopenharmony_ci		dl = fw->data + be32_to_cpu(sec->offs);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci		mode |= mt7996_patch_sec_mode(sec_key_idx);
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci		ret = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
225162306a36Sopenharmony_ci						    mode);
225262306a36Sopenharmony_ci		if (ret) {
225362306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Download request failed\n");
225462306a36Sopenharmony_ci			goto out;
225562306a36Sopenharmony_ci		}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci		ret = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
225862306a36Sopenharmony_ci					       dl, len, 4096);
225962306a36Sopenharmony_ci		if (ret) {
226062306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Failed to send patch\n");
226162306a36Sopenharmony_ci			goto out;
226262306a36Sopenharmony_ci		}
226362306a36Sopenharmony_ci	}
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	ret = mt76_connac_mcu_start_patch(&dev->mt76);
226662306a36Sopenharmony_ci	if (ret)
226762306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start patch\n");
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ciout:
227062306a36Sopenharmony_ci	sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, 0);
227162306a36Sopenharmony_ci	switch (sem) {
227262306a36Sopenharmony_ci	case PATCH_REL_SEM_SUCCESS:
227362306a36Sopenharmony_ci		break;
227462306a36Sopenharmony_ci	default:
227562306a36Sopenharmony_ci		ret = -EAGAIN;
227662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
227762306a36Sopenharmony_ci		break;
227862306a36Sopenharmony_ci	}
227962306a36Sopenharmony_ci	release_firmware(fw);
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	return ret;
228262306a36Sopenharmony_ci}
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_cistatic int
228562306a36Sopenharmony_cimt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
228662306a36Sopenharmony_ci			     const struct mt7996_fw_trailer *hdr,
228762306a36Sopenharmony_ci			     const u8 *data, enum mt7996_ram_type type)
228862306a36Sopenharmony_ci{
228962306a36Sopenharmony_ci	int i, offset = 0;
229062306a36Sopenharmony_ci	u32 override = 0, option = 0;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	for (i = 0; i < hdr->n_region; i++) {
229362306a36Sopenharmony_ci		const struct mt7996_fw_region *region;
229462306a36Sopenharmony_ci		int err;
229562306a36Sopenharmony_ci		u32 len, addr, mode;
229662306a36Sopenharmony_ci
229762306a36Sopenharmony_ci		region = (const struct mt7996_fw_region *)((const u8 *)hdr -
229862306a36Sopenharmony_ci			 (hdr->n_region - i) * sizeof(*region));
229962306a36Sopenharmony_ci		/* DSP and WA use same mode */
230062306a36Sopenharmony_ci		mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
230162306a36Sopenharmony_ci						   region->feature_set,
230262306a36Sopenharmony_ci						   type != MT7996_RAM_TYPE_WM);
230362306a36Sopenharmony_ci		len = le32_to_cpu(region->len);
230462306a36Sopenharmony_ci		addr = le32_to_cpu(region->addr);
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci		if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR)
230762306a36Sopenharmony_ci			override = addr;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci		err = mt76_connac_mcu_init_download(&dev->mt76, addr, len,
231062306a36Sopenharmony_ci						    mode);
231162306a36Sopenharmony_ci		if (err) {
231262306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Download request failed\n");
231362306a36Sopenharmony_ci			return err;
231462306a36Sopenharmony_ci		}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci		err = __mt76_mcu_send_firmware(&dev->mt76, MCU_CMD(FW_SCATTER),
231762306a36Sopenharmony_ci					       data + offset, len, 4096);
231862306a36Sopenharmony_ci		if (err) {
231962306a36Sopenharmony_ci			dev_err(dev->mt76.dev, "Failed to send firmware.\n");
232062306a36Sopenharmony_ci			return err;
232162306a36Sopenharmony_ci		}
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci		offset += len;
232462306a36Sopenharmony_ci	}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	if (override)
232762306a36Sopenharmony_ci		option |= FW_START_OVERRIDE;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	if (type == MT7996_RAM_TYPE_WA)
233062306a36Sopenharmony_ci		option |= FW_START_WORKING_PDA_CR4;
233162306a36Sopenharmony_ci	else if (type == MT7996_RAM_TYPE_DSP)
233262306a36Sopenharmony_ci		option |= FW_START_WORKING_PDA_DSP;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	return mt76_connac_mcu_start_firmware(&dev->mt76, override, option);
233562306a36Sopenharmony_ci}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_cistatic int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type,
233862306a36Sopenharmony_ci			     const char *fw_file, enum mt7996_ram_type ram_type)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	const struct mt7996_fw_trailer *hdr;
234162306a36Sopenharmony_ci	const struct firmware *fw;
234262306a36Sopenharmony_ci	int ret;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	ret = request_firmware(&fw, fw_file, dev->mt76.dev);
234562306a36Sopenharmony_ci	if (ret)
234662306a36Sopenharmony_ci		return ret;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
234962306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Invalid firmware\n");
235062306a36Sopenharmony_ci		ret = -EINVAL;
235162306a36Sopenharmony_ci		goto out;
235262306a36Sopenharmony_ci	}
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
235562306a36Sopenharmony_ci	dev_info(dev->mt76.dev, "%s Firmware Version: %.10s, Build Time: %.15s\n",
235662306a36Sopenharmony_ci		 fw_type, hdr->fw_ver, hdr->build_date);
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, ram_type);
235962306a36Sopenharmony_ci	if (ret) {
236062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to start %s firmware\n", fw_type);
236162306a36Sopenharmony_ci		goto out;
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	snprintf(dev->mt76.hw->wiphy->fw_version,
236562306a36Sopenharmony_ci		 sizeof(dev->mt76.hw->wiphy->fw_version),
236662306a36Sopenharmony_ci		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ciout:
236962306a36Sopenharmony_ci	release_firmware(fw);
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	return ret;
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_cistatic int mt7996_load_ram(struct mt7996_dev *dev)
237562306a36Sopenharmony_ci{
237662306a36Sopenharmony_ci	int ret;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM,
237962306a36Sopenharmony_ci				MT7996_RAM_TYPE_WM);
238062306a36Sopenharmony_ci	if (ret)
238162306a36Sopenharmony_ci		return ret;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP,
238462306a36Sopenharmony_ci				MT7996_RAM_TYPE_DSP);
238562306a36Sopenharmony_ci	if (ret)
238662306a36Sopenharmony_ci		return ret;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci	return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA,
238962306a36Sopenharmony_ci				 MT7996_RAM_TYPE_WA);
239062306a36Sopenharmony_ci}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_cistatic int
239362306a36Sopenharmony_cimt7996_firmware_state(struct mt7996_dev *dev, bool wa)
239462306a36Sopenharmony_ci{
239562306a36Sopenharmony_ci	u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE,
239662306a36Sopenharmony_ci			       wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD);
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,
239962306a36Sopenharmony_ci			    state, 1000)) {
240062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
240162306a36Sopenharmony_ci		return -EIO;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci	return 0;
240462306a36Sopenharmony_ci}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_cistatic int
240762306a36Sopenharmony_cimt7996_mcu_restart(struct mt76_dev *dev)
240862306a36Sopenharmony_ci{
240962306a36Sopenharmony_ci	struct {
241062306a36Sopenharmony_ci		u8 __rsv1[4];
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci		__le16 tag;
241362306a36Sopenharmony_ci		__le16 len;
241462306a36Sopenharmony_ci		u8 power_mode;
241562306a36Sopenharmony_ci		u8 __rsv2[3];
241662306a36Sopenharmony_ci	} __packed req = {
241762306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_POWER_OFF),
241862306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
241962306a36Sopenharmony_ci		.power_mode = 1,
242062306a36Sopenharmony_ci	};
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(POWER_CTRL), &req,
242362306a36Sopenharmony_ci				 sizeof(req), false);
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_cistatic int mt7996_load_firmware(struct mt7996_dev *dev)
242762306a36Sopenharmony_ci{
242862306a36Sopenharmony_ci	int ret;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	/* make sure fw is download state */
243162306a36Sopenharmony_ci	if (mt7996_firmware_state(dev, false)) {
243262306a36Sopenharmony_ci		/* restart firmware once */
243362306a36Sopenharmony_ci		mt7996_mcu_restart(&dev->mt76);
243462306a36Sopenharmony_ci		ret = mt7996_firmware_state(dev, false);
243562306a36Sopenharmony_ci		if (ret) {
243662306a36Sopenharmony_ci			dev_err(dev->mt76.dev,
243762306a36Sopenharmony_ci				"Firmware is not ready for download\n");
243862306a36Sopenharmony_ci			return ret;
243962306a36Sopenharmony_ci		}
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	ret = mt7996_load_patch(dev);
244362306a36Sopenharmony_ci	if (ret)
244462306a36Sopenharmony_ci		return ret;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	ret = mt7996_load_ram(dev);
244762306a36Sopenharmony_ci	if (ret)
244862306a36Sopenharmony_ci		return ret;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	ret = mt7996_firmware_state(dev, true);
245162306a36Sopenharmony_ci	if (ret)
245262306a36Sopenharmony_ci		return ret;
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	dev_dbg(dev->mt76.dev, "Firmware init done\n");
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	return 0;
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ciint mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl)
246262306a36Sopenharmony_ci{
246362306a36Sopenharmony_ci	struct {
246462306a36Sopenharmony_ci		u8 _rsv[4];
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci		__le16 tag;
246762306a36Sopenharmony_ci		__le16 len;
246862306a36Sopenharmony_ci		u8 ctrl;
246962306a36Sopenharmony_ci		u8 interval;
247062306a36Sopenharmony_ci		u8 _rsv2[2];
247162306a36Sopenharmony_ci	} __packed data = {
247262306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_LOG_CTRL),
247362306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(data) - 4),
247462306a36Sopenharmony_ci		.ctrl = ctrl,
247562306a36Sopenharmony_ci	};
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	if (type == MCU_FW_LOG_WA)
247862306a36Sopenharmony_ci		return mt76_mcu_send_msg(&dev->mt76, MCU_WA_UNI_CMD(WSYS_CONFIG),
247962306a36Sopenharmony_ci					 &data, sizeof(data), true);
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(WSYS_CONFIG), &data,
248262306a36Sopenharmony_ci				 sizeof(data), true);
248362306a36Sopenharmony_ci}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ciint mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level)
248662306a36Sopenharmony_ci{
248762306a36Sopenharmony_ci	struct {
248862306a36Sopenharmony_ci		u8 _rsv[4];
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci		__le16 tag;
249162306a36Sopenharmony_ci		__le16 len;
249262306a36Sopenharmony_ci		__le32 module_idx;
249362306a36Sopenharmony_ci		u8 level;
249462306a36Sopenharmony_ci		u8 _rsv2[3];
249562306a36Sopenharmony_ci	} data = {
249662306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_DBG_CTRL),
249762306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(data) - 4),
249862306a36Sopenharmony_ci		.module_idx = cpu_to_le32(module),
249962306a36Sopenharmony_ci		.level = level,
250062306a36Sopenharmony_ci	};
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(WSYS_CONFIG), &data,
250362306a36Sopenharmony_ci				 sizeof(data), false);
250462306a36Sopenharmony_ci}
250562306a36Sopenharmony_ci
250662306a36Sopenharmony_cistatic int mt7996_mcu_set_mwds(struct mt7996_dev *dev, bool enabled)
250762306a36Sopenharmony_ci{
250862306a36Sopenharmony_ci	struct {
250962306a36Sopenharmony_ci		u8 enable;
251062306a36Sopenharmony_ci		u8 _rsv[3];
251162306a36Sopenharmony_ci	} __packed req = {
251262306a36Sopenharmony_ci		.enable = enabled
251362306a36Sopenharmony_ci	};
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req,
251662306a36Sopenharmony_ci				 sizeof(req), false);
251762306a36Sopenharmony_ci}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_cistatic void mt7996_add_rx_airtime_tlv(struct sk_buff *skb, u8 band_idx)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct vow_rx_airtime *req;
252262306a36Sopenharmony_ci	struct tlv *tlv;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_VOW_RX_AT_AIRTIME_CLR_EN, sizeof(*req));
252562306a36Sopenharmony_ci	req = (struct vow_rx_airtime *)tlv;
252662306a36Sopenharmony_ci	req->enable = true;
252762306a36Sopenharmony_ci	req->band = band_idx;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_VOW_RX_AT_AIRTIME_EN, sizeof(*req));
253062306a36Sopenharmony_ci	req = (struct vow_rx_airtime *)tlv;
253162306a36Sopenharmony_ci	req->enable = true;
253262306a36Sopenharmony_ci	req->band = band_idx;
253362306a36Sopenharmony_ci}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_cistatic int
253662306a36Sopenharmony_cimt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
253762306a36Sopenharmony_ci{
253862306a36Sopenharmony_ci	struct uni_header hdr = {};
253962306a36Sopenharmony_ci	struct sk_buff *skb;
254062306a36Sopenharmony_ci	int len, num;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support);
254362306a36Sopenharmony_ci	len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime);
254462306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
254562306a36Sopenharmony_ci	if (!skb)
254662306a36Sopenharmony_ci		return -ENOMEM;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	skb_put_data(skb, &hdr, sizeof(hdr));
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx);
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	if (dev->dbdc_support)
255362306a36Sopenharmony_ci		mt7996_add_rx_airtime_tlv(skb, MT_BAND1);
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	if (dev->tbtc_support)
255662306a36Sopenharmony_ci		mt7996_add_rx_airtime_tlv(skb, MT_BAND2);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
255962306a36Sopenharmony_ci				     MCU_WM_UNI_CMD(VOW), true);
256062306a36Sopenharmony_ci}
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ciint mt7996_mcu_init_firmware(struct mt7996_dev *dev)
256362306a36Sopenharmony_ci{
256462306a36Sopenharmony_ci	int ret;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	/* force firmware operation mode into normal state,
256762306a36Sopenharmony_ci	 * which should be set before firmware download stage.
256862306a36Sopenharmony_ci	 */
256962306a36Sopenharmony_ci	mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	ret = mt7996_driver_own(dev, 0);
257262306a36Sopenharmony_ci	if (ret)
257362306a36Sopenharmony_ci		return ret;
257462306a36Sopenharmony_ci	/* set driver own for band1 when two hif exist */
257562306a36Sopenharmony_ci	if (dev->hif2) {
257662306a36Sopenharmony_ci		ret = mt7996_driver_own(dev, 1);
257762306a36Sopenharmony_ci		if (ret)
257862306a36Sopenharmony_ci			return ret;
257962306a36Sopenharmony_ci	}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	ret = mt7996_load_firmware(dev);
258262306a36Sopenharmony_ci	if (ret)
258362306a36Sopenharmony_ci		return ret;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
258662306a36Sopenharmony_ci	ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0);
258762306a36Sopenharmony_ci	if (ret)
258862306a36Sopenharmony_ci		return ret;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	ret = mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
259162306a36Sopenharmony_ci	if (ret)
259262306a36Sopenharmony_ci		return ret;
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	ret = mt7996_mcu_set_mwds(dev, 1);
259562306a36Sopenharmony_ci	if (ret)
259662306a36Sopenharmony_ci		return ret;
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci	ret = mt7996_mcu_init_rx_airtime(dev);
259962306a36Sopenharmony_ci	if (ret)
260062306a36Sopenharmony_ci		return ret;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	return mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
260362306a36Sopenharmony_ci				 MCU_WA_PARAM_RED, 0, 0);
260462306a36Sopenharmony_ci}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ciint mt7996_mcu_init(struct mt7996_dev *dev)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	static const struct mt76_mcu_ops mt7996_mcu_ops = {
260962306a36Sopenharmony_ci		.headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
261062306a36Sopenharmony_ci		.mcu_skb_send_msg = mt7996_mcu_send_message,
261162306a36Sopenharmony_ci		.mcu_parse_response = mt7996_mcu_parse_response,
261262306a36Sopenharmony_ci	};
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	dev->mt76.mcu_ops = &mt7996_mcu_ops;
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	return mt7996_mcu_init_firmware(dev);
261762306a36Sopenharmony_ci}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_civoid mt7996_mcu_exit(struct mt7996_dev *dev)
262062306a36Sopenharmony_ci{
262162306a36Sopenharmony_ci	mt7996_mcu_restart(&dev->mt76);
262262306a36Sopenharmony_ci	if (mt7996_firmware_state(dev, false)) {
262362306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to exit mcu\n");
262462306a36Sopenharmony_ci		goto out;
262562306a36Sopenharmony_ci	}
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
262862306a36Sopenharmony_ci	if (dev->hif2)
262962306a36Sopenharmony_ci		mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
263062306a36Sopenharmony_ci			MT_TOP_LPCR_HOST_FW_OWN);
263162306a36Sopenharmony_ciout:
263262306a36Sopenharmony_ci	skb_queue_purge(&dev->mt76.mcu.res_q);
263362306a36Sopenharmony_ci}
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ciint mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans)
263662306a36Sopenharmony_ci{
263762306a36Sopenharmony_ci	struct {
263862306a36Sopenharmony_ci		u8 __rsv[4];
263962306a36Sopenharmony_ci	} __packed hdr;
264062306a36Sopenharmony_ci	struct hdr_trans_blacklist *req_blacklist;
264162306a36Sopenharmony_ci	struct hdr_trans_en *req_en;
264262306a36Sopenharmony_ci	struct sk_buff *skb;
264362306a36Sopenharmony_ci	struct tlv *tlv;
264462306a36Sopenharmony_ci	int len = MT7996_HDR_TRANS_MAX_SIZE + sizeof(hdr);
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
264762306a36Sopenharmony_ci	if (!skb)
264862306a36Sopenharmony_ci		return -ENOMEM;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci	skb_put_data(skb, &hdr, sizeof(hdr));
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_HDR_TRANS_EN, sizeof(*req_en));
265362306a36Sopenharmony_ci	req_en = (struct hdr_trans_en *)tlv;
265462306a36Sopenharmony_ci	req_en->enable = hdr_trans;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_HDR_TRANS_VLAN,
265762306a36Sopenharmony_ci				     sizeof(struct hdr_trans_vlan));
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (hdr_trans) {
266062306a36Sopenharmony_ci		tlv = mt7996_mcu_add_uni_tlv(skb, UNI_HDR_TRANS_BLACKLIST,
266162306a36Sopenharmony_ci					     sizeof(*req_blacklist));
266262306a36Sopenharmony_ci		req_blacklist = (struct hdr_trans_blacklist *)tlv;
266362306a36Sopenharmony_ci		req_blacklist->enable = 1;
266462306a36Sopenharmony_ci		req_blacklist->type = cpu_to_le16(ETH_P_PAE);
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
266862306a36Sopenharmony_ci				     MCU_WM_UNI_CMD(RX_HDR_TRANS), true);
266962306a36Sopenharmony_ci}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ciint mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif)
267262306a36Sopenharmony_ci{
267362306a36Sopenharmony_ci#define MCU_EDCA_AC_PARAM	0
267462306a36Sopenharmony_ci#define WMM_AIFS_SET		BIT(0)
267562306a36Sopenharmony_ci#define WMM_CW_MIN_SET		BIT(1)
267662306a36Sopenharmony_ci#define WMM_CW_MAX_SET		BIT(2)
267762306a36Sopenharmony_ci#define WMM_TXOP_SET		BIT(3)
267862306a36Sopenharmony_ci#define WMM_PARAM_SET		(WMM_AIFS_SET | WMM_CW_MIN_SET | \
267962306a36Sopenharmony_ci				 WMM_CW_MAX_SET | WMM_TXOP_SET)
268062306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
268162306a36Sopenharmony_ci	struct {
268262306a36Sopenharmony_ci		u8 bss_idx;
268362306a36Sopenharmony_ci		u8 __rsv[3];
268462306a36Sopenharmony_ci	} __packed hdr = {
268562306a36Sopenharmony_ci		.bss_idx = mvif->mt76.idx,
268662306a36Sopenharmony_ci	};
268762306a36Sopenharmony_ci	struct sk_buff *skb;
268862306a36Sopenharmony_ci	int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca);
268962306a36Sopenharmony_ci	int ac;
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
269262306a36Sopenharmony_ci	if (!skb)
269362306a36Sopenharmony_ci		return -ENOMEM;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	skb_put_data(skb, &hdr, sizeof(hdr));
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
269862306a36Sopenharmony_ci		struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
269962306a36Sopenharmony_ci		struct edca *e;
270062306a36Sopenharmony_ci		struct tlv *tlv;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci		tlv = mt7996_mcu_add_uni_tlv(skb, MCU_EDCA_AC_PARAM, sizeof(*e));
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci		e = (struct edca *)tlv;
270562306a36Sopenharmony_ci		e->set = WMM_PARAM_SET;
270662306a36Sopenharmony_ci		e->queue = ac;
270762306a36Sopenharmony_ci		e->aifs = q->aifs;
270862306a36Sopenharmony_ci		e->txop = cpu_to_le16(q->txop);
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci		if (q->cw_min)
271162306a36Sopenharmony_ci			e->cw_min = fls(q->cw_min);
271262306a36Sopenharmony_ci		else
271362306a36Sopenharmony_ci			e->cw_min = 5;
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci		if (q->cw_max)
271662306a36Sopenharmony_ci			e->cw_max = fls(q->cw_max);
271762306a36Sopenharmony_ci		else
271862306a36Sopenharmony_ci			e->cw_max = 10;
271962306a36Sopenharmony_ci	}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
272262306a36Sopenharmony_ci				     MCU_WM_UNI_CMD(EDCA_UPDATE), true);
272362306a36Sopenharmony_ci}
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ciint mt7996_mcu_set_fcc5_lpn(struct mt7996_dev *dev, int val)
272662306a36Sopenharmony_ci{
272762306a36Sopenharmony_ci	struct {
272862306a36Sopenharmony_ci		u8 _rsv[4];
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci		__le16 tag;
273162306a36Sopenharmony_ci		__le16 len;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci		__le32 ctrl;
273462306a36Sopenharmony_ci		__le16 min_lpn;
273562306a36Sopenharmony_ci		u8 rsv[2];
273662306a36Sopenharmony_ci	} __packed req = {
273762306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_RDD_CTRL_SET_TH),
273862306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci		.ctrl = cpu_to_le32(0x1),
274162306a36Sopenharmony_ci		.min_lpn = cpu_to_le16(val),
274262306a36Sopenharmony_ci	};
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL),
274562306a36Sopenharmony_ci				 &req, sizeof(req), true);
274662306a36Sopenharmony_ci}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ciint mt7996_mcu_set_pulse_th(struct mt7996_dev *dev,
274962306a36Sopenharmony_ci			    const struct mt7996_dfs_pulse *pulse)
275062306a36Sopenharmony_ci{
275162306a36Sopenharmony_ci	struct {
275262306a36Sopenharmony_ci		u8 _rsv[4];
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci		__le16 tag;
275562306a36Sopenharmony_ci		__le16 len;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci		__le32 ctrl;
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci		__le32 max_width;		/* us */
276062306a36Sopenharmony_ci		__le32 max_pwr;			/* dbm */
276162306a36Sopenharmony_ci		__le32 min_pwr;			/* dbm */
276262306a36Sopenharmony_ci		__le32 min_stgr_pri;		/* us */
276362306a36Sopenharmony_ci		__le32 max_stgr_pri;		/* us */
276462306a36Sopenharmony_ci		__le32 min_cr_pri;		/* us */
276562306a36Sopenharmony_ci		__le32 max_cr_pri;		/* us */
276662306a36Sopenharmony_ci	} __packed req = {
276762306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_RDD_CTRL_SET_TH),
276862306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci		.ctrl = cpu_to_le32(0x3),
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci#define __req_field(field) .field = cpu_to_le32(pulse->field)
277362306a36Sopenharmony_ci		__req_field(max_width),
277462306a36Sopenharmony_ci		__req_field(max_pwr),
277562306a36Sopenharmony_ci		__req_field(min_pwr),
277662306a36Sopenharmony_ci		__req_field(min_stgr_pri),
277762306a36Sopenharmony_ci		__req_field(max_stgr_pri),
277862306a36Sopenharmony_ci		__req_field(min_cr_pri),
277962306a36Sopenharmony_ci		__req_field(max_cr_pri),
278062306a36Sopenharmony_ci#undef __req_field
278162306a36Sopenharmony_ci	};
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL),
278462306a36Sopenharmony_ci				 &req, sizeof(req), true);
278562306a36Sopenharmony_ci}
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ciint mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
278862306a36Sopenharmony_ci			    const struct mt7996_dfs_pattern *pattern)
278962306a36Sopenharmony_ci{
279062306a36Sopenharmony_ci	struct {
279162306a36Sopenharmony_ci		u8 _rsv[4];
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci		__le16 tag;
279462306a36Sopenharmony_ci		__le16 len;
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci		__le32 ctrl;
279762306a36Sopenharmony_ci		__le16 radar_type;
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci		u8 enb;
280062306a36Sopenharmony_ci		u8 stgr;
280162306a36Sopenharmony_ci		u8 min_crpn;
280262306a36Sopenharmony_ci		u8 max_crpn;
280362306a36Sopenharmony_ci		u8 min_crpr;
280462306a36Sopenharmony_ci		u8 min_pw;
280562306a36Sopenharmony_ci		__le32 min_pri;
280662306a36Sopenharmony_ci		__le32 max_pri;
280762306a36Sopenharmony_ci		u8 max_pw;
280862306a36Sopenharmony_ci		u8 min_crbn;
280962306a36Sopenharmony_ci		u8 max_crbn;
281062306a36Sopenharmony_ci		u8 min_stgpn;
281162306a36Sopenharmony_ci		u8 max_stgpn;
281262306a36Sopenharmony_ci		u8 min_stgpr;
281362306a36Sopenharmony_ci		u8 rsv[2];
281462306a36Sopenharmony_ci		__le32 min_stgpr_diff;
281562306a36Sopenharmony_ci	} __packed req = {
281662306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_RDD_CTRL_SET_TH),
281762306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci		.ctrl = cpu_to_le32(0x2),
282062306a36Sopenharmony_ci		.radar_type = cpu_to_le16(index),
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci#define __req_field_u8(field) .field = pattern->field
282362306a36Sopenharmony_ci#define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
282462306a36Sopenharmony_ci		__req_field_u8(enb),
282562306a36Sopenharmony_ci		__req_field_u8(stgr),
282662306a36Sopenharmony_ci		__req_field_u8(min_crpn),
282762306a36Sopenharmony_ci		__req_field_u8(max_crpn),
282862306a36Sopenharmony_ci		__req_field_u8(min_crpr),
282962306a36Sopenharmony_ci		__req_field_u8(min_pw),
283062306a36Sopenharmony_ci		__req_field_u32(min_pri),
283162306a36Sopenharmony_ci		__req_field_u32(max_pri),
283262306a36Sopenharmony_ci		__req_field_u8(max_pw),
283362306a36Sopenharmony_ci		__req_field_u8(min_crbn),
283462306a36Sopenharmony_ci		__req_field_u8(max_crbn),
283562306a36Sopenharmony_ci		__req_field_u8(min_stgpn),
283662306a36Sopenharmony_ci		__req_field_u8(max_stgpn),
283762306a36Sopenharmony_ci		__req_field_u8(min_stgpr),
283862306a36Sopenharmony_ci		__req_field_u32(min_stgpr_diff),
283962306a36Sopenharmony_ci#undef __req_field_u8
284062306a36Sopenharmony_ci#undef __req_field_u32
284162306a36Sopenharmony_ci	};
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL),
284462306a36Sopenharmony_ci				 &req, sizeof(req), true);
284562306a36Sopenharmony_ci}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_cistatic int
284862306a36Sopenharmony_cimt7996_mcu_background_chain_ctrl(struct mt7996_phy *phy,
284962306a36Sopenharmony_ci				 struct cfg80211_chan_def *chandef,
285062306a36Sopenharmony_ci				 int cmd)
285162306a36Sopenharmony_ci{
285262306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
285362306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
285462306a36Sopenharmony_ci	struct ieee80211_channel *chan = mphy->chandef.chan;
285562306a36Sopenharmony_ci	int freq = mphy->chandef.center_freq1;
285662306a36Sopenharmony_ci	struct mt7996_mcu_background_chain_ctrl req = {
285762306a36Sopenharmony_ci		.tag = cpu_to_le16(0),
285862306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
285962306a36Sopenharmony_ci		.monitor_scan_type = 2, /* simple rx */
286062306a36Sopenharmony_ci	};
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP)
286362306a36Sopenharmony_ci		return -EINVAL;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	if (!cfg80211_chandef_valid(&mphy->chandef))
286662306a36Sopenharmony_ci		return -EINVAL;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	switch (cmd) {
286962306a36Sopenharmony_ci	case CH_SWITCH_BACKGROUND_SCAN_START: {
287062306a36Sopenharmony_ci		req.chan = chan->hw_value;
287162306a36Sopenharmony_ci		req.central_chan = ieee80211_frequency_to_channel(freq);
287262306a36Sopenharmony_ci		req.bw = mt76_connac_chan_bw(&mphy->chandef);
287362306a36Sopenharmony_ci		req.monitor_chan = chandef->chan->hw_value;
287462306a36Sopenharmony_ci		req.monitor_central_chan =
287562306a36Sopenharmony_ci			ieee80211_frequency_to_channel(chandef->center_freq1);
287662306a36Sopenharmony_ci		req.monitor_bw = mt76_connac_chan_bw(chandef);
287762306a36Sopenharmony_ci		req.band_idx = phy->mt76->band_idx;
287862306a36Sopenharmony_ci		req.scan_mode = 1;
287962306a36Sopenharmony_ci		break;
288062306a36Sopenharmony_ci	}
288162306a36Sopenharmony_ci	case CH_SWITCH_BACKGROUND_SCAN_RUNNING:
288262306a36Sopenharmony_ci		req.monitor_chan = chandef->chan->hw_value;
288362306a36Sopenharmony_ci		req.monitor_central_chan =
288462306a36Sopenharmony_ci			ieee80211_frequency_to_channel(chandef->center_freq1);
288562306a36Sopenharmony_ci		req.band_idx = phy->mt76->band_idx;
288662306a36Sopenharmony_ci		req.scan_mode = 2;
288762306a36Sopenharmony_ci		break;
288862306a36Sopenharmony_ci	case CH_SWITCH_BACKGROUND_SCAN_STOP:
288962306a36Sopenharmony_ci		req.chan = chan->hw_value;
289062306a36Sopenharmony_ci		req.central_chan = ieee80211_frequency_to_channel(freq);
289162306a36Sopenharmony_ci		req.bw = mt76_connac_chan_bw(&mphy->chandef);
289262306a36Sopenharmony_ci		req.tx_stream = hweight8(mphy->antenna_mask);
289362306a36Sopenharmony_ci		req.rx_stream = mphy->antenna_mask;
289462306a36Sopenharmony_ci		break;
289562306a36Sopenharmony_ci	default:
289662306a36Sopenharmony_ci		return -EINVAL;
289762306a36Sopenharmony_ci	}
289862306a36Sopenharmony_ci	req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1;
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(OFFCH_SCAN_CTRL),
290162306a36Sopenharmony_ci				 &req, sizeof(req), false);
290262306a36Sopenharmony_ci}
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ciint mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
290562306a36Sopenharmony_ci				     struct cfg80211_chan_def *chandef)
290662306a36Sopenharmony_ci{
290762306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
290862306a36Sopenharmony_ci	int err, region;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	if (!chandef) { /* disable offchain */
291162306a36Sopenharmony_ci		err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, MT_RX_SEL2,
291262306a36Sopenharmony_ci					 0, 0);
291362306a36Sopenharmony_ci		if (err)
291462306a36Sopenharmony_ci			return err;
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci		return mt7996_mcu_background_chain_ctrl(phy, NULL,
291762306a36Sopenharmony_ci				CH_SWITCH_BACKGROUND_SCAN_STOP);
291862306a36Sopenharmony_ci	}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	err = mt7996_mcu_background_chain_ctrl(phy, chandef,
292162306a36Sopenharmony_ci					       CH_SWITCH_BACKGROUND_SCAN_START);
292262306a36Sopenharmony_ci	if (err)
292362306a36Sopenharmony_ci		return err;
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	switch (dev->mt76.region) {
292662306a36Sopenharmony_ci	case NL80211_DFS_ETSI:
292762306a36Sopenharmony_ci		region = 0;
292862306a36Sopenharmony_ci		break;
292962306a36Sopenharmony_ci	case NL80211_DFS_JP:
293062306a36Sopenharmony_ci		region = 2;
293162306a36Sopenharmony_ci		break;
293262306a36Sopenharmony_ci	case NL80211_DFS_FCC:
293362306a36Sopenharmony_ci	default:
293462306a36Sopenharmony_ci		region = 1;
293562306a36Sopenharmony_ci		break;
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	return mt7996_mcu_rdd_cmd(dev, RDD_START, MT_RX_SEL2,
293962306a36Sopenharmony_ci				  0, region);
294062306a36Sopenharmony_ci}
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ciint mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
294362306a36Sopenharmony_ci{
294462306a36Sopenharmony_ci	static const u8 ch_band[] = {
294562306a36Sopenharmony_ci		[NL80211_BAND_2GHZ] = 0,
294662306a36Sopenharmony_ci		[NL80211_BAND_5GHZ] = 1,
294762306a36Sopenharmony_ci		[NL80211_BAND_6GHZ] = 2,
294862306a36Sopenharmony_ci	};
294962306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
295062306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
295162306a36Sopenharmony_ci	int freq1 = chandef->center_freq1;
295262306a36Sopenharmony_ci	u8 band_idx = phy->mt76->band_idx;
295362306a36Sopenharmony_ci	struct {
295462306a36Sopenharmony_ci		/* fixed field */
295562306a36Sopenharmony_ci		u8 __rsv[4];
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci		__le16 tag;
295862306a36Sopenharmony_ci		__le16 len;
295962306a36Sopenharmony_ci		u8 control_ch;
296062306a36Sopenharmony_ci		u8 center_ch;
296162306a36Sopenharmony_ci		u8 bw;
296262306a36Sopenharmony_ci		u8 tx_path_num;
296362306a36Sopenharmony_ci		u8 rx_path;	/* mask or num */
296462306a36Sopenharmony_ci		u8 switch_reason;
296562306a36Sopenharmony_ci		u8 band_idx;
296662306a36Sopenharmony_ci		u8 center_ch2;	/* for 80+80 only */
296762306a36Sopenharmony_ci		__le16 cac_case;
296862306a36Sopenharmony_ci		u8 channel_band;
296962306a36Sopenharmony_ci		u8 rsv0;
297062306a36Sopenharmony_ci		__le32 outband_freq;
297162306a36Sopenharmony_ci		u8 txpower_drop;
297262306a36Sopenharmony_ci		u8 ap_bw;
297362306a36Sopenharmony_ci		u8 ap_center_ch;
297462306a36Sopenharmony_ci		u8 rsv1[53];
297562306a36Sopenharmony_ci	} __packed req = {
297662306a36Sopenharmony_ci		.tag = cpu_to_le16(tag),
297762306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
297862306a36Sopenharmony_ci		.control_ch = chandef->chan->hw_value,
297962306a36Sopenharmony_ci		.center_ch = ieee80211_frequency_to_channel(freq1),
298062306a36Sopenharmony_ci		.bw = mt76_connac_chan_bw(chandef),
298162306a36Sopenharmony_ci		.tx_path_num = hweight16(phy->mt76->chainmask),
298262306a36Sopenharmony_ci		.rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx],
298362306a36Sopenharmony_ci		.band_idx = band_idx,
298462306a36Sopenharmony_ci		.channel_band = ch_band[chandef->chan->band],
298562306a36Sopenharmony_ci	};
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci	if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
298862306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_NORMAL;
298962306a36Sopenharmony_ci	else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
299062306a36Sopenharmony_ci		 phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
299162306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
299262306a36Sopenharmony_ci	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
299362306a36Sopenharmony_ci					  NL80211_IFTYPE_AP))
299462306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_DFS;
299562306a36Sopenharmony_ci	else
299662306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_NORMAL;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	if (tag == UNI_CHANNEL_SWITCH)
299962306a36Sopenharmony_ci		req.rx_path = hweight8(req.rx_path);
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
300262306a36Sopenharmony_ci		int freq2 = chandef->center_freq2;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci		req.center_ch2 = ieee80211_frequency_to_channel(freq2);
300562306a36Sopenharmony_ci	}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(CHANNEL_SWITCH),
300862306a36Sopenharmony_ci				 &req, sizeof(req), true);
300962306a36Sopenharmony_ci}
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_cistatic int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
301262306a36Sopenharmony_ci{
301362306a36Sopenharmony_ci#define MAX_PAGE_IDX_MASK	GENMASK(7, 5)
301462306a36Sopenharmony_ci#define PAGE_IDX_MASK		GENMASK(4, 2)
301562306a36Sopenharmony_ci#define PER_PAGE_SIZE		0x400
301662306a36Sopenharmony_ci	struct mt7996_mcu_eeprom req = {
301762306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),
301862306a36Sopenharmony_ci		.buffer_mode = EE_MODE_BUFFER
301962306a36Sopenharmony_ci	};
302062306a36Sopenharmony_ci	u16 eeprom_size = MT7996_EEPROM_SIZE;
302162306a36Sopenharmony_ci	u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE);
302262306a36Sopenharmony_ci	u8 *eep = (u8 *)dev->mt76.eeprom.data;
302362306a36Sopenharmony_ci	int eep_len, i;
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci	for (i = 0; i < total; i++, eep += eep_len) {
302662306a36Sopenharmony_ci		struct sk_buff *skb;
302762306a36Sopenharmony_ci		int ret, msg_len;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci		if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE))
303062306a36Sopenharmony_ci			eep_len = eeprom_size % PER_PAGE_SIZE;
303162306a36Sopenharmony_ci		else
303262306a36Sopenharmony_ci			eep_len = PER_PAGE_SIZE;
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_ci		msg_len = sizeof(req) + eep_len;
303562306a36Sopenharmony_ci		skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, msg_len);
303662306a36Sopenharmony_ci		if (!skb)
303762306a36Sopenharmony_ci			return -ENOMEM;
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci		req.len = cpu_to_le16(msg_len - 4);
304062306a36Sopenharmony_ci		req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
304162306a36Sopenharmony_ci			     FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
304262306a36Sopenharmony_ci		req.buf_len = cpu_to_le16(eep_len);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci		skb_put_data(skb, &req, sizeof(req));
304562306a36Sopenharmony_ci		skb_put_data(skb, eep, eep_len);
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci		ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
304862306a36Sopenharmony_ci					    MCU_WM_UNI_CMD(EFUSE_CTRL), true);
304962306a36Sopenharmony_ci		if (ret)
305062306a36Sopenharmony_ci			return ret;
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	return 0;
305462306a36Sopenharmony_ci}
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ciint mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
305762306a36Sopenharmony_ci{
305862306a36Sopenharmony_ci	struct mt7996_mcu_eeprom req = {
305962306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),
306062306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
306162306a36Sopenharmony_ci		.buffer_mode = EE_MODE_EFUSE,
306262306a36Sopenharmony_ci		.format = EE_FORMAT_WHOLE
306362306a36Sopenharmony_ci	};
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	if (dev->flash_mode)
306662306a36Sopenharmony_ci		return mt7996_mcu_set_eeprom_flash(dev);
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
306962306a36Sopenharmony_ci				 &req, sizeof(req), true);
307062306a36Sopenharmony_ci}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ciint mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
307362306a36Sopenharmony_ci{
307462306a36Sopenharmony_ci	struct {
307562306a36Sopenharmony_ci		u8 _rsv[4];
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci		__le16 tag;
307862306a36Sopenharmony_ci		__le16 len;
307962306a36Sopenharmony_ci		__le32 addr;
308062306a36Sopenharmony_ci		__le32 valid;
308162306a36Sopenharmony_ci		u8 data[16];
308262306a36Sopenharmony_ci	} __packed req = {
308362306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_EFUSE_ACCESS),
308462306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
308562306a36Sopenharmony_ci		.addr = cpu_to_le32(round_down(offset,
308662306a36Sopenharmony_ci				    MT7996_EEPROM_BLOCK_SIZE)),
308762306a36Sopenharmony_ci	};
308862306a36Sopenharmony_ci	struct sk_buff *skb;
308962306a36Sopenharmony_ci	bool valid;
309062306a36Sopenharmony_ci	int ret;
309162306a36Sopenharmony_ci
309262306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
309362306a36Sopenharmony_ci					MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL),
309462306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
309562306a36Sopenharmony_ci	if (ret)
309662306a36Sopenharmony_ci		return ret;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	valid = le32_to_cpu(*(__le32 *)(skb->data + 16));
309962306a36Sopenharmony_ci	if (valid) {
310062306a36Sopenharmony_ci		u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12));
310162306a36Sopenharmony_ci		u8 *buf = (u8 *)dev->mt76.eeprom.data + addr;
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci		skb_pull(skb, 48);
310462306a36Sopenharmony_ci		memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE);
310562306a36Sopenharmony_ci	}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	dev_kfree_skb(skb);
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci	return 0;
311062306a36Sopenharmony_ci}
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ciint mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num)
311362306a36Sopenharmony_ci{
311462306a36Sopenharmony_ci	struct {
311562306a36Sopenharmony_ci		u8 _rsv[4];
311662306a36Sopenharmony_ci
311762306a36Sopenharmony_ci		__le16 tag;
311862306a36Sopenharmony_ci		__le16 len;
311962306a36Sopenharmony_ci		u8 num;
312062306a36Sopenharmony_ci		u8 version;
312162306a36Sopenharmony_ci		u8 die_idx;
312262306a36Sopenharmony_ci		u8 _rsv2;
312362306a36Sopenharmony_ci	} __packed req = {
312462306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_EFUSE_FREE_BLOCK),
312562306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
312662306a36Sopenharmony_ci		.version = 2,
312762306a36Sopenharmony_ci	};
312862306a36Sopenharmony_ci	struct sk_buff *skb;
312962306a36Sopenharmony_ci	int ret;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), &req,
313262306a36Sopenharmony_ci					sizeof(req), true, &skb);
313362306a36Sopenharmony_ci	if (ret)
313462306a36Sopenharmony_ci		return ret;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	*block_num = *(u8 *)(skb->data + 8);
313762306a36Sopenharmony_ci	dev_kfree_skb(skb);
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	return 0;
314062306a36Sopenharmony_ci}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_ciint mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap)
314362306a36Sopenharmony_ci{
314462306a36Sopenharmony_ci#define NIC_CAP	3
314562306a36Sopenharmony_ci#define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION	0x21
314662306a36Sopenharmony_ci	struct {
314762306a36Sopenharmony_ci		u8 _rsv[4];
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci		__le16 tag;
315062306a36Sopenharmony_ci		__le16 len;
315162306a36Sopenharmony_ci	} __packed req = {
315262306a36Sopenharmony_ci		.tag = cpu_to_le16(NIC_CAP),
315362306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
315462306a36Sopenharmony_ci	};
315562306a36Sopenharmony_ci	struct sk_buff *skb;
315662306a36Sopenharmony_ci	u8 *buf;
315762306a36Sopenharmony_ci	int ret;
315862306a36Sopenharmony_ci
315962306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
316062306a36Sopenharmony_ci					MCU_WM_UNI_CMD_QUERY(CHIP_CONFIG), &req,
316162306a36Sopenharmony_ci					sizeof(req), true, &skb);
316262306a36Sopenharmony_ci	if (ret)
316362306a36Sopenharmony_ci		return ret;
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	/* fixed field */
316662306a36Sopenharmony_ci	skb_pull(skb, 4);
316762306a36Sopenharmony_ci
316862306a36Sopenharmony_ci	buf = skb->data;
316962306a36Sopenharmony_ci	while (buf - skb->data < skb->len) {
317062306a36Sopenharmony_ci		struct tlv *tlv = (struct tlv *)buf;
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci		switch (le16_to_cpu(tlv->tag)) {
317362306a36Sopenharmony_ci		case UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION:
317462306a36Sopenharmony_ci			*cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv)));
317562306a36Sopenharmony_ci			break;
317662306a36Sopenharmony_ci		default:
317762306a36Sopenharmony_ci			break;
317862306a36Sopenharmony_ci		}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci		buf += le16_to_cpu(tlv->len);
318162306a36Sopenharmony_ci	}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	dev_kfree_skb(skb);
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	return 0;
318662306a36Sopenharmony_ci}
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ciint mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch)
318962306a36Sopenharmony_ci{
319062306a36Sopenharmony_ci	struct {
319162306a36Sopenharmony_ci		struct {
319262306a36Sopenharmony_ci			u8 band;
319362306a36Sopenharmony_ci			u8 __rsv[3];
319462306a36Sopenharmony_ci		} hdr;
319562306a36Sopenharmony_ci		struct {
319662306a36Sopenharmony_ci			__le16 tag;
319762306a36Sopenharmony_ci			__le16 len;
319862306a36Sopenharmony_ci			__le32 offs;
319962306a36Sopenharmony_ci		} data[4];
320062306a36Sopenharmony_ci	} __packed req = {
320162306a36Sopenharmony_ci		.hdr.band = phy->mt76->band_idx,
320262306a36Sopenharmony_ci	};
320362306a36Sopenharmony_ci	/* strict order */
320462306a36Sopenharmony_ci	static const u32 offs[] = {
320562306a36Sopenharmony_ci		UNI_MIB_TX_TIME,
320662306a36Sopenharmony_ci		UNI_MIB_RX_TIME,
320762306a36Sopenharmony_ci		UNI_MIB_OBSS_AIRTIME,
320862306a36Sopenharmony_ci		UNI_MIB_NON_WIFI_TIME,
320962306a36Sopenharmony_ci	};
321062306a36Sopenharmony_ci	struct mt76_channel_state *state = phy->mt76->chan_state;
321162306a36Sopenharmony_ci	struct mt76_channel_state *state_ts = &phy->state_ts;
321262306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
321362306a36Sopenharmony_ci	struct mt7996_mcu_mib *res;
321462306a36Sopenharmony_ci	struct sk_buff *skb;
321562306a36Sopenharmony_ci	int i, ret;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
321862306a36Sopenharmony_ci		req.data[i].tag = cpu_to_le16(UNI_CMD_MIB_DATA);
321962306a36Sopenharmony_ci		req.data[i].len = cpu_to_le16(sizeof(req.data[i]));
322062306a36Sopenharmony_ci		req.data[i].offs = cpu_to_le32(offs[i]);
322162306a36Sopenharmony_ci	}
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(GET_MIB_INFO),
322462306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
322562306a36Sopenharmony_ci	if (ret)
322662306a36Sopenharmony_ci		return ret;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	skb_pull(skb, sizeof(req.hdr));
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	res = (struct mt7996_mcu_mib *)(skb->data);
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	if (chan_switch)
323362306a36Sopenharmony_ci		goto out;
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci#define __res_u64(s) le64_to_cpu(res[s].data)
323662306a36Sopenharmony_ci	state->cc_tx += __res_u64(1) - state_ts->cc_tx;
323762306a36Sopenharmony_ci	state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx;
323862306a36Sopenharmony_ci	state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx;
323962306a36Sopenharmony_ci	state->cc_busy += __res_u64(0) + __res_u64(1) + __res_u64(2) + __res_u64(3) -
324062306a36Sopenharmony_ci			  state_ts->cc_busy;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ciout:
324362306a36Sopenharmony_ci	state_ts->cc_tx = __res_u64(1);
324462306a36Sopenharmony_ci	state_ts->cc_bss_rx = __res_u64(2);
324562306a36Sopenharmony_ci	state_ts->cc_rx = __res_u64(2) + __res_u64(3);
324662306a36Sopenharmony_ci	state_ts->cc_busy = __res_u64(0) + __res_u64(1) + __res_u64(2) + __res_u64(3);
324762306a36Sopenharmony_ci#undef __res_u64
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	dev_kfree_skb(skb);
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	return 0;
325262306a36Sopenharmony_ci}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ciint mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
325562306a36Sopenharmony_ci{
325662306a36Sopenharmony_ci	struct {
325762306a36Sopenharmony_ci		u8 rsv[4];
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci		__le16 tag;
326062306a36Sopenharmony_ci		__le16 len;
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci		union {
326362306a36Sopenharmony_ci			struct {
326462306a36Sopenharmony_ci				__le32 mask;
326562306a36Sopenharmony_ci			} __packed set;
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci			struct {
326862306a36Sopenharmony_ci				u8 method;
326962306a36Sopenharmony_ci				u8 band;
327062306a36Sopenharmony_ci				u8 rsv2[2];
327162306a36Sopenharmony_ci			} __packed trigger;
327262306a36Sopenharmony_ci		};
327362306a36Sopenharmony_ci	} __packed req = {
327462306a36Sopenharmony_ci		.tag = cpu_to_le16(action),
327562306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
327662306a36Sopenharmony_ci	};
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	switch (action) {
327962306a36Sopenharmony_ci	case UNI_CMD_SER_SET:
328062306a36Sopenharmony_ci		req.set.mask = cpu_to_le32(val);
328162306a36Sopenharmony_ci		break;
328262306a36Sopenharmony_ci	case UNI_CMD_SER_TRIGGER:
328362306a36Sopenharmony_ci		req.trigger.method = val;
328462306a36Sopenharmony_ci		req.trigger.band = band;
328562306a36Sopenharmony_ci		break;
328662306a36Sopenharmony_ci	default:
328762306a36Sopenharmony_ci		return -EINVAL;
328862306a36Sopenharmony_ci	}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SER),
329162306a36Sopenharmony_ci				 &req, sizeof(req), false);
329262306a36Sopenharmony_ci}
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_ciint mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action)
329562306a36Sopenharmony_ci{
329662306a36Sopenharmony_ci#define MT7996_BF_MAX_SIZE	sizeof(union bf_tag_tlv)
329762306a36Sopenharmony_ci#define BF_PROCESSING	4
329862306a36Sopenharmony_ci	struct uni_header hdr;
329962306a36Sopenharmony_ci	struct sk_buff *skb;
330062306a36Sopenharmony_ci	struct tlv *tlv;
330162306a36Sopenharmony_ci	int len = sizeof(hdr) + MT7996_BF_MAX_SIZE;
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	memset(&hdr, 0, sizeof(hdr));
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
330662306a36Sopenharmony_ci	if (!skb)
330762306a36Sopenharmony_ci		return -ENOMEM;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	skb_put_data(skb, &hdr, sizeof(hdr));
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	switch (action) {
331262306a36Sopenharmony_ci	case BF_SOUNDING_ON: {
331362306a36Sopenharmony_ci		struct bf_sounding_on *req_snd_on;
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci		tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_snd_on));
331662306a36Sopenharmony_ci		req_snd_on = (struct bf_sounding_on *)tlv;
331762306a36Sopenharmony_ci		req_snd_on->snd_mode = BF_PROCESSING;
331862306a36Sopenharmony_ci		break;
331962306a36Sopenharmony_ci	}
332062306a36Sopenharmony_ci	case BF_HW_EN_UPDATE: {
332162306a36Sopenharmony_ci		struct bf_hw_en_status_update *req_hw_en;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci		tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_hw_en));
332462306a36Sopenharmony_ci		req_hw_en = (struct bf_hw_en_status_update *)tlv;
332562306a36Sopenharmony_ci		req_hw_en->ebf = true;
332662306a36Sopenharmony_ci		req_hw_en->ibf = dev->ibf;
332762306a36Sopenharmony_ci		break;
332862306a36Sopenharmony_ci	}
332962306a36Sopenharmony_ci	case BF_MOD_EN_CTRL: {
333062306a36Sopenharmony_ci		struct bf_mod_en_ctrl *req_mod_en;
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci		tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_mod_en));
333362306a36Sopenharmony_ci		req_mod_en = (struct bf_mod_en_ctrl *)tlv;
333462306a36Sopenharmony_ci		req_mod_en->bf_num = 3;
333562306a36Sopenharmony_ci		req_mod_en->bf_bitmap = GENMASK(2, 0);
333662306a36Sopenharmony_ci		break;
333762306a36Sopenharmony_ci	}
333862306a36Sopenharmony_ci	default:
333962306a36Sopenharmony_ci		return -EINVAL;
334062306a36Sopenharmony_ci	}
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(BF), true);
334362306a36Sopenharmony_ci}
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_cistatic int
334662306a36Sopenharmony_cimt7996_mcu_enable_obss_spr(struct mt7996_phy *phy, u16 action, u8 val)
334762306a36Sopenharmony_ci{
334862306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
334962306a36Sopenharmony_ci	struct {
335062306a36Sopenharmony_ci		u8 band_idx;
335162306a36Sopenharmony_ci		u8 __rsv[3];
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci		__le16 tag;
335462306a36Sopenharmony_ci		__le16 len;
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci		__le32 val;
335762306a36Sopenharmony_ci	} __packed req = {
335862306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
335962306a36Sopenharmony_ci		.tag = cpu_to_le16(action),
336062306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
336162306a36Sopenharmony_ci		.val = cpu_to_le32(val),
336262306a36Sopenharmony_ci	};
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR),
336562306a36Sopenharmony_ci				 &req, sizeof(req), true);
336662306a36Sopenharmony_ci}
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_cistatic int
336962306a36Sopenharmony_cimt7996_mcu_set_obss_spr_pd(struct mt7996_phy *phy,
337062306a36Sopenharmony_ci			   struct ieee80211_he_obss_pd *he_obss_pd)
337162306a36Sopenharmony_ci{
337262306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
337362306a36Sopenharmony_ci	u8 max_th = 82, non_srg_max_th = 62;
337462306a36Sopenharmony_ci	struct {
337562306a36Sopenharmony_ci		u8 band_idx;
337662306a36Sopenharmony_ci		u8 __rsv[3];
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci		__le16 tag;
337962306a36Sopenharmony_ci		__le16 len;
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci		u8 pd_th_non_srg;
338262306a36Sopenharmony_ci		u8 pd_th_srg;
338362306a36Sopenharmony_ci		u8 period_offs;
338462306a36Sopenharmony_ci		u8 rcpi_src;
338562306a36Sopenharmony_ci		__le16 obss_pd_min;
338662306a36Sopenharmony_ci		__le16 obss_pd_min_srg;
338762306a36Sopenharmony_ci		u8 resp_txpwr_mode;
338862306a36Sopenharmony_ci		u8 txpwr_restrict_mode;
338962306a36Sopenharmony_ci		u8 txpwr_ref;
339062306a36Sopenharmony_ci		u8 __rsv2[3];
339162306a36Sopenharmony_ci	} __packed req = {
339262306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
339362306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_CMD_SR_SET_PARAM),
339462306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
339562306a36Sopenharmony_ci		.obss_pd_min = cpu_to_le16(max_th),
339662306a36Sopenharmony_ci		.obss_pd_min_srg = cpu_to_le16(max_th),
339762306a36Sopenharmony_ci		.txpwr_restrict_mode = 2,
339862306a36Sopenharmony_ci		.txpwr_ref = 21
339962306a36Sopenharmony_ci	};
340062306a36Sopenharmony_ci	int ret;
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci	/* disable firmware dynamical PD asjustment */
340362306a36Sopenharmony_ci	ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_DPD, false);
340462306a36Sopenharmony_ci	if (ret)
340562306a36Sopenharmony_ci		return ret;
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	if (he_obss_pd->sr_ctrl &
340862306a36Sopenharmony_ci	    IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)
340962306a36Sopenharmony_ci		req.pd_th_non_srg = max_th;
341062306a36Sopenharmony_ci	else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
341162306a36Sopenharmony_ci		req.pd_th_non_srg  = max_th - he_obss_pd->non_srg_max_offset;
341262306a36Sopenharmony_ci	else
341362306a36Sopenharmony_ci		req.pd_th_non_srg  = non_srg_max_th;
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
341662306a36Sopenharmony_ci		req.pd_th_srg = max_th - he_obss_pd->max_offset;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR),
341962306a36Sopenharmony_ci				 &req, sizeof(req), true);
342062306a36Sopenharmony_ci}
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_cistatic int
342362306a36Sopenharmony_cimt7996_mcu_set_obss_spr_siga(struct mt7996_phy *phy, struct ieee80211_vif *vif,
342462306a36Sopenharmony_ci			     struct ieee80211_he_obss_pd *he_obss_pd)
342562306a36Sopenharmony_ci{
342662306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
342762306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
342862306a36Sopenharmony_ci	u8 omac = mvif->mt76.omac_idx;
342962306a36Sopenharmony_ci	struct {
343062306a36Sopenharmony_ci		u8 band_idx;
343162306a36Sopenharmony_ci		u8 __rsv[3];
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci		__le16 tag;
343462306a36Sopenharmony_ci		__le16 len;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci		u8 omac;
343762306a36Sopenharmony_ci		u8 __rsv2[3];
343862306a36Sopenharmony_ci		u8 flag[20];
343962306a36Sopenharmony_ci	} __packed req = {
344062306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
344162306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_CMD_SR_SET_SIGA),
344262306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
344362306a36Sopenharmony_ci		.omac = omac > HW_BSSID_MAX ? omac - 12 : omac,
344462306a36Sopenharmony_ci	};
344562306a36Sopenharmony_ci	int ret;
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_ci	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED)
344862306a36Sopenharmony_ci		req.flag[req.omac] = 0xf;
344962306a36Sopenharmony_ci	else
345062306a36Sopenharmony_ci		return 0;
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_ci	/* switch to normal AP mode */
345362306a36Sopenharmony_ci	ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_MODE, 0);
345462306a36Sopenharmony_ci	if (ret)
345562306a36Sopenharmony_ci		return ret;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR),
345862306a36Sopenharmony_ci				 &req, sizeof(req), true);
345962306a36Sopenharmony_ci}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_cistatic int
346262306a36Sopenharmony_cimt7996_mcu_set_obss_spr_bitmap(struct mt7996_phy *phy,
346362306a36Sopenharmony_ci			       struct ieee80211_he_obss_pd *he_obss_pd)
346462306a36Sopenharmony_ci{
346562306a36Sopenharmony_ci	struct mt7996_dev *dev = phy->dev;
346662306a36Sopenharmony_ci	struct {
346762306a36Sopenharmony_ci		u8 band_idx;
346862306a36Sopenharmony_ci		u8 __rsv[3];
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci		__le16 tag;
347162306a36Sopenharmony_ci		__le16 len;
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci		__le32 color_l[2];
347462306a36Sopenharmony_ci		__le32 color_h[2];
347562306a36Sopenharmony_ci		__le32 bssid_l[2];
347662306a36Sopenharmony_ci		__le32 bssid_h[2];
347762306a36Sopenharmony_ci	} __packed req = {
347862306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
347962306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_CMD_SR_SET_SRG_BITMAP),
348062306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
348162306a36Sopenharmony_ci	};
348262306a36Sopenharmony_ci	u32 bitmap;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap));
348562306a36Sopenharmony_ci	req.color_l[req.band_idx] = cpu_to_le32(bitmap);
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap));
348862306a36Sopenharmony_ci	req.color_h[req.band_idx] = cpu_to_le32(bitmap);
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap));
349162306a36Sopenharmony_ci	req.bssid_l[req.band_idx] = cpu_to_le32(bitmap);
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap));
349462306a36Sopenharmony_ci	req.bssid_h[req.band_idx] = cpu_to_le32(bitmap);
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(SR), &req,
349762306a36Sopenharmony_ci				 sizeof(req), true);
349862306a36Sopenharmony_ci}
349962306a36Sopenharmony_ci
350062306a36Sopenharmony_ciint mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
350162306a36Sopenharmony_ci			    struct ieee80211_he_obss_pd *he_obss_pd)
350262306a36Sopenharmony_ci{
350362306a36Sopenharmony_ci	int ret;
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	/* enable firmware scene detection algorithms */
350662306a36Sopenharmony_ci	ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_SD,
350762306a36Sopenharmony_ci					 sr_scene_detect);
350862306a36Sopenharmony_ci	if (ret)
350962306a36Sopenharmony_ci		return ret;
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	/* firmware dynamically adjusts PD threshold so skip manual control */
351262306a36Sopenharmony_ci	if (sr_scene_detect && !he_obss_pd->enable)
351362306a36Sopenharmony_ci		return 0;
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	/* enable spatial reuse */
351662306a36Sopenharmony_ci	ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE,
351762306a36Sopenharmony_ci					 he_obss_pd->enable);
351862306a36Sopenharmony_ci	if (ret)
351962306a36Sopenharmony_ci		return ret;
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	if (sr_scene_detect || !he_obss_pd->enable)
352262306a36Sopenharmony_ci		return 0;
352362306a36Sopenharmony_ci
352462306a36Sopenharmony_ci	ret = mt7996_mcu_enable_obss_spr(phy, UNI_CMD_SR_ENABLE_TX, true);
352562306a36Sopenharmony_ci	if (ret)
352662306a36Sopenharmony_ci		return ret;
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	/* set SRG/non-SRG OBSS PD threshold */
352962306a36Sopenharmony_ci	ret = mt7996_mcu_set_obss_spr_pd(phy, he_obss_pd);
353062306a36Sopenharmony_ci	if (ret)
353162306a36Sopenharmony_ci		return ret;
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci	/* Set SR prohibit */
353462306a36Sopenharmony_ci	ret = mt7996_mcu_set_obss_spr_siga(phy, vif, he_obss_pd);
353562306a36Sopenharmony_ci	if (ret)
353662306a36Sopenharmony_ci		return ret;
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci	/* set SRG BSS color/BSSID bitmap */
353962306a36Sopenharmony_ci	return mt7996_mcu_set_obss_spr_bitmap(phy, he_obss_pd);
354062306a36Sopenharmony_ci}
354162306a36Sopenharmony_ci
354262306a36Sopenharmony_ciint mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif,
354362306a36Sopenharmony_ci				struct cfg80211_he_bss_color *he_bss_color)
354462306a36Sopenharmony_ci{
354562306a36Sopenharmony_ci	int len = sizeof(struct bss_req_hdr) + sizeof(struct bss_color_tlv);
354662306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
354762306a36Sopenharmony_ci	struct bss_color_tlv *bss_color;
354862306a36Sopenharmony_ci	struct sk_buff *skb;
354962306a36Sopenharmony_ci	struct tlv *tlv;
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len);
355262306a36Sopenharmony_ci	if (IS_ERR(skb))
355362306a36Sopenharmony_ci		return PTR_ERR(skb);
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BSS_COLOR,
355662306a36Sopenharmony_ci				      sizeof(*bss_color));
355762306a36Sopenharmony_ci	bss_color = (struct bss_color_tlv *)tlv;
355862306a36Sopenharmony_ci	bss_color->enable = he_bss_color->enabled;
355962306a36Sopenharmony_ci	bss_color->color = he_bss_color->color;
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
356262306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
356362306a36Sopenharmony_ci}
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci#define TWT_AGRT_TRIGGER	BIT(0)
356662306a36Sopenharmony_ci#define TWT_AGRT_ANNOUNCE	BIT(1)
356762306a36Sopenharmony_ci#define TWT_AGRT_PROTECT	BIT(2)
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ciint mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
357062306a36Sopenharmony_ci			       struct mt7996_vif *mvif,
357162306a36Sopenharmony_ci			       struct mt7996_twt_flow *flow,
357262306a36Sopenharmony_ci			       int cmd)
357362306a36Sopenharmony_ci{
357462306a36Sopenharmony_ci	struct {
357562306a36Sopenharmony_ci		/* fixed field */
357662306a36Sopenharmony_ci		u8 bss;
357762306a36Sopenharmony_ci		u8 _rsv[3];
357862306a36Sopenharmony_ci
357962306a36Sopenharmony_ci		__le16 tag;
358062306a36Sopenharmony_ci		__le16 len;
358162306a36Sopenharmony_ci		u8 tbl_idx;
358262306a36Sopenharmony_ci		u8 cmd;
358362306a36Sopenharmony_ci		u8 own_mac_idx;
358462306a36Sopenharmony_ci		u8 flowid; /* 0xff for group id */
358562306a36Sopenharmony_ci		__le16 peer_id; /* specify the peer_id (msb=0)
358662306a36Sopenharmony_ci				 * or group_id (msb=1)
358762306a36Sopenharmony_ci				 */
358862306a36Sopenharmony_ci		u8 duration; /* 256 us */
358962306a36Sopenharmony_ci		u8 bss_idx;
359062306a36Sopenharmony_ci		__le64 start_tsf;
359162306a36Sopenharmony_ci		__le16 mantissa;
359262306a36Sopenharmony_ci		u8 exponent;
359362306a36Sopenharmony_ci		u8 is_ap;
359462306a36Sopenharmony_ci		u8 agrt_params;
359562306a36Sopenharmony_ci		u8 __rsv2[23];
359662306a36Sopenharmony_ci	} __packed req = {
359762306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_CMD_TWT_ARGT_UPDATE),
359862306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
359962306a36Sopenharmony_ci		.tbl_idx = flow->table_id,
360062306a36Sopenharmony_ci		.cmd = cmd,
360162306a36Sopenharmony_ci		.own_mac_idx = mvif->mt76.omac_idx,
360262306a36Sopenharmony_ci		.flowid = flow->id,
360362306a36Sopenharmony_ci		.peer_id = cpu_to_le16(flow->wcid),
360462306a36Sopenharmony_ci		.duration = flow->duration,
360562306a36Sopenharmony_ci		.bss = mvif->mt76.idx,
360662306a36Sopenharmony_ci		.bss_idx = mvif->mt76.idx,
360762306a36Sopenharmony_ci		.start_tsf = cpu_to_le64(flow->tsf),
360862306a36Sopenharmony_ci		.mantissa = flow->mantissa,
360962306a36Sopenharmony_ci		.exponent = flow->exp,
361062306a36Sopenharmony_ci		.is_ap = true,
361162306a36Sopenharmony_ci	};
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	if (flow->protection)
361462306a36Sopenharmony_ci		req.agrt_params |= TWT_AGRT_PROTECT;
361562306a36Sopenharmony_ci	if (!flow->flowtype)
361662306a36Sopenharmony_ci		req.agrt_params |= TWT_AGRT_ANNOUNCE;
361762306a36Sopenharmony_ci	if (flow->trigger)
361862306a36Sopenharmony_ci		req.agrt_params |= TWT_AGRT_TRIGGER;
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TWT),
362162306a36Sopenharmony_ci				 &req, sizeof(req), true);
362262306a36Sopenharmony_ci}
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ciint mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val)
362562306a36Sopenharmony_ci{
362662306a36Sopenharmony_ci	struct {
362762306a36Sopenharmony_ci		u8 band_idx;
362862306a36Sopenharmony_ci		u8 _rsv[3];
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_ci		__le16 tag;
363162306a36Sopenharmony_ci		__le16 len;
363262306a36Sopenharmony_ci		__le32 len_thresh;
363362306a36Sopenharmony_ci		__le32 pkt_thresh;
363462306a36Sopenharmony_ci	} __packed req = {
363562306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
363662306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_BAND_CONFIG_RTS_THRESHOLD),
363762306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
363862306a36Sopenharmony_ci		.len_thresh = cpu_to_le32(val),
363962306a36Sopenharmony_ci		.pkt_thresh = cpu_to_le32(0x2),
364062306a36Sopenharmony_ci	};
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
364362306a36Sopenharmony_ci				 &req, sizeof(req), true);
364462306a36Sopenharmony_ci}
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ciint mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)
364762306a36Sopenharmony_ci{
364862306a36Sopenharmony_ci	struct {
364962306a36Sopenharmony_ci		u8 band_idx;
365062306a36Sopenharmony_ci		u8 _rsv[3];
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci		__le16 tag;
365362306a36Sopenharmony_ci		__le16 len;
365462306a36Sopenharmony_ci		u8 enable;
365562306a36Sopenharmony_ci		u8 _rsv2[3];
365662306a36Sopenharmony_ci	} __packed req = {
365762306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
365862306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_BAND_CONFIG_RADIO_ENABLE),
365962306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
366062306a36Sopenharmony_ci		.enable = enable,
366162306a36Sopenharmony_ci	};
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci	return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
366462306a36Sopenharmony_ci				 &req, sizeof(req), true);
366562306a36Sopenharmony_ci}
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ciint mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
366862306a36Sopenharmony_ci		       u8 rx_sel, u8 val)
366962306a36Sopenharmony_ci{
367062306a36Sopenharmony_ci	struct {
367162306a36Sopenharmony_ci		u8 _rsv[4];
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci		__le16 tag;
367462306a36Sopenharmony_ci		__le16 len;
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci		u8 ctrl;
367762306a36Sopenharmony_ci		u8 rdd_idx;
367862306a36Sopenharmony_ci		u8 rdd_rx_sel;
367962306a36Sopenharmony_ci		u8 val;
368062306a36Sopenharmony_ci		u8 rsv[4];
368162306a36Sopenharmony_ci	} __packed req = {
368262306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_RDD_CTRL_PARM),
368362306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
368462306a36Sopenharmony_ci		.ctrl = cmd,
368562306a36Sopenharmony_ci		.rdd_idx = index,
368662306a36Sopenharmony_ci		.rdd_rx_sel = rx_sel,
368762306a36Sopenharmony_ci		.val = val,
368862306a36Sopenharmony_ci	};
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RDD_CTRL),
369162306a36Sopenharmony_ci				 &req, sizeof(req), true);
369262306a36Sopenharmony_ci}
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_ciint mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
369562306a36Sopenharmony_ci				     struct ieee80211_vif *vif,
369662306a36Sopenharmony_ci				     struct ieee80211_sta *sta)
369762306a36Sopenharmony_ci{
369862306a36Sopenharmony_ci	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
369962306a36Sopenharmony_ci	struct mt7996_sta *msta;
370062306a36Sopenharmony_ci	struct sk_buff *skb;
370162306a36Sopenharmony_ci
370262306a36Sopenharmony_ci	msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
370562306a36Sopenharmony_ci					      &msta->wcid,
370662306a36Sopenharmony_ci					      MT7996_STA_UPDATE_MAX_SIZE);
370762306a36Sopenharmony_ci	if (IS_ERR(skb))
370862306a36Sopenharmony_ci		return PTR_ERR(skb);
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	/* starec hdr trans */
371162306a36Sopenharmony_ci	mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
371262306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
371362306a36Sopenharmony_ci				     MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
371462306a36Sopenharmony_ci}
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ciint mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set)
371762306a36Sopenharmony_ci{
371862306a36Sopenharmony_ci	struct {
371962306a36Sopenharmony_ci		u8 __rsv1[4];
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci		__le16 tag;
372262306a36Sopenharmony_ci		__le16 len;
372362306a36Sopenharmony_ci		__le16 idx;
372462306a36Sopenharmony_ci		u8 __rsv2[2];
372562306a36Sopenharmony_ci		__le32 ofs;
372662306a36Sopenharmony_ci		__le32 data;
372762306a36Sopenharmony_ci	} __packed *res, req = {
372862306a36Sopenharmony_ci		.tag = cpu_to_le16(UNI_CMD_ACCESS_RF_REG_BASIC),
372962306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci		.idx = cpu_to_le16(u32_get_bits(regidx, GENMASK(31, 24))),
373262306a36Sopenharmony_ci		.ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))),
373362306a36Sopenharmony_ci		.data = set ? cpu_to_le32(*val) : 0,
373462306a36Sopenharmony_ci	};
373562306a36Sopenharmony_ci	struct sk_buff *skb;
373662306a36Sopenharmony_ci	int ret;
373762306a36Sopenharmony_ci
373862306a36Sopenharmony_ci	if (set)
373962306a36Sopenharmony_ci		return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REG_ACCESS),
374062306a36Sopenharmony_ci					 &req, sizeof(req), true);
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
374362306a36Sopenharmony_ci					MCU_WM_UNI_CMD_QUERY(REG_ACCESS),
374462306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
374562306a36Sopenharmony_ci	if (ret)
374662306a36Sopenharmony_ci		return ret;
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci	res = (void *)skb->data;
374962306a36Sopenharmony_ci	*val = le32_to_cpu(res->data);
375062306a36Sopenharmony_ci	dev_kfree_skb(skb);
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	return 0;
375362306a36Sopenharmony_ci}
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ciint mt7996_mcu_trigger_assert(struct mt7996_dev *dev)
375662306a36Sopenharmony_ci{
375762306a36Sopenharmony_ci	struct {
375862306a36Sopenharmony_ci		__le16 tag;
375962306a36Sopenharmony_ci		__le16 len;
376062306a36Sopenharmony_ci		u8 enable;
376162306a36Sopenharmony_ci		u8 rsv[3];
376262306a36Sopenharmony_ci	} __packed req = {
376362306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
376462306a36Sopenharmony_ci		.enable = true,
376562306a36Sopenharmony_ci	};
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ASSERT_DUMP),
376862306a36Sopenharmony_ci				 &req, sizeof(req), false);
376962306a36Sopenharmony_ci}
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ciint mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
377262306a36Sopenharmony_ci{
377362306a36Sopenharmony_ci	struct {
377462306a36Sopenharmony_ci		u8 __rsv1[4];
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci		__le16 tag;
377762306a36Sopenharmony_ci		__le16 len;
377862306a36Sopenharmony_ci
377962306a36Sopenharmony_ci		union {
378062306a36Sopenharmony_ci			struct {
378162306a36Sopenharmony_ci				u8 type;
378262306a36Sopenharmony_ci				u8 __rsv2[3];
378362306a36Sopenharmony_ci			} __packed platform_type;
378462306a36Sopenharmony_ci			struct {
378562306a36Sopenharmony_ci				u8 type;
378662306a36Sopenharmony_ci				u8 dest;
378762306a36Sopenharmony_ci				u8 __rsv2[2];
378862306a36Sopenharmony_ci			} __packed bypass_mode;
378962306a36Sopenharmony_ci			struct {
379062306a36Sopenharmony_ci				u8 path;
379162306a36Sopenharmony_ci				u8 __rsv2[3];
379262306a36Sopenharmony_ci			} __packed txfree_path;
379362306a36Sopenharmony_ci		};
379462306a36Sopenharmony_ci	} __packed req = {
379562306a36Sopenharmony_ci		.tag = cpu_to_le16(tag),
379662306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - 4),
379762306a36Sopenharmony_ci	};
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	switch (tag) {
380062306a36Sopenharmony_ci	case UNI_RRO_SET_PLATFORM_TYPE:
380162306a36Sopenharmony_ci		req.platform_type.type = val;
380262306a36Sopenharmony_ci		break;
380362306a36Sopenharmony_ci	case UNI_RRO_SET_BYPASS_MODE:
380462306a36Sopenharmony_ci		req.bypass_mode.type = val;
380562306a36Sopenharmony_ci		break;
380662306a36Sopenharmony_ci	case UNI_RRO_SET_TXFREE_PATH:
380762306a36Sopenharmony_ci		req.txfree_path.path = val;
380862306a36Sopenharmony_ci		break;
380962306a36Sopenharmony_ci	default:
381062306a36Sopenharmony_ci		return -EINVAL;
381162306a36Sopenharmony_ci	}
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
381462306a36Sopenharmony_ci				 sizeof(req), true);
381562306a36Sopenharmony_ci}
3816