162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/fs.h>
562306a36Sopenharmony_ci#include "mt7915.h"
662306a36Sopenharmony_ci#include "mcu.h"
762306a36Sopenharmony_ci#include "mac.h"
862306a36Sopenharmony_ci#include "eeprom.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define fw_name(_dev, name, ...)	({			\
1162306a36Sopenharmony_ci	char *_fw;						\
1262306a36Sopenharmony_ci	switch (mt76_chip(&(_dev)->mt76)) {			\
1362306a36Sopenharmony_ci	case 0x7915:						\
1462306a36Sopenharmony_ci		_fw = MT7915_##name;				\
1562306a36Sopenharmony_ci		break;						\
1662306a36Sopenharmony_ci	case 0x7981:						\
1762306a36Sopenharmony_ci		_fw = MT7981_##name;				\
1862306a36Sopenharmony_ci		break;						\
1962306a36Sopenharmony_ci	case 0x7986:						\
2062306a36Sopenharmony_ci		_fw = MT7986_##name##__VA_ARGS__;		\
2162306a36Sopenharmony_ci		break;						\
2262306a36Sopenharmony_ci	default:						\
2362306a36Sopenharmony_ci		_fw = MT7916_##name;				\
2462306a36Sopenharmony_ci		break;						\
2562306a36Sopenharmony_ci	}							\
2662306a36Sopenharmony_ci	_fw;							\
2762306a36Sopenharmony_ci})
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define fw_name_var(_dev, name)		(mt7915_check_adie(dev, false) ?	\
3062306a36Sopenharmony_ci					 fw_name(_dev, name) :			\
3162306a36Sopenharmony_ci					 fw_name(_dev, name, _MT7975))
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define MCU_PATCH_ADDRESS		0x200000
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define HE_PHY(p, c)			u8_get_bits(c, IEEE80211_HE_PHY_##p)
3662306a36Sopenharmony_ci#define HE_MAC(m, c)			u8_get_bits(c, IEEE80211_HE_MAC_##m)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic bool sr_scene_detect = true;
3962306a36Sopenharmony_cimodule_param(sr_scene_detect, bool, 0644);
4062306a36Sopenharmony_ciMODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic u8
4362306a36Sopenharmony_cimt7915_mcu_get_sta_nss(u16 mcs_map)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	u8 nss;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	for (nss = 8; nss > 0; nss--) {
4862306a36Sopenharmony_ci		u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci		if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED)
5162306a36Sopenharmony_ci			break;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return nss - 1;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void
5862306a36Sopenharmony_cimt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
5962306a36Sopenharmony_ci			  u16 mcs_map)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
6262306a36Sopenharmony_ci	struct mt7915_dev *dev = msta->vif->phy->dev;
6362306a36Sopenharmony_ci	enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
6462306a36Sopenharmony_ci	const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs;
6562306a36Sopenharmony_ci	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	for (nss = 0; nss < max_nss; nss++) {
6862306a36Sopenharmony_ci		int mcs;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		switch ((mcs_map >> (2 * nss)) & 0x3) {
7162306a36Sopenharmony_ci		case IEEE80211_HE_MCS_SUPPORT_0_11:
7262306a36Sopenharmony_ci			mcs = GENMASK(11, 0);
7362306a36Sopenharmony_ci			break;
7462306a36Sopenharmony_ci		case IEEE80211_HE_MCS_SUPPORT_0_9:
7562306a36Sopenharmony_ci			mcs = GENMASK(9, 0);
7662306a36Sopenharmony_ci			break;
7762306a36Sopenharmony_ci		case IEEE80211_HE_MCS_SUPPORT_0_7:
7862306a36Sopenharmony_ci			mcs = GENMASK(7, 0);
7962306a36Sopenharmony_ci			break;
8062306a36Sopenharmony_ci		default:
8162306a36Sopenharmony_ci			mcs = 0;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		switch (mcs) {
8762306a36Sopenharmony_ci		case 0 ... 7:
8862306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
8962306a36Sopenharmony_ci			break;
9062306a36Sopenharmony_ci		case 8 ... 9:
9162306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
9262306a36Sopenharmony_ci			break;
9362306a36Sopenharmony_ci		case 10 ... 11:
9462306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
9562306a36Sopenharmony_ci			break;
9662306a36Sopenharmony_ci		default:
9762306a36Sopenharmony_ci			mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
9862306a36Sopenharmony_ci			break;
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci		mcs_map &= ~(0x3 << (nss * 2));
10162306a36Sopenharmony_ci		mcs_map |= mcs << (nss * 2);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		/* only support 2ss on 160MHz for mt7915 */
10462306a36Sopenharmony_ci		if (is_mt7915(&dev->mt76) && nss > 1 &&
10562306a36Sopenharmony_ci		    sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
10662306a36Sopenharmony_ci			break;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	*he_mcs = cpu_to_le16(mcs_map);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void
11362306a36Sopenharmony_cimt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
11462306a36Sopenharmony_ci			   const u16 *mask)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
11762306a36Sopenharmony_ci	struct mt7915_dev *dev = msta->vif->phy->dev;
11862306a36Sopenharmony_ci	u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
11962306a36Sopenharmony_ci	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
12062306a36Sopenharmony_ci	u16 mcs;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
12362306a36Sopenharmony_ci		switch (mcs_map & 0x3) {
12462306a36Sopenharmony_ci		case IEEE80211_VHT_MCS_SUPPORT_0_9:
12562306a36Sopenharmony_ci			mcs = GENMASK(9, 0);
12662306a36Sopenharmony_ci			break;
12762306a36Sopenharmony_ci		case IEEE80211_VHT_MCS_SUPPORT_0_8:
12862306a36Sopenharmony_ci			mcs = GENMASK(8, 0);
12962306a36Sopenharmony_ci			break;
13062306a36Sopenharmony_ci		case IEEE80211_VHT_MCS_SUPPORT_0_7:
13162306a36Sopenharmony_ci			mcs = GENMASK(7, 0);
13262306a36Sopenharmony_ci			break;
13362306a36Sopenharmony_ci		default:
13462306a36Sopenharmony_ci			mcs = 0;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		/* only support 2ss on 160MHz for mt7915 */
14062306a36Sopenharmony_ci		if (is_mt7915(&dev->mt76) && nss > 1 &&
14162306a36Sopenharmony_ci		    sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
14262306a36Sopenharmony_ci			break;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic void
14762306a36Sopenharmony_cimt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
14862306a36Sopenharmony_ci			  const u8 *mask)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	for (nss = 0; nss < max_nss; nss++)
15362306a36Sopenharmony_ci		ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss];
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int
15762306a36Sopenharmony_cimt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
15862306a36Sopenharmony_ci			  struct sk_buff *skb, int seq)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct mt76_connac2_mcu_rxd *rxd;
16162306a36Sopenharmony_ci	int ret = 0;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (!skb) {
16462306a36Sopenharmony_ci		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
16562306a36Sopenharmony_ci			cmd, seq);
16662306a36Sopenharmony_ci		return -ETIMEDOUT;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
17062306a36Sopenharmony_ci	if (seq != rxd->seq &&
17162306a36Sopenharmony_ci	    !(rxd->eid == MCU_CMD_EXT_CID &&
17262306a36Sopenharmony_ci	      rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
17362306a36Sopenharmony_ci		return -EAGAIN;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
17662306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd) - 4);
17762306a36Sopenharmony_ci		ret = *skb->data;
17862306a36Sopenharmony_ci	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
17962306a36Sopenharmony_ci		skb_pull(skb, sizeof(*rxd) + 4);
18062306a36Sopenharmony_ci		ret = le32_to_cpu(*(__le32 *)skb->data);
18162306a36Sopenharmony_ci	} else {
18262306a36Sopenharmony_ci		skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return ret;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic int
18962306a36Sopenharmony_cimt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
19062306a36Sopenharmony_ci			int cmd, int *wait_seq)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
19362306a36Sopenharmony_ci	enum mt76_mcuq_id qid;
19462306a36Sopenharmony_ci	int ret;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, wait_seq);
19762306a36Sopenharmony_ci	if (ret)
19862306a36Sopenharmony_ci		return ret;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (cmd == MCU_CMD(FW_SCATTER))
20162306a36Sopenharmony_ci		qid = MT_MCUQ_FWDL;
20262306a36Sopenharmony_ci	else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
20362306a36Sopenharmony_ci		qid = MT_MCUQ_WA;
20462306a36Sopenharmony_ci	else
20562306a36Sopenharmony_ci		qid = MT_MCUQ_WM;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciint mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct {
21362306a36Sopenharmony_ci		__le32 args[3];
21462306a36Sopenharmony_ci	} req = {
21562306a36Sopenharmony_ci		.args = {
21662306a36Sopenharmony_ci			cpu_to_le32(a1),
21762306a36Sopenharmony_ci			cpu_to_le32(a2),
21862306a36Sopenharmony_ci			cpu_to_le32(a3),
21962306a36Sopenharmony_ci		},
22062306a36Sopenharmony_ci	};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void
22662306a36Sopenharmony_cimt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	if (vif->bss_conf.csa_active)
22962306a36Sopenharmony_ci		ieee80211_csa_finish(vif);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic void
23362306a36Sopenharmony_cimt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
23662306a36Sopenharmony_ci	struct mt7915_mcu_csa_notify *c;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	c = (struct mt7915_mcu_csa_notify *)skb->data;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (c->band_idx > MT_BAND1)
24162306a36Sopenharmony_ci		return;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if ((c->band_idx && !dev->phy.mt76->band_idx) &&
24462306a36Sopenharmony_ci	    dev->mt76.phys[MT_BAND1])
24562306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
24862306a36Sopenharmony_ci			IEEE80211_IFACE_ITER_RESUME_ALL,
24962306a36Sopenharmony_ci			mt7915_mcu_csa_finish, mphy->hw);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void
25362306a36Sopenharmony_cimt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
25662306a36Sopenharmony_ci	struct mt7915_mcu_thermal_notify *t;
25762306a36Sopenharmony_ci	struct mt7915_phy *phy;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	t = (struct mt7915_mcu_thermal_notify *)skb->data;
26062306a36Sopenharmony_ci	if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE)
26162306a36Sopenharmony_ci		return;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (t->ctrl.band_idx > MT_BAND1)
26462306a36Sopenharmony_ci		return;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) &&
26762306a36Sopenharmony_ci	    dev->mt76.phys[MT_BAND1])
26862306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	phy = (struct mt7915_phy *)mphy->priv;
27162306a36Sopenharmony_ci	phy->throttle_state = t->ctrl.duty.duty_cycle;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void
27562306a36Sopenharmony_cimt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
27862306a36Sopenharmony_ci	struct mt7915_mcu_rdd_report *r;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	r = (struct mt7915_mcu_rdd_report *)skb->data;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (r->band_idx > MT_RX_SEL2)
28362306a36Sopenharmony_ci		return;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if ((r->band_idx && !dev->phy.mt76->band_idx) &&
28662306a36Sopenharmony_ci	    dev->mt76.phys[MT_BAND1])
28762306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (r->band_idx == MT_RX_SEL2)
29062306a36Sopenharmony_ci		cfg80211_background_radar_event(mphy->hw->wiphy,
29162306a36Sopenharmony_ci						&dev->rdd2_chandef,
29262306a36Sopenharmony_ci						GFP_ATOMIC);
29362306a36Sopenharmony_ci	else
29462306a36Sopenharmony_ci		ieee80211_radar_detected(mphy->hw);
29562306a36Sopenharmony_ci	dev->hw_pattern++;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic void
29962306a36Sopenharmony_cimt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct mt76_connac2_mcu_rxd *rxd;
30262306a36Sopenharmony_ci	int len = skb->len - sizeof(*rxd);
30362306a36Sopenharmony_ci	const char *data, *type;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
30662306a36Sopenharmony_ci	data = (char *)&rxd[1];
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	switch (rxd->s2d_index) {
30962306a36Sopenharmony_ci	case 0:
31062306a36Sopenharmony_ci		if (mt7915_debugfs_rx_log(dev, data, len))
31162306a36Sopenharmony_ci			return;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci		type = "WM";
31462306a36Sopenharmony_ci		break;
31562306a36Sopenharmony_ci	case 2:
31662306a36Sopenharmony_ci		type = "WA";
31762306a36Sopenharmony_ci		break;
31862306a36Sopenharmony_ci	default:
31962306a36Sopenharmony_ci		type = "unknown";
32062306a36Sopenharmony_ci		break;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void
32762306a36Sopenharmony_cimt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	if (!vif->bss_conf.color_change_active)
33062306a36Sopenharmony_ci		return;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	ieee80211_color_change_finish(vif);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void
33662306a36Sopenharmony_cimt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
33962306a36Sopenharmony_ci	struct mt7915_mcu_bcc_notify *b;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	b = (struct mt7915_mcu_bcc_notify *)skb->data;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (b->band_idx > MT_BAND1)
34462306a36Sopenharmony_ci		return;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if ((b->band_idx && !dev->phy.mt76->band_idx) &&
34762306a36Sopenharmony_ci	    dev->mt76.phys[MT_BAND1])
34862306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
35162306a36Sopenharmony_ci			IEEE80211_IFACE_ITER_RESUME_ALL,
35262306a36Sopenharmony_ci			mt7915_mcu_cca_finish, mphy->hw);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic void
35662306a36Sopenharmony_cimt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct mt76_connac2_mcu_rxd *rxd;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
36162306a36Sopenharmony_ci	switch (rxd->ext_eid) {
36262306a36Sopenharmony_ci	case MCU_EXT_EVENT_THERMAL_PROTECT:
36362306a36Sopenharmony_ci		mt7915_mcu_rx_thermal_notify(dev, skb);
36462306a36Sopenharmony_ci		break;
36562306a36Sopenharmony_ci	case MCU_EXT_EVENT_RDD_REPORT:
36662306a36Sopenharmony_ci		mt7915_mcu_rx_radar_detected(dev, skb);
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci	case MCU_EXT_EVENT_CSA_NOTIFY:
36962306a36Sopenharmony_ci		mt7915_mcu_rx_csa_notify(dev, skb);
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci	case MCU_EXT_EVENT_FW_LOG_2_HOST:
37262306a36Sopenharmony_ci		mt7915_mcu_rx_log_message(dev, skb);
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci	case MCU_EXT_EVENT_BCC_NOTIFY:
37562306a36Sopenharmony_ci		mt7915_mcu_rx_bcc_notify(dev, skb);
37662306a36Sopenharmony_ci		break;
37762306a36Sopenharmony_ci	default:
37862306a36Sopenharmony_ci		break;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic void
38362306a36Sopenharmony_cimt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct mt76_connac2_mcu_rxd *rxd;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
38862306a36Sopenharmony_ci	switch (rxd->eid) {
38962306a36Sopenharmony_ci	case MCU_EVENT_EXT:
39062306a36Sopenharmony_ci		mt7915_mcu_rx_ext_event(dev, skb);
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	default:
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci	dev_kfree_skb(skb);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_civoid mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct mt76_connac2_mcu_rxd *rxd;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
40362306a36Sopenharmony_ci	if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
40462306a36Sopenharmony_ci	     rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
40562306a36Sopenharmony_ci	     rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
40662306a36Sopenharmony_ci	     rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
40762306a36Sopenharmony_ci	     rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
40862306a36Sopenharmony_ci	     !rxd->seq) &&
40962306a36Sopenharmony_ci	     !(rxd->eid == MCU_CMD_EXT_CID &&
41062306a36Sopenharmony_ci	       rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
41162306a36Sopenharmony_ci		mt7915_mcu_rx_unsolicited_event(dev, skb);
41262306a36Sopenharmony_ci	else
41362306a36Sopenharmony_ci		mt76_mcu_rx_event(&dev->mt76, skb);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic struct tlv *
41762306a36Sopenharmony_cimt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len,
41862306a36Sopenharmony_ci			     __le16 *sub_ntlv, __le16 *len)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct tlv *ptlv, tlv = {
42162306a36Sopenharmony_ci		.tag = cpu_to_le16(sub_tag),
42262306a36Sopenharmony_ci		.len = cpu_to_le16(sub_len),
42362306a36Sopenharmony_ci	};
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	ptlv = skb_put(skb, sub_len);
42662306a36Sopenharmony_ci	memcpy(ptlv, &tlv, sizeof(tlv));
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	le16_add_cpu(sub_ntlv, 1);
42962306a36Sopenharmony_ci	le16_add_cpu(len, sub_len);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return ptlv;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci/** bss info **/
43562306a36Sopenharmony_cistruct mt7915_he_obss_narrow_bw_ru_data {
43662306a36Sopenharmony_ci	bool tolerated;
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
44062306a36Sopenharmony_ci						   struct cfg80211_bss *bss,
44162306a36Sopenharmony_ci						   void *_data)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct mt7915_he_obss_narrow_bw_ru_data *data = _data;
44462306a36Sopenharmony_ci	const struct element *elem;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	rcu_read_lock();
44762306a36Sopenharmony_ci	elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (!elem || elem->datalen <= 10 ||
45062306a36Sopenharmony_ci	    !(elem->data[10] &
45162306a36Sopenharmony_ci	      WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT))
45262306a36Sopenharmony_ci		data->tolerated = false;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	rcu_read_unlock();
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
45862306a36Sopenharmony_ci					      struct ieee80211_vif *vif)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct mt7915_he_obss_narrow_bw_ru_data iter_data = {
46162306a36Sopenharmony_ci		.tolerated = true,
46262306a36Sopenharmony_ci	};
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR))
46562306a36Sopenharmony_ci		return false;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef,
46862306a36Sopenharmony_ci			  mt7915_check_he_obss_narrow_bw_ru_iter,
46962306a36Sopenharmony_ci			  &iter_data);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/*
47262306a36Sopenharmony_ci	 * If there is at least one AP on radar channel that cannot
47362306a36Sopenharmony_ci	 * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.
47462306a36Sopenharmony_ci	 */
47562306a36Sopenharmony_ci	return !iter_data.tolerated;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void
47962306a36Sopenharmony_cimt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
48062306a36Sopenharmony_ci			struct mt7915_phy *phy)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
48362306a36Sopenharmony_ci	struct bss_info_rf_ch *ch;
48462306a36Sopenharmony_ci	struct tlv *tlv;
48562306a36Sopenharmony_ci	int freq1 = chandef->center_freq1;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch));
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	ch = (struct bss_info_rf_ch *)tlv;
49062306a36Sopenharmony_ci	ch->pri_ch = chandef->chan->hw_value;
49162306a36Sopenharmony_ci	ch->center_ch0 = ieee80211_frequency_to_channel(freq1);
49262306a36Sopenharmony_ci	ch->bw = mt76_connac_chan_bw(chandef);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
49562306a36Sopenharmony_ci		int freq2 = chandef->center_freq2;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		ch->center_ch1 = ieee80211_frequency_to_channel(freq2);
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) {
50162306a36Sopenharmony_ci		struct mt76_phy *mphy = phy->mt76;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		ch->he_ru26_block =
50462306a36Sopenharmony_ci			mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif);
50562306a36Sopenharmony_ci		ch->he_all_disable = false;
50662306a36Sopenharmony_ci	} else {
50762306a36Sopenharmony_ci		ch->he_all_disable = true;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void
51262306a36Sopenharmony_cimt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
51362306a36Sopenharmony_ci		      struct mt7915_phy *phy)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	int max_nss = hweight8(phy->mt76->antenna_mask);
51662306a36Sopenharmony_ci	struct bss_info_ra *ra;
51762306a36Sopenharmony_ci	struct tlv *tlv;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra));
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	ra = (struct bss_info_ra *)tlv;
52262306a36Sopenharmony_ci	ra->op_mode = vif->type == NL80211_IFTYPE_AP;
52362306a36Sopenharmony_ci	ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC;
52462306a36Sopenharmony_ci	ra->short_preamble = true;
52562306a36Sopenharmony_ci	ra->tx_streams = max_nss;
52662306a36Sopenharmony_ci	ra->rx_streams = max_nss;
52762306a36Sopenharmony_ci	ra->algo = 4;
52862306a36Sopenharmony_ci	ra->train_up_rule = 2;
52962306a36Sopenharmony_ci	ra->train_up_high_thres = 110;
53062306a36Sopenharmony_ci	ra->train_up_rule_rssi = -70;
53162306a36Sopenharmony_ci	ra->low_traffic_thres = 2;
53262306a36Sopenharmony_ci	ra->phy_cap = cpu_to_le32(0xfdf);
53362306a36Sopenharmony_ci	ra->interval = cpu_to_le32(500);
53462306a36Sopenharmony_ci	ra->fast_interval = cpu_to_le32(100);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void
53862306a36Sopenharmony_cimt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
53962306a36Sopenharmony_ci		      struct mt7915_phy *phy)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci#define DEFAULT_HE_PE_DURATION		4
54262306a36Sopenharmony_ci#define DEFAULT_HE_DURATION_RTS_THRES	1023
54362306a36Sopenharmony_ci	const struct ieee80211_sta_he_cap *cap;
54462306a36Sopenharmony_ci	struct bss_info_he *he;
54562306a36Sopenharmony_ci	struct tlv *tlv;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	he = (struct bss_info_he *)tlv;
55262306a36Sopenharmony_ci	he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
55362306a36Sopenharmony_ci	if (!he->he_pe_duration)
55462306a36Sopenharmony_ci		he->he_pe_duration = DEFAULT_HE_PE_DURATION;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
55762306a36Sopenharmony_ci	if (!he->he_rts_thres)
55862306a36Sopenharmony_ci		he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;
56162306a36Sopenharmony_ci	he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;
56262306a36Sopenharmony_ci	he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void
56662306a36Sopenharmony_cimt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci#define TXD_CMP_MAP1		GENMASK(15, 0)
56962306a36Sopenharmony_ci#define TXD_CMP_MAP2		(GENMASK(31, 0) & ~BIT(23))
57062306a36Sopenharmony_ci	struct bss_info_hw_amsdu *amsdu;
57162306a36Sopenharmony_ci	struct tlv *tlv;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	amsdu = (struct bss_info_hw_amsdu *)tlv;
57662306a36Sopenharmony_ci	amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
57762306a36Sopenharmony_ci	amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
57862306a36Sopenharmony_ci	amsdu->trig_thres = cpu_to_le16(2);
57962306a36Sopenharmony_ci	amsdu->enable = true;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void
58362306a36Sopenharmony_cimt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct bss_info_bmc_rate *bmc;
58662306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
58762306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
58862306a36Sopenharmony_ci	struct tlv *tlv;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc));
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	bmc = (struct bss_info_bmc_rate *)tlv;
59362306a36Sopenharmony_ci	if (band == NL80211_BAND_2GHZ) {
59462306a36Sopenharmony_ci		bmc->short_preamble = true;
59562306a36Sopenharmony_ci	} else {
59662306a36Sopenharmony_ci		bmc->bc_trans = cpu_to_le16(0x2000);
59762306a36Sopenharmony_ci		bmc->mc_trans = cpu_to_le16(0x2080);
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic int
60262306a36Sopenharmony_cimt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif,
60362306a36Sopenharmony_ci		       bool bssid, bool enable)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
60662306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
60762306a36Sopenharmony_ci	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
60862306a36Sopenharmony_ci	u32 mask = phy->omac_mask >> 32 & ~BIT(idx);
60962306a36Sopenharmony_ci	const u8 *addr = vif->addr;
61062306a36Sopenharmony_ci	struct {
61162306a36Sopenharmony_ci		u8 mode;
61262306a36Sopenharmony_ci		u8 force_clear;
61362306a36Sopenharmony_ci		u8 clear_bitmap[8];
61462306a36Sopenharmony_ci		u8 entry_count;
61562306a36Sopenharmony_ci		u8 write;
61662306a36Sopenharmony_ci		u8 band;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci		u8 index;
61962306a36Sopenharmony_ci		u8 bssid;
62062306a36Sopenharmony_ci		u8 addr[ETH_ALEN];
62162306a36Sopenharmony_ci	} __packed req = {
62262306a36Sopenharmony_ci		.mode = !!mask || enable,
62362306a36Sopenharmony_ci		.entry_count = 1,
62462306a36Sopenharmony_ci		.write = 1,
62562306a36Sopenharmony_ci		.band = phy->mt76->band_idx,
62662306a36Sopenharmony_ci		.index = idx * 2 + bssid,
62762306a36Sopenharmony_ci	};
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	if (bssid)
63062306a36Sopenharmony_ci		addr = vif->bss_conf.bssid;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (enable)
63362306a36Sopenharmony_ci		ether_addr_copy(req.addr, addr);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req,
63662306a36Sopenharmony_ci				 sizeof(req), true);
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ciint mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
64062306a36Sopenharmony_ci			    struct ieee80211_vif *vif, int enable)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
64362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
64462306a36Sopenharmony_ci	struct sk_buff *skb;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) {
64762306a36Sopenharmony_ci		mt7915_mcu_muar_config(phy, vif, false, enable);
64862306a36Sopenharmony_ci		mt7915_mcu_muar_config(phy, vif, true, enable);
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
65262306a36Sopenharmony_ci					      MT7915_BSS_UPDATE_MAX_SIZE);
65362306a36Sopenharmony_ci	if (IS_ERR(skb))
65462306a36Sopenharmony_ci		return PTR_ERR(skb);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	/* bss_omac must be first */
65762306a36Sopenharmony_ci	if (enable)
65862306a36Sopenharmony_ci		mt76_connac_mcu_bss_omac_tlv(skb, vif);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	mt76_connac_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76,
66162306a36Sopenharmony_ci				      mvif->sta.wcid.idx, enable);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	if (vif->type == NL80211_IFTYPE_MONITOR)
66462306a36Sopenharmony_ci		goto out;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (enable) {
66762306a36Sopenharmony_ci		mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
66862306a36Sopenharmony_ci		mt7915_mcu_bss_bmc_tlv(skb, phy);
66962306a36Sopenharmony_ci		mt7915_mcu_bss_ra_tlv(skb, vif, phy);
67062306a36Sopenharmony_ci		mt7915_mcu_bss_hw_amsdu_tlv(skb);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		if (vif->bss_conf.he_support)
67362306a36Sopenharmony_ci			mt7915_mcu_bss_he_tlv(skb, vif, phy);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		if (mvif->mt76.omac_idx >= EXT_BSSID_START &&
67662306a36Sopenharmony_ci		    mvif->mt76.omac_idx < REPEATER_BSSID_START)
67762306a36Sopenharmony_ci			mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ciout:
68062306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
68162306a36Sopenharmony_ci				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci/** starec & wtbl **/
68562306a36Sopenharmony_ciint mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
68662306a36Sopenharmony_ci			 struct ieee80211_ampdu_params *params,
68762306a36Sopenharmony_ci			 bool enable)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
69062306a36Sopenharmony_ci	struct mt7915_vif *mvif = msta->vif;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (enable && !params->amsdu)
69362306a36Sopenharmony_ci		msta->wcid.amsdu = false;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
69662306a36Sopenharmony_ci				      MCU_EXT_CMD(STA_REC_UPDATE),
69762306a36Sopenharmony_ci				      enable, true);
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ciint mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
70162306a36Sopenharmony_ci			 struct ieee80211_ampdu_params *params,
70262306a36Sopenharmony_ci			 bool enable)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
70562306a36Sopenharmony_ci	struct mt7915_vif *mvif = msta->vif;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
70862306a36Sopenharmony_ci				      MCU_EXT_CMD(STA_REC_UPDATE),
70962306a36Sopenharmony_ci				      enable, false);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic void
71362306a36Sopenharmony_cimt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
71462306a36Sopenharmony_ci		      struct ieee80211_vif *vif)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
71762306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
71862306a36Sopenharmony_ci	struct ieee80211_he_mcs_nss_supp mcs_map;
71962306a36Sopenharmony_ci	struct sta_rec_he *he;
72062306a36Sopenharmony_ci	struct tlv *tlv;
72162306a36Sopenharmony_ci	u32 cap = 0;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (!sta->deflink.he_cap.has_he)
72462306a36Sopenharmony_ci		return;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	he = (struct sta_rec_he *)tlv;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)
73162306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_HTC;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
73462306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_BSR;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
73762306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_OM;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU)
74062306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
74362306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_BQR;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	if (elem->phy_cap_info[0] &
74662306a36Sopenharmony_ci	    (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G |
74762306a36Sopenharmony_ci	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
74862306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (mvif->cap.he_ldpc &&
75162306a36Sopenharmony_ci	    (elem->phy_cap_info[1] &
75262306a36Sopenharmony_ci	     IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
75362306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_LDPC;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (elem->phy_cap_info[1] &
75662306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US)
75762306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (elem->phy_cap_info[2] &
76062306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US)
76162306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (elem->phy_cap_info[2] &
76462306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ)
76562306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	if (elem->phy_cap_info[2] &
76862306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
76962306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if (elem->phy_cap_info[6] &
77262306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB)
77362306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (elem->phy_cap_info[6] &
77662306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)
77762306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (elem->phy_cap_info[7] &
78062306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI)
78162306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI;
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	if (elem->phy_cap_info[7] &
78462306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ)
78562306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_GT_80M_TX_STBC;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	if (elem->phy_cap_info[7] &
78862306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
78962306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_GT_80M_RX_STBC;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (elem->phy_cap_info[8] &
79262306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI)
79362306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (elem->phy_cap_info[8] &
79662306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI)
79762306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (elem->phy_cap_info[9] &
80062306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)
80162306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (elem->phy_cap_info[9] &
80462306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU)
80562306a36Sopenharmony_ci		cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	he->he_cap = cpu_to_le32(cap);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
81062306a36Sopenharmony_ci	switch (sta->deflink.bandwidth) {
81162306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
81262306a36Sopenharmony_ci		if (elem->phy_cap_info[0] &
81362306a36Sopenharmony_ci		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
81462306a36Sopenharmony_ci			mt7915_mcu_set_sta_he_mcs(sta,
81562306a36Sopenharmony_ci						  &he->max_nss_mcs[CMD_HE_MCS_BW8080],
81662306a36Sopenharmony_ci						  le16_to_cpu(mcs_map.rx_mcs_80p80));
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		mt7915_mcu_set_sta_he_mcs(sta,
81962306a36Sopenharmony_ci					  &he->max_nss_mcs[CMD_HE_MCS_BW160],
82062306a36Sopenharmony_ci					  le16_to_cpu(mcs_map.rx_mcs_160));
82162306a36Sopenharmony_ci		fallthrough;
82262306a36Sopenharmony_ci	default:
82362306a36Sopenharmony_ci		mt7915_mcu_set_sta_he_mcs(sta,
82462306a36Sopenharmony_ci					  &he->max_nss_mcs[CMD_HE_MCS_BW80],
82562306a36Sopenharmony_ci					  le16_to_cpu(mcs_map.rx_mcs_80));
82662306a36Sopenharmony_ci		break;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	he->t_frame_dur =
83062306a36Sopenharmony_ci		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
83162306a36Sopenharmony_ci	he->max_ampdu_exp =
83262306a36Sopenharmony_ci		HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	he->bw_set =
83562306a36Sopenharmony_ci		HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]);
83662306a36Sopenharmony_ci	he->device_class =
83762306a36Sopenharmony_ci		HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]);
83862306a36Sopenharmony_ci	he->punc_pream_rx =
83962306a36Sopenharmony_ci		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	he->dcm_tx_mode =
84262306a36Sopenharmony_ci		HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]);
84362306a36Sopenharmony_ci	he->dcm_tx_max_nss =
84462306a36Sopenharmony_ci		HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]);
84562306a36Sopenharmony_ci	he->dcm_rx_mode =
84662306a36Sopenharmony_ci		HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]);
84762306a36Sopenharmony_ci	he->dcm_rx_max_nss =
84862306a36Sopenharmony_ci		HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]);
84962306a36Sopenharmony_ci	he->dcm_rx_max_nss =
85062306a36Sopenharmony_ci		HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	he->pkt_ext = 2;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic void
85662306a36Sopenharmony_cimt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
85762306a36Sopenharmony_ci			struct ieee80211_sta *sta, struct ieee80211_vif *vif)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
86062306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
86162306a36Sopenharmony_ci	struct sta_rec_muru *muru;
86262306a36Sopenharmony_ci	struct tlv *tlv;
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
86562306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP)
86662306a36Sopenharmony_ci		return;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	muru = (struct sta_rec_muru *)tlv;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
87362306a36Sopenharmony_ci			       mvif->cap.vht_mu_ebfer ||
87462306a36Sopenharmony_ci			       mvif->cap.vht_mu_ebfee;
87562306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
87662306a36Sopenharmony_ci		muru->cfg.mimo_ul_en = true;
87762306a36Sopenharmony_ci	muru->cfg.ofdma_dl_en = true;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported)
88062306a36Sopenharmony_ci		muru->mimo_dl.vht_mu_bfee =
88162306a36Sopenharmony_ci			!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (!sta->deflink.he_cap.has_he)
88462306a36Sopenharmony_ci		return;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	muru->mimo_dl.partial_bw_dl_mimo =
88762306a36Sopenharmony_ci		HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	muru->mimo_ul.full_ul_mimo =
89062306a36Sopenharmony_ci		HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
89162306a36Sopenharmony_ci	muru->mimo_ul.partial_ul_mimo =
89262306a36Sopenharmony_ci		HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	muru->ofdma_dl.punc_pream_rx =
89562306a36Sopenharmony_ci		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
89662306a36Sopenharmony_ci	muru->ofdma_dl.he_20m_in_40m_2g =
89762306a36Sopenharmony_ci		HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
89862306a36Sopenharmony_ci	muru->ofdma_dl.he_20m_in_160m =
89962306a36Sopenharmony_ci		HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
90062306a36Sopenharmony_ci	muru->ofdma_dl.he_80m_in_160m =
90162306a36Sopenharmony_ci		HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	muru->ofdma_ul.t_frame_dur =
90462306a36Sopenharmony_ci		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
90562306a36Sopenharmony_ci	muru->ofdma_ul.mu_cascading =
90662306a36Sopenharmony_ci		HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
90762306a36Sopenharmony_ci	muru->ofdma_ul.uo_ra =
90862306a36Sopenharmony_ci		HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic void
91262306a36Sopenharmony_cimt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	struct sta_rec_ht *ht;
91562306a36Sopenharmony_ci	struct tlv *tlv;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (!sta->deflink.ht_cap.ht_supported)
91862306a36Sopenharmony_ci		return;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	ht = (struct sta_rec_ht *)tlv;
92362306a36Sopenharmony_ci	ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
92462306a36Sopenharmony_ci}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic void
92762306a36Sopenharmony_cimt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	struct sta_rec_vht *vht;
93062306a36Sopenharmony_ci	struct tlv *tlv;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (!sta->deflink.vht_cap.vht_supported)
93362306a36Sopenharmony_ci		return;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	vht = (struct sta_rec_vht *)tlv;
93862306a36Sopenharmony_ci	vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
93962306a36Sopenharmony_ci	vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
94062306a36Sopenharmony_ci	vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic void
94462306a36Sopenharmony_cimt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
94562306a36Sopenharmony_ci			 struct ieee80211_vif *vif, struct ieee80211_sta *sta)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
94862306a36Sopenharmony_ci	struct sta_rec_amsdu *amsdu;
94962306a36Sopenharmony_ci	struct tlv *tlv;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
95262306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP)
95362306a36Sopenharmony_ci		return;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	if (!sta->deflink.agg.max_amsdu_len)
95662306a36Sopenharmony_ci	    return;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
95962306a36Sopenharmony_ci	amsdu = (struct sta_rec_amsdu *)tlv;
96062306a36Sopenharmony_ci	amsdu->max_amsdu_num = 8;
96162306a36Sopenharmony_ci	amsdu->amsdu_en = true;
96262306a36Sopenharmony_ci	msta->wcid.amsdu = true;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	switch (sta->deflink.agg.max_amsdu_len) {
96562306a36Sopenharmony_ci	case IEEE80211_MAX_MPDU_LEN_VHT_11454:
96662306a36Sopenharmony_ci		if (!is_mt7915(&dev->mt76)) {
96762306a36Sopenharmony_ci			amsdu->max_mpdu_size =
96862306a36Sopenharmony_ci				IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
96962306a36Sopenharmony_ci			return;
97062306a36Sopenharmony_ci		}
97162306a36Sopenharmony_ci		fallthrough;
97262306a36Sopenharmony_ci	case IEEE80211_MAX_MPDU_LEN_HT_7935:
97362306a36Sopenharmony_ci	case IEEE80211_MAX_MPDU_LEN_VHT_7991:
97462306a36Sopenharmony_ci		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
97562306a36Sopenharmony_ci		return;
97662306a36Sopenharmony_ci	default:
97762306a36Sopenharmony_ci		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
97862306a36Sopenharmony_ci		return;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic int
98362306a36Sopenharmony_cimt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
98462306a36Sopenharmony_ci			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
98762306a36Sopenharmony_ci	struct mt7915_sta *msta;
98862306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
98962306a36Sopenharmony_ci	struct mt76_wcid *wcid;
99062306a36Sopenharmony_ci	struct tlv *tlv;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
99362306a36Sopenharmony_ci	wcid = sta ? &msta->wcid : NULL;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
99662306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
99762306a36Sopenharmony_ci						  WTBL_RESET_AND_SET, tlv,
99862306a36Sopenharmony_ci						  &skb);
99962306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
100062306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, skb, vif, sta, tlv,
100362306a36Sopenharmony_ci					 wtbl_hdr);
100462306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
100562306a36Sopenharmony_ci	if (sta)
100662306a36Sopenharmony_ci		mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
100762306a36Sopenharmony_ci					    wtbl_hdr, mvif->cap.ht_ldpc,
100862306a36Sopenharmony_ci					    mvif->cap.vht_ldpc);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	return 0;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic inline bool
101462306a36Sopenharmony_cimt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
101562306a36Sopenharmony_ci			struct ieee80211_sta *sta, bool bfee)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
101862306a36Sopenharmony_ci	int sts = hweight16(phy->mt76->chainmask);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (vif->type != NL80211_IFTYPE_STATION &&
102162306a36Sopenharmony_ci	    vif->type != NL80211_IFTYPE_AP)
102262306a36Sopenharmony_ci		return false;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (!bfee && sts < 2)
102562306a36Sopenharmony_ci		return false;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
102862306a36Sopenharmony_ci		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci		if (bfee)
103162306a36Sopenharmony_ci			return mvif->cap.he_su_ebfee &&
103262306a36Sopenharmony_ci			       HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
103362306a36Sopenharmony_ci		else
103462306a36Sopenharmony_ci			return mvif->cap.he_su_ebfer &&
103562306a36Sopenharmony_ci			       HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported) {
103962306a36Sopenharmony_ci		u32 cap = sta->deflink.vht_cap.cap;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci		if (bfee)
104262306a36Sopenharmony_ci			return mvif->cap.vht_su_ebfee &&
104362306a36Sopenharmony_ci			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
104462306a36Sopenharmony_ci		else
104562306a36Sopenharmony_ci			return mvif->cap.vht_su_ebfer &&
104662306a36Sopenharmony_ci			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	return false;
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic void
105362306a36Sopenharmony_cimt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	bf->sounding_phy = MT_PHY_TYPE_OFDM;
105662306a36Sopenharmony_ci	bf->ndp_rate = 0;				/* mcs0 */
105762306a36Sopenharmony_ci	bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT;	/* ofdm 24m */
105862306a36Sopenharmony_ci	bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT;	/* ofdm 24m */
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_cistatic void
106262306a36Sopenharmony_cimt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
106362306a36Sopenharmony_ci		       struct sta_rec_bf *bf)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
106662306a36Sopenharmony_ci	u8 n = 0;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_HT;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) &&
107162306a36Sopenharmony_ci	    (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED))
107262306a36Sopenharmony_ci		n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK,
107362306a36Sopenharmony_ci			      mcs->tx_params);
107462306a36Sopenharmony_ci	else if (mcs->rx_mask[3])
107562306a36Sopenharmony_ci		n = 3;
107662306a36Sopenharmony_ci	else if (mcs->rx_mask[2])
107762306a36Sopenharmony_ci		n = 2;
107862306a36Sopenharmony_ci	else if (mcs->rx_mask[1])
107962306a36Sopenharmony_ci		n = 1;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	bf->nrow = hweight8(phy->mt76->chainmask) - 1;
108262306a36Sopenharmony_ci	bf->ncol = min_t(u8, bf->nrow, n);
108362306a36Sopenharmony_ci	bf->ibf_ncol = n;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic void
108762306a36Sopenharmony_cimt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
108862306a36Sopenharmony_ci			struct sta_rec_bf *bf, bool explicit)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
109162306a36Sopenharmony_ci	struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
109262306a36Sopenharmony_ci	u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
109362306a36Sopenharmony_ci	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
109462306a36Sopenharmony_ci	u8 tx_ant = hweight8(phy->mt76->chainmask) - 1;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_VHT;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (explicit) {
109962306a36Sopenharmony_ci		u8 sts, snd_dim;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		mt7915_mcu_sta_sounding_rate(bf);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
110462306a36Sopenharmony_ci				pc->cap);
110562306a36Sopenharmony_ci		snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
110662306a36Sopenharmony_ci				    vc->cap);
110762306a36Sopenharmony_ci		bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
110862306a36Sopenharmony_ci		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
110962306a36Sopenharmony_ci		bf->ibf_ncol = bf->ncol;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
111262306a36Sopenharmony_ci			bf->nrow = 1;
111362306a36Sopenharmony_ci	} else {
111462306a36Sopenharmony_ci		bf->nrow = tx_ant;
111562306a36Sopenharmony_ci		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
111662306a36Sopenharmony_ci		bf->ibf_ncol = nss_mcs;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
111962306a36Sopenharmony_ci			bf->ibf_nrow = 1;
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_cistatic void
112462306a36Sopenharmony_cimt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
112562306a36Sopenharmony_ci		       struct mt7915_phy *phy, struct sta_rec_bf *bf)
112662306a36Sopenharmony_ci{
112762306a36Sopenharmony_ci	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
112862306a36Sopenharmony_ci	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
112962306a36Sopenharmony_ci	const struct ieee80211_sta_he_cap *vc =
113062306a36Sopenharmony_ci		mt76_connac_get_he_phy_cap(phy->mt76, vif);
113162306a36Sopenharmony_ci	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
113262306a36Sopenharmony_ci	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
113362306a36Sopenharmony_ci	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
113462306a36Sopenharmony_ci	u8 snd_dim, sts;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	bf->tx_mode = MT_PHY_TYPE_HE_SU;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	mt7915_mcu_sta_sounding_rate(bf);
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
114162306a36Sopenharmony_ci				pe->phy_cap_info[6]);
114262306a36Sopenharmony_ci	bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
114362306a36Sopenharmony_ci				pe->phy_cap_info[6]);
114462306a36Sopenharmony_ci	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
114562306a36Sopenharmony_ci			 ve->phy_cap_info[5]);
114662306a36Sopenharmony_ci	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
114762306a36Sopenharmony_ci		     pe->phy_cap_info[4]);
114862306a36Sopenharmony_ci	bf->nrow = min_t(u8, snd_dim, sts);
114962306a36Sopenharmony_ci	bf->ncol = min_t(u8, nss_mcs, bf->nrow);
115062306a36Sopenharmony_ci	bf->ibf_ncol = bf->ncol;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
115362306a36Sopenharmony_ci		return;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/* go over for 160MHz and 80p80 */
115662306a36Sopenharmony_ci	if (pe->phy_cap_info[0] &
115762306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
115862306a36Sopenharmony_ci		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160);
115962306a36Sopenharmony_ci		nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		bf->ncol_gt_bw80 = nss_mcs;
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	if (pe->phy_cap_info[0] &
116562306a36Sopenharmony_ci	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
116662306a36Sopenharmony_ci		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80);
116762306a36Sopenharmony_ci		nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci		if (bf->ncol_gt_bw80)
117062306a36Sopenharmony_ci			bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs);
117162306a36Sopenharmony_ci		else
117262306a36Sopenharmony_ci			bf->ncol_gt_bw80 = nss_mcs;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
117662306a36Sopenharmony_ci			 ve->phy_cap_info[5]);
117762306a36Sopenharmony_ci	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
117862306a36Sopenharmony_ci		     pe->phy_cap_info[4]);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	bf->nrow_gt_bw80 = min_t(int, snd_dim, sts);
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic void
118462306a36Sopenharmony_cimt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
118562306a36Sopenharmony_ci			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
118662306a36Sopenharmony_ci{
118762306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
118862306a36Sopenharmony_ci	struct mt7915_phy *phy = mvif->phy;
118962306a36Sopenharmony_ci	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
119062306a36Sopenharmony_ci	struct sta_rec_bf *bf;
119162306a36Sopenharmony_ci	struct tlv *tlv;
119262306a36Sopenharmony_ci	const u8 matrix[4][4] = {
119362306a36Sopenharmony_ci		{0, 0, 0, 0},
119462306a36Sopenharmony_ci		{1, 1, 0, 0},	/* 2x1, 2x2, 2x3, 2x4 */
119562306a36Sopenharmony_ci		{2, 4, 4, 0},	/* 3x1, 3x2, 3x3, 3x4 */
119662306a36Sopenharmony_ci		{3, 5, 6, 0}	/* 4x1, 4x2, 4x3, 4x4 */
119762306a36Sopenharmony_ci	};
119862306a36Sopenharmony_ci	bool ebf;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
120162306a36Sopenharmony_ci		return;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	ebf = mt7915_is_ebf_supported(phy, vif, sta, false);
120462306a36Sopenharmony_ci	if (!ebf && !dev->ibf)
120562306a36Sopenharmony_ci		return;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
120862306a36Sopenharmony_ci	bf = (struct sta_rec_bf *)tlv;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	/* he: eBF only, in accordance with spec
121162306a36Sopenharmony_ci	 * vht: support eBF and iBF
121262306a36Sopenharmony_ci	 * ht: iBF only, since mac80211 lacks of eBF support
121362306a36Sopenharmony_ci	 */
121462306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he && ebf)
121562306a36Sopenharmony_ci		mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
121662306a36Sopenharmony_ci	else if (sta->deflink.vht_cap.vht_supported)
121762306a36Sopenharmony_ci		mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
121862306a36Sopenharmony_ci	else if (sta->deflink.ht_cap.ht_supported)
121962306a36Sopenharmony_ci		mt7915_mcu_sta_bfer_ht(sta, phy, bf);
122062306a36Sopenharmony_ci	else
122162306a36Sopenharmony_ci		return;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	bf->bf_cap = ebf ? ebf : dev->ibf << 1;
122462306a36Sopenharmony_ci	bf->bw = sta->deflink.bandwidth;
122562306a36Sopenharmony_ci	bf->ibf_dbw = sta->deflink.bandwidth;
122662306a36Sopenharmony_ci	bf->ibf_nrow = tx_ant;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
122962306a36Sopenharmony_ci		bf->ibf_timeout = 0x48;
123062306a36Sopenharmony_ci	else
123162306a36Sopenharmony_ci		bf->ibf_timeout = 0x18;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if (ebf && bf->nrow != tx_ant)
123462306a36Sopenharmony_ci		bf->mem_20m = matrix[tx_ant][bf->ncol];
123562306a36Sopenharmony_ci	else
123662306a36Sopenharmony_ci		bf->mem_20m = matrix[bf->nrow][bf->ncol];
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	switch (sta->deflink.bandwidth) {
123962306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
124062306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_80:
124162306a36Sopenharmony_ci		bf->mem_total = bf->mem_20m * 2;
124262306a36Sopenharmony_ci		break;
124362306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_40:
124462306a36Sopenharmony_ci		bf->mem_total = bf->mem_20m;
124562306a36Sopenharmony_ci		break;
124662306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_20:
124762306a36Sopenharmony_ci	default:
124862306a36Sopenharmony_ci		break;
124962306a36Sopenharmony_ci	}
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_cistatic void
125362306a36Sopenharmony_cimt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
125462306a36Sopenharmony_ci			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
125762306a36Sopenharmony_ci	struct mt7915_phy *phy = mvif->phy;
125862306a36Sopenharmony_ci	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
125962306a36Sopenharmony_ci	struct sta_rec_bfee *bfee;
126062306a36Sopenharmony_ci	struct tlv *tlv;
126162306a36Sopenharmony_ci	u8 nrow = 0;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
126462306a36Sopenharmony_ci		return;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (!mt7915_is_ebf_supported(phy, vif, sta, true))
126762306a36Sopenharmony_ci		return;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
127062306a36Sopenharmony_ci	bfee = (struct sta_rec_bfee *)tlv;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
127362306a36Sopenharmony_ci		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci		nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
127662306a36Sopenharmony_ci			      pe->phy_cap_info[5]);
127762306a36Sopenharmony_ci	} else if (sta->deflink.vht_cap.vht_supported) {
127862306a36Sopenharmony_ci		struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci		nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
128162306a36Sopenharmony_ci				 pc->cap);
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	/* reply with identity matrix to avoid 2x2 BF negative gain */
128562306a36Sopenharmony_ci	bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_cistatic enum mcu_mmps_mode
128962306a36Sopenharmony_cimt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	switch (smps) {
129262306a36Sopenharmony_ci	case IEEE80211_SMPS_OFF:
129362306a36Sopenharmony_ci		return MCU_MMPS_DISABLE;
129462306a36Sopenharmony_ci	case IEEE80211_SMPS_STATIC:
129562306a36Sopenharmony_ci		return MCU_MMPS_STATIC;
129662306a36Sopenharmony_ci	case IEEE80211_SMPS_DYNAMIC:
129762306a36Sopenharmony_ci		return MCU_MMPS_DYNAMIC;
129862306a36Sopenharmony_ci	default:
129962306a36Sopenharmony_ci		return MCU_MMPS_DISABLE;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ciint mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
130462306a36Sopenharmony_ci				   struct ieee80211_vif *vif,
130562306a36Sopenharmony_ci				   struct ieee80211_sta *sta,
130662306a36Sopenharmony_ci				   void *data, u32 field)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
130962306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
131062306a36Sopenharmony_ci	struct sta_phy *phy = data;
131162306a36Sopenharmony_ci	struct sta_rec_ra_fixed *ra;
131262306a36Sopenharmony_ci	struct sk_buff *skb;
131362306a36Sopenharmony_ci	struct tlv *tlv;
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
131662306a36Sopenharmony_ci					    &msta->wcid);
131762306a36Sopenharmony_ci	if (IS_ERR(skb))
131862306a36Sopenharmony_ci		return PTR_ERR(skb);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
132162306a36Sopenharmony_ci	ra = (struct sta_rec_ra_fixed *)tlv;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	switch (field) {
132462306a36Sopenharmony_ci	case RATE_PARAM_AUTO:
132562306a36Sopenharmony_ci		break;
132662306a36Sopenharmony_ci	case RATE_PARAM_FIXED:
132762306a36Sopenharmony_ci	case RATE_PARAM_FIXED_MCS:
132862306a36Sopenharmony_ci	case RATE_PARAM_FIXED_GI:
132962306a36Sopenharmony_ci	case RATE_PARAM_FIXED_HE_LTF:
133062306a36Sopenharmony_ci		if (phy)
133162306a36Sopenharmony_ci			ra->phy = *phy;
133262306a36Sopenharmony_ci		break;
133362306a36Sopenharmony_ci	case RATE_PARAM_MMPS_UPDATE:
133462306a36Sopenharmony_ci		ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
133562306a36Sopenharmony_ci		break;
133662306a36Sopenharmony_ci	case RATE_PARAM_SPE_UPDATE:
133762306a36Sopenharmony_ci		ra->spe_idx = *(u8 *)data;
133862306a36Sopenharmony_ci		break;
133962306a36Sopenharmony_ci	default:
134062306a36Sopenharmony_ci		break;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	ra->field = cpu_to_le32(field);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
134562306a36Sopenharmony_ci				     MCU_EXT_CMD(STA_REC_UPDATE), true);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ciint mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
134962306a36Sopenharmony_ci			struct ieee80211_sta *sta)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
135262306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
135362306a36Sopenharmony_ci	struct wtbl_req_hdr *wtbl_hdr;
135462306a36Sopenharmony_ci	struct tlv *sta_wtbl;
135562306a36Sopenharmony_ci	struct sk_buff *skb;
135662306a36Sopenharmony_ci	int ret;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
135962306a36Sopenharmony_ci					    &msta->wcid);
136062306a36Sopenharmony_ci	if (IS_ERR(skb))
136162306a36Sopenharmony_ci		return PTR_ERR(skb);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
136462306a36Sopenharmony_ci					   sizeof(struct tlv));
136562306a36Sopenharmony_ci	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
136662306a36Sopenharmony_ci						  WTBL_SET, sta_wtbl, &skb);
136762306a36Sopenharmony_ci	if (IS_ERR(wtbl_hdr))
136862306a36Sopenharmony_ci		return PTR_ERR(wtbl_hdr);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
137362306a36Sopenharmony_ci				    MCU_EXT_CMD(STA_REC_UPDATE), true);
137462306a36Sopenharmony_ci	if (ret)
137562306a36Sopenharmony_ci		return ret;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL,
137862306a36Sopenharmony_ci					      RATE_PARAM_MMPS_UPDATE);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic int
138262306a36Sopenharmony_cimt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif,
138362306a36Sopenharmony_ci		       struct ieee80211_sta *sta)
138462306a36Sopenharmony_ci{
138562306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
138662306a36Sopenharmony_ci	struct mt76_phy *mphy = mvif->phy->mt76;
138762306a36Sopenharmony_ci	u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
139062306a36Sopenharmony_ci					      RATE_PARAM_SPE_UPDATE);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic int
139462306a36Sopenharmony_cimt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
139562306a36Sopenharmony_ci			       struct ieee80211_vif *vif,
139662306a36Sopenharmony_ci			       struct ieee80211_sta *sta)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
139962306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
140062306a36Sopenharmony_ci	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
140162306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
140262306a36Sopenharmony_ci	struct sta_phy phy = {};
140362306a36Sopenharmony_ci	int ret, nrates = 0;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he)			\
140662306a36Sopenharmony_ci	do {									\
140762306a36Sopenharmony_ci		u8 i, gi = mask->control[band]._gi;				\
140862306a36Sopenharmony_ci		gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;		\
140962306a36Sopenharmony_ci		for (i = 0; i <= sta->deflink.bandwidth; i++) {			\
141062306a36Sopenharmony_ci			phy.sgi |= gi << (i << (_he));				\
141162306a36Sopenharmony_ci			phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\
141262306a36Sopenharmony_ci		}								\
141362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) {	\
141462306a36Sopenharmony_ci			if (!mask->control[band]._mcs[i])			\
141562306a36Sopenharmony_ci				continue;					\
141662306a36Sopenharmony_ci			nrates += hweight16(mask->control[band]._mcs[i]);	\
141762306a36Sopenharmony_ci			phy.mcs = ffs(mask->control[band]._mcs[i]) - 1;		\
141862306a36Sopenharmony_ci			if (_ht)						\
141962306a36Sopenharmony_ci				phy.mcs += 8 * i;				\
142062306a36Sopenharmony_ci		}								\
142162306a36Sopenharmony_ci	} while (0)
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
142462306a36Sopenharmony_ci		__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
142562306a36Sopenharmony_ci	} else if (sta->deflink.vht_cap.vht_supported) {
142662306a36Sopenharmony_ci		__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
142762306a36Sopenharmony_ci	} else if (sta->deflink.ht_cap.ht_supported) {
142862306a36Sopenharmony_ci		__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
142962306a36Sopenharmony_ci	} else {
143062306a36Sopenharmony_ci		nrates = hweight32(mask->control[band].legacy);
143162306a36Sopenharmony_ci		phy.mcs = ffs(mask->control[band].legacy) - 1;
143262306a36Sopenharmony_ci	}
143362306a36Sopenharmony_ci#undef __sta_phy_bitrate_mask_check
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	/* fall back to auto rate control */
143662306a36Sopenharmony_ci	if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
143762306a36Sopenharmony_ci	    mask->control[band].he_gi == GENMASK(7, 0) &&
143862306a36Sopenharmony_ci	    mask->control[band].he_ltf == GENMASK(7, 0) &&
143962306a36Sopenharmony_ci	    nrates != 1)
144062306a36Sopenharmony_ci		return 0;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	/* fixed single rate */
144362306a36Sopenharmony_ci	if (nrates == 1) {
144462306a36Sopenharmony_ci		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
144562306a36Sopenharmony_ci						     RATE_PARAM_FIXED_MCS);
144662306a36Sopenharmony_ci		if (ret)
144762306a36Sopenharmony_ci			return ret;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/* fixed GI */
145162306a36Sopenharmony_ci	if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
145262306a36Sopenharmony_ci	    mask->control[band].he_gi != GENMASK(7, 0)) {
145362306a36Sopenharmony_ci		struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
145462306a36Sopenharmony_ci		u32 addr;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci		/* firmware updates only TXCMD but doesn't take WTBL into
145762306a36Sopenharmony_ci		 * account, so driver should update here to reflect the
145862306a36Sopenharmony_ci		 * actual txrate hardware sends out.
145962306a36Sopenharmony_ci		 */
146062306a36Sopenharmony_ci		addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
146162306a36Sopenharmony_ci		if (sta->deflink.he_cap.has_he)
146262306a36Sopenharmony_ci			mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
146362306a36Sopenharmony_ci		else
146462306a36Sopenharmony_ci			mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
146762306a36Sopenharmony_ci						     RATE_PARAM_FIXED_GI);
146862306a36Sopenharmony_ci		if (ret)
146962306a36Sopenharmony_ci			return ret;
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	/* fixed HE_LTF */
147362306a36Sopenharmony_ci	if (mask->control[band].he_ltf != GENMASK(7, 0)) {
147462306a36Sopenharmony_ci		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
147562306a36Sopenharmony_ci						     RATE_PARAM_FIXED_HE_LTF);
147662306a36Sopenharmony_ci		if (ret)
147762306a36Sopenharmony_ci			return ret;
147862306a36Sopenharmony_ci	}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	return mt7915_mcu_set_spe_idx(dev, vif, sta);
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_cistatic void
148462306a36Sopenharmony_cimt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
148562306a36Sopenharmony_ci			     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
148862306a36Sopenharmony_ci	struct mt76_phy *mphy = mvif->phy->mt76;
148962306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &mphy->chandef;
149062306a36Sopenharmony_ci	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
149162306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
149262306a36Sopenharmony_ci	struct sta_rec_ra *ra;
149362306a36Sopenharmony_ci	struct tlv *tlv;
149462306a36Sopenharmony_ci	u32 supp_rate = sta->deflink.supp_rates[band];
149562306a36Sopenharmony_ci	u32 cap = sta->wme ? STA_CAP_WMM : 0;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
149862306a36Sopenharmony_ci	ra = (struct sta_rec_ra *)tlv;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	ra->valid = true;
150162306a36Sopenharmony_ci	ra->auto_rate = true;
150262306a36Sopenharmony_ci	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
150362306a36Sopenharmony_ci	ra->channel = chandef->chan->hw_value;
150462306a36Sopenharmony_ci	ra->bw = sta->deflink.bandwidth;
150562306a36Sopenharmony_ci	ra->phy.bw = sta->deflink.bandwidth;
150662306a36Sopenharmony_ci	ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	if (supp_rate) {
150962306a36Sopenharmony_ci		supp_rate &= mask->control[band].legacy;
151062306a36Sopenharmony_ci		ra->rate_len = hweight32(supp_rate);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci		if (band == NL80211_BAND_2GHZ) {
151362306a36Sopenharmony_ci			ra->supp_mode = MODE_CCK;
151462306a36Sopenharmony_ci			ra->supp_cck_rate = supp_rate & GENMASK(3, 0);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci			if (ra->rate_len > 4) {
151762306a36Sopenharmony_ci				ra->supp_mode |= MODE_OFDM;
151862306a36Sopenharmony_ci				ra->supp_ofdm_rate = supp_rate >> 4;
151962306a36Sopenharmony_ci			}
152062306a36Sopenharmony_ci		} else {
152162306a36Sopenharmony_ci			ra->supp_mode = MODE_OFDM;
152262306a36Sopenharmony_ci			ra->supp_ofdm_rate = supp_rate;
152362306a36Sopenharmony_ci		}
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	if (sta->deflink.ht_cap.ht_supported) {
152762306a36Sopenharmony_ci		ra->supp_mode |= MODE_HT;
152862306a36Sopenharmony_ci		ra->af = sta->deflink.ht_cap.ampdu_factor;
152962306a36Sopenharmony_ci		ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci		cap |= STA_CAP_HT;
153262306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
153362306a36Sopenharmony_ci			cap |= STA_CAP_SGI_20;
153462306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
153562306a36Sopenharmony_ci			cap |= STA_CAP_SGI_40;
153662306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
153762306a36Sopenharmony_ci			cap |= STA_CAP_TX_STBC;
153862306a36Sopenharmony_ci		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
153962306a36Sopenharmony_ci			cap |= STA_CAP_RX_STBC;
154062306a36Sopenharmony_ci		if (mvif->cap.ht_ldpc &&
154162306a36Sopenharmony_ci		    (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
154262306a36Sopenharmony_ci			cap |= STA_CAP_LDPC;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci		mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
154562306a36Sopenharmony_ci					  mask->control[band].ht_mcs);
154662306a36Sopenharmony_ci		ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
154762306a36Sopenharmony_ci	}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (sta->deflink.vht_cap.vht_supported) {
155062306a36Sopenharmony_ci		u8 af;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci		ra->supp_mode |= MODE_VHT;
155362306a36Sopenharmony_ci		af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
155462306a36Sopenharmony_ci			       sta->deflink.vht_cap.cap);
155562306a36Sopenharmony_ci		ra->af = max_t(u8, ra->af, af);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci		cap |= STA_CAP_VHT;
155862306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
155962306a36Sopenharmony_ci			cap |= STA_CAP_VHT_SGI_80;
156062306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
156162306a36Sopenharmony_ci			cap |= STA_CAP_VHT_SGI_160;
156262306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
156362306a36Sopenharmony_ci			cap |= STA_CAP_VHT_TX_STBC;
156462306a36Sopenharmony_ci		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
156562306a36Sopenharmony_ci			cap |= STA_CAP_VHT_RX_STBC;
156662306a36Sopenharmony_ci		if (mvif->cap.vht_ldpc &&
156762306a36Sopenharmony_ci		    (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
156862306a36Sopenharmony_ci			cap |= STA_CAP_VHT_LDPC;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci		mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
157162306a36Sopenharmony_ci					   mask->control[band].vht_mcs);
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	if (sta->deflink.he_cap.has_he) {
157562306a36Sopenharmony_ci		ra->supp_mode |= MODE_HE;
157662306a36Sopenharmony_ci		cap |= STA_CAP_HE;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		if (sta->deflink.he_6ghz_capa.capa)
157962306a36Sopenharmony_ci			ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
158062306a36Sopenharmony_ci					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
158162306a36Sopenharmony_ci	}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	ra->sta_cap = cpu_to_le32(cap);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ciint mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
158762306a36Sopenharmony_ci			     struct ieee80211_sta *sta, bool changed)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
159062306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
159162306a36Sopenharmony_ci	struct sk_buff *skb;
159262306a36Sopenharmony_ci	int ret;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
159562306a36Sopenharmony_ci					    &msta->wcid);
159662306a36Sopenharmony_ci	if (IS_ERR(skb))
159762306a36Sopenharmony_ci		return PTR_ERR(skb);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	/* firmware rc algorithm refers to sta_rec_he for HE control.
160062306a36Sopenharmony_ci	 * once dev->rc_work changes the settings driver should also
160162306a36Sopenharmony_ci	 * update sta_rec_he here.
160262306a36Sopenharmony_ci	 */
160362306a36Sopenharmony_ci	if (changed)
160462306a36Sopenharmony_ci		mt7915_mcu_sta_he_tlv(skb, sta, vif);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	/* sta_rec_ra accommodates BW, NSS and only MCS range format
160762306a36Sopenharmony_ci	 * i.e 0-{7,8,9} for VHT.
160862306a36Sopenharmony_ci	 */
160962306a36Sopenharmony_ci	mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
161262306a36Sopenharmony_ci				    MCU_EXT_CMD(STA_REC_UPDATE), true);
161362306a36Sopenharmony_ci	if (ret)
161462306a36Sopenharmony_ci		return ret;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	/* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE,
161762306a36Sopenharmony_ci	 * and updates as peer fixed rate parameters, which overrides
161862306a36Sopenharmony_ci	 * sta_rec_ra and firmware rate control algorithm.
161962306a36Sopenharmony_ci	 */
162062306a36Sopenharmony_ci	return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistatic int
162462306a36Sopenharmony_cimt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
162562306a36Sopenharmony_ci		     struct ieee80211_sta *sta)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci#define MT_STA_BSS_GROUP		1
162862306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
162962306a36Sopenharmony_ci	struct mt7915_sta *msta;
163062306a36Sopenharmony_ci	struct {
163162306a36Sopenharmony_ci		__le32 action;
163262306a36Sopenharmony_ci		u8 wlan_idx_lo;
163362306a36Sopenharmony_ci		u8 status;
163462306a36Sopenharmony_ci		u8 wlan_idx_hi;
163562306a36Sopenharmony_ci		u8 rsv0[5];
163662306a36Sopenharmony_ci		__le32 val;
163762306a36Sopenharmony_ci		u8 rsv1[8];
163862306a36Sopenharmony_ci	} __packed req = {
163962306a36Sopenharmony_ci		.action = cpu_to_le32(MT_STA_BSS_GROUP),
164062306a36Sopenharmony_ci		.val = cpu_to_le32(mvif->mt76.idx % 16),
164162306a36Sopenharmony_ci	};
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
164462306a36Sopenharmony_ci	req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx);
164562306a36Sopenharmony_ci	req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req,
164862306a36Sopenharmony_ci				 sizeof(req), true);
164962306a36Sopenharmony_ci}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ciint mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
165262306a36Sopenharmony_ci		       struct ieee80211_sta *sta, bool enable)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
165562306a36Sopenharmony_ci	struct mt7915_sta *msta;
165662306a36Sopenharmony_ci	struct sk_buff *skb;
165762306a36Sopenharmony_ci	int ret;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
166262306a36Sopenharmony_ci					    &msta->wcid);
166362306a36Sopenharmony_ci	if (IS_ERR(skb))
166462306a36Sopenharmony_ci		return PTR_ERR(skb);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	/* starec basic */
166762306a36Sopenharmony_ci	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable,
166862306a36Sopenharmony_ci				      !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
166962306a36Sopenharmony_ci	if (!enable)
167062306a36Sopenharmony_ci		goto out;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	/* tag order is in accordance with firmware dependency. */
167362306a36Sopenharmony_ci	if (sta) {
167462306a36Sopenharmony_ci		/* starec bfer */
167562306a36Sopenharmony_ci		mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta);
167662306a36Sopenharmony_ci		/* starec ht */
167762306a36Sopenharmony_ci		mt7915_mcu_sta_ht_tlv(skb, sta);
167862306a36Sopenharmony_ci		/* starec vht */
167962306a36Sopenharmony_ci		mt7915_mcu_sta_vht_tlv(skb, sta);
168062306a36Sopenharmony_ci		/* starec uapsd */
168162306a36Sopenharmony_ci		mt76_connac_mcu_sta_uapsd(skb, vif, sta);
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta);
168562306a36Sopenharmony_ci	if (ret) {
168662306a36Sopenharmony_ci		dev_kfree_skb(skb);
168762306a36Sopenharmony_ci		return ret;
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	if (sta) {
169162306a36Sopenharmony_ci		/* starec amsdu */
169262306a36Sopenharmony_ci		mt7915_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
169362306a36Sopenharmony_ci		/* starec he */
169462306a36Sopenharmony_ci		mt7915_mcu_sta_he_tlv(skb, sta, vif);
169562306a36Sopenharmony_ci		/* starec muru */
169662306a36Sopenharmony_ci		mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif);
169762306a36Sopenharmony_ci		/* starec bfee */
169862306a36Sopenharmony_ci		mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta);
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	ret = mt7915_mcu_add_group(dev, vif, sta);
170262306a36Sopenharmony_ci	if (ret) {
170362306a36Sopenharmony_ci		dev_kfree_skb(skb);
170462306a36Sopenharmony_ci		return ret;
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ciout:
170762306a36Sopenharmony_ci	ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
170862306a36Sopenharmony_ci	if (ret)
170962306a36Sopenharmony_ci		return ret;
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
171262306a36Sopenharmony_ci				     MCU_EXT_CMD(STA_REC_UPDATE), true);
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ciint mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci#ifdef CONFIG_NET_MEDIATEK_SOC_WED
171862306a36Sopenharmony_ci	struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
171962306a36Sopenharmony_ci	struct {
172062306a36Sopenharmony_ci		__le32 args[2];
172162306a36Sopenharmony_ci	} req = {
172262306a36Sopenharmony_ci		.args[0] = cpu_to_le32(1),
172362306a36Sopenharmony_ci		.args[1] = cpu_to_le32(6),
172462306a36Sopenharmony_ci	};
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL,
172762306a36Sopenharmony_ci					 &req, sizeof(req));
172862306a36Sopenharmony_ci#else
172962306a36Sopenharmony_ci	return 0;
173062306a36Sopenharmony_ci#endif
173162306a36Sopenharmony_ci}
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ciint mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
173462306a36Sopenharmony_ci			    struct ieee80211_vif *vif, bool enable)
173562306a36Sopenharmony_ci{
173662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
173762306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
173862306a36Sopenharmony_ci	struct {
173962306a36Sopenharmony_ci		struct req_hdr {
174062306a36Sopenharmony_ci			u8 omac_idx;
174162306a36Sopenharmony_ci			u8 band_idx;
174262306a36Sopenharmony_ci			__le16 tlv_num;
174362306a36Sopenharmony_ci			u8 is_tlv_append;
174462306a36Sopenharmony_ci			u8 rsv[3];
174562306a36Sopenharmony_ci		} __packed hdr;
174662306a36Sopenharmony_ci		struct req_tlv {
174762306a36Sopenharmony_ci			__le16 tag;
174862306a36Sopenharmony_ci			__le16 len;
174962306a36Sopenharmony_ci			u8 active;
175062306a36Sopenharmony_ci			u8 band_idx;
175162306a36Sopenharmony_ci			u8 omac_addr[ETH_ALEN];
175262306a36Sopenharmony_ci		} __packed tlv;
175362306a36Sopenharmony_ci	} data = {
175462306a36Sopenharmony_ci		.hdr = {
175562306a36Sopenharmony_ci			.omac_idx = mvif->mt76.omac_idx,
175662306a36Sopenharmony_ci			.band_idx = mvif->mt76.band_idx,
175762306a36Sopenharmony_ci			.tlv_num = cpu_to_le16(1),
175862306a36Sopenharmony_ci			.is_tlv_append = 1,
175962306a36Sopenharmony_ci		},
176062306a36Sopenharmony_ci		.tlv = {
176162306a36Sopenharmony_ci			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
176262306a36Sopenharmony_ci			.len = cpu_to_le16(sizeof(struct req_tlv)),
176362306a36Sopenharmony_ci			.active = enable,
176462306a36Sopenharmony_ci			.band_idx = mvif->mt76.band_idx,
176562306a36Sopenharmony_ci		},
176662306a36Sopenharmony_ci	};
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
176962306a36Sopenharmony_ci		return mt7915_mcu_muar_config(phy, vif, false, enable);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
177262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
177362306a36Sopenharmony_ci				 &data, sizeof(data), true);
177462306a36Sopenharmony_ci}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_cistatic void
177762306a36Sopenharmony_cimt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
177862306a36Sopenharmony_ci			 struct sk_buff *skb, struct bss_info_bcn *bcn,
177962306a36Sopenharmony_ci			 struct ieee80211_mutable_offsets *offs)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	struct bss_info_bcn_cntdwn *info;
178262306a36Sopenharmony_ci	struct tlv *tlv;
178362306a36Sopenharmony_ci	int sub_tag;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	if (!offs->cntdwn_counter_offs[0])
178662306a36Sopenharmony_ci		return;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC;
178962306a36Sopenharmony_ci	tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info),
179062306a36Sopenharmony_ci					   &bcn->sub_ntlv, &bcn->len);
179162306a36Sopenharmony_ci	info = (struct bss_info_bcn_cntdwn *)tlv;
179262306a36Sopenharmony_ci	info->cnt = skb->data[offs->cntdwn_counter_offs[0]];
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_cistatic void
179662306a36Sopenharmony_cimt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
179762306a36Sopenharmony_ci		       struct ieee80211_vif *vif, struct bss_info_bcn *bcn,
179862306a36Sopenharmony_ci		       struct ieee80211_mutable_offsets *offs)
179962306a36Sopenharmony_ci{
180062306a36Sopenharmony_ci	struct bss_info_bcn_mbss *mbss;
180162306a36Sopenharmony_ci	const struct element *elem;
180262306a36Sopenharmony_ci	struct tlv *tlv;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	if (!vif->bss_conf.bssid_indicator)
180562306a36Sopenharmony_ci		return;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID,
180862306a36Sopenharmony_ci					   sizeof(*mbss), &bcn->sub_ntlv,
180962306a36Sopenharmony_ci					   &bcn->len);
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	mbss = (struct bss_info_bcn_mbss *)tlv;
181262306a36Sopenharmony_ci	mbss->offset[0] = cpu_to_le16(offs->tim_offset);
181362306a36Sopenharmony_ci	mbss->bitmap = cpu_to_le32(1);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID,
181662306a36Sopenharmony_ci			    &skb->data[offs->mbssid_off],
181762306a36Sopenharmony_ci			    skb->len - offs->mbssid_off) {
181862306a36Sopenharmony_ci		const struct element *sub_elem;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci		if (elem->datalen < 2)
182162306a36Sopenharmony_ci			continue;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci		for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) {
182462306a36Sopenharmony_ci			const struct ieee80211_bssid_index *idx;
182562306a36Sopenharmony_ci			const u8 *idx_ie;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci			if (sub_elem->id || sub_elem->datalen < 4)
182862306a36Sopenharmony_ci				continue; /* not a valid BSS profile */
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci			/* Find WLAN_EID_MULTI_BSSID_IDX
183162306a36Sopenharmony_ci			 * in the merged nontransmitted profile
183262306a36Sopenharmony_ci			 */
183362306a36Sopenharmony_ci			idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
183462306a36Sopenharmony_ci						  sub_elem->data,
183562306a36Sopenharmony_ci						  sub_elem->datalen);
183662306a36Sopenharmony_ci			if (!idx_ie || idx_ie[1] < sizeof(*idx))
183762306a36Sopenharmony_ci				continue;
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci			idx = (void *)(idx_ie + 2);
184062306a36Sopenharmony_ci			if (!idx->bssid_index || idx->bssid_index > 31)
184162306a36Sopenharmony_ci				continue;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci			mbss->offset[idx->bssid_index] =
184462306a36Sopenharmony_ci				cpu_to_le16(idx_ie - skb->data);
184562306a36Sopenharmony_ci			mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index));
184662306a36Sopenharmony_ci		}
184762306a36Sopenharmony_ci	}
184862306a36Sopenharmony_ci}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic void
185162306a36Sopenharmony_cimt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
185262306a36Sopenharmony_ci		       struct sk_buff *rskb, struct sk_buff *skb,
185362306a36Sopenharmony_ci		       struct bss_info_bcn *bcn,
185462306a36Sopenharmony_ci		       struct ieee80211_mutable_offsets *offs)
185562306a36Sopenharmony_ci{
185662306a36Sopenharmony_ci	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
185762306a36Sopenharmony_ci	struct bss_info_bcn_cont *cont;
185862306a36Sopenharmony_ci	struct tlv *tlv;
185962306a36Sopenharmony_ci	u8 *buf;
186062306a36Sopenharmony_ci	int len = sizeof(*cont) + MT_TXD_SIZE + skb->len;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
186362306a36Sopenharmony_ci	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT,
186462306a36Sopenharmony_ci					   len, &bcn->sub_ntlv, &bcn->len);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	cont = (struct bss_info_bcn_cont *)tlv;
186762306a36Sopenharmony_ci	cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
186862306a36Sopenharmony_ci	cont->tim_ofs = cpu_to_le16(offs->tim_offset);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	if (offs->cntdwn_counter_offs[0]) {
187162306a36Sopenharmony_ci		u16 offset = offs->cntdwn_counter_offs[0];
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci		if (vif->bss_conf.csa_active)
187462306a36Sopenharmony_ci			cont->csa_ofs = cpu_to_le16(offset - 4);
187562306a36Sopenharmony_ci		if (vif->bss_conf.color_change_active)
187662306a36Sopenharmony_ci			cont->bcc_ofs = cpu_to_le16(offset - 3);
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	buf = (u8 *)tlv + sizeof(*cont);
188062306a36Sopenharmony_ci	mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
188162306a36Sopenharmony_ci			      0, BSS_CHANGED_BEACON);
188262306a36Sopenharmony_ci	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
188362306a36Sopenharmony_ci}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ciint
188662306a36Sopenharmony_cimt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
188762306a36Sopenharmony_ci			     u32 changed)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci#define OFFLOAD_TX_MODE_SU	BIT(0)
189062306a36Sopenharmony_ci#define OFFLOAD_TX_MODE_MU	BIT(1)
189162306a36Sopenharmony_ci	struct ieee80211_hw *hw = mt76_hw(dev);
189262306a36Sopenharmony_ci	struct mt7915_phy *phy = mt7915_hw_phy(hw);
189362306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
189462306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
189562306a36Sopenharmony_ci	enum nl80211_band band = chandef->chan->band;
189662306a36Sopenharmony_ci	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
189762306a36Sopenharmony_ci	struct bss_info_bcn *bcn;
189862306a36Sopenharmony_ci	struct bss_info_inband_discovery *discov;
189962306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
190062306a36Sopenharmony_ci	struct sk_buff *rskb, *skb = NULL;
190162306a36Sopenharmony_ci	struct tlv *tlv, *sub_tlv;
190262306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
190362306a36Sopenharmony_ci	u8 *buf, interval;
190462306a36Sopenharmony_ci	int len;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	if (vif->bss_conf.nontransmitted)
190762306a36Sopenharmony_ci		return 0;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
191062306a36Sopenharmony_ci					       MT7915_MAX_BSS_OFFLOAD_SIZE);
191162306a36Sopenharmony_ci	if (IS_ERR(rskb))
191262306a36Sopenharmony_ci		return PTR_ERR(rskb);
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
191562306a36Sopenharmony_ci	bcn = (struct bss_info_bcn *)tlv;
191662306a36Sopenharmony_ci	bcn->enable = true;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	if (changed & BSS_CHANGED_FILS_DISCOVERY &&
191962306a36Sopenharmony_ci	    vif->bss_conf.fils_discovery.max_interval) {
192062306a36Sopenharmony_ci		interval = vif->bss_conf.fils_discovery.max_interval;
192162306a36Sopenharmony_ci		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
192262306a36Sopenharmony_ci	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
192362306a36Sopenharmony_ci		   vif->bss_conf.unsol_bcast_probe_resp_interval) {
192462306a36Sopenharmony_ci		interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
192562306a36Sopenharmony_ci		skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	if (!skb) {
192962306a36Sopenharmony_ci		dev_kfree_skb(rskb);
193062306a36Sopenharmony_ci		return -EINVAL;
193162306a36Sopenharmony_ci	}
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
193462306a36Sopenharmony_ci	info->control.vif = vif;
193562306a36Sopenharmony_ci	info->band = band;
193662306a36Sopenharmony_ci	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
193962306a36Sopenharmony_ci	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (skb->len > MT7915_MAX_BEACON_SIZE) {
194262306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "inband discovery size limit exceed\n");
194362306a36Sopenharmony_ci		dev_kfree_skb(rskb);
194462306a36Sopenharmony_ci		dev_kfree_skb(skb);
194562306a36Sopenharmony_ci		return -EINVAL;
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	sub_tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
194962306a36Sopenharmony_ci					       len, &bcn->sub_ntlv, &bcn->len);
195062306a36Sopenharmony_ci	discov = (struct bss_info_inband_discovery *)sub_tlv;
195162306a36Sopenharmony_ci	discov->tx_mode = OFFLOAD_TX_MODE_SU;
195262306a36Sopenharmony_ci	/* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
195362306a36Sopenharmony_ci	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
195462306a36Sopenharmony_ci	discov->tx_interval = interval;
195562306a36Sopenharmony_ci	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
195662306a36Sopenharmony_ci	discov->enable = true;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	buf = (u8 *)sub_tlv + sizeof(*discov);
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
196162306a36Sopenharmony_ci			      0, changed);
196262306a36Sopenharmony_ci	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	dev_kfree_skb(skb);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
196762306a36Sopenharmony_ci				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
196862306a36Sopenharmony_ci}
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ciint mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
197162306a36Sopenharmony_ci			  int en, u32 changed)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	struct mt7915_dev *dev = mt7915_hw_dev(hw);
197462306a36Sopenharmony_ci	struct mt7915_phy *phy = mt7915_hw_phy(hw);
197562306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
197662306a36Sopenharmony_ci	struct ieee80211_mutable_offsets offs;
197762306a36Sopenharmony_ci	struct ieee80211_tx_info *info;
197862306a36Sopenharmony_ci	struct sk_buff *skb, *rskb;
197962306a36Sopenharmony_ci	struct tlv *tlv;
198062306a36Sopenharmony_ci	struct bss_info_bcn *bcn;
198162306a36Sopenharmony_ci	int len = MT7915_MAX_BSS_OFFLOAD_SIZE;
198262306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	if (vif->bss_conf.nontransmitted)
198562306a36Sopenharmony_ci		return 0;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
198862306a36Sopenharmony_ci					       NULL, len);
198962306a36Sopenharmony_ci	if (IS_ERR(rskb))
199062306a36Sopenharmony_ci		return PTR_ERR(rskb);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
199362306a36Sopenharmony_ci	bcn = (struct bss_info_bcn *)tlv;
199462306a36Sopenharmony_ci	bcn->enable = en;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (!en)
199762306a36Sopenharmony_ci		goto out;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
200062306a36Sopenharmony_ci	if (!skb) {
200162306a36Sopenharmony_ci		dev_kfree_skb(rskb);
200262306a36Sopenharmony_ci		return -EINVAL;
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	if (skb->len > MT7915_MAX_BEACON_SIZE) {
200662306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
200762306a36Sopenharmony_ci		dev_kfree_skb(rskb);
200862306a36Sopenharmony_ci		dev_kfree_skb(skb);
200962306a36Sopenharmony_ci		return -EINVAL;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	info = IEEE80211_SKB_CB(skb);
201362306a36Sopenharmony_ci	info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
201662306a36Sopenharmony_ci	mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
201762306a36Sopenharmony_ci	mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
201862306a36Sopenharmony_ci	dev_kfree_skb(skb);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ciout:
202162306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
202262306a36Sopenharmony_ci				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
202362306a36Sopenharmony_ci}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_cistatic int mt7915_driver_own(struct mt7915_dev *dev, u8 band)
202662306a36Sopenharmony_ci{
202762306a36Sopenharmony_ci	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN);
202862306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band),
202962306a36Sopenharmony_ci			    MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) {
203062306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for driver own\n");
203162306a36Sopenharmony_ci		return -EIO;
203262306a36Sopenharmony_ci	}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	/* clear irq when the driver own success */
203562306a36Sopenharmony_ci	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band),
203662306a36Sopenharmony_ci		MT_TOP_LPCR_HOST_BAND_STAT);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	return 0;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic int
204262306a36Sopenharmony_cimt7915_firmware_state(struct mt7915_dev *dev, bool wa)
204362306a36Sopenharmony_ci{
204462306a36Sopenharmony_ci	u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE,
204562306a36Sopenharmony_ci			       wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD);
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,
204862306a36Sopenharmony_ci			    state, 1000)) {
204962306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
205062306a36Sopenharmony_ci		return -EIO;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci	return 0;
205362306a36Sopenharmony_ci}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_cistatic int mt7915_load_firmware(struct mt7915_dev *dev)
205662306a36Sopenharmony_ci{
205762306a36Sopenharmony_ci	int ret;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	/* make sure fw is download state */
206062306a36Sopenharmony_ci	if (mt7915_firmware_state(dev, false)) {
206162306a36Sopenharmony_ci		/* restart firmware once */
206262306a36Sopenharmony_ci		mt76_connac_mcu_restart(&dev->mt76);
206362306a36Sopenharmony_ci		ret = mt7915_firmware_state(dev, false);
206462306a36Sopenharmony_ci		if (ret) {
206562306a36Sopenharmony_ci			dev_err(dev->mt76.dev,
206662306a36Sopenharmony_ci				"Firmware is not ready for download\n");
206762306a36Sopenharmony_ci			return ret;
206862306a36Sopenharmony_ci		}
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH));
207262306a36Sopenharmony_ci	if (ret)
207362306a36Sopenharmony_ci		return ret;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM),
207662306a36Sopenharmony_ci				    fw_name(dev, FIRMWARE_WA));
207762306a36Sopenharmony_ci	if (ret)
207862306a36Sopenharmony_ci		return ret;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	ret = mt7915_firmware_state(dev, true);
208162306a36Sopenharmony_ci	if (ret)
208262306a36Sopenharmony_ci		return ret;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	dev_dbg(dev->mt76.dev, "Firmware init done\n");
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	return 0;
208962306a36Sopenharmony_ci}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ciint mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl)
209262306a36Sopenharmony_ci{
209362306a36Sopenharmony_ci	struct {
209462306a36Sopenharmony_ci		u8 ctrl_val;
209562306a36Sopenharmony_ci		u8 pad[3];
209662306a36Sopenharmony_ci	} data = {
209762306a36Sopenharmony_ci		.ctrl_val = ctrl
209862306a36Sopenharmony_ci	};
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	if (type == MCU_FW_LOG_WA)
210162306a36Sopenharmony_ci		return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(FW_LOG_2_HOST),
210262306a36Sopenharmony_ci					 &data, sizeof(data), true);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data,
210562306a36Sopenharmony_ci				 sizeof(data), true);
210662306a36Sopenharmony_ci}
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ciint mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
210962306a36Sopenharmony_ci{
211062306a36Sopenharmony_ci	struct {
211162306a36Sopenharmony_ci		u8 ver;
211262306a36Sopenharmony_ci		u8 pad;
211362306a36Sopenharmony_ci		__le16 len;
211462306a36Sopenharmony_ci		u8 level;
211562306a36Sopenharmony_ci		u8 rsv[3];
211662306a36Sopenharmony_ci		__le32 module_idx;
211762306a36Sopenharmony_ci	} data = {
211862306a36Sopenharmony_ci		.module_idx = cpu_to_le32(module),
211962306a36Sopenharmony_ci		.level = level,
212062306a36Sopenharmony_ci	};
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data,
212362306a36Sopenharmony_ci				 sizeof(data), false);
212462306a36Sopenharmony_ci}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ciint mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled)
212762306a36Sopenharmony_ci{
212862306a36Sopenharmony_ci	struct {
212962306a36Sopenharmony_ci		__le32 cmd;
213062306a36Sopenharmony_ci		u8 enable;
213162306a36Sopenharmony_ci	} data = {
213262306a36Sopenharmony_ci		.cmd = cpu_to_le32(MURU_SET_TXC_TX_STATS_EN),
213362306a36Sopenharmony_ci		.enable = enabled,
213462306a36Sopenharmony_ci	};
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &data,
213762306a36Sopenharmony_ci				sizeof(data), false);
213862306a36Sopenharmony_ci}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ciint mt7915_mcu_muru_debug_get(struct mt7915_phy *phy)
214162306a36Sopenharmony_ci{
214262306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
214362306a36Sopenharmony_ci	struct sk_buff *skb;
214462306a36Sopenharmony_ci	struct mt7915_mcu_muru_stats *mu_stats;
214562306a36Sopenharmony_ci	int ret;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	struct {
214862306a36Sopenharmony_ci		__le32 cmd;
214962306a36Sopenharmony_ci		u8 band_idx;
215062306a36Sopenharmony_ci	} req = {
215162306a36Sopenharmony_ci		.cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS),
215262306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
215362306a36Sopenharmony_ci	};
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL),
215662306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
215762306a36Sopenharmony_ci	if (ret)
215862306a36Sopenharmony_ci		return ret;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci	/* accumulate stats, these are clear-on-read */
216362306a36Sopenharmony_ci#define __dl_u32(s)	 phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s)
216462306a36Sopenharmony_ci#define __ul_u32(s)	 phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s)
216562306a36Sopenharmony_ci	__dl_u32(cck_cnt);
216662306a36Sopenharmony_ci	__dl_u32(ofdm_cnt);
216762306a36Sopenharmony_ci	__dl_u32(htmix_cnt);
216862306a36Sopenharmony_ci	__dl_u32(htgf_cnt);
216962306a36Sopenharmony_ci	__dl_u32(vht_su_cnt);
217062306a36Sopenharmony_ci	__dl_u32(vht_2mu_cnt);
217162306a36Sopenharmony_ci	__dl_u32(vht_3mu_cnt);
217262306a36Sopenharmony_ci	__dl_u32(vht_4mu_cnt);
217362306a36Sopenharmony_ci	__dl_u32(he_su_cnt);
217462306a36Sopenharmony_ci	__dl_u32(he_2ru_cnt);
217562306a36Sopenharmony_ci	__dl_u32(he_2mu_cnt);
217662306a36Sopenharmony_ci	__dl_u32(he_3ru_cnt);
217762306a36Sopenharmony_ci	__dl_u32(he_3mu_cnt);
217862306a36Sopenharmony_ci	__dl_u32(he_4ru_cnt);
217962306a36Sopenharmony_ci	__dl_u32(he_4mu_cnt);
218062306a36Sopenharmony_ci	__dl_u32(he_5to8ru_cnt);
218162306a36Sopenharmony_ci	__dl_u32(he_9to16ru_cnt);
218262306a36Sopenharmony_ci	__dl_u32(he_gtr16ru_cnt);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	__ul_u32(hetrig_su_cnt);
218562306a36Sopenharmony_ci	__ul_u32(hetrig_2ru_cnt);
218662306a36Sopenharmony_ci	__ul_u32(hetrig_3ru_cnt);
218762306a36Sopenharmony_ci	__ul_u32(hetrig_4ru_cnt);
218862306a36Sopenharmony_ci	__ul_u32(hetrig_5to8ru_cnt);
218962306a36Sopenharmony_ci	__ul_u32(hetrig_9to16ru_cnt);
219062306a36Sopenharmony_ci	__ul_u32(hetrig_gtr16ru_cnt);
219162306a36Sopenharmony_ci	__ul_u32(hetrig_2mu_cnt);
219262306a36Sopenharmony_ci	__ul_u32(hetrig_3mu_cnt);
219362306a36Sopenharmony_ci	__ul_u32(hetrig_4mu_cnt);
219462306a36Sopenharmony_ci#undef __dl_u32
219562306a36Sopenharmony_ci#undef __ul_u32
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	dev_kfree_skb(skb);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return 0;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_cistatic int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled)
220362306a36Sopenharmony_ci{
220462306a36Sopenharmony_ci	struct {
220562306a36Sopenharmony_ci		u8 enable;
220662306a36Sopenharmony_ci		u8 _rsv[3];
220762306a36Sopenharmony_ci	} __packed req = {
220862306a36Sopenharmony_ci		.enable = enabled
220962306a36Sopenharmony_ci	};
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req,
221262306a36Sopenharmony_ci				 sizeof(req), false);
221362306a36Sopenharmony_ci}
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ciint mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val)
221662306a36Sopenharmony_ci{
221762306a36Sopenharmony_ci	struct {
221862306a36Sopenharmony_ci		__le32 cmd;
221962306a36Sopenharmony_ci		u8 val[4];
222062306a36Sopenharmony_ci	} __packed req = {
222162306a36Sopenharmony_ci		.cmd = cpu_to_le32(cmd),
222262306a36Sopenharmony_ci	};
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci	put_unaligned_le32(val, req.val);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req,
222762306a36Sopenharmony_ci				 sizeof(req), false);
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cistatic int
223162306a36Sopenharmony_cimt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci#define RX_AIRTIME_FEATURE_CTRL		1
223462306a36Sopenharmony_ci#define RX_AIRTIME_BITWISE_CTRL		2
223562306a36Sopenharmony_ci#define RX_AIRTIME_CLEAR_EN	1
223662306a36Sopenharmony_ci	struct {
223762306a36Sopenharmony_ci		__le16 field;
223862306a36Sopenharmony_ci		__le16 sub_field;
223962306a36Sopenharmony_ci		__le32 set_status;
224062306a36Sopenharmony_ci		__le32 get_status;
224162306a36Sopenharmony_ci		u8 _rsv[12];
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci		bool airtime_en;
224462306a36Sopenharmony_ci		bool mibtime_en;
224562306a36Sopenharmony_ci		bool earlyend_en;
224662306a36Sopenharmony_ci		u8 _rsv1[9];
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci		bool airtime_clear;
224962306a36Sopenharmony_ci		bool mibtime_clear;
225062306a36Sopenharmony_ci		u8 _rsv2[98];
225162306a36Sopenharmony_ci	} __packed req = {
225262306a36Sopenharmony_ci		.field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL),
225362306a36Sopenharmony_ci		.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN),
225462306a36Sopenharmony_ci		.airtime_clear = true,
225562306a36Sopenharmony_ci	};
225662306a36Sopenharmony_ci	int ret;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
225962306a36Sopenharmony_ci				sizeof(req), true);
226062306a36Sopenharmony_ci	if (ret)
226162306a36Sopenharmony_ci		return ret;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL);
226462306a36Sopenharmony_ci	req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN);
226562306a36Sopenharmony_ci	req.airtime_en = true;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
226862306a36Sopenharmony_ci				 sizeof(req), true);
226962306a36Sopenharmony_ci}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_cistatic int mt7915_red_set_watermark(struct mt7915_dev *dev)
227262306a36Sopenharmony_ci{
227362306a36Sopenharmony_ci#define RED_GLOBAL_TOKEN_WATERMARK 2
227462306a36Sopenharmony_ci	struct {
227562306a36Sopenharmony_ci		__le32 args[3];
227662306a36Sopenharmony_ci		u8 cmd;
227762306a36Sopenharmony_ci		u8 version;
227862306a36Sopenharmony_ci		u8 __rsv1[4];
227962306a36Sopenharmony_ci		__le16 len;
228062306a36Sopenharmony_ci		__le16 high_mark;
228162306a36Sopenharmony_ci		__le16 low_mark;
228262306a36Sopenharmony_ci		u8 __rsv2[12];
228362306a36Sopenharmony_ci	} __packed req = {
228462306a36Sopenharmony_ci		.args[0] = cpu_to_le32(MCU_WA_PARAM_RED_SETTING),
228562306a36Sopenharmony_ci		.cmd = RED_GLOBAL_TOKEN_WATERMARK,
228662306a36Sopenharmony_ci		.len = cpu_to_le16(sizeof(req) - sizeof(req.args)),
228762306a36Sopenharmony_ci		.high_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256),
228862306a36Sopenharmony_ci		.low_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256 - 1536),
228962306a36Sopenharmony_ci	};
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET), &req,
229262306a36Sopenharmony_ci				 sizeof(req), false);
229362306a36Sopenharmony_ci}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_cistatic int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
229662306a36Sopenharmony_ci{
229762306a36Sopenharmony_ci#define RED_DISABLE		0
229862306a36Sopenharmony_ci#define RED_BY_WA_ENABLE	2
229962306a36Sopenharmony_ci	int ret;
230062306a36Sopenharmony_ci	u32 red_type = enabled ? RED_BY_WA_ENABLE : RED_DISABLE;
230162306a36Sopenharmony_ci	__le32 req = cpu_to_le32(red_type);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	if (enabled) {
230462306a36Sopenharmony_ci		ret = mt7915_red_set_watermark(dev);
230562306a36Sopenharmony_ci		if (ret < 0)
230662306a36Sopenharmony_ci			return ret;
230762306a36Sopenharmony_ci	}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RED_ENABLE), &req,
231062306a36Sopenharmony_ci				sizeof(req), false);
231162306a36Sopenharmony_ci	if (ret < 0)
231262306a36Sopenharmony_ci		return ret;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
231562306a36Sopenharmony_ci				 MCU_WA_PARAM_RED, enabled, 0);
231662306a36Sopenharmony_ci}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ciint mt7915_mcu_init_firmware(struct mt7915_dev *dev)
231962306a36Sopenharmony_ci{
232062306a36Sopenharmony_ci	int ret;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	/* force firmware operation mode into normal state,
232362306a36Sopenharmony_ci	 * which should be set before firmware download stage.
232462306a36Sopenharmony_ci	 */
232562306a36Sopenharmony_ci	mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	ret = mt7915_driver_own(dev, 0);
232862306a36Sopenharmony_ci	if (ret)
232962306a36Sopenharmony_ci		return ret;
233062306a36Sopenharmony_ci	/* set driver own for band1 when two hif exist */
233162306a36Sopenharmony_ci	if (dev->hif2) {
233262306a36Sopenharmony_ci		ret = mt7915_driver_own(dev, 1);
233362306a36Sopenharmony_ci		if (ret)
233462306a36Sopenharmony_ci			return ret;
233562306a36Sopenharmony_ci	}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	ret = mt7915_load_firmware(dev);
233862306a36Sopenharmony_ci	if (ret)
233962306a36Sopenharmony_ci		return ret;
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
234262306a36Sopenharmony_ci	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0);
234362306a36Sopenharmony_ci	if (ret)
234462306a36Sopenharmony_ci		return ret;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
234762306a36Sopenharmony_ci	if (ret)
234862306a36Sopenharmony_ci		return ret;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
235162306a36Sopenharmony_ci	     is_mt7915(&dev->mt76)) ||
235262306a36Sopenharmony_ci	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
235362306a36Sopenharmony_ci		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	ret = mt7915_mcu_set_mwds(dev, 1);
235662306a36Sopenharmony_ci	if (ret)
235762306a36Sopenharmony_ci		return ret;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE,
236062306a36Sopenharmony_ci				       MURU_PLATFORM_TYPE_PERF_LEVEL_2);
236162306a36Sopenharmony_ci	if (ret)
236262306a36Sopenharmony_ci		return ret;
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	ret = mt7915_mcu_init_rx_airtime(dev);
236562306a36Sopenharmony_ci	if (ret)
236662306a36Sopenharmony_ci		return ret;
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	return mt7915_mcu_set_red(dev, mtk_wed_device_active(&dev->mt76.mmio.wed));
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ciint mt7915_mcu_init(struct mt7915_dev *dev)
237262306a36Sopenharmony_ci{
237362306a36Sopenharmony_ci	static const struct mt76_mcu_ops mt7915_mcu_ops = {
237462306a36Sopenharmony_ci		.headroom = sizeof(struct mt76_connac2_mcu_txd),
237562306a36Sopenharmony_ci		.mcu_skb_send_msg = mt7915_mcu_send_message,
237662306a36Sopenharmony_ci		.mcu_parse_response = mt7915_mcu_parse_response,
237762306a36Sopenharmony_ci	};
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	dev->mt76.mcu_ops = &mt7915_mcu_ops;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	return mt7915_mcu_init_firmware(dev);
238262306a36Sopenharmony_ci}
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_civoid mt7915_mcu_exit(struct mt7915_dev *dev)
238562306a36Sopenharmony_ci{
238662306a36Sopenharmony_ci	mt76_connac_mcu_restart(&dev->mt76);
238762306a36Sopenharmony_ci	if (mt7915_firmware_state(dev, false)) {
238862306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "Failed to exit mcu\n");
238962306a36Sopenharmony_ci		goto out;
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
239362306a36Sopenharmony_ci	if (dev->hif2)
239462306a36Sopenharmony_ci		mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
239562306a36Sopenharmony_ci			MT_TOP_LPCR_HOST_FW_OWN);
239662306a36Sopenharmony_ciout:
239762306a36Sopenharmony_ci	skb_queue_purge(&dev->mt76.mcu.res_q);
239862306a36Sopenharmony_ci}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_cistatic int
240162306a36Sopenharmony_cimt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band)
240262306a36Sopenharmony_ci{
240362306a36Sopenharmony_ci	struct {
240462306a36Sopenharmony_ci		u8 operation;
240562306a36Sopenharmony_ci		u8 count;
240662306a36Sopenharmony_ci		u8 _rsv[2];
240762306a36Sopenharmony_ci		u8 index;
240862306a36Sopenharmony_ci		u8 enable;
240962306a36Sopenharmony_ci		__le16 etype;
241062306a36Sopenharmony_ci	} req = {
241162306a36Sopenharmony_ci		.operation = 1,
241262306a36Sopenharmony_ci		.count = 1,
241362306a36Sopenharmony_ci		.enable = 1,
241462306a36Sopenharmony_ci		.etype = cpu_to_le16(ETH_P_PAE),
241562306a36Sopenharmony_ci	};
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
241862306a36Sopenharmony_ci				 &req, sizeof(req), false);
241962306a36Sopenharmony_ci}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ciint mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
242262306a36Sopenharmony_ci		       bool enable, bool hdr_trans)
242362306a36Sopenharmony_ci{
242462306a36Sopenharmony_ci	struct {
242562306a36Sopenharmony_ci		u8 operation;
242662306a36Sopenharmony_ci		u8 enable;
242762306a36Sopenharmony_ci		u8 check_bssid;
242862306a36Sopenharmony_ci		u8 insert_vlan;
242962306a36Sopenharmony_ci		u8 remove_vlan;
243062306a36Sopenharmony_ci		u8 tid;
243162306a36Sopenharmony_ci		u8 mode;
243262306a36Sopenharmony_ci		u8 rsv;
243362306a36Sopenharmony_ci	} __packed req_trans = {
243462306a36Sopenharmony_ci		.enable = hdr_trans,
243562306a36Sopenharmony_ci	};
243662306a36Sopenharmony_ci	struct {
243762306a36Sopenharmony_ci		u8 enable;
243862306a36Sopenharmony_ci		u8 band;
243962306a36Sopenharmony_ci		u8 rsv[2];
244062306a36Sopenharmony_ci	} __packed req_mac = {
244162306a36Sopenharmony_ci		.enable = enable,
244262306a36Sopenharmony_ci		.band = band,
244362306a36Sopenharmony_ci	};
244462306a36Sopenharmony_ci	int ret;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
244762306a36Sopenharmony_ci				&req_trans, sizeof(req_trans), false);
244862306a36Sopenharmony_ci	if (ret)
244962306a36Sopenharmony_ci		return ret;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	if (hdr_trans)
245262306a36Sopenharmony_ci		mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band);
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL),
245562306a36Sopenharmony_ci				 &req_mac, sizeof(req_mac), true);
245662306a36Sopenharmony_ci}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ciint mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param)
245962306a36Sopenharmony_ci{
246062306a36Sopenharmony_ci	struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param;
246162306a36Sopenharmony_ci	u8 num = req->total;
246262306a36Sopenharmony_ci	size_t len = sizeof(*req) -
246362306a36Sopenharmony_ci		     (IEEE80211_NUM_ACS - num) * sizeof(struct edca);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req,
246662306a36Sopenharmony_ci				 len, true);
246762306a36Sopenharmony_ci}
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ciint mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
247062306a36Sopenharmony_ci{
247162306a36Sopenharmony_ci#define TX_CMD_MODE		1
247262306a36Sopenharmony_ci	struct mt7915_mcu_tx req = {
247362306a36Sopenharmony_ci		.valid = true,
247462306a36Sopenharmony_ci		.mode = TX_CMD_MODE,
247562306a36Sopenharmony_ci		.total = IEEE80211_NUM_ACS,
247662306a36Sopenharmony_ci	};
247762306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
247862306a36Sopenharmony_ci	int ac;
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
248162306a36Sopenharmony_ci		struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
248262306a36Sopenharmony_ci		struct edca *e = &req.edca[ac];
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci		e->set = WMM_PARAM_SET;
248562306a36Sopenharmony_ci		e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
248662306a36Sopenharmony_ci		e->aifs = q->aifs;
248762306a36Sopenharmony_ci		e->txop = cpu_to_le16(q->txop);
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci		if (q->cw_min)
249062306a36Sopenharmony_ci			e->cw_min = fls(q->cw_min);
249162306a36Sopenharmony_ci		else
249262306a36Sopenharmony_ci			e->cw_min = 5;
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_ci		if (q->cw_max)
249562306a36Sopenharmony_ci			e->cw_max = cpu_to_le16(fls(q->cw_max));
249662306a36Sopenharmony_ci		else
249762306a36Sopenharmony_ci			e->cw_max = cpu_to_le16(10);
249862306a36Sopenharmony_ci	}
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	return mt7915_mcu_update_edca(dev, &req);
250162306a36Sopenharmony_ci}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ciint mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val)
250462306a36Sopenharmony_ci{
250562306a36Sopenharmony_ci	struct {
250662306a36Sopenharmony_ci		__le32 tag;
250762306a36Sopenharmony_ci		__le16 min_lpn;
250862306a36Sopenharmony_ci		u8 rsv[2];
250962306a36Sopenharmony_ci	} __packed req = {
251062306a36Sopenharmony_ci		.tag = cpu_to_le32(0x1),
251162306a36Sopenharmony_ci		.min_lpn = cpu_to_le16(val),
251262306a36Sopenharmony_ci	};
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
251562306a36Sopenharmony_ci				 sizeof(req), true);
251662306a36Sopenharmony_ci}
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ciint mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
251962306a36Sopenharmony_ci			    const struct mt7915_dfs_pulse *pulse)
252062306a36Sopenharmony_ci{
252162306a36Sopenharmony_ci	struct {
252262306a36Sopenharmony_ci		__le32 tag;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci		__le32 max_width;		/* us */
252562306a36Sopenharmony_ci		__le32 max_pwr;			/* dbm */
252662306a36Sopenharmony_ci		__le32 min_pwr;			/* dbm */
252762306a36Sopenharmony_ci		__le32 min_stgr_pri;		/* us */
252862306a36Sopenharmony_ci		__le32 max_stgr_pri;		/* us */
252962306a36Sopenharmony_ci		__le32 min_cr_pri;		/* us */
253062306a36Sopenharmony_ci		__le32 max_cr_pri;		/* us */
253162306a36Sopenharmony_ci	} __packed req = {
253262306a36Sopenharmony_ci		.tag = cpu_to_le32(0x3),
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci#define __req_field(field) .field = cpu_to_le32(pulse->field)
253562306a36Sopenharmony_ci		__req_field(max_width),
253662306a36Sopenharmony_ci		__req_field(max_pwr),
253762306a36Sopenharmony_ci		__req_field(min_pwr),
253862306a36Sopenharmony_ci		__req_field(min_stgr_pri),
253962306a36Sopenharmony_ci		__req_field(max_stgr_pri),
254062306a36Sopenharmony_ci		__req_field(min_cr_pri),
254162306a36Sopenharmony_ci		__req_field(max_cr_pri),
254262306a36Sopenharmony_ci#undef __req_field
254362306a36Sopenharmony_ci	};
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
254662306a36Sopenharmony_ci				 sizeof(req), true);
254762306a36Sopenharmony_ci}
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ciint mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
255062306a36Sopenharmony_ci			    const struct mt7915_dfs_pattern *pattern)
255162306a36Sopenharmony_ci{
255262306a36Sopenharmony_ci	struct {
255362306a36Sopenharmony_ci		__le32 tag;
255462306a36Sopenharmony_ci		__le16 radar_type;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci		u8 enb;
255762306a36Sopenharmony_ci		u8 stgr;
255862306a36Sopenharmony_ci		u8 min_crpn;
255962306a36Sopenharmony_ci		u8 max_crpn;
256062306a36Sopenharmony_ci		u8 min_crpr;
256162306a36Sopenharmony_ci		u8 min_pw;
256262306a36Sopenharmony_ci		__le32 min_pri;
256362306a36Sopenharmony_ci		__le32 max_pri;
256462306a36Sopenharmony_ci		u8 max_pw;
256562306a36Sopenharmony_ci		u8 min_crbn;
256662306a36Sopenharmony_ci		u8 max_crbn;
256762306a36Sopenharmony_ci		u8 min_stgpn;
256862306a36Sopenharmony_ci		u8 max_stgpn;
256962306a36Sopenharmony_ci		u8 min_stgpr;
257062306a36Sopenharmony_ci		u8 rsv[2];
257162306a36Sopenharmony_ci		__le32 min_stgpr_diff;
257262306a36Sopenharmony_ci	} __packed req = {
257362306a36Sopenharmony_ci		.tag = cpu_to_le32(0x2),
257462306a36Sopenharmony_ci		.radar_type = cpu_to_le16(index),
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci#define __req_field_u8(field) .field = pattern->field
257762306a36Sopenharmony_ci#define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
257862306a36Sopenharmony_ci		__req_field_u8(enb),
257962306a36Sopenharmony_ci		__req_field_u8(stgr),
258062306a36Sopenharmony_ci		__req_field_u8(min_crpn),
258162306a36Sopenharmony_ci		__req_field_u8(max_crpn),
258262306a36Sopenharmony_ci		__req_field_u8(min_crpr),
258362306a36Sopenharmony_ci		__req_field_u8(min_pw),
258462306a36Sopenharmony_ci		__req_field_u32(min_pri),
258562306a36Sopenharmony_ci		__req_field_u32(max_pri),
258662306a36Sopenharmony_ci		__req_field_u8(max_pw),
258762306a36Sopenharmony_ci		__req_field_u8(min_crbn),
258862306a36Sopenharmony_ci		__req_field_u8(max_crbn),
258962306a36Sopenharmony_ci		__req_field_u8(min_stgpn),
259062306a36Sopenharmony_ci		__req_field_u8(max_stgpn),
259162306a36Sopenharmony_ci		__req_field_u8(min_stgpr),
259262306a36Sopenharmony_ci		__req_field_u32(min_stgpr_diff),
259362306a36Sopenharmony_ci#undef __req_field_u8
259462306a36Sopenharmony_ci#undef __req_field_u32
259562306a36Sopenharmony_ci	};
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
259862306a36Sopenharmony_ci				 sizeof(req), true);
259962306a36Sopenharmony_ci}
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_cistatic int
260262306a36Sopenharmony_cimt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
260362306a36Sopenharmony_ci				 struct cfg80211_chan_def *chandef,
260462306a36Sopenharmony_ci				 int cmd)
260562306a36Sopenharmony_ci{
260662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
260762306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
260862306a36Sopenharmony_ci	struct ieee80211_channel *chan = mphy->chandef.chan;
260962306a36Sopenharmony_ci	int freq = mphy->chandef.center_freq1;
261062306a36Sopenharmony_ci	struct mt7915_mcu_background_chain_ctrl req = {
261162306a36Sopenharmony_ci		.monitor_scan_type = 2, /* simple rx */
261262306a36Sopenharmony_ci	};
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP)
261562306a36Sopenharmony_ci		return -EINVAL;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	if (!cfg80211_chandef_valid(&mphy->chandef))
261862306a36Sopenharmony_ci		return -EINVAL;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	switch (cmd) {
262162306a36Sopenharmony_ci	case CH_SWITCH_BACKGROUND_SCAN_START: {
262262306a36Sopenharmony_ci		req.chan = chan->hw_value;
262362306a36Sopenharmony_ci		req.central_chan = ieee80211_frequency_to_channel(freq);
262462306a36Sopenharmony_ci		req.bw = mt76_connac_chan_bw(&mphy->chandef);
262562306a36Sopenharmony_ci		req.monitor_chan = chandef->chan->hw_value;
262662306a36Sopenharmony_ci		req.monitor_central_chan =
262762306a36Sopenharmony_ci			ieee80211_frequency_to_channel(chandef->center_freq1);
262862306a36Sopenharmony_ci		req.monitor_bw = mt76_connac_chan_bw(chandef);
262962306a36Sopenharmony_ci		req.band_idx = phy->mt76->band_idx;
263062306a36Sopenharmony_ci		req.scan_mode = 1;
263162306a36Sopenharmony_ci		break;
263262306a36Sopenharmony_ci	}
263362306a36Sopenharmony_ci	case CH_SWITCH_BACKGROUND_SCAN_RUNNING:
263462306a36Sopenharmony_ci		req.monitor_chan = chandef->chan->hw_value;
263562306a36Sopenharmony_ci		req.monitor_central_chan =
263662306a36Sopenharmony_ci			ieee80211_frequency_to_channel(chandef->center_freq1);
263762306a36Sopenharmony_ci		req.band_idx = phy->mt76->band_idx;
263862306a36Sopenharmony_ci		req.scan_mode = 2;
263962306a36Sopenharmony_ci		break;
264062306a36Sopenharmony_ci	case CH_SWITCH_BACKGROUND_SCAN_STOP:
264162306a36Sopenharmony_ci		req.chan = chan->hw_value;
264262306a36Sopenharmony_ci		req.central_chan = ieee80211_frequency_to_channel(freq);
264362306a36Sopenharmony_ci		req.bw = mt76_connac_chan_bw(&mphy->chandef);
264462306a36Sopenharmony_ci		req.tx_stream = hweight8(mphy->antenna_mask);
264562306a36Sopenharmony_ci		req.rx_stream = mphy->antenna_mask;
264662306a36Sopenharmony_ci		break;
264762306a36Sopenharmony_ci	default:
264862306a36Sopenharmony_ci		return -EINVAL;
264962306a36Sopenharmony_ci	}
265062306a36Sopenharmony_ci	req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1;
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL),
265362306a36Sopenharmony_ci				 &req, sizeof(req), false);
265462306a36Sopenharmony_ci}
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ciint mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
265762306a36Sopenharmony_ci				     struct cfg80211_chan_def *chandef)
265862306a36Sopenharmony_ci{
265962306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
266062306a36Sopenharmony_ci	int err, region;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	if (!chandef) { /* disable offchain */
266362306a36Sopenharmony_ci		err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2,
266462306a36Sopenharmony_ci					      0, 0);
266562306a36Sopenharmony_ci		if (err)
266662306a36Sopenharmony_ci			return err;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci		return mt7915_mcu_background_chain_ctrl(phy, NULL,
266962306a36Sopenharmony_ci				CH_SWITCH_BACKGROUND_SCAN_STOP);
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	err = mt7915_mcu_background_chain_ctrl(phy, chandef,
267362306a36Sopenharmony_ci					       CH_SWITCH_BACKGROUND_SCAN_START);
267462306a36Sopenharmony_ci	if (err)
267562306a36Sopenharmony_ci		return err;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	switch (dev->mt76.region) {
267862306a36Sopenharmony_ci	case NL80211_DFS_ETSI:
267962306a36Sopenharmony_ci		region = 0;
268062306a36Sopenharmony_ci		break;
268162306a36Sopenharmony_ci	case NL80211_DFS_JP:
268262306a36Sopenharmony_ci		region = 2;
268362306a36Sopenharmony_ci		break;
268462306a36Sopenharmony_ci	case NL80211_DFS_FCC:
268562306a36Sopenharmony_ci	default:
268662306a36Sopenharmony_ci		region = 1;
268762306a36Sopenharmony_ci		break;
268862306a36Sopenharmony_ci	}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2,
269162306a36Sopenharmony_ci				       0, region);
269262306a36Sopenharmony_ci}
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ciint mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
269562306a36Sopenharmony_ci{
269662306a36Sopenharmony_ci	static const u8 ch_band[] = {
269762306a36Sopenharmony_ci		[NL80211_BAND_2GHZ] = 0,
269862306a36Sopenharmony_ci		[NL80211_BAND_5GHZ] = 1,
269962306a36Sopenharmony_ci		[NL80211_BAND_6GHZ] = 2,
270062306a36Sopenharmony_ci	};
270162306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
270262306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
270362306a36Sopenharmony_ci	int freq1 = chandef->center_freq1;
270462306a36Sopenharmony_ci	u8 band = phy->mt76->band_idx;
270562306a36Sopenharmony_ci	struct {
270662306a36Sopenharmony_ci		u8 control_ch;
270762306a36Sopenharmony_ci		u8 center_ch;
270862306a36Sopenharmony_ci		u8 bw;
270962306a36Sopenharmony_ci		u8 tx_path_num;
271062306a36Sopenharmony_ci		u8 rx_path;	/* mask or num */
271162306a36Sopenharmony_ci		u8 switch_reason;
271262306a36Sopenharmony_ci		u8 band_idx;
271362306a36Sopenharmony_ci		u8 center_ch2;	/* for 80+80 only */
271462306a36Sopenharmony_ci		__le16 cac_case;
271562306a36Sopenharmony_ci		u8 channel_band;
271662306a36Sopenharmony_ci		u8 rsv0;
271762306a36Sopenharmony_ci		__le32 outband_freq;
271862306a36Sopenharmony_ci		u8 txpower_drop;
271962306a36Sopenharmony_ci		u8 ap_bw;
272062306a36Sopenharmony_ci		u8 ap_center_ch;
272162306a36Sopenharmony_ci		u8 rsv1[57];
272262306a36Sopenharmony_ci	} __packed req = {
272362306a36Sopenharmony_ci		.control_ch = chandef->chan->hw_value,
272462306a36Sopenharmony_ci		.center_ch = ieee80211_frequency_to_channel(freq1),
272562306a36Sopenharmony_ci		.bw = mt76_connac_chan_bw(chandef),
272662306a36Sopenharmony_ci		.tx_path_num = hweight16(phy->mt76->chainmask),
272762306a36Sopenharmony_ci		.rx_path = phy->mt76->chainmask >> (dev->chainshift * band),
272862306a36Sopenharmony_ci		.band_idx = band,
272962306a36Sopenharmony_ci		.channel_band = ch_band[chandef->chan->band],
273062306a36Sopenharmony_ci	};
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
273362306a36Sopenharmony_ci	if (phy->mt76->test.tx_antenna_mask &&
273462306a36Sopenharmony_ci	    mt76_testmode_enabled(phy->mt76)) {
273562306a36Sopenharmony_ci		req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask);
273662306a36Sopenharmony_ci		req.rx_path = phy->mt76->test.tx_antenna_mask;
273762306a36Sopenharmony_ci	}
273862306a36Sopenharmony_ci#endif
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	if (mt76_connac_spe_idx(phy->mt76->antenna_mask))
274162306a36Sopenharmony_ci		req.tx_path_num = fls(phy->mt76->antenna_mask);
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
274462306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_NORMAL;
274562306a36Sopenharmony_ci	else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
274662306a36Sopenharmony_ci		 phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
274762306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
274862306a36Sopenharmony_ci	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
274962306a36Sopenharmony_ci					  NL80211_IFTYPE_AP))
275062306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_DFS;
275162306a36Sopenharmony_ci	else
275262306a36Sopenharmony_ci		req.switch_reason = CH_SWITCH_NORMAL;
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
275562306a36Sopenharmony_ci		req.rx_path = hweight8(req.rx_path);
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
275862306a36Sopenharmony_ci		int freq2 = chandef->center_freq2;
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci		req.center_ch2 = ieee80211_frequency_to_channel(freq2);
276162306a36Sopenharmony_ci	}
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
276462306a36Sopenharmony_ci}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_cistatic int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci#define MAX_PAGE_IDX_MASK	GENMASK(7, 5)
276962306a36Sopenharmony_ci#define PAGE_IDX_MASK		GENMASK(4, 2)
277062306a36Sopenharmony_ci#define PER_PAGE_SIZE		0x400
277162306a36Sopenharmony_ci	struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER };
277262306a36Sopenharmony_ci	u16 eeprom_size = mt7915_eeprom_size(dev);
277362306a36Sopenharmony_ci	u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE);
277462306a36Sopenharmony_ci	u8 *eep = (u8 *)dev->mt76.eeprom.data;
277562306a36Sopenharmony_ci	int eep_len;
277662306a36Sopenharmony_ci	int i;
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci	for (i = 0; i < total; i++, eep += eep_len) {
277962306a36Sopenharmony_ci		struct sk_buff *skb;
278062306a36Sopenharmony_ci		int ret;
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci		if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE))
278362306a36Sopenharmony_ci			eep_len = eeprom_size % PER_PAGE_SIZE;
278462306a36Sopenharmony_ci		else
278562306a36Sopenharmony_ci			eep_len = PER_PAGE_SIZE;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
278862306a36Sopenharmony_ci					 sizeof(req) + eep_len);
278962306a36Sopenharmony_ci		if (!skb)
279062306a36Sopenharmony_ci			return -ENOMEM;
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci		req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
279362306a36Sopenharmony_ci			     FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
279462306a36Sopenharmony_ci		req.len = cpu_to_le16(eep_len);
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci		skb_put_data(skb, &req, sizeof(req));
279762306a36Sopenharmony_ci		skb_put_data(skb, eep, eep_len);
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci		ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
280062306a36Sopenharmony_ci					    MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
280162306a36Sopenharmony_ci		if (ret)
280262306a36Sopenharmony_ci			return ret;
280362306a36Sopenharmony_ci	}
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	return 0;
280662306a36Sopenharmony_ci}
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ciint mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
280962306a36Sopenharmony_ci{
281062306a36Sopenharmony_ci	struct mt7915_mcu_eeprom req = {
281162306a36Sopenharmony_ci		.buffer_mode = EE_MODE_EFUSE,
281262306a36Sopenharmony_ci		.format = EE_FORMAT_WHOLE,
281362306a36Sopenharmony_ci	};
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	if (dev->flash_mode)
281662306a36Sopenharmony_ci		return mt7915_mcu_set_eeprom_flash(dev);
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
281962306a36Sopenharmony_ci				 &req, sizeof(req), true);
282062306a36Sopenharmony_ci}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ciint mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
282362306a36Sopenharmony_ci{
282462306a36Sopenharmony_ci	struct mt7915_mcu_eeprom_info req = {
282562306a36Sopenharmony_ci		.addr = cpu_to_le32(round_down(offset,
282662306a36Sopenharmony_ci				    MT7915_EEPROM_BLOCK_SIZE)),
282762306a36Sopenharmony_ci	};
282862306a36Sopenharmony_ci	struct mt7915_mcu_eeprom_info *res;
282962306a36Sopenharmony_ci	struct sk_buff *skb;
283062306a36Sopenharmony_ci	int ret;
283162306a36Sopenharmony_ci	u8 *buf;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
283462306a36Sopenharmony_ci					MCU_EXT_QUERY(EFUSE_ACCESS),
283562306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
283662306a36Sopenharmony_ci	if (ret)
283762306a36Sopenharmony_ci		return ret;
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	res = (struct mt7915_mcu_eeprom_info *)skb->data;
284062306a36Sopenharmony_ci	buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
284162306a36Sopenharmony_ci	memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
284262306a36Sopenharmony_ci	dev_kfree_skb(skb);
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	return 0;
284562306a36Sopenharmony_ci}
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ciint mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num)
284862306a36Sopenharmony_ci{
284962306a36Sopenharmony_ci	struct {
285062306a36Sopenharmony_ci		u8 _rsv;
285162306a36Sopenharmony_ci		u8 version;
285262306a36Sopenharmony_ci		u8 die_idx;
285362306a36Sopenharmony_ci		u8 _rsv2;
285462306a36Sopenharmony_ci	} __packed req = {
285562306a36Sopenharmony_ci		.version = 1,
285662306a36Sopenharmony_ci	};
285762306a36Sopenharmony_ci	struct sk_buff *skb;
285862306a36Sopenharmony_ci	int ret;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
286162306a36Sopenharmony_ci					MCU_EXT_QUERY(EFUSE_FREE_BLOCK),
286262306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
286362306a36Sopenharmony_ci	if (ret)
286462306a36Sopenharmony_ci		return ret;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	*block_num = *(u8 *)skb->data;
286762306a36Sopenharmony_ci	dev_kfree_skb(skb);
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	return 0;
287062306a36Sopenharmony_ci}
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_cistatic int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
287362306a36Sopenharmony_ci				  u8 *data, u32 len, int cmd)
287462306a36Sopenharmony_ci{
287562306a36Sopenharmony_ci	struct {
287662306a36Sopenharmony_ci		u8 dir;
287762306a36Sopenharmony_ci		u8 valid;
287862306a36Sopenharmony_ci		__le16 bitmap;
287962306a36Sopenharmony_ci		s8 precal;
288062306a36Sopenharmony_ci		u8 action;
288162306a36Sopenharmony_ci		u8 band;
288262306a36Sopenharmony_ci		u8 idx;
288362306a36Sopenharmony_ci		u8 rsv[4];
288462306a36Sopenharmony_ci		__le32 len;
288562306a36Sopenharmony_ci	} req = {};
288662306a36Sopenharmony_ci	struct sk_buff *skb;
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
288962306a36Sopenharmony_ci	if (!skb)
289062306a36Sopenharmony_ci		return -ENOMEM;
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	req.idx = idx;
289362306a36Sopenharmony_ci	req.len = cpu_to_le32(len);
289462306a36Sopenharmony_ci	skb_put_data(skb, &req, sizeof(req));
289562306a36Sopenharmony_ci	skb_put_data(skb, data, len);
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false);
289862306a36Sopenharmony_ci}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ciint mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
290162306a36Sopenharmony_ci{
290262306a36Sopenharmony_ci	u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
290362306a36Sopenharmony_ci	u32 total = MT_EE_CAL_GROUP_SIZE;
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_ci	if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP))
290662306a36Sopenharmony_ci		return 0;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	/*
290962306a36Sopenharmony_ci	 * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG
291062306a36Sopenharmony_ci	 * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC
291162306a36Sopenharmony_ci	 */
291262306a36Sopenharmony_ci	while (total > 0) {
291362306a36Sopenharmony_ci		int ret, len;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci		len = min_t(u32, total, MT_EE_CAL_UNIT);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci		ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len,
291862306a36Sopenharmony_ci					     MCU_EXT_CMD(GROUP_PRE_CAL_INFO));
291962306a36Sopenharmony_ci		if (ret)
292062306a36Sopenharmony_ci			return ret;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci		total -= len;
292362306a36Sopenharmony_ci		cal += len;
292462306a36Sopenharmony_ci		idx++;
292562306a36Sopenharmony_ci	}
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	return 0;
292862306a36Sopenharmony_ci}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_cistatic int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	int i;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	for (i = 0; i < n_freqs; i++)
293562306a36Sopenharmony_ci		if (cur == freqs[i])
293662306a36Sopenharmony_ci			return i;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	return -1;
293962306a36Sopenharmony_ci}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_cistatic int mt7915_dpd_freq_idx(u16 freq, u8 bw)
294262306a36Sopenharmony_ci{
294362306a36Sopenharmony_ci	static const u16 freq_list[] = {
294462306a36Sopenharmony_ci		5180, 5200, 5220, 5240,
294562306a36Sopenharmony_ci		5260, 5280, 5300, 5320,
294662306a36Sopenharmony_ci		5500, 5520, 5540, 5560,
294762306a36Sopenharmony_ci		5580, 5600, 5620, 5640,
294862306a36Sopenharmony_ci		5660, 5680, 5700, 5745,
294962306a36Sopenharmony_ci		5765, 5785, 5805, 5825
295062306a36Sopenharmony_ci	};
295162306a36Sopenharmony_ci	int offset_2g = ARRAY_SIZE(freq_list);
295262306a36Sopenharmony_ci	int idx;
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	if (freq < 4000) {
295562306a36Sopenharmony_ci		if (freq < 2432)
295662306a36Sopenharmony_ci			return offset_2g;
295762306a36Sopenharmony_ci		if (freq < 2457)
295862306a36Sopenharmony_ci			return offset_2g + 1;
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci		return offset_2g + 2;
296162306a36Sopenharmony_ci	}
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	if (bw == NL80211_CHAN_WIDTH_80P80 || bw == NL80211_CHAN_WIDTH_160)
296462306a36Sopenharmony_ci		return -1;
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci	if (bw != NL80211_CHAN_WIDTH_20) {
296762306a36Sopenharmony_ci		idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
296862306a36Sopenharmony_ci					   freq + 10);
296962306a36Sopenharmony_ci		if (idx >= 0)
297062306a36Sopenharmony_ci			return idx;
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci		idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
297362306a36Sopenharmony_ci					   freq - 10);
297462306a36Sopenharmony_ci		if (idx >= 0)
297562306a36Sopenharmony_ci			return idx;
297662306a36Sopenharmony_ci	}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	return mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
297962306a36Sopenharmony_ci}
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ciint mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
298262306a36Sopenharmony_ci{
298362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
298462306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
298562306a36Sopenharmony_ci	u16 total = 2, center_freq = chandef->center_freq1;
298662306a36Sopenharmony_ci	u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
298762306a36Sopenharmony_ci	int idx;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD))
299062306a36Sopenharmony_ci		return 0;
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
299362306a36Sopenharmony_ci	if (idx < 0)
299462306a36Sopenharmony_ci		return -EINVAL;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	/* Items: Tx DPD, Tx Flatness */
299762306a36Sopenharmony_ci	idx = idx * 2;
299862306a36Sopenharmony_ci	cal += MT_EE_CAL_GROUP_SIZE;
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_ci	while (total--) {
300162306a36Sopenharmony_ci		int ret;
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci		cal += (idx * MT_EE_CAL_UNIT);
300462306a36Sopenharmony_ci		ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT,
300562306a36Sopenharmony_ci					     MCU_EXT_CMD(DPD_PRE_CAL_INFO));
300662306a36Sopenharmony_ci		if (ret)
300762306a36Sopenharmony_ci			return ret;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci		idx++;
301062306a36Sopenharmony_ci	}
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	return 0;
301362306a36Sopenharmony_ci}
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ciint mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch)
301662306a36Sopenharmony_ci{
301762306a36Sopenharmony_ci	struct mt76_channel_state *state = phy->mt76->chan_state;
301862306a36Sopenharmony_ci	struct mt76_channel_state *state_ts = &phy->state_ts;
301962306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
302062306a36Sopenharmony_ci	struct mt7915_mcu_mib *res, req[5];
302162306a36Sopenharmony_ci	struct sk_buff *skb;
302262306a36Sopenharmony_ci	static const u32 *offs;
302362306a36Sopenharmony_ci	int i, ret, len, offs_cc;
302462306a36Sopenharmony_ci	u64 cc_tx;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	/* strict order */
302762306a36Sopenharmony_ci	if (is_mt7915(&dev->mt76)) {
302862306a36Sopenharmony_ci		static const u32 chip_offs[] = {
302962306a36Sopenharmony_ci			MIB_NON_WIFI_TIME,
303062306a36Sopenharmony_ci			MIB_TX_TIME,
303162306a36Sopenharmony_ci			MIB_RX_TIME,
303262306a36Sopenharmony_ci			MIB_OBSS_AIRTIME,
303362306a36Sopenharmony_ci			MIB_TXOP_INIT_COUNT,
303462306a36Sopenharmony_ci		};
303562306a36Sopenharmony_ci		len = ARRAY_SIZE(chip_offs);
303662306a36Sopenharmony_ci		offs = chip_offs;
303762306a36Sopenharmony_ci		offs_cc = 20;
303862306a36Sopenharmony_ci	} else {
303962306a36Sopenharmony_ci		static const u32 chip_offs[] = {
304062306a36Sopenharmony_ci			MIB_NON_WIFI_TIME_V2,
304162306a36Sopenharmony_ci			MIB_TX_TIME_V2,
304262306a36Sopenharmony_ci			MIB_RX_TIME_V2,
304362306a36Sopenharmony_ci			MIB_OBSS_AIRTIME_V2
304462306a36Sopenharmony_ci		};
304562306a36Sopenharmony_ci		len = ARRAY_SIZE(chip_offs);
304662306a36Sopenharmony_ci		offs = chip_offs;
304762306a36Sopenharmony_ci		offs_cc = 0;
304862306a36Sopenharmony_ci	}
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
305162306a36Sopenharmony_ci		req[i].band = cpu_to_le32(phy->mt76->band_idx);
305262306a36Sopenharmony_ci		req[i].offs = cpu_to_le32(offs[i]);
305362306a36Sopenharmony_ci	}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO),
305662306a36Sopenharmony_ci					req, len * sizeof(req[0]), true, &skb);
305762306a36Sopenharmony_ci	if (ret)
305862306a36Sopenharmony_ci		return ret;
305962306a36Sopenharmony_ci
306062306a36Sopenharmony_ci	res = (struct mt7915_mcu_mib *)(skb->data + offs_cc);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci#define __res_u64(s) le64_to_cpu(res[s].data)
306362306a36Sopenharmony_ci	/* subtract Tx backoff time from Tx duration */
306462306a36Sopenharmony_ci	cc_tx = is_mt7915(&dev->mt76) ? __res_u64(1) - __res_u64(4) : __res_u64(1);
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	if (chan_switch)
306762306a36Sopenharmony_ci		goto out;
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_ci	state->cc_tx += cc_tx - state_ts->cc_tx;
307062306a36Sopenharmony_ci	state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx;
307162306a36Sopenharmony_ci	state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx;
307262306a36Sopenharmony_ci	state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) -
307362306a36Sopenharmony_ci			  state_ts->cc_busy;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ciout:
307662306a36Sopenharmony_ci	state_ts->cc_tx = cc_tx;
307762306a36Sopenharmony_ci	state_ts->cc_bss_rx = __res_u64(2);
307862306a36Sopenharmony_ci	state_ts->cc_rx = __res_u64(2) + __res_u64(3);
307962306a36Sopenharmony_ci	state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3);
308062306a36Sopenharmony_ci#undef __res_u64
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	dev_kfree_skb(skb);
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	return 0;
308562306a36Sopenharmony_ci}
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ciint mt7915_mcu_get_temperature(struct mt7915_phy *phy)
308862306a36Sopenharmony_ci{
308962306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
309062306a36Sopenharmony_ci	struct {
309162306a36Sopenharmony_ci		u8 ctrl_id;
309262306a36Sopenharmony_ci		u8 action;
309362306a36Sopenharmony_ci		u8 band_idx;
309462306a36Sopenharmony_ci		u8 rsv[5];
309562306a36Sopenharmony_ci	} req = {
309662306a36Sopenharmony_ci		.ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
309762306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
309862306a36Sopenharmony_ci	};
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
310162306a36Sopenharmony_ci				 sizeof(req), true);
310262306a36Sopenharmony_ci}
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ciint mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
310562306a36Sopenharmony_ci{
310662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
310762306a36Sopenharmony_ci	struct mt7915_mcu_thermal_ctrl req = {
310862306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
310962306a36Sopenharmony_ci		.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG,
311062306a36Sopenharmony_ci	};
311162306a36Sopenharmony_ci	int level, ret;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	/* set duty cycle and level */
311462306a36Sopenharmony_ci	for (level = 0; level < 4; level++) {
311562306a36Sopenharmony_ci		req.duty.duty_level = level;
311662306a36Sopenharmony_ci		req.duty.duty_cycle = state;
311762306a36Sopenharmony_ci		state /= 2;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci		ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
312062306a36Sopenharmony_ci					&req, sizeof(req), false);
312162306a36Sopenharmony_ci		if (ret)
312262306a36Sopenharmony_ci			return ret;
312362306a36Sopenharmony_ci	}
312462306a36Sopenharmony_ci	return 0;
312562306a36Sopenharmony_ci}
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ciint mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy)
312862306a36Sopenharmony_ci{
312962306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
313062306a36Sopenharmony_ci	struct {
313162306a36Sopenharmony_ci		struct mt7915_mcu_thermal_ctrl ctrl;
313262306a36Sopenharmony_ci
313362306a36Sopenharmony_ci		__le32 trigger_temp;
313462306a36Sopenharmony_ci		__le32 restore_temp;
313562306a36Sopenharmony_ci		__le16 sustain_time;
313662306a36Sopenharmony_ci		u8 rsv[2];
313762306a36Sopenharmony_ci	} __packed req = {
313862306a36Sopenharmony_ci		.ctrl = {
313962306a36Sopenharmony_ci			.band_idx = phy->mt76->band_idx,
314062306a36Sopenharmony_ci			.type.protect_type = 1,
314162306a36Sopenharmony_ci			.type.trigger_type = 1,
314262306a36Sopenharmony_ci		},
314362306a36Sopenharmony_ci	};
314462306a36Sopenharmony_ci	int ret;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
314762306a36Sopenharmony_ci	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
314862306a36Sopenharmony_ci				&req, sizeof(req.ctrl), false);
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci	if (ret)
315162306a36Sopenharmony_ci		return ret;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	/* set high-temperature trigger threshold */
315462306a36Sopenharmony_ci	req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
315562306a36Sopenharmony_ci	/* add a safety margin ~10 */
315662306a36Sopenharmony_ci	req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
315762306a36Sopenharmony_ci	req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
315862306a36Sopenharmony_ci	req.sustain_time = cpu_to_le16(10);
315962306a36Sopenharmony_ci
316062306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
316162306a36Sopenharmony_ci				 &req, sizeof(req), false);
316262306a36Sopenharmony_ci}
316362306a36Sopenharmony_ci
316462306a36Sopenharmony_ciint mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower)
316562306a36Sopenharmony_ci{
316662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
316762306a36Sopenharmony_ci	struct {
316862306a36Sopenharmony_ci		u8 format_id;
316962306a36Sopenharmony_ci		u8 rsv;
317062306a36Sopenharmony_ci		u8 band_idx;
317162306a36Sopenharmony_ci		s8 txpower_min;
317262306a36Sopenharmony_ci	} __packed req = {
317362306a36Sopenharmony_ci		.format_id = TX_POWER_LIMIT_FRAME_MIN,
317462306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
317562306a36Sopenharmony_ci		.txpower_min = txpower * 2, /* 0.5db */
317662306a36Sopenharmony_ci	};
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76,
317962306a36Sopenharmony_ci				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
318062306a36Sopenharmony_ci				 sizeof(req), true);
318162306a36Sopenharmony_ci}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ciint mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
318462306a36Sopenharmony_ci				 struct ieee80211_vif *vif,
318562306a36Sopenharmony_ci				 struct ieee80211_sta *sta, s8 txpower)
318662306a36Sopenharmony_ci{
318762306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
318862306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
318962306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
319062306a36Sopenharmony_ci	struct {
319162306a36Sopenharmony_ci		u8 format_id;
319262306a36Sopenharmony_ci		u8 rsv[3];
319362306a36Sopenharmony_ci		u8 band_idx;
319462306a36Sopenharmony_ci		s8 txpower_max;
319562306a36Sopenharmony_ci		__le16 wcid;
319662306a36Sopenharmony_ci		s8 txpower_offs[48];
319762306a36Sopenharmony_ci	} __packed req = {
319862306a36Sopenharmony_ci		.format_id = TX_POWER_LIMIT_FRAME,
319962306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
320062306a36Sopenharmony_ci		.txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2),
320162306a36Sopenharmony_ci		.wcid = cpu_to_le16(msta->wcid.idx),
320262306a36Sopenharmony_ci	};
320362306a36Sopenharmony_ci	int ret;
320462306a36Sopenharmony_ci	s8 txpower_sku[MT7915_SKU_RATE_NUM];
320562306a36Sopenharmony_ci
320662306a36Sopenharmony_ci	ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku));
320762306a36Sopenharmony_ci	if (ret)
320862306a36Sopenharmony_ci		return ret;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	txpower = mt7915_get_power_bound(phy, txpower);
321162306a36Sopenharmony_ci	if (txpower > mphy->txpower_cur || txpower < 0)
321262306a36Sopenharmony_ci		return -EINVAL;
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	if (txpower) {
321562306a36Sopenharmony_ci		u32 offs, len, i;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci		if (sta->deflink.ht_cap.ht_supported) {
321862306a36Sopenharmony_ci			const u8 *sku_len = mt7915_sku_group_len;
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci			offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM];
322162306a36Sopenharmony_ci			len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40];
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci			if (sta->deflink.vht_cap.vht_supported) {
322462306a36Sopenharmony_ci				offs += len;
322562306a36Sopenharmony_ci				len = sku_len[SKU_VHT_BW20] * 4;
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci				if (sta->deflink.he_cap.has_he) {
322862306a36Sopenharmony_ci					offs += len + sku_len[SKU_HE_RU26] * 3;
322962306a36Sopenharmony_ci					len = sku_len[SKU_HE_RU242] * 4;
323062306a36Sopenharmony_ci				}
323162306a36Sopenharmony_ci			}
323262306a36Sopenharmony_ci		} else {
323362306a36Sopenharmony_ci			return -EINVAL;
323462306a36Sopenharmony_ci		}
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci		for (i = 0; i < len; i++, offs++)
323762306a36Sopenharmony_ci			req.txpower_offs[i] =
323862306a36Sopenharmony_ci				DIV_ROUND_UP(txpower - txpower_sku[offs], 2);
323962306a36Sopenharmony_ci	}
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76,
324262306a36Sopenharmony_ci				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
324362306a36Sopenharmony_ci				 sizeof(req), true);
324462306a36Sopenharmony_ci}
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ciint mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
324762306a36Sopenharmony_ci{
324862306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
324962306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
325062306a36Sopenharmony_ci	struct ieee80211_hw *hw = mphy->hw;
325162306a36Sopenharmony_ci	struct mt7915_mcu_txpower_sku req = {
325262306a36Sopenharmony_ci		.format_id = TX_POWER_LIMIT_TABLE,
325362306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
325462306a36Sopenharmony_ci	};
325562306a36Sopenharmony_ci	struct mt76_power_limits limits_array;
325662306a36Sopenharmony_ci	s8 *la = (s8 *)&limits_array;
325762306a36Sopenharmony_ci	int i, idx;
325862306a36Sopenharmony_ci	int tx_power;
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	tx_power = mt7915_get_power_bound(phy, hw->conf.power_level);
326162306a36Sopenharmony_ci	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
326262306a36Sopenharmony_ci					      &limits_array, tx_power);
326362306a36Sopenharmony_ci	mphy->txpower_cur = tx_power;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
326662306a36Sopenharmony_ci		u8 mcs_num, len = mt7915_sku_group_len[i];
326762306a36Sopenharmony_ci		int j;
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci		if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) {
327062306a36Sopenharmony_ci			mcs_num = 10;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci			if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
327362306a36Sopenharmony_ci				la = (s8 *)&limits_array + 12;
327462306a36Sopenharmony_ci		} else {
327562306a36Sopenharmony_ci			mcs_num = len;
327662306a36Sopenharmony_ci		}
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci		for (j = 0; j < min_t(u8, mcs_num, len); j++)
327962306a36Sopenharmony_ci			req.txpower_sku[idx + j] = la[j];
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci		la += mcs_num;
328262306a36Sopenharmony_ci		idx += len;
328362306a36Sopenharmony_ci	}
328462306a36Sopenharmony_ci
328562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76,
328662306a36Sopenharmony_ci				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
328762306a36Sopenharmony_ci				 sizeof(req), true);
328862306a36Sopenharmony_ci}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ciint mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
329162306a36Sopenharmony_ci{
329262306a36Sopenharmony_ci#define RATE_POWER_INFO	2
329362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
329462306a36Sopenharmony_ci	struct {
329562306a36Sopenharmony_ci		u8 format_id;
329662306a36Sopenharmony_ci		u8 category;
329762306a36Sopenharmony_ci		u8 band_idx;
329862306a36Sopenharmony_ci		u8 _rsv;
329962306a36Sopenharmony_ci	} __packed req = {
330062306a36Sopenharmony_ci		.format_id = TX_POWER_LIMIT_INFO,
330162306a36Sopenharmony_ci		.category = RATE_POWER_INFO,
330262306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
330362306a36Sopenharmony_ci	};
330462306a36Sopenharmony_ci	s8 txpower_sku[MT7915_SKU_RATE_NUM][2];
330562306a36Sopenharmony_ci	struct sk_buff *skb;
330662306a36Sopenharmony_ci	int ret, i;
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
330962306a36Sopenharmony_ci					MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
331062306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
331162306a36Sopenharmony_ci	if (ret)
331262306a36Sopenharmony_ci		return ret;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku));
331562306a36Sopenharmony_ci	for (i = 0; i < len; i++)
331662306a36Sopenharmony_ci		txpower[i] = txpower_sku[i][req.band_idx];
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	dev_kfree_skb(skb);
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	return 0;
332162306a36Sopenharmony_ci}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ciint mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
332462306a36Sopenharmony_ci			      u8 en)
332562306a36Sopenharmony_ci{
332662306a36Sopenharmony_ci	struct {
332762306a36Sopenharmony_ci		u8 test_mode_en;
332862306a36Sopenharmony_ci		u8 param_idx;
332962306a36Sopenharmony_ci		u8 _rsv[2];
333062306a36Sopenharmony_ci
333162306a36Sopenharmony_ci		u8 enable;
333262306a36Sopenharmony_ci		u8 _rsv2[3];
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci		u8 pad[8];
333562306a36Sopenharmony_ci	} __packed req = {
333662306a36Sopenharmony_ci		.test_mode_en = test_mode,
333762306a36Sopenharmony_ci		.param_idx = param,
333862306a36Sopenharmony_ci		.enable = en,
333962306a36Sopenharmony_ci	};
334062306a36Sopenharmony_ci
334162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req,
334262306a36Sopenharmony_ci				 sizeof(req), false);
334362306a36Sopenharmony_ci}
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ciint mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
334662306a36Sopenharmony_ci{
334762306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
334862306a36Sopenharmony_ci	struct mt7915_sku {
334962306a36Sopenharmony_ci		u8 format_id;
335062306a36Sopenharmony_ci		u8 sku_enable;
335162306a36Sopenharmony_ci		u8 band_idx;
335262306a36Sopenharmony_ci		u8 rsv;
335362306a36Sopenharmony_ci	} __packed req = {
335462306a36Sopenharmony_ci		.format_id = TX_POWER_LIMIT_ENABLE,
335562306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
335662306a36Sopenharmony_ci		.sku_enable = enable,
335762306a36Sopenharmony_ci	};
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76,
336062306a36Sopenharmony_ci				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
336162306a36Sopenharmony_ci				 sizeof(req), true);
336262306a36Sopenharmony_ci}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ciint mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
336562306a36Sopenharmony_ci{
336662306a36Sopenharmony_ci	struct {
336762306a36Sopenharmony_ci		u8 action;
336862306a36Sopenharmony_ci		u8 set;
336962306a36Sopenharmony_ci		u8 band;
337062306a36Sopenharmony_ci		u8 rsv;
337162306a36Sopenharmony_ci	} req = {
337262306a36Sopenharmony_ci		.action = action,
337362306a36Sopenharmony_ci		.set = set,
337462306a36Sopenharmony_ci		.band = band,
337562306a36Sopenharmony_ci	};
337662306a36Sopenharmony_ci
337762306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER),
337862306a36Sopenharmony_ci				 &req, sizeof(req), false);
337962306a36Sopenharmony_ci}
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ciint mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
338262306a36Sopenharmony_ci{
338362306a36Sopenharmony_ci	struct {
338462306a36Sopenharmony_ci		u8 action;
338562306a36Sopenharmony_ci		union {
338662306a36Sopenharmony_ci			struct {
338762306a36Sopenharmony_ci				u8 snd_mode;
338862306a36Sopenharmony_ci				u8 sta_num;
338962306a36Sopenharmony_ci				u8 rsv;
339062306a36Sopenharmony_ci				u8 wlan_idx[4];
339162306a36Sopenharmony_ci				__le32 snd_period;	/* ms */
339262306a36Sopenharmony_ci			} __packed snd;
339362306a36Sopenharmony_ci			struct {
339462306a36Sopenharmony_ci				bool ebf;
339562306a36Sopenharmony_ci				bool ibf;
339662306a36Sopenharmony_ci				u8 rsv;
339762306a36Sopenharmony_ci			} __packed type;
339862306a36Sopenharmony_ci			struct {
339962306a36Sopenharmony_ci				u8 bf_num;
340062306a36Sopenharmony_ci				u8 bf_bitmap;
340162306a36Sopenharmony_ci				u8 bf_sel[8];
340262306a36Sopenharmony_ci				u8 rsv[5];
340362306a36Sopenharmony_ci			} __packed mod;
340462306a36Sopenharmony_ci		};
340562306a36Sopenharmony_ci	} __packed req = {
340662306a36Sopenharmony_ci		.action = action,
340762306a36Sopenharmony_ci	};
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci#define MT_BF_PROCESSING	4
341062306a36Sopenharmony_ci	switch (action) {
341162306a36Sopenharmony_ci	case MT_BF_SOUNDING_ON:
341262306a36Sopenharmony_ci		req.snd.snd_mode = MT_BF_PROCESSING;
341362306a36Sopenharmony_ci		break;
341462306a36Sopenharmony_ci	case MT_BF_TYPE_UPDATE:
341562306a36Sopenharmony_ci		req.type.ebf = true;
341662306a36Sopenharmony_ci		req.type.ibf = dev->ibf;
341762306a36Sopenharmony_ci		break;
341862306a36Sopenharmony_ci	case MT_BF_MODULE_UPDATE:
341962306a36Sopenharmony_ci		req.mod.bf_num = 2;
342062306a36Sopenharmony_ci		req.mod.bf_bitmap = GENMASK(1, 0);
342162306a36Sopenharmony_ci		break;
342262306a36Sopenharmony_ci	default:
342362306a36Sopenharmony_ci		return -EINVAL;
342462306a36Sopenharmony_ci	}
342562306a36Sopenharmony_ci
342662306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
342762306a36Sopenharmony_ci				 sizeof(req), true);
342862306a36Sopenharmony_ci}
342962306a36Sopenharmony_ci
343062306a36Sopenharmony_cistatic int
343162306a36Sopenharmony_cimt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val)
343262306a36Sopenharmony_ci{
343362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
343462306a36Sopenharmony_ci	struct mt7915_mcu_sr_ctrl req = {
343562306a36Sopenharmony_ci		.action = action,
343662306a36Sopenharmony_ci		.argnum = 1,
343762306a36Sopenharmony_ci		.band_idx = phy->mt76->band_idx,
343862306a36Sopenharmony_ci		.val = cpu_to_le32(val),
343962306a36Sopenharmony_ci	};
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
344262306a36Sopenharmony_ci				 sizeof(req), true);
344362306a36Sopenharmony_ci}
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_cistatic int
344662306a36Sopenharmony_cimt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy,
344762306a36Sopenharmony_ci			   struct ieee80211_he_obss_pd *he_obss_pd)
344862306a36Sopenharmony_ci{
344962306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
345062306a36Sopenharmony_ci	struct {
345162306a36Sopenharmony_ci		struct mt7915_mcu_sr_ctrl ctrl;
345262306a36Sopenharmony_ci		struct {
345362306a36Sopenharmony_ci			u8 pd_th_non_srg;
345462306a36Sopenharmony_ci			u8 pd_th_srg;
345562306a36Sopenharmony_ci			u8 period_offs;
345662306a36Sopenharmony_ci			u8 rcpi_src;
345762306a36Sopenharmony_ci			__le16 obss_pd_min;
345862306a36Sopenharmony_ci			__le16 obss_pd_min_srg;
345962306a36Sopenharmony_ci			u8 resp_txpwr_mode;
346062306a36Sopenharmony_ci			u8 txpwr_restrict_mode;
346162306a36Sopenharmony_ci			u8 txpwr_ref;
346262306a36Sopenharmony_ci			u8 rsv[3];
346362306a36Sopenharmony_ci		} __packed param;
346462306a36Sopenharmony_ci	} __packed req = {
346562306a36Sopenharmony_ci		.ctrl = {
346662306a36Sopenharmony_ci			.action = SPR_SET_PARAM,
346762306a36Sopenharmony_ci			.argnum = 9,
346862306a36Sopenharmony_ci			.band_idx = phy->mt76->band_idx,
346962306a36Sopenharmony_ci		},
347062306a36Sopenharmony_ci	};
347162306a36Sopenharmony_ci	int ret;
347262306a36Sopenharmony_ci	u8 max_th = 82, non_srg_max_th = 62;
347362306a36Sopenharmony_ci
347462306a36Sopenharmony_ci	/* disable firmware dynamical PD asjustment */
347562306a36Sopenharmony_ci	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false);
347662306a36Sopenharmony_ci	if (ret)
347762306a36Sopenharmony_ci		return ret;
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci	if (he_obss_pd->sr_ctrl &
348062306a36Sopenharmony_ci	    IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)
348162306a36Sopenharmony_ci		req.param.pd_th_non_srg = max_th;
348262306a36Sopenharmony_ci	else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
348362306a36Sopenharmony_ci		req.param.pd_th_non_srg  = max_th - he_obss_pd->non_srg_max_offset;
348462306a36Sopenharmony_ci	else
348562306a36Sopenharmony_ci		req.param.pd_th_non_srg  = non_srg_max_th;
348662306a36Sopenharmony_ci
348762306a36Sopenharmony_ci	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
348862306a36Sopenharmony_ci		req.param.pd_th_srg = max_th - he_obss_pd->max_offset;
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci	req.param.obss_pd_min = cpu_to_le16(82);
349162306a36Sopenharmony_ci	req.param.obss_pd_min_srg = cpu_to_le16(82);
349262306a36Sopenharmony_ci	req.param.txpwr_restrict_mode = 2;
349362306a36Sopenharmony_ci	req.param.txpwr_ref = 21;
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
349662306a36Sopenharmony_ci				 sizeof(req), true);
349762306a36Sopenharmony_ci}
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_cistatic int
350062306a36Sopenharmony_cimt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif,
350162306a36Sopenharmony_ci			     struct ieee80211_he_obss_pd *he_obss_pd)
350262306a36Sopenharmony_ci{
350362306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
350462306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
350562306a36Sopenharmony_ci	u8 omac = mvif->mt76.omac_idx;
350662306a36Sopenharmony_ci	struct {
350762306a36Sopenharmony_ci		struct mt7915_mcu_sr_ctrl ctrl;
350862306a36Sopenharmony_ci		struct {
350962306a36Sopenharmony_ci			u8 omac;
351062306a36Sopenharmony_ci			u8 rsv[3];
351162306a36Sopenharmony_ci			u8 flag[20];
351262306a36Sopenharmony_ci		} __packed siga;
351362306a36Sopenharmony_ci	} __packed req = {
351462306a36Sopenharmony_ci		.ctrl = {
351562306a36Sopenharmony_ci			.action = SPR_SET_SIGA,
351662306a36Sopenharmony_ci			.argnum = 1,
351762306a36Sopenharmony_ci			.band_idx = phy->mt76->band_idx,
351862306a36Sopenharmony_ci		},
351962306a36Sopenharmony_ci		.siga = {
352062306a36Sopenharmony_ci			.omac = omac > HW_BSSID_MAX ? omac - 12 : omac,
352162306a36Sopenharmony_ci		},
352262306a36Sopenharmony_ci	};
352362306a36Sopenharmony_ci	int ret;
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED)
352662306a36Sopenharmony_ci		req.siga.flag[req.siga.omac] = 0xf;
352762306a36Sopenharmony_ci	else
352862306a36Sopenharmony_ci		return 0;
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	/* switch to normal AP mode */
353162306a36Sopenharmony_ci	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0);
353262306a36Sopenharmony_ci	if (ret)
353362306a36Sopenharmony_ci		return ret;
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
353662306a36Sopenharmony_ci				 sizeof(req), true);
353762306a36Sopenharmony_ci}
353862306a36Sopenharmony_ci
353962306a36Sopenharmony_cistatic int
354062306a36Sopenharmony_cimt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy,
354162306a36Sopenharmony_ci			       struct ieee80211_he_obss_pd *he_obss_pd)
354262306a36Sopenharmony_ci{
354362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
354462306a36Sopenharmony_ci	struct {
354562306a36Sopenharmony_ci		struct mt7915_mcu_sr_ctrl ctrl;
354662306a36Sopenharmony_ci		struct {
354762306a36Sopenharmony_ci			__le32 color_l[2];
354862306a36Sopenharmony_ci			__le32 color_h[2];
354962306a36Sopenharmony_ci			__le32 bssid_l[2];
355062306a36Sopenharmony_ci			__le32 bssid_h[2];
355162306a36Sopenharmony_ci		} __packed bitmap;
355262306a36Sopenharmony_ci	} __packed req = {
355362306a36Sopenharmony_ci		.ctrl = {
355462306a36Sopenharmony_ci			.action = SPR_SET_SRG_BITMAP,
355562306a36Sopenharmony_ci			.argnum = 4,
355662306a36Sopenharmony_ci			.band_idx = phy->mt76->band_idx,
355762306a36Sopenharmony_ci		},
355862306a36Sopenharmony_ci	};
355962306a36Sopenharmony_ci	u32 bitmap;
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap));
356262306a36Sopenharmony_ci	req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap));
356562306a36Sopenharmony_ci	req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap));
356862306a36Sopenharmony_ci	req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap));
357162306a36Sopenharmony_ci	req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
357462306a36Sopenharmony_ci				 sizeof(req), true);
357562306a36Sopenharmony_ci}
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ciint mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
357862306a36Sopenharmony_ci			    struct ieee80211_he_obss_pd *he_obss_pd)
357962306a36Sopenharmony_ci{
358062306a36Sopenharmony_ci	int ret;
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	/* enable firmware scene detection algorithms */
358362306a36Sopenharmony_ci	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect);
358462306a36Sopenharmony_ci	if (ret)
358562306a36Sopenharmony_ci		return ret;
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci	/* firmware dynamically adjusts PD threshold so skip manual control */
358862306a36Sopenharmony_ci	if (sr_scene_detect && !he_obss_pd->enable)
358962306a36Sopenharmony_ci		return 0;
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	/* enable spatial reuse */
359262306a36Sopenharmony_ci	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable);
359362306a36Sopenharmony_ci	if (ret)
359462306a36Sopenharmony_ci		return ret;
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci	if (sr_scene_detect || !he_obss_pd->enable)
359762306a36Sopenharmony_ci		return 0;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true);
360062306a36Sopenharmony_ci	if (ret)
360162306a36Sopenharmony_ci		return ret;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci	/* set SRG/non-SRG OBSS PD threshold */
360462306a36Sopenharmony_ci	ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd);
360562306a36Sopenharmony_ci	if (ret)
360662306a36Sopenharmony_ci		return ret;
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	/* Set SR prohibit */
360962306a36Sopenharmony_ci	ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd);
361062306a36Sopenharmony_ci	if (ret)
361162306a36Sopenharmony_ci		return ret;
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	/* set SRG BSS color/BSSID bitmap */
361462306a36Sopenharmony_ci	return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd);
361562306a36Sopenharmony_ci}
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ciint mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
361862306a36Sopenharmony_ci			   struct ieee80211_sta *sta, struct rate_info *rate)
361962306a36Sopenharmony_ci{
362062306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
362162306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
362262306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
362362306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
362462306a36Sopenharmony_ci	struct {
362562306a36Sopenharmony_ci		u8 category;
362662306a36Sopenharmony_ci		u8 band;
362762306a36Sopenharmony_ci		__le16 wcid;
362862306a36Sopenharmony_ci	} __packed req = {
362962306a36Sopenharmony_ci		.category = MCU_PHY_STATE_CONTENTION_RX_RATE,
363062306a36Sopenharmony_ci		.band = mvif->mt76.band_idx,
363162306a36Sopenharmony_ci		.wcid = cpu_to_le16(msta->wcid.idx),
363262306a36Sopenharmony_ci	};
363362306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
363462306a36Sopenharmony_ci	struct mt7915_mcu_phy_rx_info *res;
363562306a36Sopenharmony_ci	struct sk_buff *skb;
363662306a36Sopenharmony_ci	int ret;
363762306a36Sopenharmony_ci	bool cck = false;
363862306a36Sopenharmony_ci
363962306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO),
364062306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
364162306a36Sopenharmony_ci	if (ret)
364262306a36Sopenharmony_ci		return ret;
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci	res = (struct mt7915_mcu_phy_rx_info *)skb->data;
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_ci	rate->mcs = res->rate;
364762306a36Sopenharmony_ci	rate->nss = res->nsts + 1;
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	switch (res->mode) {
365062306a36Sopenharmony_ci	case MT_PHY_TYPE_CCK:
365162306a36Sopenharmony_ci		cck = true;
365262306a36Sopenharmony_ci		fallthrough;
365362306a36Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
365462306a36Sopenharmony_ci		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
365562306a36Sopenharmony_ci			sband = &mphy->sband_5g.sband;
365662306a36Sopenharmony_ci		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
365762306a36Sopenharmony_ci			sband = &mphy->sband_6g.sband;
365862306a36Sopenharmony_ci		else
365962306a36Sopenharmony_ci			sband = &mphy->sband_2g.sband;
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci		rate->mcs = mt76_get_rate(&dev->mt76, sband, rate->mcs, cck);
366262306a36Sopenharmony_ci		rate->legacy = sband->bitrates[rate->mcs].bitrate;
366362306a36Sopenharmony_ci		break;
366462306a36Sopenharmony_ci	case MT_PHY_TYPE_HT:
366562306a36Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
366662306a36Sopenharmony_ci		if (rate->mcs > 31) {
366762306a36Sopenharmony_ci			ret = -EINVAL;
366862306a36Sopenharmony_ci			goto out;
366962306a36Sopenharmony_ci		}
367062306a36Sopenharmony_ci
367162306a36Sopenharmony_ci		rate->flags = RATE_INFO_FLAGS_MCS;
367262306a36Sopenharmony_ci		if (res->gi)
367362306a36Sopenharmony_ci			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
367462306a36Sopenharmony_ci		break;
367562306a36Sopenharmony_ci	case MT_PHY_TYPE_VHT:
367662306a36Sopenharmony_ci		if (rate->mcs > 9) {
367762306a36Sopenharmony_ci			ret = -EINVAL;
367862306a36Sopenharmony_ci			goto out;
367962306a36Sopenharmony_ci		}
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci		rate->flags = RATE_INFO_FLAGS_VHT_MCS;
368262306a36Sopenharmony_ci		if (res->gi)
368362306a36Sopenharmony_ci			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
368462306a36Sopenharmony_ci		break;
368562306a36Sopenharmony_ci	case MT_PHY_TYPE_HE_SU:
368662306a36Sopenharmony_ci	case MT_PHY_TYPE_HE_EXT_SU:
368762306a36Sopenharmony_ci	case MT_PHY_TYPE_HE_TB:
368862306a36Sopenharmony_ci	case MT_PHY_TYPE_HE_MU:
368962306a36Sopenharmony_ci		if (res->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) {
369062306a36Sopenharmony_ci			ret = -EINVAL;
369162306a36Sopenharmony_ci			goto out;
369262306a36Sopenharmony_ci		}
369362306a36Sopenharmony_ci		rate->he_gi = res->gi;
369462306a36Sopenharmony_ci		rate->flags = RATE_INFO_FLAGS_HE_MCS;
369562306a36Sopenharmony_ci		break;
369662306a36Sopenharmony_ci	default:
369762306a36Sopenharmony_ci		ret = -EINVAL;
369862306a36Sopenharmony_ci		goto out;
369962306a36Sopenharmony_ci	}
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	switch (res->bw) {
370262306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_160:
370362306a36Sopenharmony_ci		rate->bw = RATE_INFO_BW_160;
370462306a36Sopenharmony_ci		break;
370562306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_80:
370662306a36Sopenharmony_ci		rate->bw = RATE_INFO_BW_80;
370762306a36Sopenharmony_ci		break;
370862306a36Sopenharmony_ci	case IEEE80211_STA_RX_BW_40:
370962306a36Sopenharmony_ci		rate->bw = RATE_INFO_BW_40;
371062306a36Sopenharmony_ci		break;
371162306a36Sopenharmony_ci	default:
371262306a36Sopenharmony_ci		rate->bw = RATE_INFO_BW_20;
371362306a36Sopenharmony_ci		break;
371462306a36Sopenharmony_ci	}
371562306a36Sopenharmony_ci
371662306a36Sopenharmony_ciout:
371762306a36Sopenharmony_ci	dev_kfree_skb(skb);
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci	return ret;
372062306a36Sopenharmony_ci}
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ciint mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
372362306a36Sopenharmony_ci				struct cfg80211_he_bss_color *he_bss_color)
372462306a36Sopenharmony_ci{
372562306a36Sopenharmony_ci	int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color);
372662306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
372762306a36Sopenharmony_ci	struct bss_info_color *bss_color;
372862306a36Sopenharmony_ci	struct sk_buff *skb;
372962306a36Sopenharmony_ci	struct tlv *tlv;
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
373262306a36Sopenharmony_ci					      NULL, len);
373362306a36Sopenharmony_ci	if (IS_ERR(skb))
373462306a36Sopenharmony_ci		return PTR_ERR(skb);
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR,
373762306a36Sopenharmony_ci				      sizeof(*bss_color));
373862306a36Sopenharmony_ci	bss_color = (struct bss_info_color *)tlv;
373962306a36Sopenharmony_ci	bss_color->disable = !he_bss_color->enabled;
374062306a36Sopenharmony_ci	bss_color->color = he_bss_color->color;
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
374362306a36Sopenharmony_ci				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
374462306a36Sopenharmony_ci}
374562306a36Sopenharmony_ci
374662306a36Sopenharmony_ci#define TWT_AGRT_TRIGGER	BIT(0)
374762306a36Sopenharmony_ci#define TWT_AGRT_ANNOUNCE	BIT(1)
374862306a36Sopenharmony_ci#define TWT_AGRT_PROTECT	BIT(2)
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ciint mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
375162306a36Sopenharmony_ci			       struct mt7915_vif *mvif,
375262306a36Sopenharmony_ci			       struct mt7915_twt_flow *flow,
375362306a36Sopenharmony_ci			       int cmd)
375462306a36Sopenharmony_ci{
375562306a36Sopenharmony_ci	struct {
375662306a36Sopenharmony_ci		u8 tbl_idx;
375762306a36Sopenharmony_ci		u8 cmd;
375862306a36Sopenharmony_ci		u8 own_mac_idx;
375962306a36Sopenharmony_ci		u8 flowid; /* 0xff for group id */
376062306a36Sopenharmony_ci		__le16 peer_id; /* specify the peer_id (msb=0)
376162306a36Sopenharmony_ci				 * or group_id (msb=1)
376262306a36Sopenharmony_ci				 */
376362306a36Sopenharmony_ci		u8 duration; /* 256 us */
376462306a36Sopenharmony_ci		u8 bss_idx;
376562306a36Sopenharmony_ci		__le64 start_tsf;
376662306a36Sopenharmony_ci		__le16 mantissa;
376762306a36Sopenharmony_ci		u8 exponent;
376862306a36Sopenharmony_ci		u8 is_ap;
376962306a36Sopenharmony_ci		u8 agrt_params;
377062306a36Sopenharmony_ci		u8 rsv[23];
377162306a36Sopenharmony_ci	} __packed req = {
377262306a36Sopenharmony_ci		.tbl_idx = flow->table_id,
377362306a36Sopenharmony_ci		.cmd = cmd,
377462306a36Sopenharmony_ci		.own_mac_idx = mvif->mt76.omac_idx,
377562306a36Sopenharmony_ci		.flowid = flow->id,
377662306a36Sopenharmony_ci		.peer_id = cpu_to_le16(flow->wcid),
377762306a36Sopenharmony_ci		.duration = flow->duration,
377862306a36Sopenharmony_ci		.bss_idx = mvif->mt76.idx,
377962306a36Sopenharmony_ci		.start_tsf = cpu_to_le64(flow->tsf),
378062306a36Sopenharmony_ci		.mantissa = flow->mantissa,
378162306a36Sopenharmony_ci		.exponent = flow->exp,
378262306a36Sopenharmony_ci		.is_ap = true,
378362306a36Sopenharmony_ci	};
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	if (flow->protection)
378662306a36Sopenharmony_ci		req.agrt_params |= TWT_AGRT_PROTECT;
378762306a36Sopenharmony_ci	if (!flow->flowtype)
378862306a36Sopenharmony_ci		req.agrt_params |= TWT_AGRT_ANNOUNCE;
378962306a36Sopenharmony_ci	if (flow->trigger)
379062306a36Sopenharmony_ci		req.agrt_params |= TWT_AGRT_TRIGGER;
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE),
379362306a36Sopenharmony_ci				 &req, sizeof(req), true);
379462306a36Sopenharmony_ci}
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ciint mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
379762306a36Sopenharmony_ci{
379862306a36Sopenharmony_ci	struct {
379962306a36Sopenharmony_ci		__le32 cmd;
380062306a36Sopenharmony_ci		__le32 num;
380162306a36Sopenharmony_ci		__le32 __rsv;
380262306a36Sopenharmony_ci		__le16 wlan_idx;
380362306a36Sopenharmony_ci	} req = {
380462306a36Sopenharmony_ci		.cmd = cpu_to_le32(0x15),
380562306a36Sopenharmony_ci		.num = cpu_to_le32(1),
380662306a36Sopenharmony_ci		.wlan_idx = cpu_to_le16(wlan_idx),
380762306a36Sopenharmony_ci	};
380862306a36Sopenharmony_ci	struct mt7915_mcu_wa_tx_stat {
380962306a36Sopenharmony_ci		__le16 wlan_idx;
381062306a36Sopenharmony_ci		u8 __rsv[2];
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci		/* tx_bytes is deprecated since WA byte counter uses u32,
381362306a36Sopenharmony_ci		 * which easily leads to overflow.
381462306a36Sopenharmony_ci		 */
381562306a36Sopenharmony_ci		__le32 tx_bytes;
381662306a36Sopenharmony_ci		__le32 tx_packets;
381762306a36Sopenharmony_ci	} *res;
381862306a36Sopenharmony_ci	struct mt76_wcid *wcid;
381962306a36Sopenharmony_ci	struct sk_buff *skb;
382062306a36Sopenharmony_ci	int ret;
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY),
382362306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
382462306a36Sopenharmony_ci	if (ret)
382562306a36Sopenharmony_ci		return ret;
382662306a36Sopenharmony_ci
382762306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
382862306a36Sopenharmony_ci		skb_pull(skb, 4);
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci	res = (struct mt7915_mcu_wa_tx_stat *)skb->data;
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	if (le16_to_cpu(res->wlan_idx) != wlan_idx) {
383362306a36Sopenharmony_ci		ret = -EINVAL;
383462306a36Sopenharmony_ci		goto out;
383562306a36Sopenharmony_ci	}
383662306a36Sopenharmony_ci
383762306a36Sopenharmony_ci	rcu_read_lock();
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
384062306a36Sopenharmony_ci	if (wcid)
384162306a36Sopenharmony_ci		wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
384262306a36Sopenharmony_ci	else
384362306a36Sopenharmony_ci		ret = -EINVAL;
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	rcu_read_unlock();
384662306a36Sopenharmony_ciout:
384762306a36Sopenharmony_ci	dev_kfree_skb(skb);
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci	return ret;
385062306a36Sopenharmony_ci}
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ciint mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
385362306a36Sopenharmony_ci{
385462306a36Sopenharmony_ci	struct {
385562306a36Sopenharmony_ci		__le32 idx;
385662306a36Sopenharmony_ci		__le32 ofs;
385762306a36Sopenharmony_ci		__le32 data;
385862306a36Sopenharmony_ci	} __packed req = {
385962306a36Sopenharmony_ci		.idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))),
386062306a36Sopenharmony_ci		.ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))),
386162306a36Sopenharmony_ci		.data = set ? cpu_to_le32(*val) : 0,
386262306a36Sopenharmony_ci	};
386362306a36Sopenharmony_ci	struct sk_buff *skb;
386462306a36Sopenharmony_ci	int ret;
386562306a36Sopenharmony_ci
386662306a36Sopenharmony_ci	if (set)
386762306a36Sopenharmony_ci		return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
386862306a36Sopenharmony_ci					 &req, sizeof(req), false);
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_ci	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
387162306a36Sopenharmony_ci					&req, sizeof(req), true, &skb);
387262306a36Sopenharmony_ci	if (ret)
387362306a36Sopenharmony_ci		return ret;
387462306a36Sopenharmony_ci
387562306a36Sopenharmony_ci	*val = le32_to_cpu(*(__le32 *)(skb->data + 8));
387662306a36Sopenharmony_ci	dev_kfree_skb(skb);
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	return 0;
387962306a36Sopenharmony_ci}
3880