xref: /openbmc/linux/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
1e57b7901SRyder Lee // SPDX-License-Identifier: ISC
2e57b7901SRyder Lee /* Copyright (C) 2020 MediaTek Inc. */
3e57b7901SRyder Lee 
4e57b7901SRyder Lee #include <linux/fs.h>
5e57b7901SRyder Lee #include "mt7915.h"
6e57b7901SRyder Lee #include "mcu.h"
7e57b7901SRyder Lee #include "mac.h"
8e57b7901SRyder Lee #include "eeprom.h"
9e57b7901SRyder Lee 
1099ad32a4SBo Jiao #define fw_name(_dev, name, ...)	({			\
1199ad32a4SBo Jiao 	char *_fw;						\
1299ad32a4SBo Jiao 	switch (mt76_chip(&(_dev)->mt76)) {			\
1399ad32a4SBo Jiao 	case 0x7915:						\
1499ad32a4SBo Jiao 		_fw = MT7915_##name;				\
1599ad32a4SBo Jiao 		break;						\
166bad146dSAlexander Couzens 	case 0x7981:						\
176bad146dSAlexander Couzens 		_fw = MT7981_##name;				\
186bad146dSAlexander Couzens 		break;						\
1999ad32a4SBo Jiao 	case 0x7986:						\
2099ad32a4SBo Jiao 		_fw = MT7986_##name##__VA_ARGS__;		\
2199ad32a4SBo Jiao 		break;						\
2299ad32a4SBo Jiao 	default:						\
2399ad32a4SBo Jiao 		_fw = MT7916_##name;				\
2499ad32a4SBo Jiao 		break;						\
2599ad32a4SBo Jiao 	}							\
2699ad32a4SBo Jiao 	_fw;							\
2799ad32a4SBo Jiao })
2899ad32a4SBo Jiao 
2999ad32a4SBo Jiao #define fw_name_var(_dev, name)		(mt7915_check_adie(dev, false) ?	\
3099ad32a4SBo Jiao 					 fw_name(_dev, name) :			\
3199ad32a4SBo Jiao 					 fw_name(_dev, name, _MT7975))
3299ad32a4SBo Jiao 
33e57b7901SRyder Lee #define MCU_PATCH_ADDRESS		0x200000
34e57b7901SRyder Lee 
35c336318fSRyder Lee #define HE_PHY(p, c)			u8_get_bits(c, IEEE80211_HE_PHY_##p)
36c336318fSRyder Lee #define HE_MAC(m, c)			u8_get_bits(c, IEEE80211_HE_MAC_##m)
37c336318fSRyder Lee 
383dc00ecfSRyder Lee static bool sr_scene_detect = true;
393dc00ecfSRyder Lee module_param(sr_scene_detect, bool, 0644);
403dc00ecfSRyder Lee MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm");
413dc00ecfSRyder Lee 
4289029a85SRyder Lee static u8
mt7915_mcu_get_sta_nss(u16 mcs_map)4389029a85SRyder Lee mt7915_mcu_get_sta_nss(u16 mcs_map)
4489029a85SRyder Lee {
4589029a85SRyder Lee 	u8 nss;
4689029a85SRyder Lee 
4789029a85SRyder Lee 	for (nss = 8; nss > 0; nss--) {
4889029a85SRyder Lee 		u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3;
4989029a85SRyder Lee 
5089029a85SRyder Lee 		if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED)
5189029a85SRyder Lee 			break;
5289029a85SRyder Lee 	}
5389029a85SRyder Lee 
5489029a85SRyder Lee 	return nss - 1;
5589029a85SRyder Lee }
5689029a85SRyder Lee 
5776be6c07SRyder Lee static void
mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta * sta,__le16 * he_mcs,u16 mcs_map)5876be6c07SRyder Lee mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
59ade25ca7SPeter Chiu 			  u16 mcs_map)
6076be6c07SRyder Lee {
6176be6c07SRyder Lee 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
6299ad32a4SBo Jiao 	struct mt7915_dev *dev = msta->vif->phy->dev;
63ade25ca7SPeter Chiu 	enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
64ade25ca7SPeter Chiu 	const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs;
65046d2e7cSSriram R 	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
6676be6c07SRyder Lee 
6776be6c07SRyder Lee 	for (nss = 0; nss < max_nss; nss++) {
6876be6c07SRyder Lee 		int mcs;
6976be6c07SRyder Lee 
7076be6c07SRyder Lee 		switch ((mcs_map >> (2 * nss)) & 0x3) {
7176be6c07SRyder Lee 		case IEEE80211_HE_MCS_SUPPORT_0_11:
7276be6c07SRyder Lee 			mcs = GENMASK(11, 0);
7376be6c07SRyder Lee 			break;
7476be6c07SRyder Lee 		case IEEE80211_HE_MCS_SUPPORT_0_9:
7576be6c07SRyder Lee 			mcs = GENMASK(9, 0);
7676be6c07SRyder Lee 			break;
7776be6c07SRyder Lee 		case IEEE80211_HE_MCS_SUPPORT_0_7:
7876be6c07SRyder Lee 			mcs = GENMASK(7, 0);
7976be6c07SRyder Lee 			break;
8076be6c07SRyder Lee 		default:
8176be6c07SRyder Lee 			mcs = 0;
8276be6c07SRyder Lee 		}
8376be6c07SRyder Lee 
8476be6c07SRyder Lee 		mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1;
8576be6c07SRyder Lee 
8676be6c07SRyder Lee 		switch (mcs) {
8776be6c07SRyder Lee 		case 0 ... 7:
8876be6c07SRyder Lee 			mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
8976be6c07SRyder Lee 			break;
9076be6c07SRyder Lee 		case 8 ... 9:
9176be6c07SRyder Lee 			mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
9276be6c07SRyder Lee 			break;
9376be6c07SRyder Lee 		case 10 ... 11:
9476be6c07SRyder Lee 			mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
9576be6c07SRyder Lee 			break;
9676be6c07SRyder Lee 		default:
9776be6c07SRyder Lee 			mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
9876be6c07SRyder Lee 			break;
9976be6c07SRyder Lee 		}
10076be6c07SRyder Lee 		mcs_map &= ~(0x3 << (nss * 2));
10176be6c07SRyder Lee 		mcs_map |= mcs << (nss * 2);
10276be6c07SRyder Lee 
10399ad32a4SBo Jiao 		/* only support 2ss on 160MHz for mt7915 */
10499ad32a4SBo Jiao 		if (is_mt7915(&dev->mt76) && nss > 1 &&
105046d2e7cSSriram R 		    sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
10676be6c07SRyder Lee 			break;
10776be6c07SRyder Lee 	}
10876be6c07SRyder Lee 
10976be6c07SRyder Lee 	*he_mcs = cpu_to_le16(mcs_map);
11076be6c07SRyder Lee }
11176be6c07SRyder Lee 
11276be6c07SRyder Lee static void
mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta * sta,__le16 * vht_mcs,const u16 * mask)11376be6c07SRyder Lee mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
11476be6c07SRyder Lee 			   const u16 *mask)
11576be6c07SRyder Lee {
11699ad32a4SBo Jiao 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
11799ad32a4SBo Jiao 	struct mt7915_dev *dev = msta->vif->phy->dev;
118046d2e7cSSriram R 	u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
119046d2e7cSSriram R 	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
12076be6c07SRyder Lee 	u16 mcs;
12176be6c07SRyder Lee 
12276be6c07SRyder Lee 	for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
12376be6c07SRyder Lee 		switch (mcs_map & 0x3) {
12476be6c07SRyder Lee 		case IEEE80211_VHT_MCS_SUPPORT_0_9:
12576be6c07SRyder Lee 			mcs = GENMASK(9, 0);
12676be6c07SRyder Lee 			break;
12776be6c07SRyder Lee 		case IEEE80211_VHT_MCS_SUPPORT_0_8:
12876be6c07SRyder Lee 			mcs = GENMASK(8, 0);
12976be6c07SRyder Lee 			break;
13076be6c07SRyder Lee 		case IEEE80211_VHT_MCS_SUPPORT_0_7:
13176be6c07SRyder Lee 			mcs = GENMASK(7, 0);
13276be6c07SRyder Lee 			break;
13376be6c07SRyder Lee 		default:
13476be6c07SRyder Lee 			mcs = 0;
13576be6c07SRyder Lee 		}
13676be6c07SRyder Lee 
13776be6c07SRyder Lee 		vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]);
13876be6c07SRyder Lee 
13999ad32a4SBo Jiao 		/* only support 2ss on 160MHz for mt7915 */
14099ad32a4SBo Jiao 		if (is_mt7915(&dev->mt76) && nss > 1 &&
141046d2e7cSSriram R 		    sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
14276be6c07SRyder Lee 			break;
14376be6c07SRyder Lee 	}
14476be6c07SRyder Lee }
14576be6c07SRyder Lee 
14676be6c07SRyder Lee static void
mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta * sta,u8 * ht_mcs,const u8 * mask)14776be6c07SRyder Lee mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
14876be6c07SRyder Lee 			  const u8 *mask)
14976be6c07SRyder Lee {
150046d2e7cSSriram R 	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
15176be6c07SRyder Lee 
15276be6c07SRyder Lee 	for (nss = 0; nss < max_nss; nss++)
153046d2e7cSSriram R 		ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss];
15476be6c07SRyder Lee }
15576be6c07SRyder Lee 
156e452c6ebSFelix Fietkau static int
mt7915_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)157e452c6ebSFelix Fietkau mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
158e452c6ebSFelix Fietkau 			  struct sk_buff *skb, int seq)
159e452c6ebSFelix Fietkau {
160fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
161e452c6ebSFelix Fietkau 	int ret = 0;
162e452c6ebSFelix Fietkau 
163e452c6ebSFelix Fietkau 	if (!skb) {
16453d35b1aSLorenzo Bianconi 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
165e452c6ebSFelix Fietkau 			cmd, seq);
166e452c6ebSFelix Fietkau 		return -ETIMEDOUT;
167e452c6ebSFelix Fietkau 	}
168e452c6ebSFelix Fietkau 
169fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
170161a7528SPeter Chiu 	if (seq != rxd->seq &&
171161a7528SPeter Chiu 	    !(rxd->eid == MCU_CMD_EXT_CID &&
172161a7528SPeter Chiu 	      rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
173e452c6ebSFelix Fietkau 		return -EAGAIN;
174e452c6ebSFelix Fietkau 
175c203dd62SFelix Fietkau 	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
176e452c6ebSFelix Fietkau 		skb_pull(skb, sizeof(*rxd) - 4);
177e452c6ebSFelix Fietkau 		ret = *skb->data;
178c203dd62SFelix Fietkau 	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
179e452c6ebSFelix Fietkau 		skb_pull(skb, sizeof(*rxd) + 4);
180e452c6ebSFelix Fietkau 		ret = le32_to_cpu(*(__le32 *)skb->data);
181c203dd62SFelix Fietkau 	} else {
182fc6ee71aSLorenzo Bianconi 		skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
183e452c6ebSFelix Fietkau 	}
184e452c6ebSFelix Fietkau 
185e452c6ebSFelix Fietkau 	return ret;
186e452c6ebSFelix Fietkau }
187e452c6ebSFelix Fietkau 
188e452c6ebSFelix Fietkau static int
mt7915_mcu_send_message(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * wait_seq)189e452c6ebSFelix Fietkau mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
190e57b7901SRyder Lee 			int cmd, int *wait_seq)
191e57b7901SRyder Lee {
192e452c6ebSFelix Fietkau 	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
193b7c56875SNathan Chancellor 	enum mt76_mcuq_id qid;
194d2f5c8edSLorenzo Bianconi 	int ret;
195e57b7901SRyder Lee 
196d2f5c8edSLorenzo Bianconi 	ret = mt76_connac2_mcu_fill_message(mdev, skb, cmd, wait_seq);
197d2f5c8edSLorenzo Bianconi 	if (ret)
198d2f5c8edSLorenzo Bianconi 		return ret;
199e452c6ebSFelix Fietkau 
200d2f5c8edSLorenzo Bianconi 	if (cmd == MCU_CMD(FW_SCATTER))
201b7c56875SNathan Chancellor 		qid = MT_MCUQ_FWDL;
202d2f5c8edSLorenzo Bianconi 	else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
203b7c56875SNathan Chancellor 		qid = MT_MCUQ_WA;
204b8135057SLorenzo Bianconi 	else
205b7c56875SNathan Chancellor 		qid = MT_MCUQ_WM;
206e57b7901SRyder Lee 
207b7c56875SNathan Chancellor 	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
208e57b7901SRyder Lee }
209e57b7901SRyder Lee 
mt7915_mcu_wa_cmd(struct mt7915_dev * dev,int cmd,u32 a1,u32 a2,u32 a3)21090f5daeaSShayne Chen int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
211f1fd2caeSFelix Fietkau {
212f1fd2caeSFelix Fietkau 	struct {
213f1fd2caeSFelix Fietkau 		__le32 args[3];
214f1fd2caeSFelix Fietkau 	} req = {
215f1fd2caeSFelix Fietkau 		.args = {
216f1fd2caeSFelix Fietkau 			cpu_to_le32(a1),
217f1fd2caeSFelix Fietkau 			cpu_to_le32(a2),
218f1fd2caeSFelix Fietkau 			cpu_to_le32(a3),
219f1fd2caeSFelix Fietkau 		},
220f1fd2caeSFelix Fietkau 	};
221f1fd2caeSFelix Fietkau 
22290f5daeaSShayne Chen 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false);
223f1fd2caeSFelix Fietkau }
224f1fd2caeSFelix Fietkau 
225f1fd2caeSFelix Fietkau static void
mt7915_mcu_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)226e57b7901SRyder Lee mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
227e57b7901SRyder Lee {
228d0a9123eSJohannes Berg 	if (vif->bss_conf.csa_active)
229e57b7901SRyder Lee 		ieee80211_csa_finish(vif);
230e57b7901SRyder Lee }
231e57b7901SRyder Lee 
232e57b7901SRyder Lee static void
mt7915_mcu_rx_csa_notify(struct mt7915_dev * dev,struct sk_buff * skb)233b6d20ce4SRyder Lee mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb)
234b6d20ce4SRyder Lee {
235b6d20ce4SRyder Lee 	struct mt76_phy *mphy = &dev->mt76.phy;
236b6d20ce4SRyder Lee 	struct mt7915_mcu_csa_notify *c;
237b6d20ce4SRyder Lee 
238b6d20ce4SRyder Lee 	c = (struct mt7915_mcu_csa_notify *)skb->data;
239b6d20ce4SRyder Lee 
2407a53eecdSRyder Lee 	if (c->band_idx > MT_BAND1)
2417a53eecdSRyder Lee 		return;
2427a53eecdSRyder Lee 
2433eb50cc9SRyder Lee 	if ((c->band_idx && !dev->phy.mt76->band_idx) &&
2443eb50cc9SRyder Lee 	    dev->mt76.phys[MT_BAND1])
245dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
246b6d20ce4SRyder Lee 
247b6d20ce4SRyder Lee 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
248b6d20ce4SRyder Lee 			IEEE80211_IFACE_ITER_RESUME_ALL,
249b6d20ce4SRyder Lee 			mt7915_mcu_csa_finish, mphy->hw);
250b6d20ce4SRyder Lee }
251b6d20ce4SRyder Lee 
252b6d20ce4SRyder Lee static void
mt7915_mcu_rx_thermal_notify(struct mt7915_dev * dev,struct sk_buff * skb)25334b877d9SRyder Lee mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb)
25434b877d9SRyder Lee {
25534b877d9SRyder Lee 	struct mt76_phy *mphy = &dev->mt76.phy;
25634b877d9SRyder Lee 	struct mt7915_mcu_thermal_notify *t;
25734b877d9SRyder Lee 	struct mt7915_phy *phy;
25834b877d9SRyder Lee 
25934b877d9SRyder Lee 	t = (struct mt7915_mcu_thermal_notify *)skb->data;
26034b877d9SRyder Lee 	if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE)
26134b877d9SRyder Lee 		return;
26234b877d9SRyder Lee 
2637a53eecdSRyder Lee 	if (t->ctrl.band_idx > MT_BAND1)
2647a53eecdSRyder Lee 		return;
2657a53eecdSRyder Lee 
2663eb50cc9SRyder Lee 	if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) &&
2673eb50cc9SRyder Lee 	    dev->mt76.phys[MT_BAND1])
268dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
26934b877d9SRyder Lee 
27034b877d9SRyder Lee 	phy = (struct mt7915_phy *)mphy->priv;
27134b877d9SRyder Lee 	phy->throttle_state = t->ctrl.duty.duty_cycle;
27234b877d9SRyder Lee }
27334b877d9SRyder Lee 
27434b877d9SRyder Lee static void
mt7915_mcu_rx_radar_detected(struct mt7915_dev * dev,struct sk_buff * skb)275e57b7901SRyder Lee mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
276e57b7901SRyder Lee {
277e57b7901SRyder Lee 	struct mt76_phy *mphy = &dev->mt76.phy;
278e57b7901SRyder Lee 	struct mt7915_mcu_rdd_report *r;
279e57b7901SRyder Lee 
280e57b7901SRyder Lee 	r = (struct mt7915_mcu_rdd_report *)skb->data;
281e57b7901SRyder Lee 
2829a399407SStanleyYP Wang 	if (r->band_idx > MT_RX_SEL2)
2837a53eecdSRyder Lee 		return;
2847a53eecdSRyder Lee 
2853eb50cc9SRyder Lee 	if ((r->band_idx && !dev->phy.mt76->band_idx) &&
2863eb50cc9SRyder Lee 	    dev->mt76.phys[MT_BAND1])
287dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
288e57b7901SRyder Lee 
28901f2cef0SLorenzo Bianconi 	if (r->band_idx == MT_RX_SEL2)
29001f2cef0SLorenzo Bianconi 		cfg80211_background_radar_event(mphy->hw->wiphy,
29101f2cef0SLorenzo Bianconi 						&dev->rdd2_chandef,
29201f2cef0SLorenzo Bianconi 						GFP_ATOMIC);
29301f2cef0SLorenzo Bianconi 	else
294e57b7901SRyder Lee 		ieee80211_radar_detected(mphy->hw);
295e57b7901SRyder Lee 	dev->hw_pattern++;
296e57b7901SRyder Lee }
297e57b7901SRyder Lee 
298e57b7901SRyder Lee static void
mt7915_mcu_rx_log_message(struct mt7915_dev * dev,struct sk_buff * skb)2995517f78bSRyder Lee mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
3005517f78bSRyder Lee {
301fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
302988845c9SFelix Fietkau 	int len = skb->len - sizeof(*rxd);
303fc6ee71aSLorenzo Bianconi 	const char *data, *type;
304fc6ee71aSLorenzo Bianconi 
305fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
306fc6ee71aSLorenzo Bianconi 	data = (char *)&rxd[1];
3075517f78bSRyder Lee 
3085517f78bSRyder Lee 	switch (rxd->s2d_index) {
3095517f78bSRyder Lee 	case 0:
310988845c9SFelix Fietkau 		if (mt7915_debugfs_rx_log(dev, data, len))
311988845c9SFelix Fietkau 			return;
312988845c9SFelix Fietkau 
3135517f78bSRyder Lee 		type = "WM";
3145517f78bSRyder Lee 		break;
3155517f78bSRyder Lee 	case 2:
3165517f78bSRyder Lee 		type = "WA";
3175517f78bSRyder Lee 		break;
3185517f78bSRyder Lee 	default:
3195517f78bSRyder Lee 		type = "unknown";
3205517f78bSRyder Lee 		break;
3215517f78bSRyder Lee 	}
3225517f78bSRyder Lee 
323988845c9SFelix Fietkau 	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
3245517f78bSRyder Lee }
3255517f78bSRyder Lee 
3265517f78bSRyder Lee static void
mt7915_mcu_cca_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)327b4b9f0a3SLorenzo Bianconi mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
328b4b9f0a3SLorenzo Bianconi {
329d0a9123eSJohannes Berg 	if (!vif->bss_conf.color_change_active)
330b4b9f0a3SLorenzo Bianconi 		return;
331b4b9f0a3SLorenzo Bianconi 
332b4b9f0a3SLorenzo Bianconi 	ieee80211_color_change_finish(vif);
333b4b9f0a3SLorenzo Bianconi }
334b4b9f0a3SLorenzo Bianconi 
335b4b9f0a3SLorenzo Bianconi static void
mt7915_mcu_rx_bcc_notify(struct mt7915_dev * dev,struct sk_buff * skb)33632406ca4SRyder Lee mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb)
33732406ca4SRyder Lee {
33832406ca4SRyder Lee 	struct mt76_phy *mphy = &dev->mt76.phy;
33932406ca4SRyder Lee 	struct mt7915_mcu_bcc_notify *b;
34032406ca4SRyder Lee 
34132406ca4SRyder Lee 	b = (struct mt7915_mcu_bcc_notify *)skb->data;
34232406ca4SRyder Lee 
3437a53eecdSRyder Lee 	if (b->band_idx > MT_BAND1)
3447a53eecdSRyder Lee 		return;
3457a53eecdSRyder Lee 
3467a53eecdSRyder Lee 	if ((b->band_idx && !dev->phy.mt76->band_idx) &&
3477a53eecdSRyder Lee 	    dev->mt76.phys[MT_BAND1])
348dc44c45cSLorenzo Bianconi 		mphy = dev->mt76.phys[MT_BAND1];
34932406ca4SRyder Lee 
35032406ca4SRyder Lee 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
35132406ca4SRyder Lee 			IEEE80211_IFACE_ITER_RESUME_ALL,
35232406ca4SRyder Lee 			mt7915_mcu_cca_finish, mphy->hw);
35332406ca4SRyder Lee }
35432406ca4SRyder Lee 
35532406ca4SRyder Lee static void
mt7915_mcu_rx_ext_event(struct mt7915_dev * dev,struct sk_buff * skb)356e57b7901SRyder Lee mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
357e57b7901SRyder Lee {
358fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
359e57b7901SRyder Lee 
360fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
361e57b7901SRyder Lee 	switch (rxd->ext_eid) {
36234b877d9SRyder Lee 	case MCU_EXT_EVENT_THERMAL_PROTECT:
36334b877d9SRyder Lee 		mt7915_mcu_rx_thermal_notify(dev, skb);
36434b877d9SRyder Lee 		break;
365e57b7901SRyder Lee 	case MCU_EXT_EVENT_RDD_REPORT:
366e57b7901SRyder Lee 		mt7915_mcu_rx_radar_detected(dev, skb);
367e57b7901SRyder Lee 		break;
368e57b7901SRyder Lee 	case MCU_EXT_EVENT_CSA_NOTIFY:
369b6d20ce4SRyder Lee 		mt7915_mcu_rx_csa_notify(dev, skb);
370e57b7901SRyder Lee 		break;
3715517f78bSRyder Lee 	case MCU_EXT_EVENT_FW_LOG_2_HOST:
3725517f78bSRyder Lee 		mt7915_mcu_rx_log_message(dev, skb);
3735517f78bSRyder Lee 		break;
374b4b9f0a3SLorenzo Bianconi 	case MCU_EXT_EVENT_BCC_NOTIFY:
37532406ca4SRyder Lee 		mt7915_mcu_rx_bcc_notify(dev, skb);
376b4b9f0a3SLorenzo Bianconi 		break;
377e57b7901SRyder Lee 	default:
378e57b7901SRyder Lee 		break;
379e57b7901SRyder Lee 	}
380e57b7901SRyder Lee }
381e57b7901SRyder Lee 
382e57b7901SRyder Lee static void
mt7915_mcu_rx_unsolicited_event(struct mt7915_dev * dev,struct sk_buff * skb)383e57b7901SRyder Lee mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb)
384e57b7901SRyder Lee {
385fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
386e57b7901SRyder Lee 
387fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
388e57b7901SRyder Lee 	switch (rxd->eid) {
389e57b7901SRyder Lee 	case MCU_EVENT_EXT:
390e57b7901SRyder Lee 		mt7915_mcu_rx_ext_event(dev, skb);
391e57b7901SRyder Lee 		break;
392e57b7901SRyder Lee 	default:
393e57b7901SRyder Lee 		break;
394e57b7901SRyder Lee 	}
395e57b7901SRyder Lee 	dev_kfree_skb(skb);
396e57b7901SRyder Lee }
397e57b7901SRyder Lee 
mt7915_mcu_rx_event(struct mt7915_dev * dev,struct sk_buff * skb)398e57b7901SRyder Lee void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
399e57b7901SRyder Lee {
400fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
401e57b7901SRyder Lee 
402fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
403161a7528SPeter Chiu 	if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
4045517f78bSRyder Lee 	     rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
405e57b7901SRyder Lee 	     rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
406e57b7901SRyder Lee 	     rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
407b4b9f0a3SLorenzo Bianconi 	     rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
408161a7528SPeter Chiu 	     !rxd->seq) &&
409161a7528SPeter Chiu 	     !(rxd->eid == MCU_CMD_EXT_CID &&
410161a7528SPeter Chiu 	       rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
411e57b7901SRyder Lee 		mt7915_mcu_rx_unsolicited_event(dev, skb);
412e57b7901SRyder Lee 	else
413e57b7901SRyder Lee 		mt76_mcu_rx_event(&dev->mt76, skb);
414e57b7901SRyder Lee }
415e57b7901SRyder Lee 
416e57b7901SRyder Lee static struct tlv *
mt7915_mcu_add_nested_subtlv(struct sk_buff * skb,int sub_tag,int sub_len,__le16 * sub_ntlv,__le16 * len)417e57b7901SRyder Lee mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len,
418e57b7901SRyder Lee 			     __le16 *sub_ntlv, __le16 *len)
419e57b7901SRyder Lee {
420e57b7901SRyder Lee 	struct tlv *ptlv, tlv = {
421e57b7901SRyder Lee 		.tag = cpu_to_le16(sub_tag),
422e57b7901SRyder Lee 		.len = cpu_to_le16(sub_len),
423e57b7901SRyder Lee 	};
424e57b7901SRyder Lee 
425ff6b26beSFelix Fietkau 	ptlv = skb_put_zero(skb, sub_len);
426e57b7901SRyder Lee 	memcpy(ptlv, &tlv, sizeof(tlv));
427e57b7901SRyder Lee 
42859283d09SLiu Shixin 	le16_add_cpu(sub_ntlv, 1);
42959283d09SLiu Shixin 	le16_add_cpu(len, sub_len);
430e57b7901SRyder Lee 
431e57b7901SRyder Lee 	return ptlv;
432e57b7901SRyder Lee }
433e57b7901SRyder Lee 
434e57b7901SRyder Lee /** bss info **/
4356094f86fSRyder Lee struct mt7915_he_obss_narrow_bw_ru_data {
4366094f86fSRyder Lee 	bool tolerated;
4376094f86fSRyder Lee };
4386094f86fSRyder Lee 
mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy * wiphy,struct cfg80211_bss * bss,void * _data)4396094f86fSRyder Lee static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
4406094f86fSRyder Lee 						   struct cfg80211_bss *bss,
4416094f86fSRyder Lee 						   void *_data)
4426094f86fSRyder Lee {
4436094f86fSRyder Lee 	struct mt7915_he_obss_narrow_bw_ru_data *data = _data;
4446094f86fSRyder Lee 	const struct element *elem;
4456094f86fSRyder Lee 
446ffbebe76SRyder Lee 	rcu_read_lock();
447f9a5c056SRyder Lee 	elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY);
4486094f86fSRyder Lee 
449d45dac07SRyder Lee 	if (!elem || elem->datalen <= 10 ||
4506094f86fSRyder Lee 	    !(elem->data[10] &
4516094f86fSRyder Lee 	      WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT))
4526094f86fSRyder Lee 		data->tolerated = false;
453ffbebe76SRyder Lee 
454ffbebe76SRyder Lee 	rcu_read_unlock();
4556094f86fSRyder Lee }
4566094f86fSRyder Lee 
mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw * hw,struct ieee80211_vif * vif)4576094f86fSRyder Lee static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
4586094f86fSRyder Lee 					      struct ieee80211_vif *vif)
4596094f86fSRyder Lee {
4606094f86fSRyder Lee 	struct mt7915_he_obss_narrow_bw_ru_data iter_data = {
4616094f86fSRyder Lee 		.tolerated = true,
4626094f86fSRyder Lee 	};
4636094f86fSRyder Lee 
4646094f86fSRyder Lee 	if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR))
4656094f86fSRyder Lee 		return false;
4666094f86fSRyder Lee 
4676094f86fSRyder Lee 	cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef,
4686094f86fSRyder Lee 			  mt7915_check_he_obss_narrow_bw_ru_iter,
4696094f86fSRyder Lee 			  &iter_data);
4706094f86fSRyder Lee 
4716094f86fSRyder Lee 	/*
4726094f86fSRyder Lee 	 * If there is at least one AP on radar channel that cannot
4736094f86fSRyder Lee 	 * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.
4746094f86fSRyder Lee 	 */
4756094f86fSRyder Lee 	return !iter_data.tolerated;
4766094f86fSRyder Lee }
4776094f86fSRyder Lee 
478e57b7901SRyder Lee static void
mt7915_mcu_bss_rfch_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)479e57b7901SRyder Lee mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
480e57b7901SRyder Lee 			struct mt7915_phy *phy)
481e57b7901SRyder Lee {
482e57b7901SRyder Lee 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
483e57b7901SRyder Lee 	struct bss_info_rf_ch *ch;
484e57b7901SRyder Lee 	struct tlv *tlv;
485e57b7901SRyder Lee 	int freq1 = chandef->center_freq1;
486e57b7901SRyder Lee 
487069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch));
488e57b7901SRyder Lee 
489e57b7901SRyder Lee 	ch = (struct bss_info_rf_ch *)tlv;
490e57b7901SRyder Lee 	ch->pri_ch = chandef->chan->hw_value;
491e57b7901SRyder Lee 	ch->center_ch0 = ieee80211_frequency_to_channel(freq1);
49244c73d17SLorenzo Bianconi 	ch->bw = mt76_connac_chan_bw(chandef);
493e57b7901SRyder Lee 
494e57b7901SRyder Lee 	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
495e57b7901SRyder Lee 		int freq2 = chandef->center_freq2;
496e57b7901SRyder Lee 
497e57b7901SRyder Lee 		ch->center_ch1 = ieee80211_frequency_to_channel(freq2);
498e57b7901SRyder Lee 	}
499e57b7901SRyder Lee 
5006094f86fSRyder Lee 	if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) {
501006b9d4aSBo Jiao 		struct mt76_phy *mphy = phy->mt76;
5026094f86fSRyder Lee 
5036094f86fSRyder Lee 		ch->he_ru26_block =
5046094f86fSRyder Lee 			mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif);
5056094f86fSRyder Lee 		ch->he_all_disable = false;
5066094f86fSRyder Lee 	} else {
507e57b7901SRyder Lee 		ch->he_all_disable = true;
508e57b7901SRyder Lee 	}
5096094f86fSRyder Lee }
510e57b7901SRyder Lee 
511e57b7901SRyder Lee static void
mt7915_mcu_bss_ra_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)512e57b7901SRyder Lee mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
513e57b7901SRyder Lee 		      struct mt7915_phy *phy)
514e57b7901SRyder Lee {
515ee0863aeSPeter Chiu 	int max_nss = hweight8(phy->mt76->antenna_mask);
516e57b7901SRyder Lee 	struct bss_info_ra *ra;
517e57b7901SRyder Lee 	struct tlv *tlv;
518e57b7901SRyder Lee 
519069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra));
520e57b7901SRyder Lee 
521e57b7901SRyder Lee 	ra = (struct bss_info_ra *)tlv;
522e57b7901SRyder Lee 	ra->op_mode = vif->type == NL80211_IFTYPE_AP;
523e57b7901SRyder Lee 	ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC;
524e57b7901SRyder Lee 	ra->short_preamble = true;
525e57b7901SRyder Lee 	ra->tx_streams = max_nss;
526e57b7901SRyder Lee 	ra->rx_streams = max_nss;
527e57b7901SRyder Lee 	ra->algo = 4;
528e57b7901SRyder Lee 	ra->train_up_rule = 2;
529e57b7901SRyder Lee 	ra->train_up_high_thres = 110;
530e57b7901SRyder Lee 	ra->train_up_rule_rssi = -70;
531e57b7901SRyder Lee 	ra->low_traffic_thres = 2;
532e57b7901SRyder Lee 	ra->phy_cap = cpu_to_le32(0xfdf);
533e57b7901SRyder Lee 	ra->interval = cpu_to_le32(500);
534e57b7901SRyder Lee 	ra->fast_interval = cpu_to_le32(100);
535e57b7901SRyder Lee }
536e57b7901SRyder Lee 
537e57b7901SRyder Lee static void
mt7915_mcu_bss_he_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)5386094f86fSRyder Lee mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
5396094f86fSRyder Lee 		      struct mt7915_phy *phy)
5406094f86fSRyder Lee {
5416094f86fSRyder Lee #define DEFAULT_HE_PE_DURATION		4
5426094f86fSRyder Lee #define DEFAULT_HE_DURATION_RTS_THRES	1023
5436094f86fSRyder Lee 	const struct ieee80211_sta_he_cap *cap;
5446094f86fSRyder Lee 	struct bss_info_he *he;
5456094f86fSRyder Lee 	struct tlv *tlv;
5466094f86fSRyder Lee 
547e6d557a7SLorenzo Bianconi 	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
5486094f86fSRyder Lee 
549069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
5506094f86fSRyder Lee 
5516094f86fSRyder Lee 	he = (struct bss_info_he *)tlv;
5522fe1a5d6SFelix Fietkau 	he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
5536094f86fSRyder Lee 	if (!he->he_pe_duration)
5546094f86fSRyder Lee 		he->he_pe_duration = DEFAULT_HE_PE_DURATION;
5556094f86fSRyder Lee 
5562fe1a5d6SFelix Fietkau 	he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
5576094f86fSRyder Lee 	if (!he->he_rts_thres)
5586094f86fSRyder Lee 		he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
5596094f86fSRyder Lee 
5606094f86fSRyder Lee 	he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;
5616094f86fSRyder Lee 	he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;
5626094f86fSRyder Lee 	he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
5636094f86fSRyder Lee }
5646094f86fSRyder Lee 
5656094f86fSRyder Lee static void
mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff * skb)566b443e55fSRyder Lee mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
567b443e55fSRyder Lee {
568b443e55fSRyder Lee #define TXD_CMP_MAP1		GENMASK(15, 0)
569b443e55fSRyder Lee #define TXD_CMP_MAP2		(GENMASK(31, 0) & ~BIT(23))
570b443e55fSRyder Lee 	struct bss_info_hw_amsdu *amsdu;
571b443e55fSRyder Lee 	struct tlv *tlv;
572b443e55fSRyder Lee 
573069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
574b443e55fSRyder Lee 
575b443e55fSRyder Lee 	amsdu = (struct bss_info_hw_amsdu *)tlv;
576b443e55fSRyder Lee 	amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
577b443e55fSRyder Lee 	amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
578b443e55fSRyder Lee 	amsdu->trig_thres = cpu_to_le16(2);
579b443e55fSRyder Lee 	amsdu->enable = true;
580b443e55fSRyder Lee }
581b443e55fSRyder Lee 
582b443e55fSRyder Lee static void
mt7915_mcu_bss_bmc_tlv(struct sk_buff * skb,struct mt7915_phy * phy)583e57b7901SRyder Lee mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy)
584e57b7901SRyder Lee {
585e57b7901SRyder Lee 	struct bss_info_bmc_rate *bmc;
586e57b7901SRyder Lee 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
587e57b7901SRyder Lee 	enum nl80211_band band = chandef->chan->band;
588e57b7901SRyder Lee 	struct tlv *tlv;
589e57b7901SRyder Lee 
590069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc));
591e57b7901SRyder Lee 
592e57b7901SRyder Lee 	bmc = (struct bss_info_bmc_rate *)tlv;
593e57b7901SRyder Lee 	if (band == NL80211_BAND_2GHZ) {
594e57b7901SRyder Lee 		bmc->short_preamble = true;
595e57b7901SRyder Lee 	} else {
596e57b7901SRyder Lee 		bmc->bc_trans = cpu_to_le16(0x2000);
597e57b7901SRyder Lee 		bmc->mc_trans = cpu_to_le16(0x2080);
598e57b7901SRyder Lee 	}
599e57b7901SRyder Lee }
600e57b7901SRyder Lee 
6018aa2c6f4SFelix Fietkau static int
mt7915_mcu_muar_config(struct mt7915_phy * phy,struct ieee80211_vif * vif,bool bssid,bool enable)6028aa2c6f4SFelix Fietkau mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif,
6038aa2c6f4SFelix Fietkau 		       bool bssid, bool enable)
6048aa2c6f4SFelix Fietkau {
6058aa2c6f4SFelix Fietkau 	struct mt7915_dev *dev = phy->dev;
6068aa2c6f4SFelix Fietkau 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
6076cf4392fSLorenzo Bianconi 	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
6088aa2c6f4SFelix Fietkau 	u32 mask = phy->omac_mask >> 32 & ~BIT(idx);
6098aa2c6f4SFelix Fietkau 	const u8 *addr = vif->addr;
6108aa2c6f4SFelix Fietkau 	struct {
6118aa2c6f4SFelix Fietkau 		u8 mode;
6128aa2c6f4SFelix Fietkau 		u8 force_clear;
6138aa2c6f4SFelix Fietkau 		u8 clear_bitmap[8];
6148aa2c6f4SFelix Fietkau 		u8 entry_count;
6158aa2c6f4SFelix Fietkau 		u8 write;
6168aa2c6f4SFelix Fietkau 		u8 band;
6178aa2c6f4SFelix Fietkau 
6188aa2c6f4SFelix Fietkau 		u8 index;
6198aa2c6f4SFelix Fietkau 		u8 bssid;
6208aa2c6f4SFelix Fietkau 		u8 addr[ETH_ALEN];
6218aa2c6f4SFelix Fietkau 	} __packed req = {
6228aa2c6f4SFelix Fietkau 		.mode = !!mask || enable,
6238aa2c6f4SFelix Fietkau 		.entry_count = 1,
6248aa2c6f4SFelix Fietkau 		.write = 1,
6253eb50cc9SRyder Lee 		.band = phy->mt76->band_idx,
6268aa2c6f4SFelix Fietkau 		.index = idx * 2 + bssid,
6278aa2c6f4SFelix Fietkau 	};
6288aa2c6f4SFelix Fietkau 
6298aa2c6f4SFelix Fietkau 	if (bssid)
6308aa2c6f4SFelix Fietkau 		addr = vif->bss_conf.bssid;
6318aa2c6f4SFelix Fietkau 
6328aa2c6f4SFelix Fietkau 	if (enable)
6338aa2c6f4SFelix Fietkau 		ether_addr_copy(req.addr, addr);
6348aa2c6f4SFelix Fietkau 
635c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req,
636cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
6378aa2c6f4SFelix Fietkau }
6388aa2c6f4SFelix Fietkau 
mt7915_mcu_add_bss_info(struct mt7915_phy * phy,struct ieee80211_vif * vif,int enable)639e57b7901SRyder Lee int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
640e57b7901SRyder Lee 			    struct ieee80211_vif *vif, int enable)
641e57b7901SRyder Lee {
642e57b7901SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
643e2c93b68SLorenzo Bianconi 	struct mt7915_dev *dev = phy->dev;
644e57b7901SRyder Lee 	struct sk_buff *skb;
645e57b7901SRyder Lee 
6466cf4392fSLorenzo Bianconi 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) {
6479add4bf2SFelix Fietkau 		mt7915_mcu_muar_config(phy, vif, false, enable);
6488aa2c6f4SFelix Fietkau 		mt7915_mcu_muar_config(phy, vif, true, enable);
6499add4bf2SFelix Fietkau 	}
6508aa2c6f4SFelix Fietkau 
651e2c93b68SLorenzo Bianconi 	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
6523e68af62SRyder Lee 					      MT7915_BSS_UPDATE_MAX_SIZE);
653e57b7901SRyder Lee 	if (IS_ERR(skb))
654e57b7901SRyder Lee 		return PTR_ERR(skb);
655e57b7901SRyder Lee 
656e57b7901SRyder Lee 	/* bss_omac must be first */
657e57b7901SRyder Lee 	if (enable)
65854735e11SLorenzo Bianconi 		mt76_connac_mcu_bss_omac_tlv(skb, vif);
659e57b7901SRyder Lee 
66049126ac1SLorenzo Bianconi 	mt76_connac_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76,
66149126ac1SLorenzo Bianconi 				      mvif->sta.wcid.idx, enable);
662e57b7901SRyder Lee 
663dae0dc2bSShayne Chen 	if (vif->type == NL80211_IFTYPE_MONITOR)
664dae0dc2bSShayne Chen 		goto out;
665dae0dc2bSShayne Chen 
666e57b7901SRyder Lee 	if (enable) {
667e57b7901SRyder Lee 		mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
668e57b7901SRyder Lee 		mt7915_mcu_bss_bmc_tlv(skb, phy);
669e57b7901SRyder Lee 		mt7915_mcu_bss_ra_tlv(skb, vif, phy);
670b443e55fSRyder Lee 		mt7915_mcu_bss_hw_amsdu_tlv(skb);
671e57b7901SRyder Lee 
6726094f86fSRyder Lee 		if (vif->bss_conf.he_support)
6736094f86fSRyder Lee 			mt7915_mcu_bss_he_tlv(skb, vif, phy);
6746094f86fSRyder Lee 
6756cf4392fSLorenzo Bianconi 		if (mvif->mt76.omac_idx >= EXT_BSSID_START &&
6766cf4392fSLorenzo Bianconi 		    mvif->mt76.omac_idx < REPEATER_BSSID_START)
67764f4e823SLorenzo Bianconi 			mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
678e57b7901SRyder Lee 	}
679dae0dc2bSShayne Chen out:
680e2c93b68SLorenzo Bianconi 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
681c203dd62SFelix Fietkau 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
682e57b7901SRyder Lee }
683e57b7901SRyder Lee 
684e57b7901SRyder Lee /** starec & wtbl **/
mt7915_mcu_add_tx_ba(struct mt7915_dev * dev,struct ieee80211_ampdu_params * params,bool enable)685e57b7901SRyder Lee int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
686e57b7901SRyder Lee 			 struct ieee80211_ampdu_params *params,
687e57b7901SRyder Lee 			 bool enable)
688e57b7901SRyder Lee {
689b5322e44SLorenzo Bianconi 	struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
690b5322e44SLorenzo Bianconi 	struct mt7915_vif *mvif = msta->vif;
6913f5625e9SFelix Fietkau 	int ret;
692b5322e44SLorenzo Bianconi 
6933f5625e9SFelix Fietkau 	mt76_worker_disable(&dev->mt76.tx_worker);
694b5322e44SLorenzo Bianconi 	if (enable && !params->amsdu)
695b5322e44SLorenzo Bianconi 		msta->wcid.amsdu = false;
6963f5625e9SFelix Fietkau 	ret = mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
697b5322e44SLorenzo Bianconi 				     MCU_EXT_CMD(STA_REC_UPDATE),
698b5322e44SLorenzo Bianconi 				     enable, true);
6993f5625e9SFelix Fietkau 	mt76_worker_enable(&dev->mt76.tx_worker);
7003f5625e9SFelix Fietkau 
7013f5625e9SFelix Fietkau 	return ret;
702e57b7901SRyder Lee }
703e57b7901SRyder Lee 
mt7915_mcu_add_rx_ba(struct mt7915_dev * dev,struct ieee80211_ampdu_params * params,bool enable)704e57b7901SRyder Lee int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
705e57b7901SRyder Lee 			 struct ieee80211_ampdu_params *params,
706e57b7901SRyder Lee 			 bool enable)
707e57b7901SRyder Lee {
708b5322e44SLorenzo Bianconi 	struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
709b5322e44SLorenzo Bianconi 	struct mt7915_vif *mvif = msta->vif;
710b5322e44SLorenzo Bianconi 
711b5322e44SLorenzo Bianconi 	return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
712b5322e44SLorenzo Bianconi 				      MCU_EXT_CMD(STA_REC_UPDATE),
713b5322e44SLorenzo Bianconi 				      enable, false);
714e57b7901SRyder Lee }
715e57b7901SRyder Lee 
716e57b7901SRyder Lee static void
mt7915_mcu_sta_he_tlv(struct sk_buff * skb,struct ieee80211_sta * sta,struct ieee80211_vif * vif)71722dffbddSRyder Lee mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
71822dffbddSRyder Lee 		      struct ieee80211_vif *vif)
719c336318fSRyder Lee {
72002a89404SFelix Fietkau 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
721046d2e7cSSriram R 	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
722ade25ca7SPeter Chiu 	struct ieee80211_he_mcs_nss_supp mcs_map;
723c336318fSRyder Lee 	struct sta_rec_he *he;
724c336318fSRyder Lee 	struct tlv *tlv;
725c336318fSRyder Lee 	u32 cap = 0;
726c336318fSRyder Lee 
727046d2e7cSSriram R 	if (!sta->deflink.he_cap.has_he)
72889bbd373SShayne Chen 		return;
72989bbd373SShayne Chen 
730069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
731c336318fSRyder Lee 
732c336318fSRyder Lee 	he = (struct sta_rec_he *)tlv;
733c336318fSRyder Lee 
734c336318fSRyder Lee 	if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)
735c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_HTC;
736c336318fSRyder Lee 
737c336318fSRyder Lee 	if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
738c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_BSR;
739c336318fSRyder Lee 
740c336318fSRyder Lee 	if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
741c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_OM;
742c336318fSRyder Lee 
7432f516444SJohannes Berg 	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU)
744c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU;
745c336318fSRyder Lee 
746c336318fSRyder Lee 	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
747c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_BQR;
748c336318fSRyder Lee 
749c336318fSRyder Lee 	if (elem->phy_cap_info[0] &
750c336318fSRyder Lee 	    (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G |
751c336318fSRyder Lee 	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
752c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
753c336318fSRyder Lee 
75402a89404SFelix Fietkau 	if (mvif->cap.he_ldpc &&
755499da720SMeiChia Chiu 	    (elem->phy_cap_info[1] &
75622dffbddSRyder Lee 	     IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
757c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_LDPC;
758c336318fSRyder Lee 
759c336318fSRyder Lee 	if (elem->phy_cap_info[1] &
760c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US)
761c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI;
762c336318fSRyder Lee 
763c336318fSRyder Lee 	if (elem->phy_cap_info[2] &
764c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US)
765c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI;
766c336318fSRyder Lee 
767c336318fSRyder Lee 	if (elem->phy_cap_info[2] &
768c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ)
769c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC;
770c336318fSRyder Lee 
771c336318fSRyder Lee 	if (elem->phy_cap_info[2] &
772c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
773c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;
774c336318fSRyder Lee 
775c336318fSRyder Lee 	if (elem->phy_cap_info[6] &
7763176487fSShayne Chen 	    IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB)
7773176487fSShayne Chen 		cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
7783176487fSShayne Chen 
7793176487fSShayne Chen 	if (elem->phy_cap_info[6] &
780c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)
781c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;
782c336318fSRyder Lee 
783c336318fSRyder Lee 	if (elem->phy_cap_info[7] &
784c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI)
785c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI;
786c336318fSRyder Lee 
787c336318fSRyder Lee 	if (elem->phy_cap_info[7] &
788c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ)
789c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_GT_80M_TX_STBC;
790c336318fSRyder Lee 
791c336318fSRyder Lee 	if (elem->phy_cap_info[7] &
792c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
793c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_GT_80M_RX_STBC;
794c336318fSRyder Lee 
795c336318fSRyder Lee 	if (elem->phy_cap_info[8] &
796c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI)
797c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI;
798c336318fSRyder Lee 
799c336318fSRyder Lee 	if (elem->phy_cap_info[8] &
800c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI)
801c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;
802c336318fSRyder Lee 
803c336318fSRyder Lee 	if (elem->phy_cap_info[9] &
804c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)
805c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;
806c336318fSRyder Lee 
807c336318fSRyder Lee 	if (elem->phy_cap_info[9] &
808c336318fSRyder Lee 	    IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU)
809c336318fSRyder Lee 		cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242;
810c336318fSRyder Lee 
811c336318fSRyder Lee 	he->he_cap = cpu_to_le32(cap);
812c336318fSRyder Lee 
813046d2e7cSSriram R 	mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
814046d2e7cSSriram R 	switch (sta->deflink.bandwidth) {
815c336318fSRyder Lee 	case IEEE80211_STA_RX_BW_160:
816c336318fSRyder Lee 		if (elem->phy_cap_info[0] &
817c336318fSRyder Lee 		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
81876be6c07SRyder Lee 			mt7915_mcu_set_sta_he_mcs(sta,
81976be6c07SRyder Lee 						  &he->max_nss_mcs[CMD_HE_MCS_BW8080],
820ade25ca7SPeter Chiu 						  le16_to_cpu(mcs_map.rx_mcs_80p80));
821c336318fSRyder Lee 
82276be6c07SRyder Lee 		mt7915_mcu_set_sta_he_mcs(sta,
82376be6c07SRyder Lee 					  &he->max_nss_mcs[CMD_HE_MCS_BW160],
824ade25ca7SPeter Chiu 					  le16_to_cpu(mcs_map.rx_mcs_160));
825aab662ccSGustavo A. R. Silva 		fallthrough;
826c336318fSRyder Lee 	default:
82776be6c07SRyder Lee 		mt7915_mcu_set_sta_he_mcs(sta,
82876be6c07SRyder Lee 					  &he->max_nss_mcs[CMD_HE_MCS_BW80],
829ade25ca7SPeter Chiu 					  le16_to_cpu(mcs_map.rx_mcs_80));
830c336318fSRyder Lee 		break;
831c336318fSRyder Lee 	}
832c336318fSRyder Lee 
833c336318fSRyder Lee 	he->t_frame_dur =
834c336318fSRyder Lee 		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
835c336318fSRyder Lee 	he->max_ampdu_exp =
836c336318fSRyder Lee 		HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]);
837c336318fSRyder Lee 
838c336318fSRyder Lee 	he->bw_set =
839c336318fSRyder Lee 		HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]);
840c336318fSRyder Lee 	he->device_class =
841c336318fSRyder Lee 		HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]);
842c336318fSRyder Lee 	he->punc_pream_rx =
843c336318fSRyder Lee 		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
844c336318fSRyder Lee 
845c336318fSRyder Lee 	he->dcm_tx_mode =
846c336318fSRyder Lee 		HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]);
847c336318fSRyder Lee 	he->dcm_tx_max_nss =
848c336318fSRyder Lee 		HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]);
849c336318fSRyder Lee 	he->dcm_rx_mode =
850c336318fSRyder Lee 		HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]);
851c336318fSRyder Lee 	he->dcm_rx_max_nss =
852c336318fSRyder Lee 		HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]);
853c336318fSRyder Lee 	he->dcm_rx_max_nss =
854c336318fSRyder Lee 		HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]);
855c336318fSRyder Lee 
856c336318fSRyder Lee 	he->pkt_ext = 2;
857c336318fSRyder Lee }
858c336318fSRyder Lee 
859c336318fSRyder Lee static void
mt7915_mcu_sta_muru_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_sta * sta,struct ieee80211_vif * vif)860c3f2ed58SFelix Fietkau mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
861c3f2ed58SFelix Fietkau 			struct ieee80211_sta *sta, struct ieee80211_vif *vif)
862c336318fSRyder Lee {
86302a89404SFelix Fietkau 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
864046d2e7cSSriram R 	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
865c336318fSRyder Lee 	struct sta_rec_muru *muru;
866c336318fSRyder Lee 	struct tlv *tlv;
867c336318fSRyder Lee 
86816bff457SShayne Chen 	if (vif->type != NL80211_IFTYPE_STATION &&
86916bff457SShayne Chen 	    vif->type != NL80211_IFTYPE_AP)
87016bff457SShayne Chen 		return;
87116bff457SShayne Chen 
872069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
873c336318fSRyder Lee 
874c336318fSRyder Lee 	muru = (struct sta_rec_muru *)tlv;
87522dffbddSRyder Lee 
87602a89404SFelix Fietkau 	muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
87702a89404SFelix Fietkau 			       mvif->cap.vht_mu_ebfer ||
87802a89404SFelix Fietkau 			       mvif->cap.vht_mu_ebfee;
879c3f2ed58SFelix Fietkau 	if (!is_mt7915(&dev->mt76))
880d98a7272SMeiChia Chiu 		muru->cfg.mimo_ul_en = true;
881d98a7272SMeiChia Chiu 	muru->cfg.ofdma_dl_en = true;
882c336318fSRyder Lee 
883046d2e7cSSriram R 	if (sta->deflink.vht_cap.vht_supported)
88416bff457SShayne Chen 		muru->mimo_dl.vht_mu_bfee =
885046d2e7cSSriram R 			!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
88616bff457SShayne Chen 
887046d2e7cSSriram R 	if (!sta->deflink.he_cap.has_he)
88816bff457SShayne Chen 		return;
88916bff457SShayne Chen 
89016bff457SShayne Chen 	muru->mimo_dl.partial_bw_dl_mimo =
89116bff457SShayne Chen 		HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
89216bff457SShayne Chen 
89316bff457SShayne Chen 	muru->mimo_ul.full_ul_mimo =
89416bff457SShayne Chen 		HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
89516bff457SShayne Chen 	muru->mimo_ul.partial_ul_mimo =
89616bff457SShayne Chen 		HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
89716bff457SShayne Chen 
898c336318fSRyder Lee 	muru->ofdma_dl.punc_pream_rx =
899c336318fSRyder Lee 		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
900c336318fSRyder Lee 	muru->ofdma_dl.he_20m_in_40m_2g =
901c336318fSRyder Lee 		HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
902c336318fSRyder Lee 	muru->ofdma_dl.he_20m_in_160m =
903c336318fSRyder Lee 		HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
904c336318fSRyder Lee 	muru->ofdma_dl.he_80m_in_160m =
905c336318fSRyder Lee 		HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
906c336318fSRyder Lee 
907c336318fSRyder Lee 	muru->ofdma_ul.t_frame_dur =
908c336318fSRyder Lee 		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
909c336318fSRyder Lee 	muru->ofdma_ul.mu_cascading =
910c336318fSRyder Lee 		HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
911c336318fSRyder Lee 	muru->ofdma_ul.uo_ra =
912c336318fSRyder Lee 		HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
913c336318fSRyder Lee }
914c336318fSRyder Lee 
915b70946ceSRyder Lee static void
mt7915_mcu_sta_ht_tlv(struct sk_buff * skb,struct ieee80211_sta * sta)91689bbd373SShayne Chen mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
91789bbd373SShayne Chen {
91889bbd373SShayne Chen 	struct sta_rec_ht *ht;
91989bbd373SShayne Chen 	struct tlv *tlv;
92089bbd373SShayne Chen 
921046d2e7cSSriram R 	if (!sta->deflink.ht_cap.ht_supported)
922b4d093e3SMeiChia Chiu 		return;
923b4d093e3SMeiChia Chiu 
924069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
92589bbd373SShayne Chen 
92689bbd373SShayne Chen 	ht = (struct sta_rec_ht *)tlv;
927046d2e7cSSriram R 	ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
92889bbd373SShayne Chen }
92989bbd373SShayne Chen 
93089bbd373SShayne Chen static void
mt7915_mcu_sta_vht_tlv(struct sk_buff * skb,struct ieee80211_sta * sta)931b70946ceSRyder Lee mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
932f68e6a1fSRyder Lee {
933b70946ceSRyder Lee 	struct sta_rec_vht *vht;
934b70946ceSRyder Lee 	struct tlv *tlv;
935f68e6a1fSRyder Lee 
936046d2e7cSSriram R 	if (!sta->deflink.vht_cap.vht_supported)
93789bbd373SShayne Chen 		return;
93889bbd373SShayne Chen 
939069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
940f68e6a1fSRyder Lee 
941b70946ceSRyder Lee 	vht = (struct sta_rec_vht *)tlv;
942046d2e7cSSriram R 	vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
943046d2e7cSSriram R 	vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
944046d2e7cSSriram R 	vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
945f68e6a1fSRyder Lee }
946f68e6a1fSRyder Lee 
947c336318fSRyder Lee static void
mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)948be1954ffSPeter Chiu mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
949be1954ffSPeter Chiu 			 struct ieee80211_vif *vif, struct ieee80211_sta *sta)
950b443e55fSRyder Lee {
951b443e55fSRyder Lee 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
952b443e55fSRyder Lee 	struct sta_rec_amsdu *amsdu;
953b443e55fSRyder Lee 	struct tlv *tlv;
954b443e55fSRyder Lee 
95589bbd373SShayne Chen 	if (vif->type != NL80211_IFTYPE_STATION &&
95689bbd373SShayne Chen 	    vif->type != NL80211_IFTYPE_AP)
95789bbd373SShayne Chen 		return;
95889bbd373SShayne Chen 
9594c51541dSBenjamin Berg 	if (!sta->deflink.agg.max_amsdu_len)
960b443e55fSRyder Lee 	    return;
961b443e55fSRyder Lee 
962069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
963b443e55fSRyder Lee 	amsdu = (struct sta_rec_amsdu *)tlv;
964b443e55fSRyder Lee 	amsdu->max_amsdu_num = 8;
965b443e55fSRyder Lee 	amsdu->amsdu_en = true;
966b443e55fSRyder Lee 	msta->wcid.amsdu = true;
967be1954ffSPeter Chiu 
9684c51541dSBenjamin Berg 	switch (sta->deflink.agg.max_amsdu_len) {
969be1954ffSPeter Chiu 	case IEEE80211_MAX_MPDU_LEN_VHT_11454:
970be1954ffSPeter Chiu 		if (!is_mt7915(&dev->mt76)) {
971be1954ffSPeter Chiu 			amsdu->max_mpdu_size =
972be1954ffSPeter Chiu 				IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
973be1954ffSPeter Chiu 			return;
974be1954ffSPeter Chiu 		}
975be1954ffSPeter Chiu 		fallthrough;
976be1954ffSPeter Chiu 	case IEEE80211_MAX_MPDU_LEN_HT_7935:
977be1954ffSPeter Chiu 	case IEEE80211_MAX_MPDU_LEN_VHT_7991:
978be1954ffSPeter Chiu 		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
979be1954ffSPeter Chiu 		return;
980be1954ffSPeter Chiu 	default:
981be1954ffSPeter Chiu 		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
982be1954ffSPeter Chiu 		return;
983be1954ffSPeter Chiu 	}
984b443e55fSRyder Lee }
985b443e55fSRyder Lee 
98689bbd373SShayne Chen static int
mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)98789bbd373SShayne Chen mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
98889bbd373SShayne Chen 			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
98989bbd373SShayne Chen {
99089bbd373SShayne Chen 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
99189bbd373SShayne Chen 	struct mt7915_sta *msta;
99289bbd373SShayne Chen 	struct wtbl_req_hdr *wtbl_hdr;
9935121585eSLorenzo Bianconi 	struct mt76_wcid *wcid;
99489bbd373SShayne Chen 	struct tlv *tlv;
99589bbd373SShayne Chen 
99689bbd373SShayne Chen 	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
9975121585eSLorenzo Bianconi 	wcid = sta ? &msta->wcid : NULL;
99889bbd373SShayne Chen 
999069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
1000a0792e15SLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
1001a0792e15SLorenzo Bianconi 						  WTBL_RESET_AND_SET, tlv,
1002a0792e15SLorenzo Bianconi 						  &skb);
100389bbd373SShayne Chen 	if (IS_ERR(wtbl_hdr))
100489bbd373SShayne Chen 		return PTR_ERR(wtbl_hdr);
100589bbd373SShayne Chen 
1006c7720971SLorenzo Bianconi 	mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, skb, vif, sta, tlv,
1007c7720971SLorenzo Bianconi 					 wtbl_hdr);
10085121585eSLorenzo Bianconi 	mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
100989bbd373SShayne Chen 	if (sta)
1010187169deSLorenzo Bianconi 		mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
101102a89404SFelix Fietkau 					    wtbl_hdr, mvif->cap.ht_ldpc,
101202a89404SFelix Fietkau 					    mvif->cap.vht_ldpc);
101389bbd373SShayne Chen 
101489bbd373SShayne Chen 	return 0;
101589bbd373SShayne Chen }
101689bbd373SShayne Chen 
1017f89f297aSRyder Lee static inline bool
mt7915_is_ebf_supported(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool bfee)1018f89f297aSRyder Lee mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
1019f89f297aSRyder Lee 			struct ieee80211_sta *sta, bool bfee)
1020f89f297aSRyder Lee {
102102a89404SFelix Fietkau 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1022f03f274bSMeiChia Chiu 	int sts = hweight16(phy->mt76->chainmask);
1023f89f297aSRyder Lee 
1024f89f297aSRyder Lee 	if (vif->type != NL80211_IFTYPE_STATION &&
1025f89f297aSRyder Lee 	    vif->type != NL80211_IFTYPE_AP)
1026f89f297aSRyder Lee 		return false;
1027f89f297aSRyder Lee 
1028f03f274bSMeiChia Chiu 	if (!bfee && sts < 2)
1029f89f297aSRyder Lee 		return false;
1030f89f297aSRyder Lee 
1031046d2e7cSSriram R 	if (sta->deflink.he_cap.has_he) {
1032046d2e7cSSriram R 		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
1033f89f297aSRyder Lee 
1034f89f297aSRyder Lee 		if (bfee)
103502a89404SFelix Fietkau 			return mvif->cap.he_su_ebfee &&
1036f89f297aSRyder Lee 			       HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
1037f89f297aSRyder Lee 		else
103802a89404SFelix Fietkau 			return mvif->cap.he_su_ebfer &&
1039f89f297aSRyder Lee 			       HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
1040f89f297aSRyder Lee 	}
1041f89f297aSRyder Lee 
1042046d2e7cSSriram R 	if (sta->deflink.vht_cap.vht_supported) {
1043046d2e7cSSriram R 		u32 cap = sta->deflink.vht_cap.cap;
1044f89f297aSRyder Lee 
1045f89f297aSRyder Lee 		if (bfee)
104602a89404SFelix Fietkau 			return mvif->cap.vht_su_ebfee &&
1047f89f297aSRyder Lee 			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
1048f89f297aSRyder Lee 		else
104902a89404SFelix Fietkau 			return mvif->cap.vht_su_ebfer &&
1050f89f297aSRyder Lee 			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
1051f89f297aSRyder Lee 	}
1052f89f297aSRyder Lee 
1053f89f297aSRyder Lee 	return false;
1054f89f297aSRyder Lee }
1055f89f297aSRyder Lee 
1056e57b7901SRyder Lee static void
mt7915_mcu_sta_sounding_rate(struct sta_rec_bf * bf)105789029a85SRyder Lee mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
105889029a85SRyder Lee {
105989029a85SRyder Lee 	bf->sounding_phy = MT_PHY_TYPE_OFDM;
106089029a85SRyder Lee 	bf->ndp_rate = 0;				/* mcs0 */
106189029a85SRyder Lee 	bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT;	/* ofdm 24m */
106289029a85SRyder Lee 	bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT;	/* ofdm 24m */
106389029a85SRyder Lee }
106489029a85SRyder Lee 
106589029a85SRyder Lee static void
mt7915_mcu_sta_bfer_ht(struct ieee80211_sta * sta,struct mt7915_phy * phy,struct sta_rec_bf * bf)10666d6dc980SRyder Lee mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
10676d6dc980SRyder Lee 		       struct sta_rec_bf *bf)
106889029a85SRyder Lee {
1069046d2e7cSSriram R 	struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
107089029a85SRyder Lee 	u8 n = 0;
107189029a85SRyder Lee 
107289029a85SRyder Lee 	bf->tx_mode = MT_PHY_TYPE_HT;
107389029a85SRyder Lee 
10742c3b26f2SLorenzo Bianconi 	if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) &&
107589029a85SRyder Lee 	    (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED))
107689029a85SRyder Lee 		n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK,
107789029a85SRyder Lee 			      mcs->tx_params);
107889029a85SRyder Lee 	else if (mcs->rx_mask[3])
107989029a85SRyder Lee 		n = 3;
108089029a85SRyder Lee 	else if (mcs->rx_mask[2])
108189029a85SRyder Lee 		n = 2;
108289029a85SRyder Lee 	else if (mcs->rx_mask[1])
108389029a85SRyder Lee 		n = 1;
108489029a85SRyder Lee 
1085a56c431eSRyder Lee 	bf->nrow = hweight8(phy->mt76->chainmask) - 1;
1086a56c431eSRyder Lee 	bf->ncol = min_t(u8, bf->nrow, n);
10876d6dc980SRyder Lee 	bf->ibf_ncol = n;
108889029a85SRyder Lee }
108989029a85SRyder Lee 
109089029a85SRyder Lee static void
mt7915_mcu_sta_bfer_vht(struct ieee80211_sta * sta,struct mt7915_phy * phy,struct sta_rec_bf * bf,bool explicit)109189029a85SRyder Lee mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
10926d6dc980SRyder Lee 			struct sta_rec_bf *bf, bool explicit)
109389029a85SRyder Lee {
1094046d2e7cSSriram R 	struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
109589029a85SRyder Lee 	struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
10966d6dc980SRyder Lee 	u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
10976d6dc980SRyder Lee 	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
10986d6dc980SRyder Lee 	u8 tx_ant = hweight8(phy->mt76->chainmask) - 1;
109989029a85SRyder Lee 
110089029a85SRyder Lee 	bf->tx_mode = MT_PHY_TYPE_VHT;
11016d6dc980SRyder Lee 
11026d6dc980SRyder Lee 	if (explicit) {
1103a56c431eSRyder Lee 		u8 sts, snd_dim;
110489029a85SRyder Lee 
110589029a85SRyder Lee 		mt7915_mcu_sta_sounding_rate(bf);
1106a56c431eSRyder Lee 
1107a56c431eSRyder Lee 		sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
110889029a85SRyder Lee 				pc->cap);
1109a56c431eSRyder Lee 		snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
111089029a85SRyder Lee 				    vc->cap);
1111a56c431eSRyder Lee 		bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
1112a56c431eSRyder Lee 		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
1113a56c431eSRyder Lee 		bf->ibf_ncol = bf->ncol;
111489029a85SRyder Lee 
1115046d2e7cSSriram R 		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
1116a56c431eSRyder Lee 			bf->nrow = 1;
11176d6dc980SRyder Lee 	} else {
1118a56c431eSRyder Lee 		bf->nrow = tx_ant;
1119a56c431eSRyder Lee 		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
11206d6dc980SRyder Lee 		bf->ibf_ncol = nss_mcs;
11216d6dc980SRyder Lee 
1122046d2e7cSSriram R 		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
11236d6dc980SRyder Lee 			bf->ibf_nrow = 1;
11246d6dc980SRyder Lee 	}
112589029a85SRyder Lee }
112689029a85SRyder Lee 
112789029a85SRyder Lee static void
mt7915_mcu_sta_bfer_he(struct ieee80211_sta * sta,struct ieee80211_vif * vif,struct mt7915_phy * phy,struct sta_rec_bf * bf)112889029a85SRyder Lee mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
112989029a85SRyder Lee 		       struct mt7915_phy *phy, struct sta_rec_bf *bf)
113089029a85SRyder Lee {
1131046d2e7cSSriram R 	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
113289029a85SRyder Lee 	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
1133e6d557a7SLorenzo Bianconi 	const struct ieee80211_sta_he_cap *vc =
1134e6d557a7SLorenzo Bianconi 		mt76_connac_get_he_phy_cap(phy->mt76, vif);
11356d6dc980SRyder Lee 	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
11366d6dc980SRyder Lee 	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
11376d6dc980SRyder Lee 	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
1138a56c431eSRyder Lee 	u8 snd_dim, sts;
113989029a85SRyder Lee 
114089029a85SRyder Lee 	bf->tx_mode = MT_PHY_TYPE_HE_SU;
1141a56c431eSRyder Lee 
114289029a85SRyder Lee 	mt7915_mcu_sta_sounding_rate(bf);
1143a56c431eSRyder Lee 
114476cf4221SJohannes Berg 	bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
114589029a85SRyder Lee 				pe->phy_cap_info[6]);
114676cf4221SJohannes Berg 	bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
114789029a85SRyder Lee 				pe->phy_cap_info[6]);
1148a56c431eSRyder Lee 	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
114989029a85SRyder Lee 			 ve->phy_cap_info[5]);
1150a56c431eSRyder Lee 	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
115189029a85SRyder Lee 		     pe->phy_cap_info[4]);
1152a56c431eSRyder Lee 	bf->nrow = min_t(u8, snd_dim, sts);
1153a56c431eSRyder Lee 	bf->ncol = min_t(u8, nss_mcs, bf->nrow);
1154a56c431eSRyder Lee 	bf->ibf_ncol = bf->ncol;
115589029a85SRyder Lee 
1156046d2e7cSSriram R 	if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
115789029a85SRyder Lee 		return;
115889029a85SRyder Lee 
115989029a85SRyder Lee 	/* go over for 160MHz and 80p80 */
116089029a85SRyder Lee 	if (pe->phy_cap_info[0] &
116189029a85SRyder Lee 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
116289029a85SRyder Lee 		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160);
116389029a85SRyder Lee 		nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
116489029a85SRyder Lee 
1165cade6939SShayne Chen 		bf->ncol_gt_bw80 = nss_mcs;
116689029a85SRyder Lee 	}
116789029a85SRyder Lee 
116889029a85SRyder Lee 	if (pe->phy_cap_info[0] &
116989029a85SRyder Lee 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
117089029a85SRyder Lee 		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80);
117189029a85SRyder Lee 		nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
117289029a85SRyder Lee 
1173cade6939SShayne Chen 		if (bf->ncol_gt_bw80)
1174cade6939SShayne Chen 			bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs);
117589029a85SRyder Lee 		else
1176cade6939SShayne Chen 			bf->ncol_gt_bw80 = nss_mcs;
117789029a85SRyder Lee 	}
117889029a85SRyder Lee 
1179a56c431eSRyder Lee 	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
118089029a85SRyder Lee 			 ve->phy_cap_info[5]);
1181a56c431eSRyder Lee 	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
118289029a85SRyder Lee 		     pe->phy_cap_info[4]);
118389029a85SRyder Lee 
1184cade6939SShayne Chen 	bf->nrow_gt_bw80 = min_t(int, snd_dim, sts);
118589029a85SRyder Lee }
118689029a85SRyder Lee 
118789029a85SRyder Lee static void
mt7915_mcu_sta_bfer_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1188f89f297aSRyder Lee mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
1189f89f297aSRyder Lee 			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
119089029a85SRyder Lee {
1191f89f297aSRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1192006b9d4aSBo Jiao 	struct mt7915_phy *phy = mvif->phy;
1193b9027e08SLorenzo Bianconi 	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
119489029a85SRyder Lee 	struct sta_rec_bf *bf;
119589029a85SRyder Lee 	struct tlv *tlv;
119689029a85SRyder Lee 	const u8 matrix[4][4] = {
119789029a85SRyder Lee 		{0, 0, 0, 0},
119889029a85SRyder Lee 		{1, 1, 0, 0},	/* 2x1, 2x2, 2x3, 2x4 */
119989029a85SRyder Lee 		{2, 4, 4, 0},	/* 3x1, 3x2, 3x3, 3x4 */
120089029a85SRyder Lee 		{3, 5, 6, 0}	/* 4x1, 4x2, 4x3, 4x4 */
120189029a85SRyder Lee 	};
1202f89f297aSRyder Lee 	bool ebf;
120389029a85SRyder Lee 
1204046d2e7cSSriram R 	if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
1205b4d093e3SMeiChia Chiu 		return;
1206b4d093e3SMeiChia Chiu 
1207f89f297aSRyder Lee 	ebf = mt7915_is_ebf_supported(phy, vif, sta, false);
1208f89f297aSRyder Lee 	if (!ebf && !dev->ibf)
1209f89f297aSRyder Lee 		return;
121089029a85SRyder Lee 
1211069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
121289029a85SRyder Lee 	bf = (struct sta_rec_bf *)tlv;
121389029a85SRyder Lee 
12146d6dc980SRyder Lee 	/* he: eBF only, in accordance with spec
12156d6dc980SRyder Lee 	 * vht: support eBF and iBF
12166d6dc980SRyder Lee 	 * ht: iBF only, since mac80211 lacks of eBF support
12176d6dc980SRyder Lee 	 */
1218046d2e7cSSriram R 	if (sta->deflink.he_cap.has_he && ebf)
12196d6dc980SRyder Lee 		mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
1220046d2e7cSSriram R 	else if (sta->deflink.vht_cap.vht_supported)
1221f89f297aSRyder Lee 		mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
1222046d2e7cSSriram R 	else if (sta->deflink.ht_cap.ht_supported)
12236d6dc980SRyder Lee 		mt7915_mcu_sta_bfer_ht(sta, phy, bf);
12246d6dc980SRyder Lee 	else
12256d6dc980SRyder Lee 		return;
12266d6dc980SRyder Lee 
1227a56c431eSRyder Lee 	bf->bf_cap = ebf ? ebf : dev->ibf << 1;
1228046d2e7cSSriram R 	bf->bw = sta->deflink.bandwidth;
1229046d2e7cSSriram R 	bf->ibf_dbw = sta->deflink.bandwidth;
123089029a85SRyder Lee 	bf->ibf_nrow = tx_ant;
12316d6dc980SRyder Lee 
1232046d2e7cSSriram R 	if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
12336d6dc980SRyder Lee 		bf->ibf_timeout = 0x48;
12346d6dc980SRyder Lee 	else
123589029a85SRyder Lee 		bf->ibf_timeout = 0x18;
123689029a85SRyder Lee 
1237a56c431eSRyder Lee 	if (ebf && bf->nrow != tx_ant)
1238a56c431eSRyder Lee 		bf->mem_20m = matrix[tx_ant][bf->ncol];
123989029a85SRyder Lee 	else
1240a56c431eSRyder Lee 		bf->mem_20m = matrix[bf->nrow][bf->ncol];
124189029a85SRyder Lee 
1242046d2e7cSSriram R 	switch (sta->deflink.bandwidth) {
124389029a85SRyder Lee 	case IEEE80211_STA_RX_BW_160:
124489029a85SRyder Lee 	case IEEE80211_STA_RX_BW_80:
124589029a85SRyder Lee 		bf->mem_total = bf->mem_20m * 2;
124689029a85SRyder Lee 		break;
124789029a85SRyder Lee 	case IEEE80211_STA_RX_BW_40:
124889029a85SRyder Lee 		bf->mem_total = bf->mem_20m;
124989029a85SRyder Lee 		break;
125089029a85SRyder Lee 	case IEEE80211_STA_RX_BW_20:
125189029a85SRyder Lee 	default:
125289029a85SRyder Lee 		break;
125389029a85SRyder Lee 	}
125489029a85SRyder Lee }
125589029a85SRyder Lee 
12562af34fa3SRyder Lee static void
mt7915_mcu_sta_bfee_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1257f89f297aSRyder Lee mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
1258f89f297aSRyder Lee 			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
12592af34fa3SRyder Lee {
1260f89f297aSRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1261006b9d4aSBo Jiao 	struct mt7915_phy *phy = mvif->phy;
1262b9027e08SLorenzo Bianconi 	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
12632af34fa3SRyder Lee 	struct sta_rec_bfee *bfee;
12642af34fa3SRyder Lee 	struct tlv *tlv;
1265a56c431eSRyder Lee 	u8 nrow = 0;
12662af34fa3SRyder Lee 
1267046d2e7cSSriram R 	if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
1268b4d093e3SMeiChia Chiu 		return;
1269b4d093e3SMeiChia Chiu 
1270f89f297aSRyder Lee 	if (!mt7915_is_ebf_supported(phy, vif, sta, true))
1271f89f297aSRyder Lee 		return;
1272f89f297aSRyder Lee 
1273069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
12742af34fa3SRyder Lee 	bfee = (struct sta_rec_bfee *)tlv;
12752af34fa3SRyder Lee 
1276046d2e7cSSriram R 	if (sta->deflink.he_cap.has_he) {
1277046d2e7cSSriram R 		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
12782af34fa3SRyder Lee 
1279a56c431eSRyder Lee 		nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
12802af34fa3SRyder Lee 			      pe->phy_cap_info[5]);
1281046d2e7cSSriram R 	} else if (sta->deflink.vht_cap.vht_supported) {
1282046d2e7cSSriram R 		struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
12832af34fa3SRyder Lee 
1284a56c431eSRyder Lee 		nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
12852af34fa3SRyder Lee 				 pc->cap);
12862af34fa3SRyder Lee 	}
12872af34fa3SRyder Lee 
12882af34fa3SRyder Lee 	/* reply with identity matrix to avoid 2x2 BF negative gain */
1289a56c431eSRyder Lee 	bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
12902af34fa3SRyder Lee }
12912af34fa3SRyder Lee 
12928f058354SRyder Lee static enum mcu_mmps_mode
mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)12938f058354SRyder Lee mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
12948f058354SRyder Lee {
12958f058354SRyder Lee 	switch (smps) {
12968f058354SRyder Lee 	case IEEE80211_SMPS_OFF:
12978f058354SRyder Lee 		return MCU_MMPS_DISABLE;
12988f058354SRyder Lee 	case IEEE80211_SMPS_STATIC:
12998f058354SRyder Lee 		return MCU_MMPS_STATIC;
13008f058354SRyder Lee 	case IEEE80211_SMPS_DYNAMIC:
13018f058354SRyder Lee 		return MCU_MMPS_DYNAMIC;
13028f058354SRyder Lee 	default:
13038f058354SRyder Lee 		return MCU_MMPS_DISABLE;
13048f058354SRyder Lee 	}
13058f058354SRyder Lee }
13068f058354SRyder Lee 
mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,void * data,u32 field)130770fd1333SRyder Lee int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
130870fd1333SRyder Lee 				   struct ieee80211_vif *vif,
130970fd1333SRyder Lee 				   struct ieee80211_sta *sta,
131070fd1333SRyder Lee 				   void *data, u32 field)
131170fd1333SRyder Lee {
131270fd1333SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
131370fd1333SRyder Lee 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
131470fd1333SRyder Lee 	struct sta_phy *phy = data;
131570fd1333SRyder Lee 	struct sta_rec_ra_fixed *ra;
131670fd1333SRyder Lee 	struct sk_buff *skb;
131770fd1333SRyder Lee 	struct tlv *tlv;
131870fd1333SRyder Lee 
1319e2c93b68SLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1320e2c93b68SLorenzo Bianconi 					    &msta->wcid);
132170fd1333SRyder Lee 	if (IS_ERR(skb))
132270fd1333SRyder Lee 		return PTR_ERR(skb);
132370fd1333SRyder Lee 
1324069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
132570fd1333SRyder Lee 	ra = (struct sta_rec_ra_fixed *)tlv;
132670fd1333SRyder Lee 
132770fd1333SRyder Lee 	switch (field) {
132870fd1333SRyder Lee 	case RATE_PARAM_AUTO:
132970fd1333SRyder Lee 		break;
13309a93364dSRyder Lee 	case RATE_PARAM_FIXED:
133170fd1333SRyder Lee 	case RATE_PARAM_FIXED_MCS:
133270fd1333SRyder Lee 	case RATE_PARAM_FIXED_GI:
133370fd1333SRyder Lee 	case RATE_PARAM_FIXED_HE_LTF:
13348f058354SRyder Lee 		if (phy)
133570fd1333SRyder Lee 			ra->phy = *phy;
133670fd1333SRyder Lee 		break;
13378f058354SRyder Lee 	case RATE_PARAM_MMPS_UPDATE:
1338261ce887SBenjamin Berg 		ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
13398f058354SRyder Lee 		break;
13407a9a957bSShayne Chen 	case RATE_PARAM_SPE_UPDATE:
13417a9a957bSShayne Chen 		ra->spe_idx = *(u8 *)data;
13427a9a957bSShayne Chen 		break;
134370fd1333SRyder Lee 	default:
134470fd1333SRyder Lee 		break;
134570fd1333SRyder Lee 	}
134670fd1333SRyder Lee 	ra->field = cpu_to_le32(field);
134770fd1333SRyder Lee 
134870fd1333SRyder Lee 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
134970fd1333SRyder Lee 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
135070fd1333SRyder Lee }
135170fd1333SRyder Lee 
mt7915_mcu_add_smps(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)13528f058354SRyder Lee int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
13538f058354SRyder Lee 			struct ieee80211_sta *sta)
13548f058354SRyder Lee {
13558f058354SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
13568f058354SRyder Lee 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
13578f058354SRyder Lee 	struct wtbl_req_hdr *wtbl_hdr;
13588f058354SRyder Lee 	struct tlv *sta_wtbl;
13598f058354SRyder Lee 	struct sk_buff *skb;
13608f058354SRyder Lee 	int ret;
13618f058354SRyder Lee 
1362e2c93b68SLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1363e2c93b68SLorenzo Bianconi 					    &msta->wcid);
13648f058354SRyder Lee 	if (IS_ERR(skb))
13658f058354SRyder Lee 		return PTR_ERR(skb);
13668f058354SRyder Lee 
1367069c8e34SLorenzo Bianconi 	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
1368069c8e34SLorenzo Bianconi 					   sizeof(struct tlv));
1369a0792e15SLorenzo Bianconi 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
1370a0792e15SLorenzo Bianconi 						  WTBL_SET, sta_wtbl, &skb);
13718f058354SRyder Lee 	if (IS_ERR(wtbl_hdr))
13728f058354SRyder Lee 		return PTR_ERR(wtbl_hdr);
13738f058354SRyder Lee 
13742557e568SLorenzo Bianconi 	mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr);
13758f058354SRyder Lee 
13768f058354SRyder Lee 	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
13778f058354SRyder Lee 				    MCU_EXT_CMD(STA_REC_UPDATE), true);
13788f058354SRyder Lee 	if (ret)
13798f058354SRyder Lee 		return ret;
13808f058354SRyder Lee 
13818f058354SRyder Lee 	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL,
13828f058354SRyder Lee 					      RATE_PARAM_MMPS_UPDATE);
13838f058354SRyder Lee }
13848f058354SRyder Lee 
138570fd1333SRyder Lee static int
mt7915_mcu_set_spe_idx(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)13867a9a957bSShayne Chen mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif,
13877a9a957bSShayne Chen 		       struct ieee80211_sta *sta)
13887a9a957bSShayne Chen {
13897a9a957bSShayne Chen 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
13907a9a957bSShayne Chen 	struct mt76_phy *mphy = mvif->phy->mt76;
13917a9a957bSShayne Chen 	u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
13927a9a957bSShayne Chen 
13937a9a957bSShayne Chen 	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
13947a9a957bSShayne Chen 					      RATE_PARAM_SPE_UPDATE);
13957a9a957bSShayne Chen }
13967a9a957bSShayne Chen 
13977a9a957bSShayne Chen static int
mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)139870fd1333SRyder Lee mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
139970fd1333SRyder Lee 			       struct ieee80211_vif *vif,
140070fd1333SRyder Lee 			       struct ieee80211_sta *sta)
140170fd1333SRyder Lee {
140270fd1333SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
140370fd1333SRyder Lee 	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
140470fd1333SRyder Lee 	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
140570fd1333SRyder Lee 	enum nl80211_band band = chandef->chan->band;
140670fd1333SRyder Lee 	struct sta_phy phy = {};
140770fd1333SRyder Lee 	int ret, nrates = 0;
140870fd1333SRyder Lee 
1409c6d3e16aSHoward Hsu #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he)			\
141070fd1333SRyder Lee 	do {									\
141170fd1333SRyder Lee 		u8 i, gi = mask->control[band]._gi;				\
141270fd1333SRyder Lee 		gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;		\
1413046d2e7cSSriram R 		for (i = 0; i <= sta->deflink.bandwidth; i++) {			\
141470fd1333SRyder Lee 			phy.sgi |= gi << (i << (_he));				\
141570fd1333SRyder Lee 			phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\
141670fd1333SRyder Lee 		}								\
1417c41d2a07SMeiChia Chiu 		for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) {	\
1418c41d2a07SMeiChia Chiu 			if (!mask->control[band]._mcs[i])			\
1419c41d2a07SMeiChia Chiu 				continue;					\
142070fd1333SRyder Lee 			nrates += hweight16(mask->control[band]._mcs[i]);	\
1421c41d2a07SMeiChia Chiu 			phy.mcs = ffs(mask->control[band]._mcs[i]) - 1;		\
1422c6d3e16aSHoward Hsu 			if (_ht)						\
1423c6d3e16aSHoward Hsu 				phy.mcs += 8 * i;				\
1424c41d2a07SMeiChia Chiu 		}								\
142570fd1333SRyder Lee 	} while (0)
142670fd1333SRyder Lee 
1427046d2e7cSSriram R 	if (sta->deflink.he_cap.has_he) {
1428c6d3e16aSHoward Hsu 		__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
1429046d2e7cSSriram R 	} else if (sta->deflink.vht_cap.vht_supported) {
1430c6d3e16aSHoward Hsu 		__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
1431046d2e7cSSriram R 	} else if (sta->deflink.ht_cap.ht_supported) {
1432c6d3e16aSHoward Hsu 		__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
143370fd1333SRyder Lee 	} else {
143470fd1333SRyder Lee 		nrates = hweight32(mask->control[band].legacy);
143570fd1333SRyder Lee 		phy.mcs = ffs(mask->control[band].legacy) - 1;
143670fd1333SRyder Lee 	}
143770fd1333SRyder Lee #undef __sta_phy_bitrate_mask_check
143870fd1333SRyder Lee 
143970fd1333SRyder Lee 	/* fall back to auto rate control */
144070fd1333SRyder Lee 	if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
144170fd1333SRyder Lee 	    mask->control[band].he_gi == GENMASK(7, 0) &&
144270fd1333SRyder Lee 	    mask->control[band].he_ltf == GENMASK(7, 0) &&
144370fd1333SRyder Lee 	    nrates != 1)
144470fd1333SRyder Lee 		return 0;
144570fd1333SRyder Lee 
144670fd1333SRyder Lee 	/* fixed single rate */
144770fd1333SRyder Lee 	if (nrates == 1) {
144870fd1333SRyder Lee 		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
144970fd1333SRyder Lee 						     RATE_PARAM_FIXED_MCS);
145070fd1333SRyder Lee 		if (ret)
145170fd1333SRyder Lee 			return ret;
145270fd1333SRyder Lee 	}
145370fd1333SRyder Lee 
145470fd1333SRyder Lee 	/* fixed GI */
145570fd1333SRyder Lee 	if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
145670fd1333SRyder Lee 	    mask->control[band].he_gi != GENMASK(7, 0)) {
145770fd1333SRyder Lee 		struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
145870fd1333SRyder Lee 		u32 addr;
145970fd1333SRyder Lee 
146070fd1333SRyder Lee 		/* firmware updates only TXCMD but doesn't take WTBL into
146170fd1333SRyder Lee 		 * account, so driver should update here to reflect the
146270fd1333SRyder Lee 		 * actual txrate hardware sends out.
146370fd1333SRyder Lee 		 */
146470fd1333SRyder Lee 		addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
1465046d2e7cSSriram R 		if (sta->deflink.he_cap.has_he)
146670fd1333SRyder Lee 			mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
146770fd1333SRyder Lee 		else
146870fd1333SRyder Lee 			mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
146970fd1333SRyder Lee 
147070fd1333SRyder Lee 		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
147170fd1333SRyder Lee 						     RATE_PARAM_FIXED_GI);
147270fd1333SRyder Lee 		if (ret)
147370fd1333SRyder Lee 			return ret;
147470fd1333SRyder Lee 	}
147570fd1333SRyder Lee 
147670fd1333SRyder Lee 	/* fixed HE_LTF */
147770fd1333SRyder Lee 	if (mask->control[band].he_ltf != GENMASK(7, 0)) {
147870fd1333SRyder Lee 		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
147970fd1333SRyder Lee 						     RATE_PARAM_FIXED_HE_LTF);
148070fd1333SRyder Lee 		if (ret)
148170fd1333SRyder Lee 			return ret;
148270fd1333SRyder Lee 	}
148370fd1333SRyder Lee 
14847a9a957bSShayne Chen 	return mt7915_mcu_set_spe_idx(dev, vif, sta);
148570fd1333SRyder Lee }
148670fd1333SRyder Lee 
148789029a85SRyder Lee static void
mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff * skb,struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1488e57b7901SRyder Lee mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
148916234741SRyder Lee 			     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
1490e57b7901SRyder Lee {
1491a441a77aSRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1492e6d557a7SLorenzo Bianconi 	struct mt76_phy *mphy = mvif->phy->mt76;
1493e6d557a7SLorenzo Bianconi 	struct cfg80211_chan_def *chandef = &mphy->chandef;
149476be6c07SRyder Lee 	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
1495a441a77aSRyder Lee 	enum nl80211_band band = chandef->chan->band;
1496e57b7901SRyder Lee 	struct sta_rec_ra *ra;
1497e57b7901SRyder Lee 	struct tlv *tlv;
1498046d2e7cSSriram R 	u32 supp_rate = sta->deflink.supp_rates[band];
1499a441a77aSRyder Lee 	u32 cap = sta->wme ? STA_CAP_WMM : 0;
1500e57b7901SRyder Lee 
1501069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
1502e57b7901SRyder Lee 	ra = (struct sta_rec_ra *)tlv;
150316234741SRyder Lee 
1504e57b7901SRyder Lee 	ra->valid = true;
1505e57b7901SRyder Lee 	ra->auto_rate = true;
1506e6d557a7SLorenzo Bianconi 	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
1507a441a77aSRyder Lee 	ra->channel = chandef->chan->hw_value;
1508046d2e7cSSriram R 	ra->bw = sta->deflink.bandwidth;
1509046d2e7cSSriram R 	ra->phy.bw = sta->deflink.bandwidth;
1510261ce887SBenjamin Berg 	ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
1511e57b7901SRyder Lee 
1512a441a77aSRyder Lee 	if (supp_rate) {
151376be6c07SRyder Lee 		supp_rate &= mask->control[band].legacy;
1514a441a77aSRyder Lee 		ra->rate_len = hweight32(supp_rate);
1515a441a77aSRyder Lee 
1516e57b7901SRyder Lee 		if (band == NL80211_BAND_2GHZ) {
1517e57b7901SRyder Lee 			ra->supp_mode = MODE_CCK;
1518e57b7901SRyder Lee 			ra->supp_cck_rate = supp_rate & GENMASK(3, 0);
1519e57b7901SRyder Lee 
1520a441a77aSRyder Lee 			if (ra->rate_len > 4) {
1521e57b7901SRyder Lee 				ra->supp_mode |= MODE_OFDM;
1522e57b7901SRyder Lee 				ra->supp_ofdm_rate = supp_rate >> 4;
1523e57b7901SRyder Lee 			}
1524e57b7901SRyder Lee 		} else {
1525e57b7901SRyder Lee 			ra->supp_mode = MODE_OFDM;
1526e57b7901SRyder Lee 			ra->supp_ofdm_rate = supp_rate;
1527e57b7901SRyder Lee 		}
1528e57b7901SRyder Lee 	}
1529e57b7901SRyder Lee 
1530046d2e7cSSriram R 	if (sta->deflink.ht_cap.ht_supported) {
1531e57b7901SRyder Lee 		ra->supp_mode |= MODE_HT;
1532046d2e7cSSriram R 		ra->af = sta->deflink.ht_cap.ampdu_factor;
1533046d2e7cSSriram R 		ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
1534e57b7901SRyder Lee 
1535e57b7901SRyder Lee 		cap |= STA_CAP_HT;
1536046d2e7cSSriram R 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
1537e57b7901SRyder Lee 			cap |= STA_CAP_SGI_20;
1538046d2e7cSSriram R 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
1539e57b7901SRyder Lee 			cap |= STA_CAP_SGI_40;
1540046d2e7cSSriram R 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
1541e57b7901SRyder Lee 			cap |= STA_CAP_TX_STBC;
1542046d2e7cSSriram R 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
1543e57b7901SRyder Lee 			cap |= STA_CAP_RX_STBC;
154402a89404SFelix Fietkau 		if (mvif->cap.ht_ldpc &&
1545046d2e7cSSriram R 		    (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
1546e57b7901SRyder Lee 			cap |= STA_CAP_LDPC;
154776be6c07SRyder Lee 
154870fd1333SRyder Lee 		mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
154970fd1333SRyder Lee 					  mask->control[band].ht_mcs);
155076be6c07SRyder Lee 		ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
1551e57b7901SRyder Lee 	}
1552e57b7901SRyder Lee 
1553046d2e7cSSriram R 	if (sta->deflink.vht_cap.vht_supported) {
1554a441a77aSRyder Lee 		u8 af;
1555e57b7901SRyder Lee 
155676be6c07SRyder Lee 		ra->supp_mode |= MODE_VHT;
1557e57b7901SRyder Lee 		af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
1558046d2e7cSSriram R 			       sta->deflink.vht_cap.cap);
1559e57b7901SRyder Lee 		ra->af = max_t(u8, ra->af, af);
1560e57b7901SRyder Lee 
1561e57b7901SRyder Lee 		cap |= STA_CAP_VHT;
1562046d2e7cSSriram R 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
1563e57b7901SRyder Lee 			cap |= STA_CAP_VHT_SGI_80;
1564046d2e7cSSriram R 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
1565e57b7901SRyder Lee 			cap |= STA_CAP_VHT_SGI_160;
1566046d2e7cSSriram R 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
1567e57b7901SRyder Lee 			cap |= STA_CAP_VHT_TX_STBC;
1568046d2e7cSSriram R 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
1569e57b7901SRyder Lee 			cap |= STA_CAP_VHT_RX_STBC;
157002a89404SFelix Fietkau 		if (mvif->cap.vht_ldpc &&
1571046d2e7cSSriram R 		    (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
1572e57b7901SRyder Lee 			cap |= STA_CAP_VHT_LDPC;
1573e57b7901SRyder Lee 
157470fd1333SRyder Lee 		mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
157570fd1333SRyder Lee 					   mask->control[band].vht_mcs);
1576e57b7901SRyder Lee 	}
1577e57b7901SRyder Lee 
1578046d2e7cSSriram R 	if (sta->deflink.he_cap.has_he) {
1579c336318fSRyder Lee 		ra->supp_mode |= MODE_HE;
1580c336318fSRyder Lee 		cap |= STA_CAP_HE;
1581b4d093e3SMeiChia Chiu 
1582046d2e7cSSriram R 		if (sta->deflink.he_6ghz_capa.capa)
1583046d2e7cSSriram R 			ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
1584b4d093e3SMeiChia Chiu 					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
1585c336318fSRyder Lee 	}
1586c336318fSRyder Lee 
1587a441a77aSRyder Lee 	ra->sta_cap = cpu_to_le32(cap);
1588e57b7901SRyder Lee }
1589e57b7901SRyder Lee 
mt7915_mcu_add_rate_ctrl(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool changed)1590e57b7901SRyder Lee int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
15912eec60dcSRyder Lee 			     struct ieee80211_sta *sta, bool changed)
1592e57b7901SRyder Lee {
1593e57b7901SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1594e57b7901SRyder Lee 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
1595e57b7901SRyder Lee 	struct sk_buff *skb;
159670fd1333SRyder Lee 	int ret;
1597e57b7901SRyder Lee 
1598e2c93b68SLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1599e2c93b68SLorenzo Bianconi 					    &msta->wcid);
1600e57b7901SRyder Lee 	if (IS_ERR(skb))
1601e57b7901SRyder Lee 		return PTR_ERR(skb);
1602e57b7901SRyder Lee 
16032eec60dcSRyder Lee 	/* firmware rc algorithm refers to sta_rec_he for HE control.
16042eec60dcSRyder Lee 	 * once dev->rc_work changes the settings driver should also
16052eec60dcSRyder Lee 	 * update sta_rec_he here.
16062eec60dcSRyder Lee 	 */
1607b4d093e3SMeiChia Chiu 	if (changed)
16082eec60dcSRyder Lee 		mt7915_mcu_sta_he_tlv(skb, sta, vif);
16092eec60dcSRyder Lee 
161070fd1333SRyder Lee 	/* sta_rec_ra accommodates BW, NSS and only MCS range format
161170fd1333SRyder Lee 	 * i.e 0-{7,8,9} for VHT.
161270fd1333SRyder Lee 	 */
1613e57b7901SRyder Lee 	mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
1614e57b7901SRyder Lee 
161570fd1333SRyder Lee 	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
1616c203dd62SFelix Fietkau 				    MCU_EXT_CMD(STA_REC_UPDATE), true);
161770fd1333SRyder Lee 	if (ret)
161870fd1333SRyder Lee 		return ret;
161970fd1333SRyder Lee 
162070fd1333SRyder Lee 	/* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE,
162170fd1333SRyder Lee 	 * and updates as peer fixed rate parameters, which overrides
162270fd1333SRyder Lee 	 * sta_rec_ra and firmware rate control algorithm.
162370fd1333SRyder Lee 	 */
162470fd1333SRyder Lee 	return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
1625f68e6a1fSRyder Lee }
1626f68e6a1fSRyder Lee 
1627798bffd8SRyder Lee static int
mt7915_mcu_add_group(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1628798bffd8SRyder Lee mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1629798bffd8SRyder Lee 		     struct ieee80211_sta *sta)
1630798bffd8SRyder Lee {
1631798bffd8SRyder Lee #define MT_STA_BSS_GROUP		1
1632798bffd8SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
163389bbd373SShayne Chen 	struct mt7915_sta *msta;
1634798bffd8SRyder Lee 	struct {
1635798bffd8SRyder Lee 		__le32 action;
1636798bffd8SRyder Lee 		u8 wlan_idx_lo;
1637798bffd8SRyder Lee 		u8 status;
1638798bffd8SRyder Lee 		u8 wlan_idx_hi;
1639798bffd8SRyder Lee 		u8 rsv0[5];
1640798bffd8SRyder Lee 		__le32 val;
1641798bffd8SRyder Lee 		u8 rsv1[8];
1642798bffd8SRyder Lee 	} __packed req = {
1643798bffd8SRyder Lee 		.action = cpu_to_le32(MT_STA_BSS_GROUP),
16446cf4392fSLorenzo Bianconi 		.val = cpu_to_le32(mvif->mt76.idx % 16),
1645798bffd8SRyder Lee 	};
1646798bffd8SRyder Lee 
164789bbd373SShayne Chen 	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
164889bbd373SShayne Chen 	req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx);
164989bbd373SShayne Chen 	req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx);
165089bbd373SShayne Chen 
1651798bffd8SRyder Lee 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req,
1652798bffd8SRyder Lee 				 sizeof(req), true);
1653798bffd8SRyder Lee }
1654798bffd8SRyder Lee 
mt7915_mcu_add_sta(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool enable)1655e57b7901SRyder Lee int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1656e57b7901SRyder Lee 		       struct ieee80211_sta *sta, bool enable)
1657e57b7901SRyder Lee {
1658e57b7901SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1659e57b7901SRyder Lee 	struct mt7915_sta *msta;
1660e57b7901SRyder Lee 	struct sk_buff *skb;
166189bbd373SShayne Chen 	int ret;
1662e57b7901SRyder Lee 
1663e57b7901SRyder Lee 	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
1664e57b7901SRyder Lee 
1665e2c93b68SLorenzo Bianconi 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1666e2c93b68SLorenzo Bianconi 					    &msta->wcid);
1667e57b7901SRyder Lee 	if (IS_ERR(skb))
1668e57b7901SRyder Lee 		return PTR_ERR(skb);
1669e57b7901SRyder Lee 
167089bbd373SShayne Chen 	/* starec basic */
16711b83d17cSSean Wang 	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable,
16728e3e7567SShayne Chen 				      !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
167389bbd373SShayne Chen 	if (!enable)
167489bbd373SShayne Chen 		goto out;
1675e57b7901SRyder Lee 
167689bbd373SShayne Chen 	/* tag order is in accordance with firmware dependency. */
1677b4d093e3SMeiChia Chiu 	if (sta) {
167889bbd373SShayne Chen 		/* starec bfer */
167989bbd373SShayne Chen 		mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta);
168089bbd373SShayne Chen 		/* starec ht */
168189bbd373SShayne Chen 		mt7915_mcu_sta_ht_tlv(skb, sta);
168289bbd373SShayne Chen 		/* starec vht */
168389bbd373SShayne Chen 		mt7915_mcu_sta_vht_tlv(skb, sta);
168489bbd373SShayne Chen 		/* starec uapsd */
1685836c0c98SLorenzo Bianconi 		mt76_connac_mcu_sta_uapsd(skb, vif, sta);
1686e57b7901SRyder Lee 	}
1687e57b7901SRyder Lee 
168889bbd373SShayne Chen 	ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta);
1689a43736cdSLorenzo Bianconi 	if (ret) {
1690a43736cdSLorenzo Bianconi 		dev_kfree_skb(skb);
169189bbd373SShayne Chen 		return ret;
1692a43736cdSLorenzo Bianconi 	}
169389bbd373SShayne Chen 
1694b4d093e3SMeiChia Chiu 	if (sta) {
169589bbd373SShayne Chen 		/* starec amsdu */
1696be1954ffSPeter Chiu 		mt7915_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
169789bbd373SShayne Chen 		/* starec he */
169889bbd373SShayne Chen 		mt7915_mcu_sta_he_tlv(skb, sta, vif);
169989bbd373SShayne Chen 		/* starec muru */
1700c3f2ed58SFelix Fietkau 		mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif);
170189bbd373SShayne Chen 		/* starec bfee */
170289bbd373SShayne Chen 		mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta);
170389bbd373SShayne Chen 	}
170489bbd373SShayne Chen 
170589bbd373SShayne Chen 	ret = mt7915_mcu_add_group(dev, vif, sta);
1706a43736cdSLorenzo Bianconi 	if (ret) {
1707a43736cdSLorenzo Bianconi 		dev_kfree_skb(skb);
170889bbd373SShayne Chen 		return ret;
1709a43736cdSLorenzo Bianconi 	}
171089bbd373SShayne Chen out:
17114f831d18SLorenzo Bianconi 	ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
17124f831d18SLorenzo Bianconi 	if (ret)
17134f831d18SLorenzo Bianconi 		return ret;
17144f831d18SLorenzo Bianconi 
1715fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
1716c203dd62SFelix Fietkau 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
1717e57b7901SRyder Lee }
1718e57b7901SRyder Lee 
mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev * dev)1719c6cde7b7SSujuan Chen int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev)
1720c6cde7b7SSujuan Chen {
1721c6cde7b7SSujuan Chen #ifdef CONFIG_NET_MEDIATEK_SOC_WED
1722c6cde7b7SSujuan Chen 	struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
1723c6cde7b7SSujuan Chen 	struct {
1724c6cde7b7SSujuan Chen 		__le32 args[2];
1725c6cde7b7SSujuan Chen 	} req = {
1726c6cde7b7SSujuan Chen 		.args[0] = cpu_to_le32(1),
1727c6cde7b7SSujuan Chen 		.args[1] = cpu_to_le32(6),
1728c6cde7b7SSujuan Chen 	};
1729c6cde7b7SSujuan Chen 
1730c6cde7b7SSujuan Chen 	return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL,
1731c6cde7b7SSujuan Chen 					 &req, sizeof(req));
1732c6cde7b7SSujuan Chen #else
1733c6cde7b7SSujuan Chen 	return 0;
1734c6cde7b7SSujuan Chen #endif
1735c6cde7b7SSujuan Chen }
1736c6cde7b7SSujuan Chen 
mt7915_mcu_add_dev_info(struct mt7915_phy * phy,struct ieee80211_vif * vif,bool enable)17378aa2c6f4SFelix Fietkau int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
1738e57b7901SRyder Lee 			    struct ieee80211_vif *vif, bool enable)
1739e57b7901SRyder Lee {
17408aa2c6f4SFelix Fietkau 	struct mt7915_dev *dev = phy->dev;
1741e57b7901SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1742e57b7901SRyder Lee 	struct {
1743e57b7901SRyder Lee 		struct req_hdr {
1744e57b7901SRyder Lee 			u8 omac_idx;
17456f917bbaSRyder Lee 			u8 band_idx;
1746e57b7901SRyder Lee 			__le16 tlv_num;
1747e57b7901SRyder Lee 			u8 is_tlv_append;
1748e57b7901SRyder Lee 			u8 rsv[3];
1749e57b7901SRyder Lee 		} __packed hdr;
1750e57b7901SRyder Lee 		struct req_tlv {
1751e57b7901SRyder Lee 			__le16 tag;
1752e57b7901SRyder Lee 			__le16 len;
1753e57b7901SRyder Lee 			u8 active;
17546f917bbaSRyder Lee 			u8 band_idx;
1755e57b7901SRyder Lee 			u8 omac_addr[ETH_ALEN];
1756e57b7901SRyder Lee 		} __packed tlv;
1757e57b7901SRyder Lee 	} data = {
1758e57b7901SRyder Lee 		.hdr = {
17596cf4392fSLorenzo Bianconi 			.omac_idx = mvif->mt76.omac_idx,
17606f917bbaSRyder Lee 			.band_idx = mvif->mt76.band_idx,
1761e57b7901SRyder Lee 			.tlv_num = cpu_to_le16(1),
1762e57b7901SRyder Lee 			.is_tlv_append = 1,
1763e57b7901SRyder Lee 		},
1764e57b7901SRyder Lee 		.tlv = {
1765e57b7901SRyder Lee 			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
1766e57b7901SRyder Lee 			.len = cpu_to_le16(sizeof(struct req_tlv)),
1767e57b7901SRyder Lee 			.active = enable,
17686f917bbaSRyder Lee 			.band_idx = mvif->mt76.band_idx,
1769e57b7901SRyder Lee 		},
1770e57b7901SRyder Lee 	};
1771e57b7901SRyder Lee 
17726cf4392fSLorenzo Bianconi 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
17738aa2c6f4SFelix Fietkau 		return mt7915_mcu_muar_config(phy, vif, false, enable);
17748aa2c6f4SFelix Fietkau 
1775e57b7901SRyder Lee 	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
1776c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
1777e57b7901SRyder Lee 				 &data, sizeof(data), true);
1778e57b7901SRyder Lee }
1779e57b7901SRyder Lee 
1780e57b7901SRyder Lee static void
mt7915_mcu_beacon_cntdwn(struct ieee80211_vif * vif,struct sk_buff * rskb,struct sk_buff * skb,struct bss_info_bcn * bcn,struct ieee80211_mutable_offsets * offs)1781b4b9f0a3SLorenzo Bianconi mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
1782b4b9f0a3SLorenzo Bianconi 			 struct sk_buff *skb, struct bss_info_bcn *bcn,
1783e57b7901SRyder Lee 			 struct ieee80211_mutable_offsets *offs)
1784e57b7901SRyder Lee {
1785b4b9f0a3SLorenzo Bianconi 	struct bss_info_bcn_cntdwn *info;
1786e57b7901SRyder Lee 	struct tlv *tlv;
1787b4b9f0a3SLorenzo Bianconi 	int sub_tag;
1788e57b7901SRyder Lee 
1789b4b9f0a3SLorenzo Bianconi 	if (!offs->cntdwn_counter_offs[0])
1790b4b9f0a3SLorenzo Bianconi 		return;
1791b4b9f0a3SLorenzo Bianconi 
1792d0a9123eSJohannes Berg 	sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC;
1793b4b9f0a3SLorenzo Bianconi 	tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info),
1794b4b9f0a3SLorenzo Bianconi 					   &bcn->sub_ntlv, &bcn->len);
1795b4b9f0a3SLorenzo Bianconi 	info = (struct bss_info_bcn_cntdwn *)tlv;
1796b4b9f0a3SLorenzo Bianconi 	info->cnt = skb->data[offs->cntdwn_counter_offs[0]];
1797e57b7901SRyder Lee }
1798e57b7901SRyder Lee 
1799e57b7901SRyder Lee static void
mt7915_mcu_beacon_mbss(struct sk_buff * rskb,struct sk_buff * skb,struct ieee80211_vif * vif,struct bss_info_bcn * bcn,struct ieee80211_mutable_offsets * offs)18006b7f9affSLorenzo Bianconi mt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
18016b7f9affSLorenzo Bianconi 		       struct ieee80211_vif *vif, struct bss_info_bcn *bcn,
18026b7f9affSLorenzo Bianconi 		       struct ieee80211_mutable_offsets *offs)
18036b7f9affSLorenzo Bianconi {
18046b7f9affSLorenzo Bianconi 	struct bss_info_bcn_mbss *mbss;
18056b7f9affSLorenzo Bianconi 	const struct element *elem;
18066b7f9affSLorenzo Bianconi 	struct tlv *tlv;
18076b7f9affSLorenzo Bianconi 
18086b7f9affSLorenzo Bianconi 	if (!vif->bss_conf.bssid_indicator)
18096b7f9affSLorenzo Bianconi 		return;
18106b7f9affSLorenzo Bianconi 
18116b7f9affSLorenzo Bianconi 	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID,
18126b7f9affSLorenzo Bianconi 					   sizeof(*mbss), &bcn->sub_ntlv,
18136b7f9affSLorenzo Bianconi 					   &bcn->len);
18146b7f9affSLorenzo Bianconi 
18156b7f9affSLorenzo Bianconi 	mbss = (struct bss_info_bcn_mbss *)tlv;
18166b7f9affSLorenzo Bianconi 	mbss->offset[0] = cpu_to_le16(offs->tim_offset);
18176b7f9affSLorenzo Bianconi 	mbss->bitmap = cpu_to_le32(1);
18186b7f9affSLorenzo Bianconi 
18196b7f9affSLorenzo Bianconi 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID,
18206b7f9affSLorenzo Bianconi 			    &skb->data[offs->mbssid_off],
18216b7f9affSLorenzo Bianconi 			    skb->len - offs->mbssid_off) {
18226b7f9affSLorenzo Bianconi 		const struct element *sub_elem;
18236b7f9affSLorenzo Bianconi 
18246b7f9affSLorenzo Bianconi 		if (elem->datalen < 2)
18256b7f9affSLorenzo Bianconi 			continue;
18266b7f9affSLorenzo Bianconi 
18276b7f9affSLorenzo Bianconi 		for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) {
1828aa796f12SLorenzo Bianconi 			const struct ieee80211_bssid_index *idx;
1829aa796f12SLorenzo Bianconi 			const u8 *idx_ie;
18306b7f9affSLorenzo Bianconi 
18316b7f9affSLorenzo Bianconi 			if (sub_elem->id || sub_elem->datalen < 4)
18326b7f9affSLorenzo Bianconi 				continue; /* not a valid BSS profile */
18336b7f9affSLorenzo Bianconi 
18346b7f9affSLorenzo Bianconi 			/* Find WLAN_EID_MULTI_BSSID_IDX
18356b7f9affSLorenzo Bianconi 			 * in the merged nontransmitted profile
18366b7f9affSLorenzo Bianconi 			 */
1837aa796f12SLorenzo Bianconi 			idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
18386b7f9affSLorenzo Bianconi 						  sub_elem->data,
18396b7f9affSLorenzo Bianconi 						  sub_elem->datalen);
1840aa796f12SLorenzo Bianconi 			if (!idx_ie || idx_ie[1] < sizeof(*idx))
18416b7f9affSLorenzo Bianconi 				continue;
18426b7f9affSLorenzo Bianconi 
1843aa796f12SLorenzo Bianconi 			idx = (void *)(idx_ie + 2);
1844aa796f12SLorenzo Bianconi 			if (!idx->bssid_index || idx->bssid_index > 31)
1845aa796f12SLorenzo Bianconi 				continue;
1846aa796f12SLorenzo Bianconi 
1847aa796f12SLorenzo Bianconi 			mbss->offset[idx->bssid_index] =
1848aa796f12SLorenzo Bianconi 				cpu_to_le16(idx_ie - skb->data);
1849aa796f12SLorenzo Bianconi 			mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index));
18506b7f9affSLorenzo Bianconi 		}
18516b7f9affSLorenzo Bianconi 	}
18526b7f9affSLorenzo Bianconi }
18536b7f9affSLorenzo Bianconi 
18546b7f9affSLorenzo Bianconi static void
mt7915_mcu_beacon_cont(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct sk_buff * rskb,struct sk_buff * skb,struct bss_info_bcn * bcn,struct ieee80211_mutable_offsets * offs)1855b4b9f0a3SLorenzo Bianconi mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1856b4b9f0a3SLorenzo Bianconi 		       struct sk_buff *rskb, struct sk_buff *skb,
1857b4b9f0a3SLorenzo Bianconi 		       struct bss_info_bcn *bcn,
1858e57b7901SRyder Lee 		       struct ieee80211_mutable_offsets *offs)
1859e57b7901SRyder Lee {
1860e57b7901SRyder Lee 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1861e57b7901SRyder Lee 	struct bss_info_bcn_cont *cont;
1862e57b7901SRyder Lee 	struct tlv *tlv;
1863e57b7901SRyder Lee 	u8 *buf;
1864e57b7901SRyder Lee 	int len = sizeof(*cont) + MT_TXD_SIZE + skb->len;
1865e57b7901SRyder Lee 
1866869f0646SMeiChia Chiu 	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
1867e57b7901SRyder Lee 	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT,
1868e57b7901SRyder Lee 					   len, &bcn->sub_ntlv, &bcn->len);
1869e57b7901SRyder Lee 
1870e57b7901SRyder Lee 	cont = (struct bss_info_bcn_cont *)tlv;
1871e57b7901SRyder Lee 	cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1872e57b7901SRyder Lee 	cont->tim_ofs = cpu_to_le16(offs->tim_offset);
1873e57b7901SRyder Lee 
1874b4b9f0a3SLorenzo Bianconi 	if (offs->cntdwn_counter_offs[0]) {
1875b4b9f0a3SLorenzo Bianconi 		u16 offset = offs->cntdwn_counter_offs[0];
1876b4b9f0a3SLorenzo Bianconi 
1877d0a9123eSJohannes Berg 		if (vif->bss_conf.csa_active)
1878b4b9f0a3SLorenzo Bianconi 			cont->csa_ofs = cpu_to_le16(offset - 4);
1879d0a9123eSJohannes Berg 		if (vif->bss_conf.color_change_active)
1880b4b9f0a3SLorenzo Bianconi 			cont->bcc_ofs = cpu_to_le16(offset - 3);
1881b4b9f0a3SLorenzo Bianconi 	}
1882e57b7901SRyder Lee 
1883e57b7901SRyder Lee 	buf = (u8 *)tlv + sizeof(*cont);
1884d502e300SLorenzo Bianconi 	mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
18851d5af0acSFelix Fietkau 			      0, BSS_CHANGED_BEACON);
1886e57b7901SRyder Lee 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
1887e57b7901SRyder Lee }
1888e57b7901SRyder Lee 
1889671985baSMeiChia Chiu int
mt7915_mcu_add_inband_discov(struct mt7915_dev * dev,struct ieee80211_vif * vif,u32 changed)1890671985baSMeiChia Chiu mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1891869f0646SMeiChia Chiu 			     u32 changed)
1892869f0646SMeiChia Chiu {
1893869f0646SMeiChia Chiu #define OFFLOAD_TX_MODE_SU	BIT(0)
1894869f0646SMeiChia Chiu #define OFFLOAD_TX_MODE_MU	BIT(1)
1895869f0646SMeiChia Chiu 	struct ieee80211_hw *hw = mt76_hw(dev);
1896869f0646SMeiChia Chiu 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
1897869f0646SMeiChia Chiu 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1898869f0646SMeiChia Chiu 	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
1899869f0646SMeiChia Chiu 	enum nl80211_band band = chandef->chan->band;
1900869f0646SMeiChia Chiu 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1901671985baSMeiChia Chiu 	struct bss_info_bcn *bcn;
1902869f0646SMeiChia Chiu 	struct bss_info_inband_discovery *discov;
1903869f0646SMeiChia Chiu 	struct ieee80211_tx_info *info;
1904671985baSMeiChia Chiu 	struct sk_buff *rskb, *skb = NULL;
1905671985baSMeiChia Chiu 	struct tlv *tlv, *sub_tlv;
1906869f0646SMeiChia Chiu 	bool ext_phy = phy != &dev->phy;
1907869f0646SMeiChia Chiu 	u8 *buf, interval;
1908869f0646SMeiChia Chiu 	int len;
1909869f0646SMeiChia Chiu 
1910671985baSMeiChia Chiu 	if (vif->bss_conf.nontransmitted)
1911671985baSMeiChia Chiu 		return 0;
1912671985baSMeiChia Chiu 
1913671985baSMeiChia Chiu 	rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
1914671985baSMeiChia Chiu 					       MT7915_MAX_BSS_OFFLOAD_SIZE);
1915671985baSMeiChia Chiu 	if (IS_ERR(rskb))
1916671985baSMeiChia Chiu 		return PTR_ERR(rskb);
1917671985baSMeiChia Chiu 
1918671985baSMeiChia Chiu 	tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
1919671985baSMeiChia Chiu 	bcn = (struct bss_info_bcn *)tlv;
1920671985baSMeiChia Chiu 	bcn->enable = true;
1921671985baSMeiChia Chiu 
1922869f0646SMeiChia Chiu 	if (changed & BSS_CHANGED_FILS_DISCOVERY &&
1923869f0646SMeiChia Chiu 	    vif->bss_conf.fils_discovery.max_interval) {
1924869f0646SMeiChia Chiu 		interval = vif->bss_conf.fils_discovery.max_interval;
1925869f0646SMeiChia Chiu 		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
1926869f0646SMeiChia Chiu 	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
1927869f0646SMeiChia Chiu 		   vif->bss_conf.unsol_bcast_probe_resp_interval) {
1928869f0646SMeiChia Chiu 		interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
1929869f0646SMeiChia Chiu 		skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
1930869f0646SMeiChia Chiu 	}
1931869f0646SMeiChia Chiu 
19323d691558SBo Jiao 	if (!skb) {
19333d691558SBo Jiao 		dev_kfree_skb(rskb);
1934671985baSMeiChia Chiu 		return -EINVAL;
19353d691558SBo Jiao 	}
1936869f0646SMeiChia Chiu 
1937869f0646SMeiChia Chiu 	info = IEEE80211_SKB_CB(skb);
1938869f0646SMeiChia Chiu 	info->control.vif = vif;
1939869f0646SMeiChia Chiu 	info->band = band;
1940a062f001SLorenzo Bianconi 	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
1941869f0646SMeiChia Chiu 
1942869f0646SMeiChia Chiu 	len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
1943869f0646SMeiChia Chiu 	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
1944869f0646SMeiChia Chiu 
1945671985baSMeiChia Chiu 	if (skb->len > MT7915_MAX_BEACON_SIZE) {
194618fced20SMeiChia Chiu 		dev_err(dev->mt76.dev, "inband discovery size limit exceed\n");
19473d691558SBo Jiao 		dev_kfree_skb(rskb);
194818fced20SMeiChia Chiu 		dev_kfree_skb(skb);
1949671985baSMeiChia Chiu 		return -EINVAL;
195018fced20SMeiChia Chiu 	}
195118fced20SMeiChia Chiu 
1952671985baSMeiChia Chiu 	sub_tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
1953869f0646SMeiChia Chiu 					       len, &bcn->sub_ntlv, &bcn->len);
1954671985baSMeiChia Chiu 	discov = (struct bss_info_inband_discovery *)sub_tlv;
1955869f0646SMeiChia Chiu 	discov->tx_mode = OFFLOAD_TX_MODE_SU;
1956869f0646SMeiChia Chiu 	/* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
1957869f0646SMeiChia Chiu 	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
1958869f0646SMeiChia Chiu 	discov->tx_interval = interval;
1959869f0646SMeiChia Chiu 	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1960869f0646SMeiChia Chiu 	discov->enable = true;
1961869f0646SMeiChia Chiu 
1962671985baSMeiChia Chiu 	buf = (u8 *)sub_tlv + sizeof(*discov);
1963869f0646SMeiChia Chiu 
1964d502e300SLorenzo Bianconi 	mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
19651d5af0acSFelix Fietkau 			      0, changed);
1966869f0646SMeiChia Chiu 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
1967869f0646SMeiChia Chiu 
1968869f0646SMeiChia Chiu 	dev_kfree_skb(skb);
1969671985baSMeiChia Chiu 
1970671985baSMeiChia Chiu 	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
1971671985baSMeiChia Chiu 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
1972869f0646SMeiChia Chiu }
1973869f0646SMeiChia Chiu 
mt7915_mcu_add_beacon(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int en,u32 changed)1974869f0646SMeiChia Chiu int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1975869f0646SMeiChia Chiu 			  int en, u32 changed)
1976e57b7901SRyder Lee {
1977e57b7901SRyder Lee 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
1978e57b7901SRyder Lee 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
1979e57b7901SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1980e57b7901SRyder Lee 	struct ieee80211_mutable_offsets offs;
1981e57b7901SRyder Lee 	struct ieee80211_tx_info *info;
1982e57b7901SRyder Lee 	struct sk_buff *skb, *rskb;
1983e57b7901SRyder Lee 	struct tlv *tlv;
1984e57b7901SRyder Lee 	struct bss_info_bcn *bcn;
198518fced20SMeiChia Chiu 	int len = MT7915_MAX_BSS_OFFLOAD_SIZE;
1986006b9d4aSBo Jiao 	bool ext_phy = phy != &dev->phy;
1987e57b7901SRyder Lee 
19886b7f9affSLorenzo Bianconi 	if (vif->bss_conf.nontransmitted)
19896b7f9affSLorenzo Bianconi 		return 0;
19906b7f9affSLorenzo Bianconi 
1991e2c93b68SLorenzo Bianconi 	rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
1992e2c93b68SLorenzo Bianconi 					       NULL, len);
1993ac15f9b6SRyder Lee 	if (IS_ERR(rskb))
1994ac15f9b6SRyder Lee 		return PTR_ERR(rskb);
1995ac15f9b6SRyder Lee 
1996069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
1997ac15f9b6SRyder Lee 	bcn = (struct bss_info_bcn *)tlv;
1998ac15f9b6SRyder Lee 	bcn->enable = en;
1999ac15f9b6SRyder Lee 
2000ac15f9b6SRyder Lee 	if (!en)
2001ac15f9b6SRyder Lee 		goto out;
2002ac15f9b6SRyder Lee 
20036e8912a5SShaul Triebitz 	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
20043d691558SBo Jiao 	if (!skb) {
20053d691558SBo Jiao 		dev_kfree_skb(rskb);
2006e57b7901SRyder Lee 		return -EINVAL;
20073d691558SBo Jiao 	}
2008e57b7901SRyder Lee 
2009671985baSMeiChia Chiu 	if (skb->len > MT7915_MAX_BEACON_SIZE) {
2010e57b7901SRyder Lee 		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
20113d691558SBo Jiao 		dev_kfree_skb(rskb);
2012e57b7901SRyder Lee 		dev_kfree_skb(skb);
2013e57b7901SRyder Lee 		return -EINVAL;
2014e57b7901SRyder Lee 	}
2015e57b7901SRyder Lee 
2016e57b7901SRyder Lee 	info = IEEE80211_SKB_CB(skb);
2017a062f001SLorenzo Bianconi 	info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
2018e57b7901SRyder Lee 
2019b4b9f0a3SLorenzo Bianconi 	mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
20206b7f9affSLorenzo Bianconi 	mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
2021b4b9f0a3SLorenzo Bianconi 	mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
2022e57b7901SRyder Lee 	dev_kfree_skb(skb);
2023e57b7901SRyder Lee 
2024ac15f9b6SRyder Lee out:
2025fa62d0e0SFelix Fietkau 	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
2026c203dd62SFelix Fietkau 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
2027e57b7901SRyder Lee }
2028e57b7901SRyder Lee 
mt7915_driver_own(struct mt7915_dev * dev,u8 band)20291c7393e6SBo Jiao static int mt7915_driver_own(struct mt7915_dev *dev, u8 band)
2030e57b7901SRyder Lee {
20311c7393e6SBo Jiao 	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN);
20321c7393e6SBo Jiao 	if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band),
203371bb496cSFelix Fietkau 			    MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) {
2034e57b7901SRyder Lee 		dev_err(dev->mt76.dev, "Timeout for driver own\n");
2035e57b7901SRyder Lee 		return -EIO;
2036e57b7901SRyder Lee 	}
2037e57b7901SRyder Lee 
20381c7393e6SBo Jiao 	/* clear irq when the driver own success */
20391c7393e6SBo Jiao 	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band),
20401c7393e6SBo Jiao 		MT_TOP_LPCR_HOST_BAND_STAT);
20411c7393e6SBo Jiao 
2042e57b7901SRyder Lee 	return 0;
2043e57b7901SRyder Lee }
2044e57b7901SRyder Lee 
2045e57b7901SRyder Lee static int
mt7915_firmware_state(struct mt7915_dev * dev,bool wa)20461c7393e6SBo Jiao mt7915_firmware_state(struct mt7915_dev *dev, bool wa)
20471c7393e6SBo Jiao {
20481c7393e6SBo Jiao 	u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE,
20491c7393e6SBo Jiao 			       wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD);
20501c7393e6SBo Jiao 
20511c7393e6SBo Jiao 	if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,
20521c7393e6SBo Jiao 			    state, 1000)) {
20531c7393e6SBo Jiao 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
20541c7393e6SBo Jiao 		return -EIO;
20551c7393e6SBo Jiao 	}
20561c7393e6SBo Jiao 	return 0;
20571c7393e6SBo Jiao }
20581c7393e6SBo Jiao 
mt7915_load_firmware(struct mt7915_dev * dev)2059e57b7901SRyder Lee static int mt7915_load_firmware(struct mt7915_dev *dev)
2060e57b7901SRyder Lee {
2061e57b7901SRyder Lee 	int ret;
2062e57b7901SRyder Lee 
20631c7393e6SBo Jiao 	/* make sure fw is download state */
20641c7393e6SBo Jiao 	if (mt7915_firmware_state(dev, false)) {
20651c7393e6SBo Jiao 		/* restart firmware once */
2066f535ccdfSLorenzo Bianconi 		mt76_connac_mcu_restart(&dev->mt76);
20671c7393e6SBo Jiao 		ret = mt7915_firmware_state(dev, false);
20681c7393e6SBo Jiao 		if (ret) {
20691c7393e6SBo Jiao 			dev_err(dev->mt76.dev,
20701c7393e6SBo Jiao 				"Firmware is not ready for download\n");
20711c7393e6SBo Jiao 			return ret;
20721c7393e6SBo Jiao 		}
20731c7393e6SBo Jiao 	}
20741c7393e6SBo Jiao 
207528fec923SLorenzo Bianconi 	ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH));
2076e57b7901SRyder Lee 	if (ret)
2077e57b7901SRyder Lee 		return ret;
2078e57b7901SRyder Lee 
2079b9ec2710SLorenzo Bianconi 	ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM),
2080b9ec2710SLorenzo Bianconi 				    fw_name(dev, FIRMWARE_WA));
2081e57b7901SRyder Lee 	if (ret)
2082e57b7901SRyder Lee 		return ret;
2083e57b7901SRyder Lee 
20841c7393e6SBo Jiao 	ret = mt7915_firmware_state(dev, true);
20851c7393e6SBo Jiao 	if (ret)
20861c7393e6SBo Jiao 		return ret;
2087e57b7901SRyder Lee 
2088e637763bSLorenzo Bianconi 	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
2089e57b7901SRyder Lee 
2090e57b7901SRyder Lee 	dev_dbg(dev->mt76.dev, "Firmware init done\n");
2091e57b7901SRyder Lee 
2092e57b7901SRyder Lee 	return 0;
2093e57b7901SRyder Lee }
2094e57b7901SRyder Lee 
mt7915_mcu_fw_log_2_host(struct mt7915_dev * dev,u8 type,u8 ctrl)20959b121acdSShayne Chen int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl)
20965517f78bSRyder Lee {
20975517f78bSRyder Lee 	struct {
20985517f78bSRyder Lee 		u8 ctrl_val;
20995517f78bSRyder Lee 		u8 pad[3];
21005517f78bSRyder Lee 	} data = {
21015517f78bSRyder Lee 		.ctrl_val = ctrl
21025517f78bSRyder Lee 	};
21035517f78bSRyder Lee 
21049b121acdSShayne Chen 	if (type == MCU_FW_LOG_WA)
21059b121acdSShayne Chen 		return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(FW_LOG_2_HOST),
21069b121acdSShayne Chen 					 &data, sizeof(data), true);
21079b121acdSShayne Chen 
2108c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data,
2109cb5cdd4cSFelix Fietkau 				 sizeof(data), true);
21105517f78bSRyder Lee }
21115517f78bSRyder Lee 
mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev * dev,u32 module,u8 level)21125517f78bSRyder Lee int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
21135517f78bSRyder Lee {
21145517f78bSRyder Lee 	struct {
21155517f78bSRyder Lee 		u8 ver;
21165517f78bSRyder Lee 		u8 pad;
2117cee236e1SFelix Fietkau 		__le16 len;
21185517f78bSRyder Lee 		u8 level;
21195517f78bSRyder Lee 		u8 rsv[3];
212019e29c69SRyder Lee 		__le32 module_idx;
21215517f78bSRyder Lee 	} data = {
21225517f78bSRyder Lee 		.module_idx = cpu_to_le32(module),
21235517f78bSRyder Lee 		.level = level,
21245517f78bSRyder Lee 	};
21255517f78bSRyder Lee 
2126c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data,
2127cb5cdd4cSFelix Fietkau 				 sizeof(data), false);
21285517f78bSRyder Lee }
21295517f78bSRyder Lee 
mt7915_mcu_muru_debug_set(struct mt7915_dev * dev,bool enabled)21301966a507SMeiChia Chiu int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled)
21311966a507SMeiChia Chiu {
21321966a507SMeiChia Chiu 	struct {
21331966a507SMeiChia Chiu 		__le32 cmd;
21341966a507SMeiChia Chiu 		u8 enable;
21351966a507SMeiChia Chiu 	} data = {
21361966a507SMeiChia Chiu 		.cmd = cpu_to_le32(MURU_SET_TXC_TX_STATS_EN),
21371966a507SMeiChia Chiu 		.enable = enabled,
21381966a507SMeiChia Chiu 	};
21391966a507SMeiChia Chiu 
21401966a507SMeiChia Chiu 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &data,
21411966a507SMeiChia Chiu 				sizeof(data), false);
21421966a507SMeiChia Chiu }
21431966a507SMeiChia Chiu 
mt7915_mcu_muru_debug_get(struct mt7915_phy * phy)21441258c156SRyder Lee int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy)
21451966a507SMeiChia Chiu {
21461966a507SMeiChia Chiu 	struct mt7915_dev *dev = phy->dev;
21471966a507SMeiChia Chiu 	struct sk_buff *skb;
21481258c156SRyder Lee 	struct mt7915_mcu_muru_stats *mu_stats;
21491966a507SMeiChia Chiu 	int ret;
21501966a507SMeiChia Chiu 
21511966a507SMeiChia Chiu 	struct {
21521966a507SMeiChia Chiu 		__le32 cmd;
21531966a507SMeiChia Chiu 		u8 band_idx;
21541966a507SMeiChia Chiu 	} req = {
21551966a507SMeiChia Chiu 		.cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS),
21563eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
21571966a507SMeiChia Chiu 	};
21581966a507SMeiChia Chiu 
21591966a507SMeiChia Chiu 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL),
21601966a507SMeiChia Chiu 					&req, sizeof(req), true, &skb);
21611966a507SMeiChia Chiu 	if (ret)
21621966a507SMeiChia Chiu 		return ret;
21631966a507SMeiChia Chiu 
21641258c156SRyder Lee 	mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data);
21651258c156SRyder Lee 
21661258c156SRyder Lee 	/* accumulate stats, these are clear-on-read */
21671258c156SRyder Lee #define __dl_u32(s)	 phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s)
21681258c156SRyder Lee #define __ul_u32(s)	 phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s)
21691258c156SRyder Lee 	__dl_u32(cck_cnt);
21701258c156SRyder Lee 	__dl_u32(ofdm_cnt);
21711258c156SRyder Lee 	__dl_u32(htmix_cnt);
21721258c156SRyder Lee 	__dl_u32(htgf_cnt);
21731258c156SRyder Lee 	__dl_u32(vht_su_cnt);
21741258c156SRyder Lee 	__dl_u32(vht_2mu_cnt);
21751258c156SRyder Lee 	__dl_u32(vht_3mu_cnt);
21761258c156SRyder Lee 	__dl_u32(vht_4mu_cnt);
21771258c156SRyder Lee 	__dl_u32(he_su_cnt);
21781258c156SRyder Lee 	__dl_u32(he_2ru_cnt);
21791258c156SRyder Lee 	__dl_u32(he_2mu_cnt);
21801258c156SRyder Lee 	__dl_u32(he_3ru_cnt);
21811258c156SRyder Lee 	__dl_u32(he_3mu_cnt);
21821258c156SRyder Lee 	__dl_u32(he_4ru_cnt);
21831258c156SRyder Lee 	__dl_u32(he_4mu_cnt);
21841258c156SRyder Lee 	__dl_u32(he_5to8ru_cnt);
21851258c156SRyder Lee 	__dl_u32(he_9to16ru_cnt);
21861258c156SRyder Lee 	__dl_u32(he_gtr16ru_cnt);
21871258c156SRyder Lee 
21881258c156SRyder Lee 	__ul_u32(hetrig_su_cnt);
21891258c156SRyder Lee 	__ul_u32(hetrig_2ru_cnt);
21901258c156SRyder Lee 	__ul_u32(hetrig_3ru_cnt);
21911258c156SRyder Lee 	__ul_u32(hetrig_4ru_cnt);
21921258c156SRyder Lee 	__ul_u32(hetrig_5to8ru_cnt);
21931258c156SRyder Lee 	__ul_u32(hetrig_9to16ru_cnt);
21941258c156SRyder Lee 	__ul_u32(hetrig_gtr16ru_cnt);
21951258c156SRyder Lee 	__ul_u32(hetrig_2mu_cnt);
21961258c156SRyder Lee 	__ul_u32(hetrig_3mu_cnt);
21971258c156SRyder Lee 	__ul_u32(hetrig_4mu_cnt);
21981258c156SRyder Lee #undef __dl_u32
21991258c156SRyder Lee #undef __ul_u32
22001258c156SRyder Lee 
22011966a507SMeiChia Chiu 	dev_kfree_skb(skb);
22021966a507SMeiChia Chiu 
22031966a507SMeiChia Chiu 	return 0;
22041966a507SMeiChia Chiu }
22051966a507SMeiChia Chiu 
mt7915_mcu_set_mwds(struct mt7915_dev * dev,bool enabled)2206e151d71eSFelix Fietkau static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled)
2207e151d71eSFelix Fietkau {
2208e151d71eSFelix Fietkau 	struct {
2209e151d71eSFelix Fietkau 		u8 enable;
2210e151d71eSFelix Fietkau 		u8 _rsv[3];
2211e151d71eSFelix Fietkau 	} __packed req = {
2212e151d71eSFelix Fietkau 		.enable = enabled
2213e151d71eSFelix Fietkau 	};
2214e151d71eSFelix Fietkau 
2215c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req,
2216cb5cdd4cSFelix Fietkau 				 sizeof(req), false);
2217e151d71eSFelix Fietkau }
2218e151d71eSFelix Fietkau 
mt7915_mcu_set_muru_ctrl(struct mt7915_dev * dev,u32 cmd,u32 val)2219e5a9f383SShayne Chen int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val)
2220e5a9f383SShayne Chen {
2221e5a9f383SShayne Chen 	struct {
2222e5a9f383SShayne Chen 		__le32 cmd;
2223e5a9f383SShayne Chen 		u8 val[4];
2224e5a9f383SShayne Chen 	} __packed req = {
2225e5a9f383SShayne Chen 		.cmd = cpu_to_le32(cmd),
2226e5a9f383SShayne Chen 	};
2227e5a9f383SShayne Chen 
2228e5a9f383SShayne Chen 	put_unaligned_le32(val, req.val);
2229e5a9f383SShayne Chen 
2230e5a9f383SShayne Chen 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req,
2231e5a9f383SShayne Chen 				 sizeof(req), false);
2232e5a9f383SShayne Chen }
2233e5a9f383SShayne Chen 
2234bbf77f6cSShayne Chen static int
mt7915_mcu_init_rx_airtime(struct mt7915_dev * dev)2235bbf77f6cSShayne Chen mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
2236bbf77f6cSShayne Chen {
2237bbf77f6cSShayne Chen #define RX_AIRTIME_FEATURE_CTRL		1
2238bbf77f6cSShayne Chen #define RX_AIRTIME_BITWISE_CTRL		2
2239bbf77f6cSShayne Chen #define RX_AIRTIME_CLEAR_EN	1
2240bbf77f6cSShayne Chen 	struct {
2241bbf77f6cSShayne Chen 		__le16 field;
2242bbf77f6cSShayne Chen 		__le16 sub_field;
2243bbf77f6cSShayne Chen 		__le32 set_status;
2244bbf77f6cSShayne Chen 		__le32 get_status;
2245bbf77f6cSShayne Chen 		u8 _rsv[12];
2246bbf77f6cSShayne Chen 
2247bbf77f6cSShayne Chen 		bool airtime_en;
2248bbf77f6cSShayne Chen 		bool mibtime_en;
2249bbf77f6cSShayne Chen 		bool earlyend_en;
2250bbf77f6cSShayne Chen 		u8 _rsv1[9];
2251bbf77f6cSShayne Chen 
2252bbf77f6cSShayne Chen 		bool airtime_clear;
2253bbf77f6cSShayne Chen 		bool mibtime_clear;
2254bbf77f6cSShayne Chen 		u8 _rsv2[98];
2255bbf77f6cSShayne Chen 	} __packed req = {
2256bbf77f6cSShayne Chen 		.field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL),
2257bbf77f6cSShayne Chen 		.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN),
2258bbf77f6cSShayne Chen 		.airtime_clear = true,
2259bbf77f6cSShayne Chen 	};
2260bbf77f6cSShayne Chen 	int ret;
2261bbf77f6cSShayne Chen 
2262bbf77f6cSShayne Chen 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
2263bbf77f6cSShayne Chen 				sizeof(req), true);
2264bbf77f6cSShayne Chen 	if (ret)
2265bbf77f6cSShayne Chen 		return ret;
2266bbf77f6cSShayne Chen 
2267bbf77f6cSShayne Chen 	req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL);
2268bbf77f6cSShayne Chen 	req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN);
2269bbf77f6cSShayne Chen 	req.airtime_en = true;
2270bbf77f6cSShayne Chen 
2271bbf77f6cSShayne Chen 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
2272bbf77f6cSShayne Chen 				 sizeof(req), true);
2273bbf77f6cSShayne Chen }
2274bbf77f6cSShayne Chen 
mt7915_red_set_watermark(struct mt7915_dev * dev)22757576a1c4SPeter Chiu static int mt7915_red_set_watermark(struct mt7915_dev *dev)
22767576a1c4SPeter Chiu {
22777576a1c4SPeter Chiu #define RED_GLOBAL_TOKEN_WATERMARK 2
22787576a1c4SPeter Chiu 	struct {
22797576a1c4SPeter Chiu 		__le32 args[3];
22807576a1c4SPeter Chiu 		u8 cmd;
22817576a1c4SPeter Chiu 		u8 version;
22827576a1c4SPeter Chiu 		u8 __rsv1[4];
22837576a1c4SPeter Chiu 		__le16 len;
22847576a1c4SPeter Chiu 		__le16 high_mark;
22857576a1c4SPeter Chiu 		__le16 low_mark;
22867576a1c4SPeter Chiu 		u8 __rsv2[12];
22877576a1c4SPeter Chiu 	} __packed req = {
22887576a1c4SPeter Chiu 		.args[0] = cpu_to_le32(MCU_WA_PARAM_RED_SETTING),
22897576a1c4SPeter Chiu 		.cmd = RED_GLOBAL_TOKEN_WATERMARK,
22907576a1c4SPeter Chiu 		.len = cpu_to_le16(sizeof(req) - sizeof(req.args)),
22917576a1c4SPeter Chiu 		.high_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256),
22927576a1c4SPeter Chiu 		.low_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256 - 1536),
22937576a1c4SPeter Chiu 	};
22947576a1c4SPeter Chiu 
22957576a1c4SPeter Chiu 	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET), &req,
22967576a1c4SPeter Chiu 				 sizeof(req), false);
22977576a1c4SPeter Chiu }
22987576a1c4SPeter Chiu 
mt7915_mcu_set_red(struct mt7915_dev * dev,bool enabled)22997576a1c4SPeter Chiu static int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
23007576a1c4SPeter Chiu {
23017576a1c4SPeter Chiu #define RED_DISABLE		0
23027576a1c4SPeter Chiu #define RED_BY_WA_ENABLE	2
23037576a1c4SPeter Chiu 	int ret;
23047576a1c4SPeter Chiu 	u32 red_type = enabled ? RED_BY_WA_ENABLE : RED_DISABLE;
23057576a1c4SPeter Chiu 	__le32 req = cpu_to_le32(red_type);
23067576a1c4SPeter Chiu 
23077576a1c4SPeter Chiu 	if (enabled) {
23087576a1c4SPeter Chiu 		ret = mt7915_red_set_watermark(dev);
23097576a1c4SPeter Chiu 		if (ret < 0)
23107576a1c4SPeter Chiu 			return ret;
23117576a1c4SPeter Chiu 	}
23127576a1c4SPeter Chiu 
23137576a1c4SPeter Chiu 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RED_ENABLE), &req,
23147576a1c4SPeter Chiu 				sizeof(req), false);
23157576a1c4SPeter Chiu 	if (ret < 0)
23167576a1c4SPeter Chiu 		return ret;
23177576a1c4SPeter Chiu 
23187576a1c4SPeter Chiu 	return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
23197576a1c4SPeter Chiu 				 MCU_WA_PARAM_RED, enabled, 0);
23207576a1c4SPeter Chiu }
23217576a1c4SPeter Chiu 
mt7915_mcu_init_firmware(struct mt7915_dev * dev)23228a55712dSBo Jiao int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
2323e57b7901SRyder Lee {
2324e57b7901SRyder Lee 	int ret;
2325e57b7901SRyder Lee 
23261c7393e6SBo Jiao 	/* force firmware operation mode into normal state,
23271c7393e6SBo Jiao 	 * which should be set before firmware download stage.
23281c7393e6SBo Jiao 	 */
23291c7393e6SBo Jiao 	mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
23301c7393e6SBo Jiao 
23311c7393e6SBo Jiao 	ret = mt7915_driver_own(dev, 0);
2332e57b7901SRyder Lee 	if (ret)
2333e57b7901SRyder Lee 		return ret;
23341c7393e6SBo Jiao 	/* set driver own for band1 when two hif exist */
23351c7393e6SBo Jiao 	if (dev->hif2) {
23361c7393e6SBo Jiao 		ret = mt7915_driver_own(dev, 1);
23371c7393e6SBo Jiao 		if (ret)
23381c7393e6SBo Jiao 			return ret;
23391c7393e6SBo Jiao 	}
2340e57b7901SRyder Lee 
2341e57b7901SRyder Lee 	ret = mt7915_load_firmware(dev);
2342e57b7901SRyder Lee 	if (ret)
2343e57b7901SRyder Lee 		return ret;
2344e57b7901SRyder Lee 
2345e57b7901SRyder Lee 	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
23469b121acdSShayne Chen 	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0);
23479b121acdSShayne Chen 	if (ret)
23489b121acdSShayne Chen 		return ret;
23499b121acdSShayne Chen 
23509b121acdSShayne Chen 	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
2351706dc08cSLorenzo Bianconi 	if (ret)
2352706dc08cSLorenzo Bianconi 		return ret;
2353e57b7901SRyder Lee 
2354*c71d2db2SFelix Fietkau 	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
2355*c71d2db2SFelix Fietkau 
2356db1a5a6cSSujuan Chen 	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
2357db1a5a6cSSujuan Chen 	     is_mt7915(&dev->mt76)) ||
2358db1a5a6cSSujuan Chen 	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
2359f68d6762SFelix Fietkau 		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
2360f68d6762SFelix Fietkau 
2361706dc08cSLorenzo Bianconi 	ret = mt7915_mcu_set_mwds(dev, 1);
2362706dc08cSLorenzo Bianconi 	if (ret)
2363706dc08cSLorenzo Bianconi 		return ret;
2364706dc08cSLorenzo Bianconi 
2365e5a9f383SShayne Chen 	ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE,
2366e5a9f383SShayne Chen 				       MURU_PLATFORM_TYPE_PERF_LEVEL_2);
2367e5a9f383SShayne Chen 	if (ret)
2368e5a9f383SShayne Chen 		return ret;
2369e5a9f383SShayne Chen 
2370bbf77f6cSShayne Chen 	ret = mt7915_mcu_init_rx_airtime(dev);
2371bbf77f6cSShayne Chen 	if (ret)
2372bbf77f6cSShayne Chen 		return ret;
2373bbf77f6cSShayne Chen 
23747576a1c4SPeter Chiu 	return mt7915_mcu_set_red(dev, mtk_wed_device_active(&dev->mt76.mmio.wed));
2375e57b7901SRyder Lee }
2376e57b7901SRyder Lee 
mt7915_mcu_init(struct mt7915_dev * dev)23778a55712dSBo Jiao int mt7915_mcu_init(struct mt7915_dev *dev)
23788a55712dSBo Jiao {
23798a55712dSBo Jiao 	static const struct mt76_mcu_ops mt7915_mcu_ops = {
23808a55712dSBo Jiao 		.headroom = sizeof(struct mt76_connac2_mcu_txd),
23818a55712dSBo Jiao 		.mcu_skb_send_msg = mt7915_mcu_send_message,
23828a55712dSBo Jiao 		.mcu_parse_response = mt7915_mcu_parse_response,
23838a55712dSBo Jiao 	};
23848a55712dSBo Jiao 
23858a55712dSBo Jiao 	dev->mt76.mcu_ops = &mt7915_mcu_ops;
23868a55712dSBo Jiao 
23878a55712dSBo Jiao 	return mt7915_mcu_init_firmware(dev);
23888a55712dSBo Jiao }
23898a55712dSBo Jiao 
mt7915_mcu_exit(struct mt7915_dev * dev)2390e57b7901SRyder Lee void mt7915_mcu_exit(struct mt7915_dev *dev)
2391e57b7901SRyder Lee {
2392f535ccdfSLorenzo Bianconi 	mt76_connac_mcu_restart(&dev->mt76);
23931c7393e6SBo Jiao 	if (mt7915_firmware_state(dev, false)) {
2394e57b7901SRyder Lee 		dev_err(dev->mt76.dev, "Failed to exit mcu\n");
239549bd7828SLorenzo Bianconi 		goto out;
2396e57b7901SRyder Lee 	}
2397e57b7901SRyder Lee 
23981c7393e6SBo Jiao 	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
23991c7393e6SBo Jiao 	if (dev->hif2)
24001c7393e6SBo Jiao 		mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
24011c7393e6SBo Jiao 			MT_TOP_LPCR_HOST_FW_OWN);
240249bd7828SLorenzo Bianconi out:
2403e57b7901SRyder Lee 	skb_queue_purge(&dev->mt76.mcu.res_q);
2404e57b7901SRyder Lee }
2405e57b7901SRyder Lee 
240690e3abf0SFelix Fietkau static int
mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev * dev,int band)240790e3abf0SFelix Fietkau mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band)
240890e3abf0SFelix Fietkau {
240990e3abf0SFelix Fietkau 	struct {
241090e3abf0SFelix Fietkau 		u8 operation;
241190e3abf0SFelix Fietkau 		u8 count;
241290e3abf0SFelix Fietkau 		u8 _rsv[2];
241390e3abf0SFelix Fietkau 		u8 index;
241490e3abf0SFelix Fietkau 		u8 enable;
241590e3abf0SFelix Fietkau 		__le16 etype;
241690e3abf0SFelix Fietkau 	} req = {
241790e3abf0SFelix Fietkau 		.operation = 1,
241890e3abf0SFelix Fietkau 		.count = 1,
241990e3abf0SFelix Fietkau 		.enable = 1,
242090e3abf0SFelix Fietkau 		.etype = cpu_to_le16(ETH_P_PAE),
242190e3abf0SFelix Fietkau 	};
242290e3abf0SFelix Fietkau 
242390e3abf0SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
242490e3abf0SFelix Fietkau 				 &req, sizeof(req), false);
242590e3abf0SFelix Fietkau }
242690e3abf0SFelix Fietkau 
mt7915_mcu_set_mac(struct mt7915_dev * dev,int band,bool enable,bool hdr_trans)2427e57b7901SRyder Lee int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
2428e57b7901SRyder Lee 		       bool enable, bool hdr_trans)
2429e57b7901SRyder Lee {
2430e57b7901SRyder Lee 	struct {
2431e57b7901SRyder Lee 		u8 operation;
2432e57b7901SRyder Lee 		u8 enable;
2433e57b7901SRyder Lee 		u8 check_bssid;
2434e57b7901SRyder Lee 		u8 insert_vlan;
2435e57b7901SRyder Lee 		u8 remove_vlan;
2436e57b7901SRyder Lee 		u8 tid;
2437e57b7901SRyder Lee 		u8 mode;
2438e57b7901SRyder Lee 		u8 rsv;
2439e57b7901SRyder Lee 	} __packed req_trans = {
2440e57b7901SRyder Lee 		.enable = hdr_trans,
2441e57b7901SRyder Lee 	};
2442e57b7901SRyder Lee 	struct {
2443e57b7901SRyder Lee 		u8 enable;
2444e57b7901SRyder Lee 		u8 band;
2445e57b7901SRyder Lee 		u8 rsv[2];
2446e57b7901SRyder Lee 	} __packed req_mac = {
2447e57b7901SRyder Lee 		.enable = enable,
2448e57b7901SRyder Lee 		.band = band,
2449e57b7901SRyder Lee 	};
2450e57b7901SRyder Lee 	int ret;
2451e57b7901SRyder Lee 
2452c203dd62SFelix Fietkau 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
2453e57b7901SRyder Lee 				&req_trans, sizeof(req_trans), false);
2454e57b7901SRyder Lee 	if (ret)
2455e57b7901SRyder Lee 		return ret;
2456e57b7901SRyder Lee 
245790e3abf0SFelix Fietkau 	if (hdr_trans)
245890e3abf0SFelix Fietkau 		mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band);
245990e3abf0SFelix Fietkau 
2460c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL),
2461e57b7901SRyder Lee 				 &req_mac, sizeof(req_mac), true);
2462e57b7901SRyder Lee }
2463e57b7901SRyder Lee 
mt7915_mcu_update_edca(struct mt7915_dev * dev,void * param)24647ff903bcSShayne Chen int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param)
24657ff903bcSShayne Chen {
24667ff903bcSShayne Chen 	struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param;
24677ff903bcSShayne Chen 	u8 num = req->total;
24687ff903bcSShayne Chen 	size_t len = sizeof(*req) -
24697ff903bcSShayne Chen 		     (IEEE80211_NUM_ACS - num) * sizeof(struct edca);
24707ff903bcSShayne Chen 
2471c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req,
24727ff903bcSShayne Chen 				 len, true);
24737ff903bcSShayne Chen }
24747ff903bcSShayne Chen 
mt7915_mcu_set_tx(struct mt7915_dev * dev,struct ieee80211_vif * vif)2475e57b7901SRyder Lee int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
2476e57b7901SRyder Lee {
2477e57b7901SRyder Lee #define TX_CMD_MODE		1
24787ff903bcSShayne Chen 	struct mt7915_mcu_tx req = {
2479e57b7901SRyder Lee 		.valid = true,
2480e57b7901SRyder Lee 		.mode = TX_CMD_MODE,
2481e57b7901SRyder Lee 		.total = IEEE80211_NUM_ACS,
2482e57b7901SRyder Lee 	};
2483e57b7901SRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
2484e57b7901SRyder Lee 	int ac;
2485e57b7901SRyder Lee 
2486e57b7901SRyder Lee 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
248780c99340SRyder Lee 		struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
2488e57b7901SRyder Lee 		struct edca *e = &req.edca[ac];
2489e57b7901SRyder Lee 
24902a341206SFelix Fietkau 		e->set = WMM_PARAM_SET;
2491182071cdSLorenzo Bianconi 		e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
249280c99340SRyder Lee 		e->aifs = q->aifs;
249380c99340SRyder Lee 		e->txop = cpu_to_le16(q->txop);
2494e57b7901SRyder Lee 
249580c99340SRyder Lee 		if (q->cw_min)
249680c99340SRyder Lee 			e->cw_min = fls(q->cw_min);
2497e57b7901SRyder Lee 		else
2498e57b7901SRyder Lee 			e->cw_min = 5;
2499e57b7901SRyder Lee 
250080c99340SRyder Lee 		if (q->cw_max)
250180c99340SRyder Lee 			e->cw_max = cpu_to_le16(fls(q->cw_max));
2502e57b7901SRyder Lee 		else
2503e57b7901SRyder Lee 			e->cw_max = cpu_to_le16(10);
2504e57b7901SRyder Lee 	}
25057ff903bcSShayne Chen 
25067ff903bcSShayne Chen 	return mt7915_mcu_update_edca(dev, &req);
2507e57b7901SRyder Lee }
2508e57b7901SRyder Lee 
mt7915_mcu_set_fcc5_lpn(struct mt7915_dev * dev,int val)2509e57b7901SRyder Lee int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val)
2510e57b7901SRyder Lee {
2511e57b7901SRyder Lee 	struct {
2512cee236e1SFelix Fietkau 		__le32 tag;
2513cee236e1SFelix Fietkau 		__le16 min_lpn;
2514e57b7901SRyder Lee 		u8 rsv[2];
2515e57b7901SRyder Lee 	} __packed req = {
2516cee236e1SFelix Fietkau 		.tag = cpu_to_le32(0x1),
2517cee236e1SFelix Fietkau 		.min_lpn = cpu_to_le16(val),
2518e57b7901SRyder Lee 	};
2519e57b7901SRyder Lee 
2520c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
2521cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
2522e57b7901SRyder Lee }
2523e57b7901SRyder Lee 
mt7915_mcu_set_pulse_th(struct mt7915_dev * dev,const struct mt7915_dfs_pulse * pulse)2524e57b7901SRyder Lee int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
2525e57b7901SRyder Lee 			    const struct mt7915_dfs_pulse *pulse)
2526e57b7901SRyder Lee {
2527e57b7901SRyder Lee 	struct {
2528cee236e1SFelix Fietkau 		__le32 tag;
2529e57b7901SRyder Lee 
2530cee236e1SFelix Fietkau 		__le32 max_width;		/* us */
2531cee236e1SFelix Fietkau 		__le32 max_pwr;			/* dbm */
2532cee236e1SFelix Fietkau 		__le32 min_pwr;			/* dbm */
2533cee236e1SFelix Fietkau 		__le32 min_stgr_pri;		/* us */
2534cee236e1SFelix Fietkau 		__le32 max_stgr_pri;		/* us */
2535cee236e1SFelix Fietkau 		__le32 min_cr_pri;		/* us */
2536cee236e1SFelix Fietkau 		__le32 max_cr_pri;		/* us */
2537cee236e1SFelix Fietkau 	} __packed req = {
2538cee236e1SFelix Fietkau 		.tag = cpu_to_le32(0x3),
2539cee236e1SFelix Fietkau 
2540cee236e1SFelix Fietkau #define __req_field(field) .field = cpu_to_le32(pulse->field)
2541cee236e1SFelix Fietkau 		__req_field(max_width),
2542cee236e1SFelix Fietkau 		__req_field(max_pwr),
2543cee236e1SFelix Fietkau 		__req_field(min_pwr),
2544cee236e1SFelix Fietkau 		__req_field(min_stgr_pri),
2545cee236e1SFelix Fietkau 		__req_field(max_stgr_pri),
2546cee236e1SFelix Fietkau 		__req_field(min_cr_pri),
2547cee236e1SFelix Fietkau 		__req_field(max_cr_pri),
2548cee236e1SFelix Fietkau #undef __req_field
2549cee236e1SFelix Fietkau 	};
2550e57b7901SRyder Lee 
2551c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
2552cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
2553e57b7901SRyder Lee }
2554e57b7901SRyder Lee 
mt7915_mcu_set_radar_th(struct mt7915_dev * dev,int index,const struct mt7915_dfs_pattern * pattern)2555e57b7901SRyder Lee int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
2556e57b7901SRyder Lee 			    const struct mt7915_dfs_pattern *pattern)
2557e57b7901SRyder Lee {
2558e57b7901SRyder Lee 	struct {
2559cee236e1SFelix Fietkau 		__le32 tag;
2560cee236e1SFelix Fietkau 		__le16 radar_type;
2561e57b7901SRyder Lee 
2562cee236e1SFelix Fietkau 		u8 enb;
2563cee236e1SFelix Fietkau 		u8 stgr;
2564cee236e1SFelix Fietkau 		u8 min_crpn;
2565cee236e1SFelix Fietkau 		u8 max_crpn;
2566cee236e1SFelix Fietkau 		u8 min_crpr;
2567cee236e1SFelix Fietkau 		u8 min_pw;
2568bb251794SLorenzo Bianconi 		__le32 min_pri;
2569bb251794SLorenzo Bianconi 		__le32 max_pri;
2570cee236e1SFelix Fietkau 		u8 max_pw;
2571cee236e1SFelix Fietkau 		u8 min_crbn;
2572cee236e1SFelix Fietkau 		u8 max_crbn;
2573cee236e1SFelix Fietkau 		u8 min_stgpn;
2574cee236e1SFelix Fietkau 		u8 max_stgpn;
2575cee236e1SFelix Fietkau 		u8 min_stgpr;
2576cee236e1SFelix Fietkau 		u8 rsv[2];
2577bb251794SLorenzo Bianconi 		__le32 min_stgpr_diff;
2578cee236e1SFelix Fietkau 	} __packed req = {
2579cee236e1SFelix Fietkau 		.tag = cpu_to_le32(0x2),
2580cee236e1SFelix Fietkau 		.radar_type = cpu_to_le16(index),
2581cee236e1SFelix Fietkau 
2582cee236e1SFelix Fietkau #define __req_field_u8(field) .field = pattern->field
2583cee236e1SFelix Fietkau #define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
2584cee236e1SFelix Fietkau 		__req_field_u8(enb),
2585cee236e1SFelix Fietkau 		__req_field_u8(stgr),
2586cee236e1SFelix Fietkau 		__req_field_u8(min_crpn),
2587cee236e1SFelix Fietkau 		__req_field_u8(max_crpn),
2588cee236e1SFelix Fietkau 		__req_field_u8(min_crpr),
2589cee236e1SFelix Fietkau 		__req_field_u8(min_pw),
2590cee236e1SFelix Fietkau 		__req_field_u32(min_pri),
2591cee236e1SFelix Fietkau 		__req_field_u32(max_pri),
2592cee236e1SFelix Fietkau 		__req_field_u8(max_pw),
2593cee236e1SFelix Fietkau 		__req_field_u8(min_crbn),
2594cee236e1SFelix Fietkau 		__req_field_u8(max_crbn),
2595cee236e1SFelix Fietkau 		__req_field_u8(min_stgpn),
2596cee236e1SFelix Fietkau 		__req_field_u8(max_stgpn),
2597cee236e1SFelix Fietkau 		__req_field_u8(min_stgpr),
2598cee236e1SFelix Fietkau 		__req_field_u32(min_stgpr_diff),
2599cee236e1SFelix Fietkau #undef __req_field_u8
2600cee236e1SFelix Fietkau #undef __req_field_u32
2601cee236e1SFelix Fietkau 	};
2602e57b7901SRyder Lee 
2603c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
2604cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
2605e57b7901SRyder Lee }
2606e57b7901SRyder Lee 
260739cdf080SLorenzo Bianconi static int
mt7915_mcu_background_chain_ctrl(struct mt7915_phy * phy,struct cfg80211_chan_def * chandef,int cmd)260839cdf080SLorenzo Bianconi mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
260939cdf080SLorenzo Bianconi 				 struct cfg80211_chan_def *chandef,
261039cdf080SLorenzo Bianconi 				 int cmd)
261139cdf080SLorenzo Bianconi {
261239cdf080SLorenzo Bianconi 	struct mt7915_dev *dev = phy->dev;
261339cdf080SLorenzo Bianconi 	struct mt76_phy *mphy = phy->mt76;
261439cdf080SLorenzo Bianconi 	struct ieee80211_channel *chan = mphy->chandef.chan;
261539cdf080SLorenzo Bianconi 	int freq = mphy->chandef.center_freq1;
261639cdf080SLorenzo Bianconi 	struct mt7915_mcu_background_chain_ctrl req = {
261739cdf080SLorenzo Bianconi 		.monitor_scan_type = 2, /* simple rx */
261839cdf080SLorenzo Bianconi 	};
261939cdf080SLorenzo Bianconi 
262039cdf080SLorenzo Bianconi 	if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP)
262139cdf080SLorenzo Bianconi 		return -EINVAL;
262239cdf080SLorenzo Bianconi 
262339cdf080SLorenzo Bianconi 	if (!cfg80211_chandef_valid(&mphy->chandef))
262439cdf080SLorenzo Bianconi 		return -EINVAL;
262539cdf080SLorenzo Bianconi 
262639cdf080SLorenzo Bianconi 	switch (cmd) {
262739cdf080SLorenzo Bianconi 	case CH_SWITCH_BACKGROUND_SCAN_START: {
262839cdf080SLorenzo Bianconi 		req.chan = chan->hw_value;
262939cdf080SLorenzo Bianconi 		req.central_chan = ieee80211_frequency_to_channel(freq);
263039cdf080SLorenzo Bianconi 		req.bw = mt76_connac_chan_bw(&mphy->chandef);
263139cdf080SLorenzo Bianconi 		req.monitor_chan = chandef->chan->hw_value;
263239cdf080SLorenzo Bianconi 		req.monitor_central_chan =
263339cdf080SLorenzo Bianconi 			ieee80211_frequency_to_channel(chandef->center_freq1);
263439cdf080SLorenzo Bianconi 		req.monitor_bw = mt76_connac_chan_bw(chandef);
26353eb50cc9SRyder Lee 		req.band_idx = phy->mt76->band_idx;
263639cdf080SLorenzo Bianconi 		req.scan_mode = 1;
263739cdf080SLorenzo Bianconi 		break;
263839cdf080SLorenzo Bianconi 	}
263939cdf080SLorenzo Bianconi 	case CH_SWITCH_BACKGROUND_SCAN_RUNNING:
264039cdf080SLorenzo Bianconi 		req.monitor_chan = chandef->chan->hw_value;
264139cdf080SLorenzo Bianconi 		req.monitor_central_chan =
264239cdf080SLorenzo Bianconi 			ieee80211_frequency_to_channel(chandef->center_freq1);
26433eb50cc9SRyder Lee 		req.band_idx = phy->mt76->band_idx;
264439cdf080SLorenzo Bianconi 		req.scan_mode = 2;
264539cdf080SLorenzo Bianconi 		break;
264639cdf080SLorenzo Bianconi 	case CH_SWITCH_BACKGROUND_SCAN_STOP:
264739cdf080SLorenzo Bianconi 		req.chan = chan->hw_value;
264839cdf080SLorenzo Bianconi 		req.central_chan = ieee80211_frequency_to_channel(freq);
264939cdf080SLorenzo Bianconi 		req.bw = mt76_connac_chan_bw(&mphy->chandef);
265039cdf080SLorenzo Bianconi 		req.tx_stream = hweight8(mphy->antenna_mask);
265139cdf080SLorenzo Bianconi 		req.rx_stream = mphy->antenna_mask;
265239cdf080SLorenzo Bianconi 		break;
265339cdf080SLorenzo Bianconi 	default:
265439cdf080SLorenzo Bianconi 		return -EINVAL;
265539cdf080SLorenzo Bianconi 	}
265639cdf080SLorenzo Bianconi 	req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1;
265739cdf080SLorenzo Bianconi 
265839cdf080SLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL),
265939cdf080SLorenzo Bianconi 				 &req, sizeof(req), false);
266039cdf080SLorenzo Bianconi }
266139cdf080SLorenzo Bianconi 
mt7915_mcu_rdd_background_enable(struct mt7915_phy * phy,struct cfg80211_chan_def * chandef)266239cdf080SLorenzo Bianconi int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
266339cdf080SLorenzo Bianconi 				     struct cfg80211_chan_def *chandef)
266439cdf080SLorenzo Bianconi {
266539cdf080SLorenzo Bianconi 	struct mt7915_dev *dev = phy->dev;
266639cdf080SLorenzo Bianconi 	int err, region;
266739cdf080SLorenzo Bianconi 
266839cdf080SLorenzo Bianconi 	if (!chandef) { /* disable offchain */
266939cdf080SLorenzo Bianconi 		err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2,
267039cdf080SLorenzo Bianconi 					      0, 0);
267139cdf080SLorenzo Bianconi 		if (err)
267239cdf080SLorenzo Bianconi 			return err;
267339cdf080SLorenzo Bianconi 
267439cdf080SLorenzo Bianconi 		return mt7915_mcu_background_chain_ctrl(phy, NULL,
267539cdf080SLorenzo Bianconi 				CH_SWITCH_BACKGROUND_SCAN_STOP);
267639cdf080SLorenzo Bianconi 	}
267739cdf080SLorenzo Bianconi 
267839cdf080SLorenzo Bianconi 	err = mt7915_mcu_background_chain_ctrl(phy, chandef,
267939cdf080SLorenzo Bianconi 					       CH_SWITCH_BACKGROUND_SCAN_START);
268039cdf080SLorenzo Bianconi 	if (err)
268139cdf080SLorenzo Bianconi 		return err;
268239cdf080SLorenzo Bianconi 
268339cdf080SLorenzo Bianconi 	switch (dev->mt76.region) {
268439cdf080SLorenzo Bianconi 	case NL80211_DFS_ETSI:
268539cdf080SLorenzo Bianconi 		region = 0;
268639cdf080SLorenzo Bianconi 		break;
268739cdf080SLorenzo Bianconi 	case NL80211_DFS_JP:
268839cdf080SLorenzo Bianconi 		region = 2;
268939cdf080SLorenzo Bianconi 		break;
269039cdf080SLorenzo Bianconi 	case NL80211_DFS_FCC:
269139cdf080SLorenzo Bianconi 	default:
269239cdf080SLorenzo Bianconi 		region = 1;
269339cdf080SLorenzo Bianconi 		break;
269439cdf080SLorenzo Bianconi 	}
269539cdf080SLorenzo Bianconi 
269639cdf080SLorenzo Bianconi 	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2,
269739cdf080SLorenzo Bianconi 				       0, region);
269839cdf080SLorenzo Bianconi }
269939cdf080SLorenzo Bianconi 
mt7915_mcu_set_chan_info(struct mt7915_phy * phy,int cmd)2700e57b7901SRyder Lee int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
2701e57b7901SRyder Lee {
2702b4d093e3SMeiChia Chiu 	static const u8 ch_band[] = {
2703b4d093e3SMeiChia Chiu 		[NL80211_BAND_2GHZ] = 0,
2704b4d093e3SMeiChia Chiu 		[NL80211_BAND_5GHZ] = 1,
2705b4d093e3SMeiChia Chiu 		[NL80211_BAND_6GHZ] = 2,
2706b4d093e3SMeiChia Chiu 	};
2707e57b7901SRyder Lee 	struct mt7915_dev *dev = phy->dev;
2708e57b7901SRyder Lee 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2709e57b7901SRyder Lee 	int freq1 = chandef->center_freq1;
27103eb50cc9SRyder Lee 	u8 band = phy->mt76->band_idx;
2711e57b7901SRyder Lee 	struct {
2712e57b7901SRyder Lee 		u8 control_ch;
2713e57b7901SRyder Lee 		u8 center_ch;
2714e57b7901SRyder Lee 		u8 bw;
2715ee0863aeSPeter Chiu 		u8 tx_path_num;
2716ee0863aeSPeter Chiu 		u8 rx_path;	/* mask or num */
2717e57b7901SRyder Lee 		u8 switch_reason;
2718e57b7901SRyder Lee 		u8 band_idx;
2719e57b7901SRyder Lee 		u8 center_ch2;	/* for 80+80 only */
2720e57b7901SRyder Lee 		__le16 cac_case;
2721e57b7901SRyder Lee 		u8 channel_band;
2722e57b7901SRyder Lee 		u8 rsv0;
2723e57b7901SRyder Lee 		__le32 outband_freq;
2724e57b7901SRyder Lee 		u8 txpower_drop;
2725e57b7901SRyder Lee 		u8 ap_bw;
2726e57b7901SRyder Lee 		u8 ap_center_ch;
2727e57b7901SRyder Lee 		u8 rsv1[57];
2728e57b7901SRyder Lee 	} __packed req = {
2729e57b7901SRyder Lee 		.control_ch = chandef->chan->hw_value,
2730e57b7901SRyder Lee 		.center_ch = ieee80211_frequency_to_channel(freq1),
273144c73d17SLorenzo Bianconi 		.bw = mt76_connac_chan_bw(chandef),
2732ee0863aeSPeter Chiu 		.tx_path_num = hweight16(phy->mt76->chainmask),
27333eb50cc9SRyder Lee 		.rx_path = phy->mt76->chainmask >> (dev->chainshift * band),
27343eb50cc9SRyder Lee 		.band_idx = band,
2735b4d093e3SMeiChia Chiu 		.channel_band = ch_band[chandef->chan->band],
2736e57b7901SRyder Lee 	};
2737e57b7901SRyder Lee 
2738aadf0953SShayne Chen #ifdef CONFIG_NL80211_TESTMODE
2739c918c74dSShayne Chen 	if (phy->mt76->test.tx_antenna_mask &&
2740b61699d2SShayne Chen 	    mt76_testmode_enabled(phy->mt76)) {
2741ee0863aeSPeter Chiu 		req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask);
2742ee0863aeSPeter Chiu 		req.rx_path = phy->mt76->test.tx_antenna_mask;
2743aadf0953SShayne Chen 	}
2744aadf0953SShayne Chen #endif
2745aadf0953SShayne Chen 
27467a9a957bSShayne Chen 	if (mt76_connac_spe_idx(phy->mt76->antenna_mask))
27477a9a957bSShayne Chen 		req.tx_path_num = fls(phy->mt76->antenna_mask);
27487a9a957bSShayne Chen 
274994ed41a7SShayne Chen 	if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
275000a883e6SFelix Fietkau 		req.switch_reason = CH_SWITCH_NORMAL;
2751e70f6ad7SStanleyYP Wang 	else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
2752e70f6ad7SStanleyYP Wang 		 phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
2753062d62e3SShayne Chen 		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
275400a883e6SFelix Fietkau 	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
275500a883e6SFelix Fietkau 					  NL80211_IFTYPE_AP))
2756e57b7901SRyder Lee 		req.switch_reason = CH_SWITCH_DFS;
2757e57b7901SRyder Lee 	else
2758e57b7901SRyder Lee 		req.switch_reason = CH_SWITCH_NORMAL;
2759e57b7901SRyder Lee 
2760c203dd62SFelix Fietkau 	if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
2761ee0863aeSPeter Chiu 		req.rx_path = hweight8(req.rx_path);
2762e57b7901SRyder Lee 
2763e57b7901SRyder Lee 	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
2764e57b7901SRyder Lee 		int freq2 = chandef->center_freq2;
2765e57b7901SRyder Lee 
2766e57b7901SRyder Lee 		req.center_ch2 = ieee80211_frequency_to_channel(freq2);
2767e57b7901SRyder Lee 	}
2768e57b7901SRyder Lee 
2769cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
2770e57b7901SRyder Lee }
2771e57b7901SRyder Lee 
mt7915_mcu_set_eeprom_flash(struct mt7915_dev * dev)277226f18380SShayne Chen static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
277326f18380SShayne Chen {
277482a980f8SShayne Chen #define MAX_PAGE_IDX_MASK	GENMASK(7, 5)
277526f18380SShayne Chen #define PAGE_IDX_MASK		GENMASK(4, 2)
277626f18380SShayne Chen #define PER_PAGE_SIZE		0x400
277726f18380SShayne Chen 	struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER };
2778beed8beaSBo Jiao 	u16 eeprom_size = mt7915_eeprom_size(dev);
2779beed8beaSBo Jiao 	u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE);
278026f18380SShayne Chen 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
278126f18380SShayne Chen 	int eep_len;
278226f18380SShayne Chen 	int i;
278326f18380SShayne Chen 
278482a980f8SShayne Chen 	for (i = 0; i < total; i++, eep += eep_len) {
278526f18380SShayne Chen 		struct sk_buff *skb;
278626f18380SShayne Chen 		int ret;
278726f18380SShayne Chen 
2788beed8beaSBo Jiao 		if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE))
2789beed8beaSBo Jiao 			eep_len = eeprom_size % PER_PAGE_SIZE;
279026f18380SShayne Chen 		else
279126f18380SShayne Chen 			eep_len = PER_PAGE_SIZE;
279226f18380SShayne Chen 
279326f18380SShayne Chen 		skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
279426f18380SShayne Chen 					 sizeof(req) + eep_len);
279526f18380SShayne Chen 		if (!skb)
279626f18380SShayne Chen 			return -ENOMEM;
279726f18380SShayne Chen 
279882a980f8SShayne Chen 		req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
279926f18380SShayne Chen 			     FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
280026f18380SShayne Chen 		req.len = cpu_to_le16(eep_len);
280126f18380SShayne Chen 
280226f18380SShayne Chen 		skb_put_data(skb, &req, sizeof(req));
280326f18380SShayne Chen 		skb_put_data(skb, eep, eep_len);
280426f18380SShayne Chen 
280526f18380SShayne Chen 		ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
2806c203dd62SFelix Fietkau 					    MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
280726f18380SShayne Chen 		if (ret)
280826f18380SShayne Chen 			return ret;
280926f18380SShayne Chen 	}
281026f18380SShayne Chen 
281126f18380SShayne Chen 	return 0;
281226f18380SShayne Chen }
281326f18380SShayne Chen 
mt7915_mcu_set_eeprom(struct mt7915_dev * dev)2814e57b7901SRyder Lee int mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
2815e57b7901SRyder Lee {
281626f18380SShayne Chen 	struct mt7915_mcu_eeprom req = {
2817e57b7901SRyder Lee 		.buffer_mode = EE_MODE_EFUSE,
2818e57b7901SRyder Lee 		.format = EE_FORMAT_WHOLE,
2819e57b7901SRyder Lee 	};
2820e57b7901SRyder Lee 
282126f18380SShayne Chen 	if (dev->flash_mode)
282226f18380SShayne Chen 		return mt7915_mcu_set_eeprom_flash(dev);
282326f18380SShayne Chen 
2824c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
2825e57b7901SRyder Lee 				 &req, sizeof(req), true);
2826e57b7901SRyder Lee }
2827e57b7901SRyder Lee 
mt7915_mcu_get_eeprom(struct mt7915_dev * dev,u32 offset)2828e57b7901SRyder Lee int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
2829e57b7901SRyder Lee {
2830e57b7901SRyder Lee 	struct mt7915_mcu_eeprom_info req = {
283183d229d2SShayne Chen 		.addr = cpu_to_le32(round_down(offset,
283283d229d2SShayne Chen 				    MT7915_EEPROM_BLOCK_SIZE)),
2833e57b7901SRyder Lee 	};
283499de49fcSFelix Fietkau 	struct mt7915_mcu_eeprom_info *res;
283599de49fcSFelix Fietkau 	struct sk_buff *skb;
283699de49fcSFelix Fietkau 	int ret;
283799de49fcSFelix Fietkau 	u8 *buf;
2838e57b7901SRyder Lee 
283959b27a7dSRyder Lee 	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
284059b27a7dSRyder Lee 					MCU_EXT_QUERY(EFUSE_ACCESS),
284159b27a7dSRyder Lee 					&req, sizeof(req), true, &skb);
284299de49fcSFelix Fietkau 	if (ret)
284399de49fcSFelix Fietkau 		return ret;
284499de49fcSFelix Fietkau 
284599de49fcSFelix Fietkau 	res = (struct mt7915_mcu_eeprom_info *)skb->data;
284699de49fcSFelix Fietkau 	buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
284783d229d2SShayne Chen 	memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
284899de49fcSFelix Fietkau 	dev_kfree_skb(skb);
284999de49fcSFelix Fietkau 
285099de49fcSFelix Fietkau 	return 0;
2851e57b7901SRyder Lee }
2852e57b7901SRyder Lee 
mt7915_mcu_get_eeprom_free_block(struct mt7915_dev * dev,u8 * block_num)2853bbc1d415SShayne Chen int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num)
2854bbc1d415SShayne Chen {
2855bbc1d415SShayne Chen 	struct {
2856bbc1d415SShayne Chen 		u8 _rsv;
2857bbc1d415SShayne Chen 		u8 version;
2858bbc1d415SShayne Chen 		u8 die_idx;
2859bbc1d415SShayne Chen 		u8 _rsv2;
2860bbc1d415SShayne Chen 	} __packed req = {
2861bbc1d415SShayne Chen 		.version = 1,
2862bbc1d415SShayne Chen 	};
2863bbc1d415SShayne Chen 	struct sk_buff *skb;
2864bbc1d415SShayne Chen 	int ret;
2865bbc1d415SShayne Chen 
286659b27a7dSRyder Lee 	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
286759b27a7dSRyder Lee 					MCU_EXT_QUERY(EFUSE_FREE_BLOCK),
286859b27a7dSRyder Lee 					&req, sizeof(req), true, &skb);
2869bbc1d415SShayne Chen 	if (ret)
2870bbc1d415SShayne Chen 		return ret;
2871bbc1d415SShayne Chen 
2872bbc1d415SShayne Chen 	*block_num = *(u8 *)skb->data;
2873bbc1d415SShayne Chen 	dev_kfree_skb(skb);
2874bbc1d415SShayne Chen 
2875bbc1d415SShayne Chen 	return 0;
2876bbc1d415SShayne Chen }
2877bbc1d415SShayne Chen 
mt7915_mcu_set_pre_cal(struct mt7915_dev * dev,u8 idx,u8 * data,u32 len,int cmd)2878495184acSRyder Lee static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
2879495184acSRyder Lee 				  u8 *data, u32 len, int cmd)
2880495184acSRyder Lee {
2881495184acSRyder Lee 	struct {
2882495184acSRyder Lee 		u8 dir;
2883495184acSRyder Lee 		u8 valid;
2884495184acSRyder Lee 		__le16 bitmap;
2885495184acSRyder Lee 		s8 precal;
2886495184acSRyder Lee 		u8 action;
2887495184acSRyder Lee 		u8 band;
2888495184acSRyder Lee 		u8 idx;
2889495184acSRyder Lee 		u8 rsv[4];
2890495184acSRyder Lee 		__le32 len;
28913924715fSDan Carpenter 	} req = {};
2892495184acSRyder Lee 	struct sk_buff *skb;
2893495184acSRyder Lee 
2894495184acSRyder Lee 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
2895495184acSRyder Lee 	if (!skb)
2896495184acSRyder Lee 		return -ENOMEM;
2897495184acSRyder Lee 
2898495184acSRyder Lee 	req.idx = idx;
2899495184acSRyder Lee 	req.len = cpu_to_le32(len);
2900495184acSRyder Lee 	skb_put_data(skb, &req, sizeof(req));
2901495184acSRyder Lee 	skb_put_data(skb, data, len);
2902495184acSRyder Lee 
2903495184acSRyder Lee 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false);
2904495184acSRyder Lee }
2905495184acSRyder Lee 
mt7915_mcu_apply_group_cal(struct mt7915_dev * dev)2906495184acSRyder Lee int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
2907495184acSRyder Lee {
2908495184acSRyder Lee 	u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
2909495184acSRyder Lee 	u32 total = MT_EE_CAL_GROUP_SIZE;
2910495184acSRyder Lee 
2911495184acSRyder Lee 	if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP))
2912495184acSRyder Lee 		return 0;
2913495184acSRyder Lee 
2914495184acSRyder Lee 	/*
2915495184acSRyder Lee 	 * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG
2916495184acSRyder Lee 	 * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC
2917495184acSRyder Lee 	 */
2918495184acSRyder Lee 	while (total > 0) {
2919495184acSRyder Lee 		int ret, len;
2920495184acSRyder Lee 
2921495184acSRyder Lee 		len = min_t(u32, total, MT_EE_CAL_UNIT);
2922495184acSRyder Lee 
2923495184acSRyder Lee 		ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len,
2924495184acSRyder Lee 					     MCU_EXT_CMD(GROUP_PRE_CAL_INFO));
2925495184acSRyder Lee 		if (ret)
2926495184acSRyder Lee 			return ret;
2927495184acSRyder Lee 
2928495184acSRyder Lee 		total -= len;
2929495184acSRyder Lee 		cal += len;
2930495184acSRyder Lee 		idx++;
2931495184acSRyder Lee 	}
2932495184acSRyder Lee 
2933495184acSRyder Lee 	return 0;
2934495184acSRyder Lee }
2935495184acSRyder Lee 
mt7915_find_freq_idx(const u16 * freqs,int n_freqs,u16 cur)2936495184acSRyder Lee static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
2937495184acSRyder Lee {
2938495184acSRyder Lee 	int i;
2939495184acSRyder Lee 
2940495184acSRyder Lee 	for (i = 0; i < n_freqs; i++)
2941495184acSRyder Lee 		if (cur == freqs[i])
2942495184acSRyder Lee 			return i;
2943495184acSRyder Lee 
2944495184acSRyder Lee 	return -1;
2945495184acSRyder Lee }
2946495184acSRyder Lee 
mt7915_dpd_freq_idx(u16 freq,u8 bw)2947495184acSRyder Lee static int mt7915_dpd_freq_idx(u16 freq, u8 bw)
2948495184acSRyder Lee {
2949495184acSRyder Lee 	static const u16 freq_list[] = {
2950495184acSRyder Lee 		5180, 5200, 5220, 5240,
2951495184acSRyder Lee 		5260, 5280, 5300, 5320,
2952495184acSRyder Lee 		5500, 5520, 5540, 5560,
2953495184acSRyder Lee 		5580, 5600, 5620, 5640,
2954495184acSRyder Lee 		5660, 5680, 5700, 5745,
2955495184acSRyder Lee 		5765, 5785, 5805, 5825
2956495184acSRyder Lee 	};
2957495184acSRyder Lee 	int offset_2g = ARRAY_SIZE(freq_list);
2958495184acSRyder Lee 	int idx;
2959495184acSRyder Lee 
2960495184acSRyder Lee 	if (freq < 4000) {
2961495184acSRyder Lee 		if (freq < 2432)
2962495184acSRyder Lee 			return offset_2g;
2963495184acSRyder Lee 		if (freq < 2457)
2964495184acSRyder Lee 			return offset_2g + 1;
2965495184acSRyder Lee 
2966495184acSRyder Lee 		return offset_2g + 2;
2967495184acSRyder Lee 	}
2968495184acSRyder Lee 
2969495184acSRyder Lee 	if (bw == NL80211_CHAN_WIDTH_80P80 || bw == NL80211_CHAN_WIDTH_160)
2970495184acSRyder Lee 		return -1;
2971495184acSRyder Lee 
2972495184acSRyder Lee 	if (bw != NL80211_CHAN_WIDTH_20) {
2973495184acSRyder Lee 		idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2974495184acSRyder Lee 					   freq + 10);
2975495184acSRyder Lee 		if (idx >= 0)
2976495184acSRyder Lee 			return idx;
2977495184acSRyder Lee 
2978495184acSRyder Lee 		idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
2979495184acSRyder Lee 					   freq - 10);
2980495184acSRyder Lee 		if (idx >= 0)
2981495184acSRyder Lee 			return idx;
2982495184acSRyder Lee 	}
2983495184acSRyder Lee 
2984495184acSRyder Lee 	return mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
2985495184acSRyder Lee }
2986495184acSRyder Lee 
mt7915_mcu_apply_tx_dpd(struct mt7915_phy * phy)2987495184acSRyder Lee int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
2988495184acSRyder Lee {
2989495184acSRyder Lee 	struct mt7915_dev *dev = phy->dev;
2990495184acSRyder Lee 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
2991861fad47SDan Carpenter 	u16 total = 2, center_freq = chandef->center_freq1;
2992495184acSRyder Lee 	u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
2993861fad47SDan Carpenter 	int idx;
2994495184acSRyder Lee 
2995495184acSRyder Lee 	if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD))
2996495184acSRyder Lee 		return 0;
2997495184acSRyder Lee 
2998495184acSRyder Lee 	idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
2999495184acSRyder Lee 	if (idx < 0)
3000495184acSRyder Lee 		return -EINVAL;
3001495184acSRyder Lee 
3002495184acSRyder Lee 	/* Items: Tx DPD, Tx Flatness */
3003495184acSRyder Lee 	idx = idx * 2;
3004495184acSRyder Lee 	cal += MT_EE_CAL_GROUP_SIZE;
3005495184acSRyder Lee 
3006495184acSRyder Lee 	while (total--) {
3007495184acSRyder Lee 		int ret;
3008495184acSRyder Lee 
3009495184acSRyder Lee 		cal += (idx * MT_EE_CAL_UNIT);
3010495184acSRyder Lee 		ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT,
3011495184acSRyder Lee 					     MCU_EXT_CMD(DPD_PRE_CAL_INFO));
3012495184acSRyder Lee 		if (ret)
3013495184acSRyder Lee 			return ret;
3014495184acSRyder Lee 
3015495184acSRyder Lee 		idx++;
3016495184acSRyder Lee 	}
3017495184acSRyder Lee 
3018495184acSRyder Lee 	return 0;
3019495184acSRyder Lee }
3020495184acSRyder Lee 
mt7915_mcu_get_chan_mib_info(struct mt7915_phy * phy,bool chan_switch)302165430028SRyder Lee int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch)
302265430028SRyder Lee {
302365430028SRyder Lee 	struct mt76_channel_state *state = phy->mt76->chan_state;
302465430028SRyder Lee 	struct mt76_channel_state *state_ts = &phy->state_ts;
302565430028SRyder Lee 	struct mt7915_dev *dev = phy->dev;
3026b0bfa005SRyder Lee 	struct mt7915_mcu_mib *res, req[5];
302765430028SRyder Lee 	struct sk_buff *skb;
30283fc36de8SRyder Lee 	static const u32 *offs;
30293fc36de8SRyder Lee 	int i, ret, len, offs_cc;
3030b0bfa005SRyder Lee 	u64 cc_tx;
3031417a4534SBo Jiao 
30323fc36de8SRyder Lee 	/* strict order */
30333fc36de8SRyder Lee 	if (is_mt7915(&dev->mt76)) {
30343fc36de8SRyder Lee 		static const u32 chip_offs[] = {
30353fc36de8SRyder Lee 			MIB_NON_WIFI_TIME,
30363fc36de8SRyder Lee 			MIB_TX_TIME,
30373fc36de8SRyder Lee 			MIB_RX_TIME,
30383fc36de8SRyder Lee 			MIB_OBSS_AIRTIME,
30393fc36de8SRyder Lee 			MIB_TXOP_INIT_COUNT,
30403fc36de8SRyder Lee 		};
30413fc36de8SRyder Lee 		len = ARRAY_SIZE(chip_offs);
30423fc36de8SRyder Lee 		offs = chip_offs;
30433fc36de8SRyder Lee 		offs_cc = 20;
30443fc36de8SRyder Lee 	} else {
30453fc36de8SRyder Lee 		static const u32 chip_offs[] = {
30463fc36de8SRyder Lee 			MIB_NON_WIFI_TIME_V2,
30473fc36de8SRyder Lee 			MIB_TX_TIME_V2,
30483fc36de8SRyder Lee 			MIB_RX_TIME_V2,
30493fc36de8SRyder Lee 			MIB_OBSS_AIRTIME_V2
30503fc36de8SRyder Lee 		};
30513fc36de8SRyder Lee 		len = ARRAY_SIZE(chip_offs);
30523fc36de8SRyder Lee 		offs = chip_offs;
30533fc36de8SRyder Lee 		offs_cc = 0;
3054cef37c78SBo Jiao 	}
305565430028SRyder Lee 
30563fc36de8SRyder Lee 	for (i = 0; i < len; i++) {
30573eb50cc9SRyder Lee 		req[i].band = cpu_to_le32(phy->mt76->band_idx);
30583fc36de8SRyder Lee 		req[i].offs = cpu_to_le32(offs[i]);
305965430028SRyder Lee 	}
306065430028SRyder Lee 
306165430028SRyder Lee 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO),
30624f1875c2SRyder Lee 					req, len * sizeof(req[0]), true, &skb);
306365430028SRyder Lee 	if (ret)
306465430028SRyder Lee 		return ret;
306565430028SRyder Lee 
30663fc36de8SRyder Lee 	res = (struct mt7915_mcu_mib *)(skb->data + offs_cc);
306765430028SRyder Lee 
3068b0bfa005SRyder Lee #define __res_u64(s) le64_to_cpu(res[s].data)
3069b0bfa005SRyder Lee 	/* subtract Tx backoff time from Tx duration */
3070b0bfa005SRyder Lee 	cc_tx = is_mt7915(&dev->mt76) ? __res_u64(1) - __res_u64(4) : __res_u64(1);
3071b0bfa005SRyder Lee 
307265430028SRyder Lee 	if (chan_switch)
307365430028SRyder Lee 		goto out;
307465430028SRyder Lee 
3075b0bfa005SRyder Lee 	state->cc_tx += cc_tx - state_ts->cc_tx;
307665430028SRyder Lee 	state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx;
307765430028SRyder Lee 	state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx;
3078b0bfa005SRyder Lee 	state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) -
3079b0bfa005SRyder Lee 			  state_ts->cc_busy;
308065430028SRyder Lee 
308165430028SRyder Lee out:
3082b0bfa005SRyder Lee 	state_ts->cc_tx = cc_tx;
308365430028SRyder Lee 	state_ts->cc_bss_rx = __res_u64(2);
308465430028SRyder Lee 	state_ts->cc_rx = __res_u64(2) + __res_u64(3);
3085b0bfa005SRyder Lee 	state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3);
308665430028SRyder Lee #undef __res_u64
308765430028SRyder Lee 
308865430028SRyder Lee 	dev_kfree_skb(skb);
308965430028SRyder Lee 
309065430028SRyder Lee 	return 0;
309165430028SRyder Lee }
309265430028SRyder Lee 
mt7915_mcu_get_temperature(struct mt7915_phy * phy)309333fe9c63SRyder Lee int mt7915_mcu_get_temperature(struct mt7915_phy *phy)
3094e57b7901SRyder Lee {
309533fe9c63SRyder Lee 	struct mt7915_dev *dev = phy->dev;
3096e57b7901SRyder Lee 	struct {
3097e57b7901SRyder Lee 		u8 ctrl_id;
3098e57b7901SRyder Lee 		u8 action;
30996f917bbaSRyder Lee 		u8 band_idx;
3100e57b7901SRyder Lee 		u8 rsv[5];
3101e57b7901SRyder Lee 	} req = {
3102e57b7901SRyder Lee 		.ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
31033eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
3104e57b7901SRyder Lee 	};
3105e57b7901SRyder Lee 
3106c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
3107e57b7901SRyder Lee 				 sizeof(req), true);
3108e57b7901SRyder Lee }
3109e57b7901SRyder Lee 
mt7915_mcu_set_thermal_throttling(struct mt7915_phy * phy,u8 state)311034b877d9SRyder Lee int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
311134b877d9SRyder Lee {
311234b877d9SRyder Lee 	struct mt7915_dev *dev = phy->dev;
31135ad42d19SHoward Hsu 	struct mt7915_mcu_thermal_ctrl req = {
31145ad42d19SHoward Hsu 		.band_idx = phy->mt76->band_idx,
31155ad42d19SHoward Hsu 		.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG,
31165ad42d19SHoward Hsu 	};
31175ad42d19SHoward Hsu 	int level, ret;
31185ad42d19SHoward Hsu 
31195ad42d19SHoward Hsu 	/* set duty cycle and level */
31205ad42d19SHoward Hsu 	for (level = 0; level < 4; level++) {
31215ad42d19SHoward Hsu 		req.duty.duty_level = level;
31225ad42d19SHoward Hsu 		req.duty.duty_cycle = state;
31235ad42d19SHoward Hsu 		state /= 2;
31245ad42d19SHoward Hsu 
31255ad42d19SHoward Hsu 		ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
31265ad42d19SHoward Hsu 					&req, sizeof(req), false);
31275ad42d19SHoward Hsu 		if (ret)
31285ad42d19SHoward Hsu 			return ret;
31295ad42d19SHoward Hsu 	}
31305ad42d19SHoward Hsu 	return 0;
31315ad42d19SHoward Hsu }
31325ad42d19SHoward Hsu 
mt7915_mcu_set_thermal_protect(struct mt7915_phy * phy)31335ad42d19SHoward Hsu int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy)
31345ad42d19SHoward Hsu {
31355ad42d19SHoward Hsu 	struct mt7915_dev *dev = phy->dev;
313634b877d9SRyder Lee 	struct {
313734b877d9SRyder Lee 		struct mt7915_mcu_thermal_ctrl ctrl;
313834b877d9SRyder Lee 
313934b877d9SRyder Lee 		__le32 trigger_temp;
314034b877d9SRyder Lee 		__le32 restore_temp;
314134b877d9SRyder Lee 		__le16 sustain_time;
314234b877d9SRyder Lee 		u8 rsv[2];
314334b877d9SRyder Lee 	} __packed req = {
314434b877d9SRyder Lee 		.ctrl = {
31453eb50cc9SRyder Lee 			.band_idx = phy->mt76->band_idx,
31465ad42d19SHoward Hsu 			.type.protect_type = 1,
31475ad42d19SHoward Hsu 			.type.trigger_type = 1,
314834b877d9SRyder Lee 		},
314934b877d9SRyder Lee 	};
315034b877d9SRyder Lee 	int ret;
315134b877d9SRyder Lee 
31525ad42d19SHoward Hsu 	req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
315334b877d9SRyder Lee 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
315434b877d9SRyder Lee 				&req, sizeof(req.ctrl), false);
31555ad42d19SHoward Hsu 
315634b877d9SRyder Lee 	if (ret)
315734b877d9SRyder Lee 		return ret;
315834b877d9SRyder Lee 
315934b877d9SRyder Lee 	/* set high-temperature trigger threshold */
316034b877d9SRyder Lee 	req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
316102ee68b9SRyder Lee 	/* add a safety margin ~10 */
316202ee68b9SRyder Lee 	req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
316302ee68b9SRyder Lee 	req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
316402ee68b9SRyder Lee 	req.sustain_time = cpu_to_le16(10);
316534b877d9SRyder Lee 
316634b877d9SRyder Lee 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
316734b877d9SRyder Lee 				 &req, sizeof(req), false);
316834b877d9SRyder Lee }
316934b877d9SRyder Lee 
mt7915_mcu_set_txpower_frame_min(struct mt7915_phy * phy,s8 txpower)317066b181b8SRyder Lee int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower)
317166b181b8SRyder Lee {
317266b181b8SRyder Lee 	struct mt7915_dev *dev = phy->dev;
317366b181b8SRyder Lee 	struct {
317466b181b8SRyder Lee 		u8 format_id;
317566b181b8SRyder Lee 		u8 rsv;
317666b181b8SRyder Lee 		u8 band_idx;
317766b181b8SRyder Lee 		s8 txpower_min;
317866b181b8SRyder Lee 	} __packed req = {
317966b181b8SRyder Lee 		.format_id = TX_POWER_LIMIT_FRAME_MIN,
31803eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
318166b181b8SRyder Lee 		.txpower_min = txpower * 2, /* 0.5db */
318266b181b8SRyder Lee 	};
318366b181b8SRyder Lee 
318466b181b8SRyder Lee 	return mt76_mcu_send_msg(&dev->mt76,
318566b181b8SRyder Lee 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
318666b181b8SRyder Lee 				 sizeof(req), true);
318766b181b8SRyder Lee }
318866b181b8SRyder Lee 
mt7915_mcu_set_txpower_frame(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,s8 txpower)318966b181b8SRyder Lee int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
319066b181b8SRyder Lee 				 struct ieee80211_vif *vif,
319166b181b8SRyder Lee 				 struct ieee80211_sta *sta, s8 txpower)
319266b181b8SRyder Lee {
319366b181b8SRyder Lee 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
319466b181b8SRyder Lee 	struct mt7915_dev *dev = phy->dev;
319566b181b8SRyder Lee 	struct mt76_phy *mphy = phy->mt76;
319666b181b8SRyder Lee 	struct {
319766b181b8SRyder Lee 		u8 format_id;
319866b181b8SRyder Lee 		u8 rsv[3];
319966b181b8SRyder Lee 		u8 band_idx;
320066b181b8SRyder Lee 		s8 txpower_max;
320166b181b8SRyder Lee 		__le16 wcid;
320266b181b8SRyder Lee 		s8 txpower_offs[48];
320366b181b8SRyder Lee 	} __packed req = {
320466b181b8SRyder Lee 		.format_id = TX_POWER_LIMIT_FRAME,
32053eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
320666b181b8SRyder Lee 		.txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2),
320766b181b8SRyder Lee 		.wcid = cpu_to_le16(msta->wcid.idx),
320866b181b8SRyder Lee 	};
320954dd1dc7SRyder Lee 	int ret;
321066b181b8SRyder Lee 	s8 txpower_sku[MT7915_SKU_RATE_NUM];
321166b181b8SRyder Lee 
321266b181b8SRyder Lee 	ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku));
321366b181b8SRyder Lee 	if (ret)
321466b181b8SRyder Lee 		return ret;
321566b181b8SRyder Lee 
321654dd1dc7SRyder Lee 	txpower = mt7915_get_power_bound(phy, txpower);
321766b181b8SRyder Lee 	if (txpower > mphy->txpower_cur || txpower < 0)
321866b181b8SRyder Lee 		return -EINVAL;
321966b181b8SRyder Lee 
322066b181b8SRyder Lee 	if (txpower) {
322166b181b8SRyder Lee 		u32 offs, len, i;
322266b181b8SRyder Lee 
322366b181b8SRyder Lee 		if (sta->deflink.ht_cap.ht_supported) {
322466b181b8SRyder Lee 			const u8 *sku_len = mt7915_sku_group_len;
322566b181b8SRyder Lee 
322666b181b8SRyder Lee 			offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM];
322766b181b8SRyder Lee 			len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40];
322866b181b8SRyder Lee 
322966b181b8SRyder Lee 			if (sta->deflink.vht_cap.vht_supported) {
323066b181b8SRyder Lee 				offs += len;
323166b181b8SRyder Lee 				len = sku_len[SKU_VHT_BW20] * 4;
323266b181b8SRyder Lee 
323366b181b8SRyder Lee 				if (sta->deflink.he_cap.has_he) {
323466b181b8SRyder Lee 					offs += len + sku_len[SKU_HE_RU26] * 3;
323566b181b8SRyder Lee 					len = sku_len[SKU_HE_RU242] * 4;
323666b181b8SRyder Lee 				}
323766b181b8SRyder Lee 			}
323866b181b8SRyder Lee 		} else {
323966b181b8SRyder Lee 			return -EINVAL;
324066b181b8SRyder Lee 		}
324166b181b8SRyder Lee 
324266b181b8SRyder Lee 		for (i = 0; i < len; i++, offs++)
324366b181b8SRyder Lee 			req.txpower_offs[i] =
324466b181b8SRyder Lee 				DIV_ROUND_UP(txpower - txpower_sku[offs], 2);
324566b181b8SRyder Lee 	}
324666b181b8SRyder Lee 
324766b181b8SRyder Lee 	return mt76_mcu_send_msg(&dev->mt76,
324866b181b8SRyder Lee 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
324966b181b8SRyder Lee 				 sizeof(req), true);
325066b181b8SRyder Lee }
325166b181b8SRyder Lee 
mt7915_mcu_set_txpower_sku(struct mt7915_phy * phy)3252ecb187a7SShayne Chen int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
3253f1d96236SRyder Lee {
3254f1d96236SRyder Lee 	struct mt7915_dev *dev = phy->dev;
3255f1d96236SRyder Lee 	struct mt76_phy *mphy = phy->mt76;
3256f1d96236SRyder Lee 	struct ieee80211_hw *hw = mphy->hw;
3257e3296759SRyder Lee 	struct mt7915_mcu_txpower_sku req = {
325866b181b8SRyder Lee 		.format_id = TX_POWER_LIMIT_TABLE,
32593eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
3260f1d96236SRyder Lee 	};
3261790d228aSShayne Chen 	struct mt76_power_limits limits_array;
3262ecb187a7SShayne Chen 	s8 *la = (s8 *)&limits_array;
326354dd1dc7SRyder Lee 	int i, idx;
326454dd1dc7SRyder Lee 	int tx_power;
3265f1d96236SRyder Lee 
326654dd1dc7SRyder Lee 	tx_power = mt7915_get_power_bound(phy, hw->conf.power_level);
3267790d228aSShayne Chen 	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
3268790d228aSShayne Chen 					      &limits_array, tx_power);
3269790d228aSShayne Chen 	mphy->txpower_cur = tx_power;
3270790d228aSShayne Chen 
3271ecb187a7SShayne Chen 	for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
3272ecb187a7SShayne Chen 		u8 mcs_num, len = mt7915_sku_group_len[i];
3273790d228aSShayne Chen 		int j;
3274790d228aSShayne Chen 
3275790d228aSShayne Chen 		if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) {
3276790d228aSShayne Chen 			mcs_num = 10;
3277790d228aSShayne Chen 
3278790d228aSShayne Chen 			if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
3279790d228aSShayne Chen 				la = (s8 *)&limits_array + 12;
3280ecb187a7SShayne Chen 		} else {
3281ecb187a7SShayne Chen 			mcs_num = len;
3282790d228aSShayne Chen 		}
3283790d228aSShayne Chen 
3284ecb187a7SShayne Chen 		for (j = 0; j < min_t(u8, mcs_num, len); j++)
3285e3296759SRyder Lee 			req.txpower_sku[idx + j] = la[j];
3286ecb187a7SShayne Chen 
3287790d228aSShayne Chen 		la += mcs_num;
3288ecb187a7SShayne Chen 		idx += len;
3289790d228aSShayne Chen 	}
3290f1d96236SRyder Lee 
3291cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76,
3292c203dd62SFelix Fietkau 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
3293cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
3294f1d96236SRyder Lee }
3295f1d96236SRyder Lee 
mt7915_mcu_get_txpower_sku(struct mt7915_phy * phy,s8 * txpower,int len)3296ae130bb8SShayne Chen int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
3297ae130bb8SShayne Chen {
3298ae130bb8SShayne Chen #define RATE_POWER_INFO	2
3299ae130bb8SShayne Chen 	struct mt7915_dev *dev = phy->dev;
3300ae130bb8SShayne Chen 	struct {
3301ae130bb8SShayne Chen 		u8 format_id;
3302ae130bb8SShayne Chen 		u8 category;
33036f917bbaSRyder Lee 		u8 band_idx;
3304ae130bb8SShayne Chen 		u8 _rsv;
3305ae130bb8SShayne Chen 	} __packed req = {
330666b181b8SRyder Lee 		.format_id = TX_POWER_LIMIT_INFO,
3307ae130bb8SShayne Chen 		.category = RATE_POWER_INFO,
33083eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
3309ae130bb8SShayne Chen 	};
331066b181b8SRyder Lee 	s8 txpower_sku[MT7915_SKU_RATE_NUM][2];
3311ae130bb8SShayne Chen 	struct sk_buff *skb;
3312ae130bb8SShayne Chen 	int ret, i;
3313ae130bb8SShayne Chen 
3314ae130bb8SShayne Chen 	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
3315ae130bb8SShayne Chen 					MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
3316ae130bb8SShayne Chen 					&req, sizeof(req), true, &skb);
3317ae130bb8SShayne Chen 	if (ret)
3318ae130bb8SShayne Chen 		return ret;
3319ae130bb8SShayne Chen 
332066b181b8SRyder Lee 	memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku));
3321ae130bb8SShayne Chen 	for (i = 0; i < len; i++)
332266b181b8SRyder Lee 		txpower[i] = txpower_sku[i][req.band_idx];
3323ae130bb8SShayne Chen 
3324ae130bb8SShayne Chen 	dev_kfree_skb(skb);
3325ae130bb8SShayne Chen 
3326ae130bb8SShayne Chen 	return 0;
3327ae130bb8SShayne Chen }
3328ae130bb8SShayne Chen 
mt7915_mcu_set_test_param(struct mt7915_dev * dev,u8 param,bool test_mode,u8 en)3329aadf0953SShayne Chen int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
3330aadf0953SShayne Chen 			      u8 en)
3331aadf0953SShayne Chen {
3332aadf0953SShayne Chen 	struct {
3333aadf0953SShayne Chen 		u8 test_mode_en;
3334aadf0953SShayne Chen 		u8 param_idx;
3335aadf0953SShayne Chen 		u8 _rsv[2];
3336aadf0953SShayne Chen 
3337aadf0953SShayne Chen 		u8 enable;
3338aadf0953SShayne Chen 		u8 _rsv2[3];
3339aadf0953SShayne Chen 
3340aadf0953SShayne Chen 		u8 pad[8];
3341aadf0953SShayne Chen 	} __packed req = {
3342aadf0953SShayne Chen 		.test_mode_en = test_mode,
3343aadf0953SShayne Chen 		.param_idx = param,
3344aadf0953SShayne Chen 		.enable = en,
3345aadf0953SShayne Chen 	};
3346aadf0953SShayne Chen 
3347c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req,
3348aadf0953SShayne Chen 				 sizeof(req), false);
3349aadf0953SShayne Chen }
3350aadf0953SShayne Chen 
mt7915_mcu_set_sku_en(struct mt7915_phy * phy,bool enable)3351f1d96236SRyder Lee int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
3352f1d96236SRyder Lee {
3353f1d96236SRyder Lee 	struct mt7915_dev *dev = phy->dev;
3354f1d96236SRyder Lee 	struct mt7915_sku {
3355f1d96236SRyder Lee 		u8 format_id;
3356f1d96236SRyder Lee 		u8 sku_enable;
33576f917bbaSRyder Lee 		u8 band_idx;
3358f1d96236SRyder Lee 		u8 rsv;
3359f1d96236SRyder Lee 	} __packed req = {
336066b181b8SRyder Lee 		.format_id = TX_POWER_LIMIT_ENABLE,
33613eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
3362f1d96236SRyder Lee 		.sku_enable = enable,
3363f1d96236SRyder Lee 	};
3364f1d96236SRyder Lee 
3365cb5cdd4cSFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76,
3366c203dd62SFelix Fietkau 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
3367cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
3368f1d96236SRyder Lee }
3369f1d96236SRyder Lee 
mt7915_mcu_set_ser(struct mt7915_dev * dev,u8 action,u8 set,u8 band)3370e57b7901SRyder Lee int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
3371e57b7901SRyder Lee {
3372e57b7901SRyder Lee 	struct {
3373e57b7901SRyder Lee 		u8 action;
3374e57b7901SRyder Lee 		u8 set;
3375e57b7901SRyder Lee 		u8 band;
3376e57b7901SRyder Lee 		u8 rsv;
3377e57b7901SRyder Lee 	} req = {
3378e57b7901SRyder Lee 		.action = action,
3379e57b7901SRyder Lee 		.set = set,
3380e57b7901SRyder Lee 		.band = band,
3381e57b7901SRyder Lee 	};
3382e57b7901SRyder Lee 
3383c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER),
3384e57b7901SRyder Lee 				 &req, sizeof(req), false);
3385e57b7901SRyder Lee }
338689029a85SRyder Lee 
mt7915_mcu_set_txbf(struct mt7915_dev * dev,u8 action)3387fd843822SRyder Lee int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
338807c0d001SRyder Lee {
338907c0d001SRyder Lee 	struct {
339007c0d001SRyder Lee 		u8 action;
3391fd843822SRyder Lee 		union {
339289029a85SRyder Lee 			struct {
339389029a85SRyder Lee 				u8 snd_mode;
339489029a85SRyder Lee 				u8 sta_num;
339589029a85SRyder Lee 				u8 rsv;
339689029a85SRyder Lee 				u8 wlan_idx[4];
339789029a85SRyder Lee 				__le32 snd_period;	/* ms */
3398fd843822SRyder Lee 			} __packed snd;
3399fd843822SRyder Lee 			struct {
3400fd843822SRyder Lee 				bool ebf;
3401fd843822SRyder Lee 				bool ibf;
3402fd843822SRyder Lee 				u8 rsv;
3403fd843822SRyder Lee 			} __packed type;
3404fd843822SRyder Lee 			struct {
3405fd843822SRyder Lee 				u8 bf_num;
3406fd843822SRyder Lee 				u8 bf_bitmap;
3407fd843822SRyder Lee 				u8 bf_sel[8];
3408fd843822SRyder Lee 				u8 rsv[5];
3409fd843822SRyder Lee 			} __packed mod;
341089029a85SRyder Lee 		};
3411fd843822SRyder Lee 	} __packed req = {
3412fd843822SRyder Lee 		.action = action,
3413fd843822SRyder Lee 	};
3414fd843822SRyder Lee 
3415fd843822SRyder Lee #define MT_BF_PROCESSING	4
3416fd843822SRyder Lee 	switch (action) {
3417fd843822SRyder Lee 	case MT_BF_SOUNDING_ON:
3418fd843822SRyder Lee 		req.snd.snd_mode = MT_BF_PROCESSING;
3419fd843822SRyder Lee 		break;
3420fd843822SRyder Lee 	case MT_BF_TYPE_UPDATE:
3421fd843822SRyder Lee 		req.type.ebf = true;
3422fd843822SRyder Lee 		req.type.ibf = dev->ibf;
3423fd843822SRyder Lee 		break;
3424fd843822SRyder Lee 	case MT_BF_MODULE_UPDATE:
3425fd843822SRyder Lee 		req.mod.bf_num = 2;
3426fd843822SRyder Lee 		req.mod.bf_bitmap = GENMASK(1, 0);
3427fd843822SRyder Lee 		break;
3428fd843822SRyder Lee 	default:
3429fd843822SRyder Lee 		return -EINVAL;
3430fd843822SRyder Lee 	}
343189029a85SRyder Lee 
3432c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
3433cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
343489029a85SRyder Lee }
343506acdd38SRyder Lee 
34363dc00ecfSRyder Lee static int
mt7915_mcu_enable_obss_spr(struct mt7915_phy * phy,u8 action,u8 val)34373dc00ecfSRyder Lee mt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val)
343806acdd38SRyder Lee {
34393dc00ecfSRyder Lee 	struct mt7915_dev *dev = phy->dev;
34403dc00ecfSRyder Lee 	struct mt7915_mcu_sr_ctrl req = {
34413dc00ecfSRyder Lee 		.action = action,
34423dc00ecfSRyder Lee 		.argnum = 1,
34433eb50cc9SRyder Lee 		.band_idx = phy->mt76->band_idx,
34443dc00ecfSRyder Lee 		.val = cpu_to_le32(val),
344506acdd38SRyder Lee 	};
344606acdd38SRyder Lee 
3447c203dd62SFelix Fietkau 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
3448cb5cdd4cSFelix Fietkau 				 sizeof(req), true);
344906acdd38SRyder Lee }
345011553d88SFelix Fietkau 
34513dc00ecfSRyder Lee static int
mt7915_mcu_set_obss_spr_pd(struct mt7915_phy * phy,struct ieee80211_he_obss_pd * he_obss_pd)34523dc00ecfSRyder Lee mt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy,
34533dc00ecfSRyder Lee 			   struct ieee80211_he_obss_pd *he_obss_pd)
34543dc00ecfSRyder Lee {
34553dc00ecfSRyder Lee 	struct mt7915_dev *dev = phy->dev;
34563dc00ecfSRyder Lee 	struct {
34573dc00ecfSRyder Lee 		struct mt7915_mcu_sr_ctrl ctrl;
34583dc00ecfSRyder Lee 		struct {
34593dc00ecfSRyder Lee 			u8 pd_th_non_srg;
34603dc00ecfSRyder Lee 			u8 pd_th_srg;
34613dc00ecfSRyder Lee 			u8 period_offs;
34623dc00ecfSRyder Lee 			u8 rcpi_src;
34633dc00ecfSRyder Lee 			__le16 obss_pd_min;
34643dc00ecfSRyder Lee 			__le16 obss_pd_min_srg;
34653dc00ecfSRyder Lee 			u8 resp_txpwr_mode;
34663dc00ecfSRyder Lee 			u8 txpwr_restrict_mode;
34673dc00ecfSRyder Lee 			u8 txpwr_ref;
34683dc00ecfSRyder Lee 			u8 rsv[3];
34693dc00ecfSRyder Lee 		} __packed param;
34703dc00ecfSRyder Lee 	} __packed req = {
34713dc00ecfSRyder Lee 		.ctrl = {
34723dc00ecfSRyder Lee 			.action = SPR_SET_PARAM,
34733dc00ecfSRyder Lee 			.argnum = 9,
34743eb50cc9SRyder Lee 			.band_idx = phy->mt76->band_idx,
34753dc00ecfSRyder Lee 		},
34763dc00ecfSRyder Lee 	};
34773dc00ecfSRyder Lee 	int ret;
34783dc00ecfSRyder Lee 	u8 max_th = 82, non_srg_max_th = 62;
34793dc00ecfSRyder Lee 
34803dc00ecfSRyder Lee 	/* disable firmware dynamical PD asjustment */
34813dc00ecfSRyder Lee 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false);
34823dc00ecfSRyder Lee 	if (ret)
34833dc00ecfSRyder Lee 		return ret;
34843dc00ecfSRyder Lee 
34853dc00ecfSRyder Lee 	if (he_obss_pd->sr_ctrl &
34863dc00ecfSRyder Lee 	    IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)
34873dc00ecfSRyder Lee 		req.param.pd_th_non_srg = max_th;
34883dc00ecfSRyder Lee 	else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
34893dc00ecfSRyder Lee 		req.param.pd_th_non_srg  = max_th - he_obss_pd->non_srg_max_offset;
34903dc00ecfSRyder Lee 	else
34913dc00ecfSRyder Lee 		req.param.pd_th_non_srg  = non_srg_max_th;
34923dc00ecfSRyder Lee 
34933dc00ecfSRyder Lee 	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
34943dc00ecfSRyder Lee 		req.param.pd_th_srg = max_th - he_obss_pd->max_offset;
34953dc00ecfSRyder Lee 
34963dc00ecfSRyder Lee 	req.param.obss_pd_min = cpu_to_le16(82);
34973dc00ecfSRyder Lee 	req.param.obss_pd_min_srg = cpu_to_le16(82);
34983dc00ecfSRyder Lee 	req.param.txpwr_restrict_mode = 2;
34993dc00ecfSRyder Lee 	req.param.txpwr_ref = 21;
35003dc00ecfSRyder Lee 
35013dc00ecfSRyder Lee 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35023dc00ecfSRyder Lee 				 sizeof(req), true);
35033dc00ecfSRyder Lee }
35043dc00ecfSRyder Lee 
35053dc00ecfSRyder Lee static int
mt7915_mcu_set_obss_spr_siga(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_he_obss_pd * he_obss_pd)35063dc00ecfSRyder Lee mt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif,
35073dc00ecfSRyder Lee 			     struct ieee80211_he_obss_pd *he_obss_pd)
35083dc00ecfSRyder Lee {
35093dc00ecfSRyder Lee 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
35103dc00ecfSRyder Lee 	struct mt7915_dev *dev = phy->dev;
35113dc00ecfSRyder Lee 	u8 omac = mvif->mt76.omac_idx;
35123dc00ecfSRyder Lee 	struct {
35133dc00ecfSRyder Lee 		struct mt7915_mcu_sr_ctrl ctrl;
35143dc00ecfSRyder Lee 		struct {
35153dc00ecfSRyder Lee 			u8 omac;
35163dc00ecfSRyder Lee 			u8 rsv[3];
35173dc00ecfSRyder Lee 			u8 flag[20];
35183dc00ecfSRyder Lee 		} __packed siga;
35193dc00ecfSRyder Lee 	} __packed req = {
35203dc00ecfSRyder Lee 		.ctrl = {
35213dc00ecfSRyder Lee 			.action = SPR_SET_SIGA,
35223dc00ecfSRyder Lee 			.argnum = 1,
35233eb50cc9SRyder Lee 			.band_idx = phy->mt76->band_idx,
35243dc00ecfSRyder Lee 		},
35253dc00ecfSRyder Lee 		.siga = {
35263dc00ecfSRyder Lee 			.omac = omac > HW_BSSID_MAX ? omac - 12 : omac,
35273dc00ecfSRyder Lee 		},
35283dc00ecfSRyder Lee 	};
35293dc00ecfSRyder Lee 	int ret;
35303dc00ecfSRyder Lee 
35313dc00ecfSRyder Lee 	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED)
35323dc00ecfSRyder Lee 		req.siga.flag[req.siga.omac] = 0xf;
35333dc00ecfSRyder Lee 	else
35343dc00ecfSRyder Lee 		return 0;
35353dc00ecfSRyder Lee 
35363dc00ecfSRyder Lee 	/* switch to normal AP mode */
35373dc00ecfSRyder Lee 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0);
35383dc00ecfSRyder Lee 	if (ret)
35393dc00ecfSRyder Lee 		return ret;
35403dc00ecfSRyder Lee 
35413dc00ecfSRyder Lee 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35423dc00ecfSRyder Lee 				 sizeof(req), true);
35433dc00ecfSRyder Lee }
35443dc00ecfSRyder Lee 
35453dc00ecfSRyder Lee static int
mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy * phy,struct ieee80211_he_obss_pd * he_obss_pd)35463dc00ecfSRyder Lee mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy,
35473dc00ecfSRyder Lee 			       struct ieee80211_he_obss_pd *he_obss_pd)
35483dc00ecfSRyder Lee {
35493dc00ecfSRyder Lee 	struct mt7915_dev *dev = phy->dev;
35503dc00ecfSRyder Lee 	struct {
35513dc00ecfSRyder Lee 		struct mt7915_mcu_sr_ctrl ctrl;
35523dc00ecfSRyder Lee 		struct {
35533dc00ecfSRyder Lee 			__le32 color_l[2];
35543dc00ecfSRyder Lee 			__le32 color_h[2];
35553dc00ecfSRyder Lee 			__le32 bssid_l[2];
35563dc00ecfSRyder Lee 			__le32 bssid_h[2];
35573dc00ecfSRyder Lee 		} __packed bitmap;
35583dc00ecfSRyder Lee 	} __packed req = {
35593dc00ecfSRyder Lee 		.ctrl = {
35603dc00ecfSRyder Lee 			.action = SPR_SET_SRG_BITMAP,
35613dc00ecfSRyder Lee 			.argnum = 4,
35623eb50cc9SRyder Lee 			.band_idx = phy->mt76->band_idx,
35633dc00ecfSRyder Lee 		},
35643dc00ecfSRyder Lee 	};
35653dc00ecfSRyder Lee 	u32 bitmap;
35663dc00ecfSRyder Lee 
35673dc00ecfSRyder Lee 	memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap));
35683dc00ecfSRyder Lee 	req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35693dc00ecfSRyder Lee 
35703dc00ecfSRyder Lee 	memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap));
35713dc00ecfSRyder Lee 	req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35723dc00ecfSRyder Lee 
35733dc00ecfSRyder Lee 	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap));
35743dc00ecfSRyder Lee 	req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35753dc00ecfSRyder Lee 
35763dc00ecfSRyder Lee 	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap));
35773dc00ecfSRyder Lee 	req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
35783dc00ecfSRyder Lee 
35793dc00ecfSRyder Lee 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35803dc00ecfSRyder Lee 				 sizeof(req), true);
35813dc00ecfSRyder Lee }
35823dc00ecfSRyder Lee 
mt7915_mcu_add_obss_spr(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_he_obss_pd * he_obss_pd)35833dc00ecfSRyder Lee int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
35843dc00ecfSRyder Lee 			    struct ieee80211_he_obss_pd *he_obss_pd)
35853dc00ecfSRyder Lee {
35863dc00ecfSRyder Lee 	int ret;
35873dc00ecfSRyder Lee 
35883dc00ecfSRyder Lee 	/* enable firmware scene detection algorithms */
35893dc00ecfSRyder Lee 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect);
35903dc00ecfSRyder Lee 	if (ret)
35913dc00ecfSRyder Lee 		return ret;
35923dc00ecfSRyder Lee 
35933dc00ecfSRyder Lee 	/* firmware dynamically adjusts PD threshold so skip manual control */
35943dc00ecfSRyder Lee 	if (sr_scene_detect && !he_obss_pd->enable)
35953dc00ecfSRyder Lee 		return 0;
35963dc00ecfSRyder Lee 
35973dc00ecfSRyder Lee 	/* enable spatial reuse */
35983dc00ecfSRyder Lee 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable);
35993dc00ecfSRyder Lee 	if (ret)
36003dc00ecfSRyder Lee 		return ret;
36013dc00ecfSRyder Lee 
36023dc00ecfSRyder Lee 	if (sr_scene_detect || !he_obss_pd->enable)
36033dc00ecfSRyder Lee 		return 0;
36043dc00ecfSRyder Lee 
36053dc00ecfSRyder Lee 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true);
36063dc00ecfSRyder Lee 	if (ret)
36073dc00ecfSRyder Lee 		return ret;
36083dc00ecfSRyder Lee 
36093dc00ecfSRyder Lee 	/* set SRG/non-SRG OBSS PD threshold */
36103dc00ecfSRyder Lee 	ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd);
36113dc00ecfSRyder Lee 	if (ret)
36123dc00ecfSRyder Lee 		return ret;
36133dc00ecfSRyder Lee 
36143dc00ecfSRyder Lee 	/* Set SR prohibit */
36153dc00ecfSRyder Lee 	ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd);
36163dc00ecfSRyder Lee 	if (ret)
36173dc00ecfSRyder Lee 		return ret;
36183dc00ecfSRyder Lee 
36193dc00ecfSRyder Lee 	/* set SRG BSS color/BSSID bitmap */
36203dc00ecfSRyder Lee 	return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd);
36213dc00ecfSRyder Lee }
36223dc00ecfSRyder Lee 
mt7915_mcu_get_rx_rate(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct rate_info * rate)362311553d88SFelix Fietkau int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
362411553d88SFelix Fietkau 			   struct ieee80211_sta *sta, struct rate_info *rate)
362511553d88SFelix Fietkau {
362611553d88SFelix Fietkau 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
362711553d88SFelix Fietkau 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
362811553d88SFelix Fietkau 	struct mt7915_dev *dev = phy->dev;
362911553d88SFelix Fietkau 	struct mt76_phy *mphy = phy->mt76;
363011553d88SFelix Fietkau 	struct {
363111553d88SFelix Fietkau 		u8 category;
363211553d88SFelix Fietkau 		u8 band;
363311553d88SFelix Fietkau 		__le16 wcid;
363411553d88SFelix Fietkau 	} __packed req = {
363511553d88SFelix Fietkau 		.category = MCU_PHY_STATE_CONTENTION_RX_RATE,
36366cf4392fSLorenzo Bianconi 		.band = mvif->mt76.band_idx,
363711553d88SFelix Fietkau 		.wcid = cpu_to_le16(msta->wcid.idx),
363811553d88SFelix Fietkau 	};
363911553d88SFelix Fietkau 	struct ieee80211_supported_band *sband;
364011553d88SFelix Fietkau 	struct mt7915_mcu_phy_rx_info *res;
364111553d88SFelix Fietkau 	struct sk_buff *skb;
364211553d88SFelix Fietkau 	int ret;
36437883906dSRyder Lee 	bool cck = false;
364411553d88SFelix Fietkau 
3645c203dd62SFelix Fietkau 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO),
364611553d88SFelix Fietkau 					&req, sizeof(req), true, &skb);
364711553d88SFelix Fietkau 	if (ret)
364811553d88SFelix Fietkau 		return ret;
364911553d88SFelix Fietkau 
365011553d88SFelix Fietkau 	res = (struct mt7915_mcu_phy_rx_info *)skb->data;
365111553d88SFelix Fietkau 
365211553d88SFelix Fietkau 	rate->mcs = res->rate;
365311553d88SFelix Fietkau 	rate->nss = res->nsts + 1;
365411553d88SFelix Fietkau 
365511553d88SFelix Fietkau 	switch (res->mode) {
365611553d88SFelix Fietkau 	case MT_PHY_TYPE_CCK:
36577883906dSRyder Lee 		cck = true;
36587883906dSRyder Lee 		fallthrough;
365911553d88SFelix Fietkau 	case MT_PHY_TYPE_OFDM:
366011553d88SFelix Fietkau 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
366111553d88SFelix Fietkau 			sband = &mphy->sband_5g.sband;
3662b4d093e3SMeiChia Chiu 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
3663b4d093e3SMeiChia Chiu 			sband = &mphy->sband_6g.sband;
366411553d88SFelix Fietkau 		else
366511553d88SFelix Fietkau 			sband = &mphy->sband_2g.sband;
366611553d88SFelix Fietkau 
36677883906dSRyder Lee 		rate->mcs = mt76_get_rate(&dev->mt76, sband, rate->mcs, cck);
36687883906dSRyder Lee 		rate->legacy = sband->bitrates[rate->mcs].bitrate;
366911553d88SFelix Fietkau 		break;
367011553d88SFelix Fietkau 	case MT_PHY_TYPE_HT:
367111553d88SFelix Fietkau 	case MT_PHY_TYPE_HT_GF:
36727883906dSRyder Lee 		if (rate->mcs > 31) {
36737883906dSRyder Lee 			ret = -EINVAL;
36747883906dSRyder Lee 			goto out;
36757883906dSRyder Lee 		}
3676bacf5047SShayne Chen 
36777883906dSRyder Lee 		rate->flags = RATE_INFO_FLAGS_MCS;
367811553d88SFelix Fietkau 		if (res->gi)
36797883906dSRyder Lee 			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
368011553d88SFelix Fietkau 		break;
368111553d88SFelix Fietkau 	case MT_PHY_TYPE_VHT:
36827883906dSRyder Lee 		if (rate->mcs > 9) {
36837883906dSRyder Lee 			ret = -EINVAL;
36847883906dSRyder Lee 			goto out;
36857883906dSRyder Lee 		}
368611553d88SFelix Fietkau 
36877883906dSRyder Lee 		rate->flags = RATE_INFO_FLAGS_VHT_MCS;
368811553d88SFelix Fietkau 		if (res->gi)
36897883906dSRyder Lee 			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
369011553d88SFelix Fietkau 		break;
369111553d88SFelix Fietkau 	case MT_PHY_TYPE_HE_SU:
369211553d88SFelix Fietkau 	case MT_PHY_TYPE_HE_EXT_SU:
369311553d88SFelix Fietkau 	case MT_PHY_TYPE_HE_TB:
369411553d88SFelix Fietkau 	case MT_PHY_TYPE_HE_MU:
36957883906dSRyder Lee 		if (res->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) {
36967883906dSRyder Lee 			ret = -EINVAL;
36977883906dSRyder Lee 			goto out;
36987883906dSRyder Lee 		}
369911553d88SFelix Fietkau 		rate->he_gi = res->gi;
37007883906dSRyder Lee 		rate->flags = RATE_INFO_FLAGS_HE_MCS;
370111553d88SFelix Fietkau 		break;
370211553d88SFelix Fietkau 	default:
37037883906dSRyder Lee 		ret = -EINVAL;
37047883906dSRyder Lee 		goto out;
370511553d88SFelix Fietkau 	}
370611553d88SFelix Fietkau 
370711553d88SFelix Fietkau 	switch (res->bw) {
370811553d88SFelix Fietkau 	case IEEE80211_STA_RX_BW_160:
370911553d88SFelix Fietkau 		rate->bw = RATE_INFO_BW_160;
371011553d88SFelix Fietkau 		break;
371111553d88SFelix Fietkau 	case IEEE80211_STA_RX_BW_80:
371211553d88SFelix Fietkau 		rate->bw = RATE_INFO_BW_80;
371311553d88SFelix Fietkau 		break;
371411553d88SFelix Fietkau 	case IEEE80211_STA_RX_BW_40:
371511553d88SFelix Fietkau 		rate->bw = RATE_INFO_BW_40;
371611553d88SFelix Fietkau 		break;
371711553d88SFelix Fietkau 	default:
371811553d88SFelix Fietkau 		rate->bw = RATE_INFO_BW_20;
371911553d88SFelix Fietkau 		break;
372011553d88SFelix Fietkau 	}
372111553d88SFelix Fietkau 
37227883906dSRyder Lee out:
3723d211c003SShayne Chen 	dev_kfree_skb(skb);
3724d211c003SShayne Chen 
37257883906dSRyder Lee 	return ret;
372611553d88SFelix Fietkau }
3727b4b9f0a3SLorenzo Bianconi 
mt7915_mcu_update_bss_color(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct cfg80211_he_bss_color * he_bss_color)3728b4b9f0a3SLorenzo Bianconi int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
3729b4b9f0a3SLorenzo Bianconi 				struct cfg80211_he_bss_color *he_bss_color)
3730b4b9f0a3SLorenzo Bianconi {
3731b4b9f0a3SLorenzo Bianconi 	int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color);
3732b4b9f0a3SLorenzo Bianconi 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
3733b4b9f0a3SLorenzo Bianconi 	struct bss_info_color *bss_color;
3734b4b9f0a3SLorenzo Bianconi 	struct sk_buff *skb;
3735b4b9f0a3SLorenzo Bianconi 	struct tlv *tlv;
3736b4b9f0a3SLorenzo Bianconi 
3737e2c93b68SLorenzo Bianconi 	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
3738e2c93b68SLorenzo Bianconi 					      NULL, len);
3739b4b9f0a3SLorenzo Bianconi 	if (IS_ERR(skb))
3740b4b9f0a3SLorenzo Bianconi 		return PTR_ERR(skb);
3741b4b9f0a3SLorenzo Bianconi 
3742069c8e34SLorenzo Bianconi 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR,
3743069c8e34SLorenzo Bianconi 				      sizeof(*bss_color));
3744b4b9f0a3SLorenzo Bianconi 	bss_color = (struct bss_info_color *)tlv;
3745b4b9f0a3SLorenzo Bianconi 	bss_color->disable = !he_bss_color->enabled;
3746b4b9f0a3SLorenzo Bianconi 	bss_color->color = he_bss_color->color;
3747b4b9f0a3SLorenzo Bianconi 
3748b4b9f0a3SLorenzo Bianconi 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
3749b4b9f0a3SLorenzo Bianconi 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
3750b4b9f0a3SLorenzo Bianconi }
3751179090a5SLorenzo Bianconi 
3752179090a5SLorenzo Bianconi #define TWT_AGRT_TRIGGER	BIT(0)
3753179090a5SLorenzo Bianconi #define TWT_AGRT_ANNOUNCE	BIT(1)
3754179090a5SLorenzo Bianconi #define TWT_AGRT_PROTECT	BIT(2)
3755179090a5SLorenzo Bianconi 
mt7915_mcu_twt_agrt_update(struct mt7915_dev * dev,struct mt7915_vif * mvif,struct mt7915_twt_flow * flow,int cmd)3756179090a5SLorenzo Bianconi int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
3757179090a5SLorenzo Bianconi 			       struct mt7915_vif *mvif,
3758179090a5SLorenzo Bianconi 			       struct mt7915_twt_flow *flow,
3759179090a5SLorenzo Bianconi 			       int cmd)
3760179090a5SLorenzo Bianconi {
3761179090a5SLorenzo Bianconi 	struct {
3762179090a5SLorenzo Bianconi 		u8 tbl_idx;
3763179090a5SLorenzo Bianconi 		u8 cmd;
3764179090a5SLorenzo Bianconi 		u8 own_mac_idx;
3765179090a5SLorenzo Bianconi 		u8 flowid; /* 0xff for group id */
3766179090a5SLorenzo Bianconi 		__le16 peer_id; /* specify the peer_id (msb=0)
3767179090a5SLorenzo Bianconi 				 * or group_id (msb=1)
3768179090a5SLorenzo Bianconi 				 */
3769179090a5SLorenzo Bianconi 		u8 duration; /* 256 us */
3770179090a5SLorenzo Bianconi 		u8 bss_idx;
3771179090a5SLorenzo Bianconi 		__le64 start_tsf;
3772179090a5SLorenzo Bianconi 		__le16 mantissa;
3773179090a5SLorenzo Bianconi 		u8 exponent;
3774179090a5SLorenzo Bianconi 		u8 is_ap;
3775179090a5SLorenzo Bianconi 		u8 agrt_params;
3776179090a5SLorenzo Bianconi 		u8 rsv[23];
3777179090a5SLorenzo Bianconi 	} __packed req = {
3778179090a5SLorenzo Bianconi 		.tbl_idx = flow->table_id,
3779179090a5SLorenzo Bianconi 		.cmd = cmd,
37806cf4392fSLorenzo Bianconi 		.own_mac_idx = mvif->mt76.omac_idx,
3781179090a5SLorenzo Bianconi 		.flowid = flow->id,
3782179090a5SLorenzo Bianconi 		.peer_id = cpu_to_le16(flow->wcid),
3783179090a5SLorenzo Bianconi 		.duration = flow->duration,
37846cf4392fSLorenzo Bianconi 		.bss_idx = mvif->mt76.idx,
3785179090a5SLorenzo Bianconi 		.start_tsf = cpu_to_le64(flow->tsf),
3786179090a5SLorenzo Bianconi 		.mantissa = flow->mantissa,
3787179090a5SLorenzo Bianconi 		.exponent = flow->exp,
3788179090a5SLorenzo Bianconi 		.is_ap = true,
3789179090a5SLorenzo Bianconi 	};
3790179090a5SLorenzo Bianconi 
3791179090a5SLorenzo Bianconi 	if (flow->protection)
3792179090a5SLorenzo Bianconi 		req.agrt_params |= TWT_AGRT_PROTECT;
3793179090a5SLorenzo Bianconi 	if (!flow->flowtype)
3794179090a5SLorenzo Bianconi 		req.agrt_params |= TWT_AGRT_ANNOUNCE;
3795179090a5SLorenzo Bianconi 	if (flow->trigger)
3796179090a5SLorenzo Bianconi 		req.agrt_params |= TWT_AGRT_TRIGGER;
3797179090a5SLorenzo Bianconi 
3798179090a5SLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE),
3799179090a5SLorenzo Bianconi 				 &req, sizeof(req), true);
3800179090a5SLorenzo Bianconi }
38010a17329aSShayne Chen 
mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev * dev,u16 wlan_idx)3802161a7528SPeter Chiu int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
3803161a7528SPeter Chiu {
3804161a7528SPeter Chiu 	struct {
3805161a7528SPeter Chiu 		__le32 cmd;
3806161a7528SPeter Chiu 		__le32 num;
3807161a7528SPeter Chiu 		__le32 __rsv;
3808161a7528SPeter Chiu 		__le16 wlan_idx;
3809161a7528SPeter Chiu 	} req = {
3810161a7528SPeter Chiu 		.cmd = cpu_to_le32(0x15),
3811161a7528SPeter Chiu 		.num = cpu_to_le32(1),
3812161a7528SPeter Chiu 		.wlan_idx = cpu_to_le16(wlan_idx),
3813161a7528SPeter Chiu 	};
3814161a7528SPeter Chiu 	struct mt7915_mcu_wa_tx_stat {
3815161a7528SPeter Chiu 		__le16 wlan_idx;
3816161a7528SPeter Chiu 		u8 __rsv[2];
3817161a7528SPeter Chiu 
3818161a7528SPeter Chiu 		/* tx_bytes is deprecated since WA byte counter uses u32,
3819161a7528SPeter Chiu 		 * which easily leads to overflow.
3820161a7528SPeter Chiu 		 */
3821161a7528SPeter Chiu 		__le32 tx_bytes;
3822161a7528SPeter Chiu 		__le32 tx_packets;
3823161a7528SPeter Chiu 	} *res;
3824161a7528SPeter Chiu 	struct mt76_wcid *wcid;
3825161a7528SPeter Chiu 	struct sk_buff *skb;
3826161a7528SPeter Chiu 	int ret;
3827161a7528SPeter Chiu 
3828161a7528SPeter Chiu 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY),
3829161a7528SPeter Chiu 					&req, sizeof(req), true, &skb);
3830161a7528SPeter Chiu 	if (ret)
3831161a7528SPeter Chiu 		return ret;
3832161a7528SPeter Chiu 
3833161a7528SPeter Chiu 	if (!is_mt7915(&dev->mt76))
3834161a7528SPeter Chiu 		skb_pull(skb, 4);
3835161a7528SPeter Chiu 
3836161a7528SPeter Chiu 	res = (struct mt7915_mcu_wa_tx_stat *)skb->data;
3837161a7528SPeter Chiu 
3838161a7528SPeter Chiu 	if (le16_to_cpu(res->wlan_idx) != wlan_idx) {
3839161a7528SPeter Chiu 		ret = -EINVAL;
3840161a7528SPeter Chiu 		goto out;
3841161a7528SPeter Chiu 	}
3842161a7528SPeter Chiu 
3843161a7528SPeter Chiu 	rcu_read_lock();
3844161a7528SPeter Chiu 
3845161a7528SPeter Chiu 	wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
3846161a7528SPeter Chiu 	if (wcid)
3847161a7528SPeter Chiu 		wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
3848161a7528SPeter Chiu 	else
3849161a7528SPeter Chiu 		ret = -EINVAL;
3850161a7528SPeter Chiu 
3851161a7528SPeter Chiu 	rcu_read_unlock();
3852161a7528SPeter Chiu out:
3853161a7528SPeter Chiu 	dev_kfree_skb(skb);
3854161a7528SPeter Chiu 
3855161a7528SPeter Chiu 	return ret;
3856161a7528SPeter Chiu }
3857161a7528SPeter Chiu 
mt7915_mcu_rf_regval(struct mt7915_dev * dev,u32 regidx,u32 * val,bool set)38580a17329aSShayne Chen int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
38590a17329aSShayne Chen {
38600a17329aSShayne Chen 	struct {
38610a17329aSShayne Chen 		__le32 idx;
38620a17329aSShayne Chen 		__le32 ofs;
38630a17329aSShayne Chen 		__le32 data;
38640a17329aSShayne Chen 	} __packed req = {
38657624ffcdSEvelyn Tsai 		.idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))),
38667624ffcdSEvelyn Tsai 		.ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))),
38670a17329aSShayne Chen 		.data = set ? cpu_to_le32(*val) : 0,
38680a17329aSShayne Chen 	};
38690a17329aSShayne Chen 	struct sk_buff *skb;
38700a17329aSShayne Chen 	int ret;
38710a17329aSShayne Chen 
38720a17329aSShayne Chen 	if (set)
38730a17329aSShayne Chen 		return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
38740a17329aSShayne Chen 					 &req, sizeof(req), false);
38750a17329aSShayne Chen 
38760a17329aSShayne Chen 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
38770a17329aSShayne Chen 					&req, sizeof(req), true, &skb);
38780a17329aSShayne Chen 	if (ret)
38790a17329aSShayne Chen 		return ret;
38800a17329aSShayne Chen 
38810a17329aSShayne Chen 	*val = le32_to_cpu(*(__le32 *)(skb->data + 8));
38820a17329aSShayne Chen 	dev_kfree_skb(skb);
38830a17329aSShayne Chen 
38840a17329aSShayne Chen 	return 0;
38850a17329aSShayne Chen }
3886