xref: /freebsd/sys/contrib/dev/mediatek/mt76/mt7915/mcu.c (revision 8ba4d145d351db26e07695b8e90697398c5dfec2)
16c92544dSBjoern A. Zeeb // SPDX-License-Identifier: ISC
26c92544dSBjoern A. Zeeb /* Copyright (C) 2020 MediaTek Inc. */
36c92544dSBjoern A. Zeeb 
46c92544dSBjoern A. Zeeb #include <linux/fs.h>
56c92544dSBjoern A. Zeeb #include "mt7915.h"
66c92544dSBjoern A. Zeeb #include "mcu.h"
76c92544dSBjoern A. Zeeb #include "mac.h"
86c92544dSBjoern A. Zeeb #include "eeprom.h"
96c92544dSBjoern A. Zeeb 
106c92544dSBjoern A. Zeeb #define fw_name(_dev, name, ...)	({			\
116c92544dSBjoern A. Zeeb 	char *_fw;						\
126c92544dSBjoern A. Zeeb 	switch (mt76_chip(&(_dev)->mt76)) {			\
136c92544dSBjoern A. Zeeb 	case 0x7915:						\
146c92544dSBjoern A. Zeeb 		_fw = MT7915_##name;				\
156c92544dSBjoern A. Zeeb 		break;						\
16cbb3ec25SBjoern A. Zeeb 	case 0x7981:						\
17cbb3ec25SBjoern A. Zeeb 		_fw = MT7981_##name;				\
18cbb3ec25SBjoern A. Zeeb 		break;						\
196c92544dSBjoern A. Zeeb 	case 0x7986:						\
206c92544dSBjoern A. Zeeb 		_fw = MT7986_##name##__VA_ARGS__;		\
216c92544dSBjoern A. Zeeb 		break;						\
226c92544dSBjoern A. Zeeb 	default:						\
236c92544dSBjoern A. Zeeb 		_fw = MT7916_##name;				\
246c92544dSBjoern A. Zeeb 		break;						\
256c92544dSBjoern A. Zeeb 	}							\
266c92544dSBjoern A. Zeeb 	_fw;							\
276c92544dSBjoern A. Zeeb })
286c92544dSBjoern A. Zeeb 
296c92544dSBjoern A. Zeeb #define fw_name_var(_dev, name)		(mt7915_check_adie(dev, false) ?	\
306c92544dSBjoern A. Zeeb 					 fw_name(_dev, name) :			\
316c92544dSBjoern A. Zeeb 					 fw_name(_dev, name, _MT7975))
326c92544dSBjoern A. Zeeb 
336c92544dSBjoern A. Zeeb #define MCU_PATCH_ADDRESS		0x200000
346c92544dSBjoern A. Zeeb 
356c92544dSBjoern A. Zeeb #define HE_PHY(p, c)			u8_get_bits(c, IEEE80211_HE_PHY_##p)
366c92544dSBjoern A. Zeeb #define HE_MAC(m, c)			u8_get_bits(c, IEEE80211_HE_MAC_##m)
376c92544dSBjoern A. Zeeb 
38cbb3ec25SBjoern A. Zeeb static bool sr_scene_detect = true;
39cbb3ec25SBjoern A. Zeeb module_param(sr_scene_detect, bool, 0644);
40cbb3ec25SBjoern A. Zeeb MODULE_PARM_DESC(sr_scene_detect, "Enable firmware scene detection algorithm");
41cbb3ec25SBjoern A. Zeeb 
426c92544dSBjoern A. Zeeb static u8
mt7915_mcu_get_sta_nss(u16 mcs_map)436c92544dSBjoern A. Zeeb mt7915_mcu_get_sta_nss(u16 mcs_map)
446c92544dSBjoern A. Zeeb {
456c92544dSBjoern A. Zeeb 	u8 nss;
466c92544dSBjoern A. Zeeb 
476c92544dSBjoern A. Zeeb 	for (nss = 8; nss > 0; nss--) {
486c92544dSBjoern A. Zeeb 		u8 nss_mcs = (mcs_map >> (2 * (nss - 1))) & 3;
496c92544dSBjoern A. Zeeb 
506c92544dSBjoern A. Zeeb 		if (nss_mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED)
516c92544dSBjoern A. Zeeb 			break;
526c92544dSBjoern A. Zeeb 	}
536c92544dSBjoern A. Zeeb 
546c92544dSBjoern A. Zeeb 	return nss - 1;
556c92544dSBjoern A. Zeeb }
566c92544dSBjoern A. Zeeb 
576c92544dSBjoern A. Zeeb static void
mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta * sta,__le16 * he_mcs,u16 mcs_map)586c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
596c92544dSBjoern A. Zeeb 			  u16 mcs_map)
606c92544dSBjoern A. Zeeb {
616c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
626c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = msta->vif->phy->dev;
636c92544dSBjoern A. Zeeb 	enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
646c92544dSBjoern A. Zeeb 	const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs;
656c92544dSBjoern A. Zeeb 	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
666c92544dSBjoern A. Zeeb 
676c92544dSBjoern A. Zeeb 	for (nss = 0; nss < max_nss; nss++) {
686c92544dSBjoern A. Zeeb 		int mcs;
696c92544dSBjoern A. Zeeb 
706c92544dSBjoern A. Zeeb 		switch ((mcs_map >> (2 * nss)) & 0x3) {
716c92544dSBjoern A. Zeeb 		case IEEE80211_HE_MCS_SUPPORT_0_11:
726c92544dSBjoern A. Zeeb 			mcs = GENMASK(11, 0);
736c92544dSBjoern A. Zeeb 			break;
746c92544dSBjoern A. Zeeb 		case IEEE80211_HE_MCS_SUPPORT_0_9:
756c92544dSBjoern A. Zeeb 			mcs = GENMASK(9, 0);
766c92544dSBjoern A. Zeeb 			break;
776c92544dSBjoern A. Zeeb 		case IEEE80211_HE_MCS_SUPPORT_0_7:
786c92544dSBjoern A. Zeeb 			mcs = GENMASK(7, 0);
796c92544dSBjoern A. Zeeb 			break;
806c92544dSBjoern A. Zeeb 		default:
816c92544dSBjoern A. Zeeb 			mcs = 0;
826c92544dSBjoern A. Zeeb 		}
836c92544dSBjoern A. Zeeb 
846c92544dSBjoern A. Zeeb 		mcs = mcs ? fls(mcs & mask[nss]) - 1 : -1;
856c92544dSBjoern A. Zeeb 
866c92544dSBjoern A. Zeeb 		switch (mcs) {
876c92544dSBjoern A. Zeeb 		case 0 ... 7:
886c92544dSBjoern A. Zeeb 			mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
896c92544dSBjoern A. Zeeb 			break;
906c92544dSBjoern A. Zeeb 		case 8 ... 9:
916c92544dSBjoern A. Zeeb 			mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
926c92544dSBjoern A. Zeeb 			break;
936c92544dSBjoern A. Zeeb 		case 10 ... 11:
946c92544dSBjoern A. Zeeb 			mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
956c92544dSBjoern A. Zeeb 			break;
966c92544dSBjoern A. Zeeb 		default:
976c92544dSBjoern A. Zeeb 			mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
986c92544dSBjoern A. Zeeb 			break;
996c92544dSBjoern A. Zeeb 		}
1006c92544dSBjoern A. Zeeb 		mcs_map &= ~(0x3 << (nss * 2));
1016c92544dSBjoern A. Zeeb 		mcs_map |= mcs << (nss * 2);
1026c92544dSBjoern A. Zeeb 
1036c92544dSBjoern A. Zeeb 		/* only support 2ss on 160MHz for mt7915 */
1046c92544dSBjoern A. Zeeb 		if (is_mt7915(&dev->mt76) && nss > 1 &&
1056c92544dSBjoern A. Zeeb 		    sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
1066c92544dSBjoern A. Zeeb 			break;
1076c92544dSBjoern A. Zeeb 	}
1086c92544dSBjoern A. Zeeb 
1096c92544dSBjoern A. Zeeb 	*he_mcs = cpu_to_le16(mcs_map);
1106c92544dSBjoern A. Zeeb }
1116c92544dSBjoern A. Zeeb 
1126c92544dSBjoern A. Zeeb static void
mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta * sta,__le16 * vht_mcs,const u16 * mask)1136c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
1146c92544dSBjoern A. Zeeb 			   const u16 *mask)
1156c92544dSBjoern A. Zeeb {
1166c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
1176c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = msta->vif->phy->dev;
1186c92544dSBjoern A. Zeeb 	u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
1196c92544dSBjoern A. Zeeb 	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
1206c92544dSBjoern A. Zeeb 	u16 mcs;
1216c92544dSBjoern A. Zeeb 
1226c92544dSBjoern A. Zeeb 	for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
1236c92544dSBjoern A. Zeeb 		switch (mcs_map & 0x3) {
1246c92544dSBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_9:
1256c92544dSBjoern A. Zeeb 			mcs = GENMASK(9, 0);
1266c92544dSBjoern A. Zeeb 			break;
1276c92544dSBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_8:
1286c92544dSBjoern A. Zeeb 			mcs = GENMASK(8, 0);
1296c92544dSBjoern A. Zeeb 			break;
1306c92544dSBjoern A. Zeeb 		case IEEE80211_VHT_MCS_SUPPORT_0_7:
1316c92544dSBjoern A. Zeeb 			mcs = GENMASK(7, 0);
1326c92544dSBjoern A. Zeeb 			break;
1336c92544dSBjoern A. Zeeb 		default:
1346c92544dSBjoern A. Zeeb 			mcs = 0;
1356c92544dSBjoern A. Zeeb 		}
1366c92544dSBjoern A. Zeeb 
1376c92544dSBjoern A. Zeeb 		vht_mcs[nss] = cpu_to_le16(mcs & mask[nss]);
1386c92544dSBjoern A. Zeeb 
1396c92544dSBjoern A. Zeeb 		/* only support 2ss on 160MHz for mt7915 */
1406c92544dSBjoern A. Zeeb 		if (is_mt7915(&dev->mt76) && nss > 1 &&
1416c92544dSBjoern A. Zeeb 		    sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
1426c92544dSBjoern A. Zeeb 			break;
1436c92544dSBjoern A. Zeeb 	}
1446c92544dSBjoern A. Zeeb }
1456c92544dSBjoern A. Zeeb 
1466c92544dSBjoern A. Zeeb static void
mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta * sta,u8 * ht_mcs,const u8 * mask)1476c92544dSBjoern A. Zeeb mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
1486c92544dSBjoern A. Zeeb 			  const u8 *mask)
1496c92544dSBjoern A. Zeeb {
1506c92544dSBjoern A. Zeeb 	int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
1516c92544dSBjoern A. Zeeb 
1526c92544dSBjoern A. Zeeb 	for (nss = 0; nss < max_nss; nss++)
1536c92544dSBjoern A. Zeeb 		ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss];
1546c92544dSBjoern A. Zeeb }
1556c92544dSBjoern A. Zeeb 
1566c92544dSBjoern A. Zeeb static int
mt7915_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)1576c92544dSBjoern A. Zeeb mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
1586c92544dSBjoern A. Zeeb 			  struct sk_buff *skb, int seq)
1596c92544dSBjoern A. Zeeb {
160*8ba4d145SBjoern A. Zeeb 	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
1616c92544dSBjoern A. Zeeb 	struct mt76_connac2_mcu_rxd *rxd;
1626c92544dSBjoern A. Zeeb 	int ret = 0;
1636c92544dSBjoern A. Zeeb 
1646c92544dSBjoern A. Zeeb 	if (!skb) {
1656c92544dSBjoern A. Zeeb 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
1666c92544dSBjoern A. Zeeb 			cmd, seq);
167*8ba4d145SBjoern A. Zeeb 
168*8ba4d145SBjoern A. Zeeb 		if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) {
169*8ba4d145SBjoern A. Zeeb 			dev->recovery.restart = true;
170*8ba4d145SBjoern A. Zeeb 			wake_up(&dev->mt76.mcu.wait);
171*8ba4d145SBjoern A. Zeeb 			queue_work(dev->mt76.wq, &dev->reset_work);
172*8ba4d145SBjoern A. Zeeb 			wake_up(&dev->reset_wait);
173*8ba4d145SBjoern A. Zeeb 		}
174*8ba4d145SBjoern A. Zeeb 
1756c92544dSBjoern A. Zeeb 		return -ETIMEDOUT;
1766c92544dSBjoern A. Zeeb 	}
1776c92544dSBjoern A. Zeeb 
1786c92544dSBjoern A. Zeeb 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
179cbb3ec25SBjoern A. Zeeb 	if (seq != rxd->seq &&
180cbb3ec25SBjoern A. Zeeb 	    !(rxd->eid == MCU_CMD_EXT_CID &&
181cbb3ec25SBjoern A. Zeeb 	      rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
1826c92544dSBjoern A. Zeeb 		return -EAGAIN;
1836c92544dSBjoern A. Zeeb 
1846c92544dSBjoern A. Zeeb 	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
1856c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd) - 4);
1866c92544dSBjoern A. Zeeb 		ret = *skb->data;
1876c92544dSBjoern A. Zeeb 	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
1886c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(*rxd) + 4);
1896c92544dSBjoern A. Zeeb 		ret = le32_to_cpu(*(__le32 *)skb->data);
1906c92544dSBjoern A. Zeeb 	} else {
1916c92544dSBjoern A. Zeeb 		skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
1926c92544dSBjoern A. Zeeb 	}
1936c92544dSBjoern A. Zeeb 
1946c92544dSBjoern A. Zeeb 	return ret;
1956c92544dSBjoern A. Zeeb }
1966c92544dSBjoern A. Zeeb 
197*8ba4d145SBjoern A. Zeeb static void
mt7915_mcu_set_timeout(struct mt76_dev * mdev,int cmd)198*8ba4d145SBjoern A. Zeeb mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd)
199*8ba4d145SBjoern A. Zeeb {
200*8ba4d145SBjoern A. Zeeb 	if ((cmd & __MCU_CMD_FIELD_ID) != MCU_CMD_EXT_CID)
201*8ba4d145SBjoern A. Zeeb 		return;
202*8ba4d145SBjoern A. Zeeb 
203*8ba4d145SBjoern A. Zeeb 	switch (FIELD_GET(__MCU_CMD_FIELD_EXT_ID, cmd)) {
204*8ba4d145SBjoern A. Zeeb 	case MCU_EXT_CMD_THERMAL_CTRL:
205*8ba4d145SBjoern A. Zeeb 	case MCU_EXT_CMD_GET_MIB_INFO:
206*8ba4d145SBjoern A. Zeeb 	case MCU_EXT_CMD_PHY_STAT_INFO:
207*8ba4d145SBjoern A. Zeeb 	case MCU_EXT_CMD_STA_REC_UPDATE:
208*8ba4d145SBjoern A. Zeeb 	case MCU_EXT_CMD_BSS_INFO_UPDATE:
209*8ba4d145SBjoern A. Zeeb 		mdev->mcu.timeout = 2 * HZ;
210*8ba4d145SBjoern A. Zeeb 		return;
211*8ba4d145SBjoern A. Zeeb 	default:
212*8ba4d145SBjoern A. Zeeb 		break;
213*8ba4d145SBjoern A. Zeeb 	}
214*8ba4d145SBjoern A. Zeeb }
215*8ba4d145SBjoern A. Zeeb 
2166c92544dSBjoern A. Zeeb static int
mt7915_mcu_send_message(struct mt76_dev * mdev,struct sk_buff * skb,int cmd,int * wait_seq)2176c92544dSBjoern A. Zeeb mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
2186c92544dSBjoern A. Zeeb 			int cmd, int *wait_seq)
2196c92544dSBjoern A. Zeeb {
2206c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
2216c92544dSBjoern A. Zeeb 	enum mt76_mcuq_id qid;
2226c92544dSBjoern A. Zeeb 
2236c92544dSBjoern A. Zeeb 	if (cmd == MCU_CMD(FW_SCATTER))
2246c92544dSBjoern A. Zeeb 		qid = MT_MCUQ_FWDL;
2256c92544dSBjoern A. Zeeb 	else if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
2266c92544dSBjoern A. Zeeb 		qid = MT_MCUQ_WA;
2276c92544dSBjoern A. Zeeb 	else
2286c92544dSBjoern A. Zeeb 		qid = MT_MCUQ_WM;
2296c92544dSBjoern A. Zeeb 
230*8ba4d145SBjoern A. Zeeb 	mt7915_mcu_set_timeout(mdev, cmd);
231*8ba4d145SBjoern A. Zeeb 
2326c92544dSBjoern A. Zeeb 	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
2336c92544dSBjoern A. Zeeb }
2346c92544dSBjoern A. Zeeb 
mt7915_mcu_wa_cmd(struct mt7915_dev * dev,int cmd,u32 a1,u32 a2,u32 a3)2356c92544dSBjoern A. Zeeb int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
2366c92544dSBjoern A. Zeeb {
2376c92544dSBjoern A. Zeeb 	struct {
2386c92544dSBjoern A. Zeeb 		__le32 args[3];
2396c92544dSBjoern A. Zeeb 	} req = {
2406c92544dSBjoern A. Zeeb 		.args = {
2416c92544dSBjoern A. Zeeb 			cpu_to_le32(a1),
2426c92544dSBjoern A. Zeeb 			cpu_to_le32(a2),
2436c92544dSBjoern A. Zeeb 			cpu_to_le32(a3),
2446c92544dSBjoern A. Zeeb 		},
2456c92544dSBjoern A. Zeeb 	};
2466c92544dSBjoern A. Zeeb 
2476c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), false);
2486c92544dSBjoern A. Zeeb }
2496c92544dSBjoern A. Zeeb 
2506c92544dSBjoern A. Zeeb static void
mt7915_mcu_csa_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)2516c92544dSBjoern A. Zeeb mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
2526c92544dSBjoern A. Zeeb {
253*8ba4d145SBjoern A. Zeeb 	if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
254*8ba4d145SBjoern A. Zeeb 		return;
255*8ba4d145SBjoern A. Zeeb 
256*8ba4d145SBjoern A. Zeeb 	ieee80211_csa_finish(vif, 0);
2576c92544dSBjoern A. Zeeb }
2586c92544dSBjoern A. Zeeb 
2596c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_csa_notify(struct mt7915_dev * dev,struct sk_buff * skb)2606c92544dSBjoern A. Zeeb mt7915_mcu_rx_csa_notify(struct mt7915_dev *dev, struct sk_buff *skb)
2616c92544dSBjoern A. Zeeb {
2626c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
2636c92544dSBjoern A. Zeeb 	struct mt7915_mcu_csa_notify *c;
2646c92544dSBjoern A. Zeeb 
2656c92544dSBjoern A. Zeeb 	c = (struct mt7915_mcu_csa_notify *)skb->data;
2666c92544dSBjoern A. Zeeb 
267cbb3ec25SBjoern A. Zeeb 	if (c->band_idx > MT_BAND1)
268cbb3ec25SBjoern A. Zeeb 		return;
269cbb3ec25SBjoern A. Zeeb 
270cbb3ec25SBjoern A. Zeeb 	if ((c->band_idx && !dev->phy.mt76->band_idx) &&
271cbb3ec25SBjoern A. Zeeb 	    dev->mt76.phys[MT_BAND1])
2726c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
2736c92544dSBjoern A. Zeeb 
2746c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
2756c92544dSBjoern A. Zeeb 			IEEE80211_IFACE_ITER_RESUME_ALL,
2766c92544dSBjoern A. Zeeb 			mt7915_mcu_csa_finish, mphy->hw);
2776c92544dSBjoern A. Zeeb }
2786c92544dSBjoern A. Zeeb 
2796c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_thermal_notify(struct mt7915_dev * dev,struct sk_buff * skb)2806c92544dSBjoern A. Zeeb mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb)
2816c92544dSBjoern A. Zeeb {
2826c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
2836c92544dSBjoern A. Zeeb 	struct mt7915_mcu_thermal_notify *t;
2846c92544dSBjoern A. Zeeb 	struct mt7915_phy *phy;
2856c92544dSBjoern A. Zeeb 
2866c92544dSBjoern A. Zeeb 	t = (struct mt7915_mcu_thermal_notify *)skb->data;
2876c92544dSBjoern A. Zeeb 	if (t->ctrl.ctrl_id != THERMAL_PROTECT_ENABLE)
2886c92544dSBjoern A. Zeeb 		return;
2896c92544dSBjoern A. Zeeb 
290cbb3ec25SBjoern A. Zeeb 	if (t->ctrl.band_idx > MT_BAND1)
291cbb3ec25SBjoern A. Zeeb 		return;
292cbb3ec25SBjoern A. Zeeb 
293cbb3ec25SBjoern A. Zeeb 	if ((t->ctrl.band_idx && !dev->phy.mt76->band_idx) &&
294cbb3ec25SBjoern A. Zeeb 	    dev->mt76.phys[MT_BAND1])
2956c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
2966c92544dSBjoern A. Zeeb 
297*8ba4d145SBjoern A. Zeeb 	phy = mphy->priv;
2986c92544dSBjoern A. Zeeb 	phy->throttle_state = t->ctrl.duty.duty_cycle;
2996c92544dSBjoern A. Zeeb }
3006c92544dSBjoern A. Zeeb 
3016c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_radar_detected(struct mt7915_dev * dev,struct sk_buff * skb)3026c92544dSBjoern A. Zeeb mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
3036c92544dSBjoern A. Zeeb {
3046c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
3056c92544dSBjoern A. Zeeb 	struct mt7915_mcu_rdd_report *r;
3066c92544dSBjoern A. Zeeb 
3076c92544dSBjoern A. Zeeb 	r = (struct mt7915_mcu_rdd_report *)skb->data;
3086c92544dSBjoern A. Zeeb 
309cbb3ec25SBjoern A. Zeeb 	if (r->band_idx > MT_RX_SEL2)
310cbb3ec25SBjoern A. Zeeb 		return;
311cbb3ec25SBjoern A. Zeeb 
312cbb3ec25SBjoern A. Zeeb 	if ((r->band_idx && !dev->phy.mt76->band_idx) &&
313cbb3ec25SBjoern A. Zeeb 	    dev->mt76.phys[MT_BAND1])
3146c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
3156c92544dSBjoern A. Zeeb 
3166c92544dSBjoern A. Zeeb 	if (r->band_idx == MT_RX_SEL2)
3176c92544dSBjoern A. Zeeb 		cfg80211_background_radar_event(mphy->hw->wiphy,
3186c92544dSBjoern A. Zeeb 						&dev->rdd2_chandef,
3196c92544dSBjoern A. Zeeb 						GFP_ATOMIC);
3206c92544dSBjoern A. Zeeb 	else
321*8ba4d145SBjoern A. Zeeb 		ieee80211_radar_detected(mphy->hw, NULL);
3226c92544dSBjoern A. Zeeb 	dev->hw_pattern++;
3236c92544dSBjoern A. Zeeb }
3246c92544dSBjoern A. Zeeb 
3256c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_log_message(struct mt7915_dev * dev,struct sk_buff * skb)3266c92544dSBjoern A. Zeeb mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
3276c92544dSBjoern A. Zeeb {
3286c92544dSBjoern A. Zeeb 	struct mt76_connac2_mcu_rxd *rxd;
3296c92544dSBjoern A. Zeeb 	int len = skb->len - sizeof(*rxd);
3306c92544dSBjoern A. Zeeb 	const char *data, *type;
3316c92544dSBjoern A. Zeeb 
3326c92544dSBjoern A. Zeeb 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
3336c92544dSBjoern A. Zeeb 	data = (char *)&rxd[1];
3346c92544dSBjoern A. Zeeb 
3356c92544dSBjoern A. Zeeb 	switch (rxd->s2d_index) {
3366c92544dSBjoern A. Zeeb 	case 0:
3376c92544dSBjoern A. Zeeb #if !defined(__FreeBSD__) || defined(CONFIG_MT7915_DEBUGFS)
3386c92544dSBjoern A. Zeeb 		if (mt7915_debugfs_rx_log(dev, data, len))
3396c92544dSBjoern A. Zeeb 			return;
3406c92544dSBjoern A. Zeeb #endif
3416c92544dSBjoern A. Zeeb 
3426c92544dSBjoern A. Zeeb 		type = "WM";
3436c92544dSBjoern A. Zeeb 		break;
3446c92544dSBjoern A. Zeeb 	case 2:
3456c92544dSBjoern A. Zeeb 		type = "WA";
3466c92544dSBjoern A. Zeeb 		break;
3476c92544dSBjoern A. Zeeb 	default:
3486c92544dSBjoern A. Zeeb 		type = "unknown";
3496c92544dSBjoern A. Zeeb 		break;
3506c92544dSBjoern A. Zeeb 	}
3516c92544dSBjoern A. Zeeb 
3526c92544dSBjoern A. Zeeb 	wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
3536c92544dSBjoern A. Zeeb }
3546c92544dSBjoern A. Zeeb 
3556c92544dSBjoern A. Zeeb static void
mt7915_mcu_cca_finish(void * priv,u8 * mac,struct ieee80211_vif * vif)3566c92544dSBjoern A. Zeeb mt7915_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
3576c92544dSBjoern A. Zeeb {
358*8ba4d145SBjoern A. Zeeb 	if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION)
3596c92544dSBjoern A. Zeeb 		return;
3606c92544dSBjoern A. Zeeb 
361*8ba4d145SBjoern A. Zeeb 	ieee80211_color_change_finish(vif, 0);
3626c92544dSBjoern A. Zeeb }
3636c92544dSBjoern A. Zeeb 
3646c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_bcc_notify(struct mt7915_dev * dev,struct sk_buff * skb)3656c92544dSBjoern A. Zeeb mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb)
3666c92544dSBjoern A. Zeeb {
3676c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = &dev->mt76.phy;
3686c92544dSBjoern A. Zeeb 	struct mt7915_mcu_bcc_notify *b;
3696c92544dSBjoern A. Zeeb 
3706c92544dSBjoern A. Zeeb 	b = (struct mt7915_mcu_bcc_notify *)skb->data;
3716c92544dSBjoern A. Zeeb 
372cbb3ec25SBjoern A. Zeeb 	if (b->band_idx > MT_BAND1)
373cbb3ec25SBjoern A. Zeeb 		return;
374cbb3ec25SBjoern A. Zeeb 
375cbb3ec25SBjoern A. Zeeb 	if ((b->band_idx && !dev->phy.mt76->band_idx) &&
376cbb3ec25SBjoern A. Zeeb 	    dev->mt76.phys[MT_BAND1])
3776c92544dSBjoern A. Zeeb 		mphy = dev->mt76.phys[MT_BAND1];
3786c92544dSBjoern A. Zeeb 
3796c92544dSBjoern A. Zeeb 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
3806c92544dSBjoern A. Zeeb 			IEEE80211_IFACE_ITER_RESUME_ALL,
3816c92544dSBjoern A. Zeeb 			mt7915_mcu_cca_finish, mphy->hw);
3826c92544dSBjoern A. Zeeb }
3836c92544dSBjoern A. Zeeb 
3846c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_ext_event(struct mt7915_dev * dev,struct sk_buff * skb)3856c92544dSBjoern A. Zeeb mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb)
3866c92544dSBjoern A. Zeeb {
3876c92544dSBjoern A. Zeeb 	struct mt76_connac2_mcu_rxd *rxd;
3886c92544dSBjoern A. Zeeb 
3896c92544dSBjoern A. Zeeb 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
3906c92544dSBjoern A. Zeeb 	switch (rxd->ext_eid) {
3916c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_THERMAL_PROTECT:
3926c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_thermal_notify(dev, skb);
3936c92544dSBjoern A. Zeeb 		break;
3946c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_RDD_REPORT:
3956c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_radar_detected(dev, skb);
3966c92544dSBjoern A. Zeeb 		break;
3976c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_CSA_NOTIFY:
3986c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_csa_notify(dev, skb);
3996c92544dSBjoern A. Zeeb 		break;
4006c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_FW_LOG_2_HOST:
4016c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_log_message(dev, skb);
4026c92544dSBjoern A. Zeeb 		break;
4036c92544dSBjoern A. Zeeb 	case MCU_EXT_EVENT_BCC_NOTIFY:
4046c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_bcc_notify(dev, skb);
4056c92544dSBjoern A. Zeeb 		break;
4066c92544dSBjoern A. Zeeb 	default:
4076c92544dSBjoern A. Zeeb 		break;
4086c92544dSBjoern A. Zeeb 	}
4096c92544dSBjoern A. Zeeb }
4106c92544dSBjoern A. Zeeb 
4116c92544dSBjoern A. Zeeb static void
mt7915_mcu_rx_unsolicited_event(struct mt7915_dev * dev,struct sk_buff * skb)4126c92544dSBjoern A. Zeeb mt7915_mcu_rx_unsolicited_event(struct mt7915_dev *dev, struct sk_buff *skb)
4136c92544dSBjoern A. Zeeb {
4146c92544dSBjoern A. Zeeb 	struct mt76_connac2_mcu_rxd *rxd;
4156c92544dSBjoern A. Zeeb 
4166c92544dSBjoern A. Zeeb 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
4176c92544dSBjoern A. Zeeb 	switch (rxd->eid) {
4186c92544dSBjoern A. Zeeb 	case MCU_EVENT_EXT:
4196c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_ext_event(dev, skb);
4206c92544dSBjoern A. Zeeb 		break;
4216c92544dSBjoern A. Zeeb 	default:
4226c92544dSBjoern A. Zeeb 		break;
4236c92544dSBjoern A. Zeeb 	}
4246c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
4256c92544dSBjoern A. Zeeb }
4266c92544dSBjoern A. Zeeb 
mt7915_mcu_rx_event(struct mt7915_dev * dev,struct sk_buff * skb)4276c92544dSBjoern A. Zeeb void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
4286c92544dSBjoern A. Zeeb {
4296c92544dSBjoern A. Zeeb 	struct mt76_connac2_mcu_rxd *rxd;
4306c92544dSBjoern A. Zeeb 
4316c92544dSBjoern A. Zeeb 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
432cbb3ec25SBjoern A. Zeeb 	if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
4336c92544dSBjoern A. Zeeb 	     rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
4346c92544dSBjoern A. Zeeb 	     rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
4356c92544dSBjoern A. Zeeb 	     rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
4366c92544dSBjoern A. Zeeb 	     rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
437cbb3ec25SBjoern A. Zeeb 	     !rxd->seq) &&
438cbb3ec25SBjoern A. Zeeb 	     !(rxd->eid == MCU_CMD_EXT_CID &&
439cbb3ec25SBjoern A. Zeeb 	       rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
4406c92544dSBjoern A. Zeeb 		mt7915_mcu_rx_unsolicited_event(dev, skb);
4416c92544dSBjoern A. Zeeb 	else
4426c92544dSBjoern A. Zeeb 		mt76_mcu_rx_event(&dev->mt76, skb);
4436c92544dSBjoern A. Zeeb }
4446c92544dSBjoern A. Zeeb 
4456c92544dSBjoern A. Zeeb static struct tlv *
mt7915_mcu_add_nested_subtlv(struct sk_buff * skb,int sub_tag,int sub_len,__le16 * sub_ntlv,__le16 * len)4466c92544dSBjoern A. Zeeb mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len,
4476c92544dSBjoern A. Zeeb 			     __le16 *sub_ntlv, __le16 *len)
4486c92544dSBjoern A. Zeeb {
4496c92544dSBjoern A. Zeeb 	struct tlv *ptlv, tlv = {
4506c92544dSBjoern A. Zeeb 		.tag = cpu_to_le16(sub_tag),
4516c92544dSBjoern A. Zeeb 		.len = cpu_to_le16(sub_len),
4526c92544dSBjoern A. Zeeb 	};
4536c92544dSBjoern A. Zeeb 
454*8ba4d145SBjoern A. Zeeb 	ptlv = skb_put_zero(skb, sub_len);
4556c92544dSBjoern A. Zeeb 	memcpy(ptlv, &tlv, sizeof(tlv));
4566c92544dSBjoern A. Zeeb 
4576c92544dSBjoern A. Zeeb 	le16_add_cpu(sub_ntlv, 1);
4586c92544dSBjoern A. Zeeb 	le16_add_cpu(len, sub_len);
4596c92544dSBjoern A. Zeeb 
4606c92544dSBjoern A. Zeeb 	return ptlv;
4616c92544dSBjoern A. Zeeb }
4626c92544dSBjoern A. Zeeb 
4636c92544dSBjoern A. Zeeb /** bss info **/
4646c92544dSBjoern A. Zeeb struct mt7915_he_obss_narrow_bw_ru_data {
4656c92544dSBjoern A. Zeeb 	bool tolerated;
4666c92544dSBjoern A. Zeeb };
4676c92544dSBjoern A. Zeeb 
mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy * wiphy,struct cfg80211_bss * bss,void * _data)4686c92544dSBjoern A. Zeeb static void mt7915_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
4696c92544dSBjoern A. Zeeb 						   struct cfg80211_bss *bss,
4706c92544dSBjoern A. Zeeb 						   void *_data)
4716c92544dSBjoern A. Zeeb {
4726c92544dSBjoern A. Zeeb 	struct mt7915_he_obss_narrow_bw_ru_data *data = _data;
4736c92544dSBjoern A. Zeeb 	const struct element *elem;
4746c92544dSBjoern A. Zeeb 
4756c92544dSBjoern A. Zeeb 	rcu_read_lock();
4766c92544dSBjoern A. Zeeb 	elem = ieee80211_bss_get_elem(bss, WLAN_EID_EXT_CAPABILITY);
4776c92544dSBjoern A. Zeeb 
4786c92544dSBjoern A. Zeeb 	if (!elem || elem->datalen <= 10 ||
4796c92544dSBjoern A. Zeeb 	    !(elem->data[10] &
4806c92544dSBjoern A. Zeeb 	      WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT))
4816c92544dSBjoern A. Zeeb 		data->tolerated = false;
4826c92544dSBjoern A. Zeeb 
4836c92544dSBjoern A. Zeeb 	rcu_read_unlock();
4846c92544dSBjoern A. Zeeb }
4856c92544dSBjoern A. Zeeb 
mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw * hw,struct ieee80211_vif * vif)4866c92544dSBjoern A. Zeeb static bool mt7915_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
4876c92544dSBjoern A. Zeeb 					      struct ieee80211_vif *vif)
4886c92544dSBjoern A. Zeeb {
4896c92544dSBjoern A. Zeeb 	struct mt7915_he_obss_narrow_bw_ru_data iter_data = {
4906c92544dSBjoern A. Zeeb 		.tolerated = true,
4916c92544dSBjoern A. Zeeb 	};
4926c92544dSBjoern A. Zeeb 
493*8ba4d145SBjoern A. Zeeb 	if (!(vif->bss_conf.chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR))
4946c92544dSBjoern A. Zeeb 		return false;
4956c92544dSBjoern A. Zeeb 
496*8ba4d145SBjoern A. Zeeb 	cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chanreq.oper,
4976c92544dSBjoern A. Zeeb 			  mt7915_check_he_obss_narrow_bw_ru_iter,
4986c92544dSBjoern A. Zeeb 			  &iter_data);
4996c92544dSBjoern A. Zeeb 
5006c92544dSBjoern A. Zeeb 	/*
5016c92544dSBjoern A. Zeeb 	 * If there is at least one AP on radar channel that cannot
5026c92544dSBjoern A. Zeeb 	 * tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.
5036c92544dSBjoern A. Zeeb 	 */
5046c92544dSBjoern A. Zeeb 	return !iter_data.tolerated;
5056c92544dSBjoern A. Zeeb }
5066c92544dSBjoern A. Zeeb 
5076c92544dSBjoern A. Zeeb static void
mt7915_mcu_bss_rfch_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)5086c92544dSBjoern A. Zeeb mt7915_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
5096c92544dSBjoern A. Zeeb 			struct mt7915_phy *phy)
5106c92544dSBjoern A. Zeeb {
5116c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
5126c92544dSBjoern A. Zeeb 	struct bss_info_rf_ch *ch;
5136c92544dSBjoern A. Zeeb 	struct tlv *tlv;
5146c92544dSBjoern A. Zeeb 	int freq1 = chandef->center_freq1;
5156c92544dSBjoern A. Zeeb 
5166c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RF_CH, sizeof(*ch));
5176c92544dSBjoern A. Zeeb 
5186c92544dSBjoern A. Zeeb 	ch = (struct bss_info_rf_ch *)tlv;
5196c92544dSBjoern A. Zeeb 	ch->pri_ch = chandef->chan->hw_value;
5206c92544dSBjoern A. Zeeb 	ch->center_ch0 = ieee80211_frequency_to_channel(freq1);
5216c92544dSBjoern A. Zeeb 	ch->bw = mt76_connac_chan_bw(chandef);
5226c92544dSBjoern A. Zeeb 
5236c92544dSBjoern A. Zeeb 	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
5246c92544dSBjoern A. Zeeb 		int freq2 = chandef->center_freq2;
5256c92544dSBjoern A. Zeeb 
5266c92544dSBjoern A. Zeeb 		ch->center_ch1 = ieee80211_frequency_to_channel(freq2);
5276c92544dSBjoern A. Zeeb 	}
5286c92544dSBjoern A. Zeeb 
5296c92544dSBjoern A. Zeeb 	if (vif->bss_conf.he_support && vif->type == NL80211_IFTYPE_STATION) {
5306c92544dSBjoern A. Zeeb 		struct mt76_phy *mphy = phy->mt76;
5316c92544dSBjoern A. Zeeb 
5326c92544dSBjoern A. Zeeb 		ch->he_ru26_block =
5336c92544dSBjoern A. Zeeb 			mt7915_check_he_obss_narrow_bw_ru(mphy->hw, vif);
5346c92544dSBjoern A. Zeeb 		ch->he_all_disable = false;
5356c92544dSBjoern A. Zeeb 	} else {
5366c92544dSBjoern A. Zeeb 		ch->he_all_disable = true;
5376c92544dSBjoern A. Zeeb 	}
5386c92544dSBjoern A. Zeeb }
5396c92544dSBjoern A. Zeeb 
5406c92544dSBjoern A. Zeeb static void
mt7915_mcu_bss_ra_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)5416c92544dSBjoern A. Zeeb mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
5426c92544dSBjoern A. Zeeb 		      struct mt7915_phy *phy)
5436c92544dSBjoern A. Zeeb {
544cbb3ec25SBjoern A. Zeeb 	int max_nss = hweight8(phy->mt76->antenna_mask);
5456c92544dSBjoern A. Zeeb 	struct bss_info_ra *ra;
5466c92544dSBjoern A. Zeeb 	struct tlv *tlv;
5476c92544dSBjoern A. Zeeb 
5486c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_RA, sizeof(*ra));
5496c92544dSBjoern A. Zeeb 
5506c92544dSBjoern A. Zeeb 	ra = (struct bss_info_ra *)tlv;
5516c92544dSBjoern A. Zeeb 	ra->op_mode = vif->type == NL80211_IFTYPE_AP;
5526c92544dSBjoern A. Zeeb 	ra->adhoc_en = vif->type == NL80211_IFTYPE_ADHOC;
5536c92544dSBjoern A. Zeeb 	ra->short_preamble = true;
5546c92544dSBjoern A. Zeeb 	ra->tx_streams = max_nss;
5556c92544dSBjoern A. Zeeb 	ra->rx_streams = max_nss;
5566c92544dSBjoern A. Zeeb 	ra->algo = 4;
5576c92544dSBjoern A. Zeeb 	ra->train_up_rule = 2;
5586c92544dSBjoern A. Zeeb 	ra->train_up_high_thres = 110;
5596c92544dSBjoern A. Zeeb 	ra->train_up_rule_rssi = -70;
5606c92544dSBjoern A. Zeeb 	ra->low_traffic_thres = 2;
5616c92544dSBjoern A. Zeeb 	ra->phy_cap = cpu_to_le32(0xfdf);
5626c92544dSBjoern A. Zeeb 	ra->interval = cpu_to_le32(500);
5636c92544dSBjoern A. Zeeb 	ra->fast_interval = cpu_to_le32(100);
5646c92544dSBjoern A. Zeeb }
5656c92544dSBjoern A. Zeeb 
5666c92544dSBjoern A. Zeeb static void
mt7915_mcu_bss_he_tlv(struct sk_buff * skb,struct ieee80211_vif * vif,struct mt7915_phy * phy)5676c92544dSBjoern A. Zeeb mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
5686c92544dSBjoern A. Zeeb 		      struct mt7915_phy *phy)
5696c92544dSBjoern A. Zeeb {
5706c92544dSBjoern A. Zeeb #define DEFAULT_HE_PE_DURATION		4
5716c92544dSBjoern A. Zeeb #define DEFAULT_HE_DURATION_RTS_THRES	1023
5726c92544dSBjoern A. Zeeb 	const struct ieee80211_sta_he_cap *cap;
5736c92544dSBjoern A. Zeeb 	struct bss_info_he *he;
5746c92544dSBjoern A. Zeeb 	struct tlv *tlv;
5756c92544dSBjoern A. Zeeb 
5766c92544dSBjoern A. Zeeb 	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
5776c92544dSBjoern A. Zeeb 
5786c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
5796c92544dSBjoern A. Zeeb 
5806c92544dSBjoern A. Zeeb 	he = (struct bss_info_he *)tlv;
5816c92544dSBjoern A. Zeeb 	he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
5826c92544dSBjoern A. Zeeb 	if (!he->he_pe_duration)
5836c92544dSBjoern A. Zeeb 		he->he_pe_duration = DEFAULT_HE_PE_DURATION;
5846c92544dSBjoern A. Zeeb 
5856c92544dSBjoern A. Zeeb 	he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
5866c92544dSBjoern A. Zeeb 	if (!he->he_rts_thres)
5876c92544dSBjoern A. Zeeb 		he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
5886c92544dSBjoern A. Zeeb 
5896c92544dSBjoern A. Zeeb 	he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;
5906c92544dSBjoern A. Zeeb 	he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;
5916c92544dSBjoern A. Zeeb 	he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
5926c92544dSBjoern A. Zeeb }
5936c92544dSBjoern A. Zeeb 
5946c92544dSBjoern A. Zeeb static void
mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff * skb)5956c92544dSBjoern A. Zeeb mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
5966c92544dSBjoern A. Zeeb {
5976c92544dSBjoern A. Zeeb #define TXD_CMP_MAP1		GENMASK(15, 0)
5986c92544dSBjoern A. Zeeb #define TXD_CMP_MAP2		(GENMASK(31, 0) & ~BIT(23))
5996c92544dSBjoern A. Zeeb 	struct bss_info_hw_amsdu *amsdu;
6006c92544dSBjoern A. Zeeb 	struct tlv *tlv;
6016c92544dSBjoern A. Zeeb 
6026c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
6036c92544dSBjoern A. Zeeb 
6046c92544dSBjoern A. Zeeb 	amsdu = (struct bss_info_hw_amsdu *)tlv;
6056c92544dSBjoern A. Zeeb 	amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
6066c92544dSBjoern A. Zeeb 	amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
6076c92544dSBjoern A. Zeeb 	amsdu->trig_thres = cpu_to_le16(2);
6086c92544dSBjoern A. Zeeb 	amsdu->enable = true;
6096c92544dSBjoern A. Zeeb }
6106c92544dSBjoern A. Zeeb 
6116c92544dSBjoern A. Zeeb static void
mt7915_mcu_bss_bmc_tlv(struct sk_buff * skb,struct mt7915_phy * phy)6126c92544dSBjoern A. Zeeb mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy)
6136c92544dSBjoern A. Zeeb {
6146c92544dSBjoern A. Zeeb 	struct bss_info_bmc_rate *bmc;
6156c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
6166c92544dSBjoern A. Zeeb 	enum nl80211_band band = chandef->chan->band;
6176c92544dSBjoern A. Zeeb 	struct tlv *tlv;
6186c92544dSBjoern A. Zeeb 
6196c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BMC_RATE, sizeof(*bmc));
6206c92544dSBjoern A. Zeeb 
6216c92544dSBjoern A. Zeeb 	bmc = (struct bss_info_bmc_rate *)tlv;
6226c92544dSBjoern A. Zeeb 	if (band == NL80211_BAND_2GHZ) {
6236c92544dSBjoern A. Zeeb 		bmc->short_preamble = true;
6246c92544dSBjoern A. Zeeb 	} else {
6256c92544dSBjoern A. Zeeb 		bmc->bc_trans = cpu_to_le16(0x2000);
6266c92544dSBjoern A. Zeeb 		bmc->mc_trans = cpu_to_le16(0x2080);
6276c92544dSBjoern A. Zeeb 	}
6286c92544dSBjoern A. Zeeb }
6296c92544dSBjoern A. Zeeb 
6306c92544dSBjoern A. Zeeb static int
mt7915_mcu_muar_config(struct mt7915_phy * phy,struct ieee80211_vif * vif,bool bssid,bool enable)6316c92544dSBjoern A. Zeeb mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif,
6326c92544dSBjoern A. Zeeb 		       bool bssid, bool enable)
6336c92544dSBjoern A. Zeeb {
6346c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
6356c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
6366c92544dSBjoern A. Zeeb 	u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
6376c92544dSBjoern A. Zeeb 	u32 mask = phy->omac_mask >> 32 & ~BIT(idx);
6386c92544dSBjoern A. Zeeb 	const u8 *addr = vif->addr;
6396c92544dSBjoern A. Zeeb 	struct {
6406c92544dSBjoern A. Zeeb 		u8 mode;
6416c92544dSBjoern A. Zeeb 		u8 force_clear;
6426c92544dSBjoern A. Zeeb 		u8 clear_bitmap[8];
6436c92544dSBjoern A. Zeeb 		u8 entry_count;
6446c92544dSBjoern A. Zeeb 		u8 write;
6456c92544dSBjoern A. Zeeb 		u8 band;
6466c92544dSBjoern A. Zeeb 
6476c92544dSBjoern A. Zeeb 		u8 index;
6486c92544dSBjoern A. Zeeb 		u8 bssid;
6496c92544dSBjoern A. Zeeb 		u8 addr[ETH_ALEN];
6506c92544dSBjoern A. Zeeb 	} __packed req = {
6516c92544dSBjoern A. Zeeb 		.mode = !!mask || enable,
6526c92544dSBjoern A. Zeeb 		.entry_count = 1,
6536c92544dSBjoern A. Zeeb 		.write = 1,
654cbb3ec25SBjoern A. Zeeb 		.band = phy->mt76->band_idx,
6556c92544dSBjoern A. Zeeb 		.index = idx * 2 + bssid,
6566c92544dSBjoern A. Zeeb 	};
6576c92544dSBjoern A. Zeeb 
6586c92544dSBjoern A. Zeeb 	if (bssid)
6596c92544dSBjoern A. Zeeb 		addr = vif->bss_conf.bssid;
6606c92544dSBjoern A. Zeeb 
6616c92544dSBjoern A. Zeeb 	if (enable)
6626c92544dSBjoern A. Zeeb 		ether_addr_copy(req.addr, addr);
6636c92544dSBjoern A. Zeeb 
6646c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MUAR_UPDATE), &req,
6656c92544dSBjoern A. Zeeb 				 sizeof(req), true);
6666c92544dSBjoern A. Zeeb }
6676c92544dSBjoern A. Zeeb 
mt7915_mcu_add_bss_info(struct mt7915_phy * phy,struct ieee80211_vif * vif,int enable)6686c92544dSBjoern A. Zeeb int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
6696c92544dSBjoern A. Zeeb 			    struct ieee80211_vif *vif, int enable)
6706c92544dSBjoern A. Zeeb {
6716c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
6726c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
6736c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
6746c92544dSBjoern A. Zeeb 
6756c92544dSBjoern A. Zeeb 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) {
6766c92544dSBjoern A. Zeeb 		mt7915_mcu_muar_config(phy, vif, false, enable);
6776c92544dSBjoern A. Zeeb 		mt7915_mcu_muar_config(phy, vif, true, enable);
6786c92544dSBjoern A. Zeeb 	}
6796c92544dSBjoern A. Zeeb 
6806c92544dSBjoern A. Zeeb 	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
6816c92544dSBjoern A. Zeeb 					      MT7915_BSS_UPDATE_MAX_SIZE);
6826c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
6836c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
6846c92544dSBjoern A. Zeeb 
6856c92544dSBjoern A. Zeeb 	/* bss_omac must be first */
6866c92544dSBjoern A. Zeeb 	if (enable)
6876c92544dSBjoern A. Zeeb 		mt76_connac_mcu_bss_omac_tlv(skb, vif);
6886c92544dSBjoern A. Zeeb 
6896c92544dSBjoern A. Zeeb 	mt76_connac_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76,
6906c92544dSBjoern A. Zeeb 				      mvif->sta.wcid.idx, enable);
6916c92544dSBjoern A. Zeeb 
6926c92544dSBjoern A. Zeeb 	if (vif->type == NL80211_IFTYPE_MONITOR)
6936c92544dSBjoern A. Zeeb 		goto out;
6946c92544dSBjoern A. Zeeb 
6956c92544dSBjoern A. Zeeb 	if (enable) {
6966c92544dSBjoern A. Zeeb 		mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
6976c92544dSBjoern A. Zeeb 		mt7915_mcu_bss_bmc_tlv(skb, phy);
6986c92544dSBjoern A. Zeeb 		mt7915_mcu_bss_ra_tlv(skb, vif, phy);
6996c92544dSBjoern A. Zeeb 		mt7915_mcu_bss_hw_amsdu_tlv(skb);
7006c92544dSBjoern A. Zeeb 
7016c92544dSBjoern A. Zeeb 		if (vif->bss_conf.he_support)
7026c92544dSBjoern A. Zeeb 			mt7915_mcu_bss_he_tlv(skb, vif, phy);
7036c92544dSBjoern A. Zeeb 
7046c92544dSBjoern A. Zeeb 		if (mvif->mt76.omac_idx >= EXT_BSSID_START &&
7056c92544dSBjoern A. Zeeb 		    mvif->mt76.omac_idx < REPEATER_BSSID_START)
7066c92544dSBjoern A. Zeeb 			mt76_connac_mcu_bss_ext_tlv(skb, &mvif->mt76);
7076c92544dSBjoern A. Zeeb 	}
7086c92544dSBjoern A. Zeeb out:
7096c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
7106c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
7116c92544dSBjoern A. Zeeb }
7126c92544dSBjoern A. Zeeb 
7136c92544dSBjoern A. Zeeb /** starec & wtbl **/
mt7915_mcu_add_tx_ba(struct mt7915_dev * dev,struct ieee80211_ampdu_params * params,bool enable)7146c92544dSBjoern A. Zeeb int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
7156c92544dSBjoern A. Zeeb 			 struct ieee80211_ampdu_params *params,
7166c92544dSBjoern A. Zeeb 			 bool enable)
7176c92544dSBjoern A. Zeeb {
7186c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
7196c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = msta->vif;
720*8ba4d145SBjoern A. Zeeb 	int ret;
7216c92544dSBjoern A. Zeeb 
722*8ba4d145SBjoern A. Zeeb 	mt76_worker_disable(&dev->mt76.tx_worker);
7236c92544dSBjoern A. Zeeb 	if (enable && !params->amsdu)
7246c92544dSBjoern A. Zeeb 		msta->wcid.amsdu = false;
725*8ba4d145SBjoern A. Zeeb 	ret = mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
7266c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(STA_REC_UPDATE),
7276c92544dSBjoern A. Zeeb 				     enable, true);
728*8ba4d145SBjoern A. Zeeb 	mt76_worker_enable(&dev->mt76.tx_worker);
729*8ba4d145SBjoern A. Zeeb 
730*8ba4d145SBjoern A. Zeeb 	return ret;
7316c92544dSBjoern A. Zeeb }
7326c92544dSBjoern A. Zeeb 
mt7915_mcu_add_rx_ba(struct mt7915_dev * dev,struct ieee80211_ampdu_params * params,bool enable)7336c92544dSBjoern A. Zeeb int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
7346c92544dSBjoern A. Zeeb 			 struct ieee80211_ampdu_params *params,
7356c92544dSBjoern A. Zeeb 			 bool enable)
7366c92544dSBjoern A. Zeeb {
7376c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)params->sta->drv_priv;
7386c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = msta->vif;
7396c92544dSBjoern A. Zeeb 
7406c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
7416c92544dSBjoern A. Zeeb 				      MCU_EXT_CMD(STA_REC_UPDATE),
7426c92544dSBjoern A. Zeeb 				      enable, false);
7436c92544dSBjoern A. Zeeb }
7446c92544dSBjoern A. Zeeb 
7456c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_he_tlv(struct sk_buff * skb,struct ieee80211_sta * sta,struct ieee80211_vif * vif)7466c92544dSBjoern A. Zeeb mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
7476c92544dSBjoern A. Zeeb 		      struct ieee80211_vif *vif)
7486c92544dSBjoern A. Zeeb {
7496c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
7506c92544dSBjoern A. Zeeb 	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
7516c92544dSBjoern A. Zeeb 	struct ieee80211_he_mcs_nss_supp mcs_map;
7526c92544dSBjoern A. Zeeb 	struct sta_rec_he *he;
7536c92544dSBjoern A. Zeeb 	struct tlv *tlv;
7546c92544dSBjoern A. Zeeb 	u32 cap = 0;
7556c92544dSBjoern A. Zeeb 
7566c92544dSBjoern A. Zeeb 	if (!sta->deflink.he_cap.has_he)
7576c92544dSBjoern A. Zeeb 		return;
7586c92544dSBjoern A. Zeeb 
7596c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
7606c92544dSBjoern A. Zeeb 
7616c92544dSBjoern A. Zeeb 	he = (struct sta_rec_he *)tlv;
7626c92544dSBjoern A. Zeeb 
7636c92544dSBjoern A. Zeeb 	if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)
7646c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_HTC;
7656c92544dSBjoern A. Zeeb 
7666c92544dSBjoern A. Zeeb 	if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
7676c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_BSR;
7686c92544dSBjoern A. Zeeb 
7696c92544dSBjoern A. Zeeb 	if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
7706c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_OM;
7716c92544dSBjoern A. Zeeb 
7726c92544dSBjoern A. Zeeb 	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU)
7736c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU;
7746c92544dSBjoern A. Zeeb 
7756c92544dSBjoern A. Zeeb 	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
7766c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_BQR;
7776c92544dSBjoern A. Zeeb 
7786c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[0] &
7796c92544dSBjoern A. Zeeb 	    (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G |
7806c92544dSBjoern A. Zeeb 	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
7816c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
7826c92544dSBjoern A. Zeeb 
7836c92544dSBjoern A. Zeeb 	if (mvif->cap.he_ldpc &&
7846c92544dSBjoern A. Zeeb 	    (elem->phy_cap_info[1] &
7856c92544dSBjoern A. Zeeb 	     IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
7866c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_LDPC;
7876c92544dSBjoern A. Zeeb 
7886c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[1] &
7896c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US)
7906c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI;
7916c92544dSBjoern A. Zeeb 
7926c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[2] &
7936c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US)
7946c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI;
7956c92544dSBjoern A. Zeeb 
7966c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[2] &
7976c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ)
7986c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC;
7996c92544dSBjoern A. Zeeb 
8006c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[2] &
8016c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
8026c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;
8036c92544dSBjoern A. Zeeb 
8046c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[6] &
8056c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB)
8066c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
8076c92544dSBjoern A. Zeeb 
8086c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[6] &
8096c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)
8106c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;
8116c92544dSBjoern A. Zeeb 
8126c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[7] &
8136c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI)
8146c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI;
8156c92544dSBjoern A. Zeeb 
8166c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[7] &
8176c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ)
8186c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_GT_80M_TX_STBC;
8196c92544dSBjoern A. Zeeb 
8206c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[7] &
8216c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
8226c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_GT_80M_RX_STBC;
8236c92544dSBjoern A. Zeeb 
8246c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[8] &
8256c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI)
8266c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI;
8276c92544dSBjoern A. Zeeb 
8286c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[8] &
8296c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI)
8306c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;
8316c92544dSBjoern A. Zeeb 
8326c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[9] &
8336c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)
8346c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;
8356c92544dSBjoern A. Zeeb 
8366c92544dSBjoern A. Zeeb 	if (elem->phy_cap_info[9] &
8376c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU)
8386c92544dSBjoern A. Zeeb 		cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242;
8396c92544dSBjoern A. Zeeb 
8406c92544dSBjoern A. Zeeb 	he->he_cap = cpu_to_le32(cap);
8416c92544dSBjoern A. Zeeb 
8426c92544dSBjoern A. Zeeb 	mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
8436c92544dSBjoern A. Zeeb 	switch (sta->deflink.bandwidth) {
8446c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_160:
8456c92544dSBjoern A. Zeeb 		if (elem->phy_cap_info[0] &
8466c92544dSBjoern A. Zeeb 		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
8476c92544dSBjoern A. Zeeb 			mt7915_mcu_set_sta_he_mcs(sta,
8486c92544dSBjoern A. Zeeb 						  &he->max_nss_mcs[CMD_HE_MCS_BW8080],
8496c92544dSBjoern A. Zeeb 						  le16_to_cpu(mcs_map.rx_mcs_80p80));
8506c92544dSBjoern A. Zeeb 
8516c92544dSBjoern A. Zeeb 		mt7915_mcu_set_sta_he_mcs(sta,
8526c92544dSBjoern A. Zeeb 					  &he->max_nss_mcs[CMD_HE_MCS_BW160],
8536c92544dSBjoern A. Zeeb 					  le16_to_cpu(mcs_map.rx_mcs_160));
8546c92544dSBjoern A. Zeeb 		fallthrough;
8556c92544dSBjoern A. Zeeb 	default:
8566c92544dSBjoern A. Zeeb 		mt7915_mcu_set_sta_he_mcs(sta,
8576c92544dSBjoern A. Zeeb 					  &he->max_nss_mcs[CMD_HE_MCS_BW80],
8586c92544dSBjoern A. Zeeb 					  le16_to_cpu(mcs_map.rx_mcs_80));
8596c92544dSBjoern A. Zeeb 		break;
8606c92544dSBjoern A. Zeeb 	}
8616c92544dSBjoern A. Zeeb 
8626c92544dSBjoern A. Zeeb 	he->t_frame_dur =
8636c92544dSBjoern A. Zeeb 		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
8646c92544dSBjoern A. Zeeb 	he->max_ampdu_exp =
8656c92544dSBjoern A. Zeeb 		HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]);
8666c92544dSBjoern A. Zeeb 
8676c92544dSBjoern A. Zeeb 	he->bw_set =
8686c92544dSBjoern A. Zeeb 		HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]);
8696c92544dSBjoern A. Zeeb 	he->device_class =
8706c92544dSBjoern A. Zeeb 		HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]);
8716c92544dSBjoern A. Zeeb 	he->punc_pream_rx =
8726c92544dSBjoern A. Zeeb 		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
8736c92544dSBjoern A. Zeeb 
8746c92544dSBjoern A. Zeeb 	he->dcm_tx_mode =
8756c92544dSBjoern A. Zeeb 		HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]);
8766c92544dSBjoern A. Zeeb 	he->dcm_tx_max_nss =
8776c92544dSBjoern A. Zeeb 		HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]);
8786c92544dSBjoern A. Zeeb 	he->dcm_rx_mode =
8796c92544dSBjoern A. Zeeb 		HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]);
8806c92544dSBjoern A. Zeeb 	he->dcm_rx_max_nss =
8816c92544dSBjoern A. Zeeb 		HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]);
8826c92544dSBjoern A. Zeeb 	he->dcm_rx_max_nss =
8836c92544dSBjoern A. Zeeb 		HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]);
8846c92544dSBjoern A. Zeeb 
8856c92544dSBjoern A. Zeeb 	he->pkt_ext = 2;
8866c92544dSBjoern A. Zeeb }
8876c92544dSBjoern A. Zeeb 
8886c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_muru_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_sta * sta,struct ieee80211_vif * vif)8896c92544dSBjoern A. Zeeb mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
8906c92544dSBjoern A. Zeeb 			struct ieee80211_sta *sta, struct ieee80211_vif *vif)
8916c92544dSBjoern A. Zeeb {
8926c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
8936c92544dSBjoern A. Zeeb 	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
8946c92544dSBjoern A. Zeeb 	struct sta_rec_muru *muru;
8956c92544dSBjoern A. Zeeb 	struct tlv *tlv;
8966c92544dSBjoern A. Zeeb 
8976c92544dSBjoern A. Zeeb 	if (vif->type != NL80211_IFTYPE_STATION &&
8986c92544dSBjoern A. Zeeb 	    vif->type != NL80211_IFTYPE_AP)
8996c92544dSBjoern A. Zeeb 		return;
9006c92544dSBjoern A. Zeeb 
9016c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
9026c92544dSBjoern A. Zeeb 
9036c92544dSBjoern A. Zeeb 	muru = (struct sta_rec_muru *)tlv;
9046c92544dSBjoern A. Zeeb 
9056c92544dSBjoern A. Zeeb 	muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
9066c92544dSBjoern A. Zeeb 			       mvif->cap.vht_mu_ebfer ||
9076c92544dSBjoern A. Zeeb 			       mvif->cap.vht_mu_ebfee;
9086c92544dSBjoern A. Zeeb 	if (!is_mt7915(&dev->mt76))
9096c92544dSBjoern A. Zeeb 		muru->cfg.mimo_ul_en = true;
9106c92544dSBjoern A. Zeeb 	muru->cfg.ofdma_dl_en = true;
9116c92544dSBjoern A. Zeeb 
9126c92544dSBjoern A. Zeeb 	if (sta->deflink.vht_cap.vht_supported)
9136c92544dSBjoern A. Zeeb 		muru->mimo_dl.vht_mu_bfee =
9146c92544dSBjoern A. Zeeb 			!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
9156c92544dSBjoern A. Zeeb 
9166c92544dSBjoern A. Zeeb 	if (!sta->deflink.he_cap.has_he)
9176c92544dSBjoern A. Zeeb 		return;
9186c92544dSBjoern A. Zeeb 
9196c92544dSBjoern A. Zeeb 	muru->mimo_dl.partial_bw_dl_mimo =
9206c92544dSBjoern A. Zeeb 		HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
9216c92544dSBjoern A. Zeeb 
9226c92544dSBjoern A. Zeeb 	muru->mimo_ul.full_ul_mimo =
9236c92544dSBjoern A. Zeeb 		HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
9246c92544dSBjoern A. Zeeb 	muru->mimo_ul.partial_ul_mimo =
9256c92544dSBjoern A. Zeeb 		HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
9266c92544dSBjoern A. Zeeb 
9276c92544dSBjoern A. Zeeb 	muru->ofdma_dl.punc_pream_rx =
9286c92544dSBjoern A. Zeeb 		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
9296c92544dSBjoern A. Zeeb 	muru->ofdma_dl.he_20m_in_40m_2g =
9306c92544dSBjoern A. Zeeb 		HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
9316c92544dSBjoern A. Zeeb 	muru->ofdma_dl.he_20m_in_160m =
9326c92544dSBjoern A. Zeeb 		HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
9336c92544dSBjoern A. Zeeb 	muru->ofdma_dl.he_80m_in_160m =
9346c92544dSBjoern A. Zeeb 		HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
9356c92544dSBjoern A. Zeeb 
9366c92544dSBjoern A. Zeeb 	muru->ofdma_ul.t_frame_dur =
9376c92544dSBjoern A. Zeeb 		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
9386c92544dSBjoern A. Zeeb 	muru->ofdma_ul.mu_cascading =
9396c92544dSBjoern A. Zeeb 		HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
9406c92544dSBjoern A. Zeeb 	muru->ofdma_ul.uo_ra =
9416c92544dSBjoern A. Zeeb 		HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
942*8ba4d145SBjoern A. Zeeb 	muru->ofdma_ul.rx_ctrl_frame_to_mbss =
943*8ba4d145SBjoern A. Zeeb 		HE_MAC(CAP3_RX_CTRL_FRAME_TO_MULTIBSS, elem->mac_cap_info[3]);
9446c92544dSBjoern A. Zeeb }
9456c92544dSBjoern A. Zeeb 
9466c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_ht_tlv(struct sk_buff * skb,struct ieee80211_sta * sta)9476c92544dSBjoern A. Zeeb mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
9486c92544dSBjoern A. Zeeb {
9496c92544dSBjoern A. Zeeb 	struct sta_rec_ht *ht;
9506c92544dSBjoern A. Zeeb 	struct tlv *tlv;
9516c92544dSBjoern A. Zeeb 
9526c92544dSBjoern A. Zeeb 	if (!sta->deflink.ht_cap.ht_supported)
9536c92544dSBjoern A. Zeeb 		return;
9546c92544dSBjoern A. Zeeb 
9556c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
9566c92544dSBjoern A. Zeeb 
9576c92544dSBjoern A. Zeeb 	ht = (struct sta_rec_ht *)tlv;
9586c92544dSBjoern A. Zeeb 	ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
9596c92544dSBjoern A. Zeeb }
9606c92544dSBjoern A. Zeeb 
9616c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_vht_tlv(struct sk_buff * skb,struct ieee80211_sta * sta)9626c92544dSBjoern A. Zeeb mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
9636c92544dSBjoern A. Zeeb {
9646c92544dSBjoern A. Zeeb 	struct sta_rec_vht *vht;
9656c92544dSBjoern A. Zeeb 	struct tlv *tlv;
9666c92544dSBjoern A. Zeeb 
9676c92544dSBjoern A. Zeeb 	if (!sta->deflink.vht_cap.vht_supported)
9686c92544dSBjoern A. Zeeb 		return;
9696c92544dSBjoern A. Zeeb 
9706c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
9716c92544dSBjoern A. Zeeb 
9726c92544dSBjoern A. Zeeb 	vht = (struct sta_rec_vht *)tlv;
9736c92544dSBjoern A. Zeeb 	vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
9746c92544dSBjoern A. Zeeb 	vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
9756c92544dSBjoern A. Zeeb 	vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
9766c92544dSBjoern A. Zeeb }
9776c92544dSBjoern A. Zeeb 
9786c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)9796c92544dSBjoern A. Zeeb mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
9806c92544dSBjoern A. Zeeb 			 struct ieee80211_vif *vif, struct ieee80211_sta *sta)
9816c92544dSBjoern A. Zeeb {
9826c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
9836c92544dSBjoern A. Zeeb 	struct sta_rec_amsdu *amsdu;
9846c92544dSBjoern A. Zeeb 	struct tlv *tlv;
9856c92544dSBjoern A. Zeeb 
9866c92544dSBjoern A. Zeeb 	if (vif->type != NL80211_IFTYPE_STATION &&
9876c92544dSBjoern A. Zeeb 	    vif->type != NL80211_IFTYPE_AP)
9886c92544dSBjoern A. Zeeb 		return;
9896c92544dSBjoern A. Zeeb 
9906c92544dSBjoern A. Zeeb 	if (!sta->deflink.agg.max_amsdu_len)
9916c92544dSBjoern A. Zeeb 	    return;
9926c92544dSBjoern A. Zeeb 
9936c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
9946c92544dSBjoern A. Zeeb 	amsdu = (struct sta_rec_amsdu *)tlv;
9956c92544dSBjoern A. Zeeb 	amsdu->max_amsdu_num = 8;
9966c92544dSBjoern A. Zeeb 	amsdu->amsdu_en = true;
9976c92544dSBjoern A. Zeeb 	msta->wcid.amsdu = true;
9986c92544dSBjoern A. Zeeb 
9996c92544dSBjoern A. Zeeb 	switch (sta->deflink.agg.max_amsdu_len) {
10006c92544dSBjoern A. Zeeb 	case IEEE80211_MAX_MPDU_LEN_VHT_11454:
10016c92544dSBjoern A. Zeeb 		if (!is_mt7915(&dev->mt76)) {
10026c92544dSBjoern A. Zeeb 			amsdu->max_mpdu_size =
10036c92544dSBjoern A. Zeeb 				IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
10046c92544dSBjoern A. Zeeb 			return;
10056c92544dSBjoern A. Zeeb 		}
10066c92544dSBjoern A. Zeeb 		fallthrough;
10076c92544dSBjoern A. Zeeb 	case IEEE80211_MAX_MPDU_LEN_HT_7935:
10086c92544dSBjoern A. Zeeb 	case IEEE80211_MAX_MPDU_LEN_VHT_7991:
10096c92544dSBjoern A. Zeeb 		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
10106c92544dSBjoern A. Zeeb 		return;
10116c92544dSBjoern A. Zeeb 	default:
10126c92544dSBjoern A. Zeeb 		amsdu->max_mpdu_size = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
10136c92544dSBjoern A. Zeeb 		return;
10146c92544dSBjoern A. Zeeb 	}
10156c92544dSBjoern A. Zeeb }
10166c92544dSBjoern A. Zeeb 
10176c92544dSBjoern A. Zeeb static int
mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)10186c92544dSBjoern A. Zeeb mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
10196c92544dSBjoern A. Zeeb 			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
10206c92544dSBjoern A. Zeeb {
10216c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
10226c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta;
10236c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
10246c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid;
10256c92544dSBjoern A. Zeeb 	struct tlv *tlv;
10266c92544dSBjoern A. Zeeb 
10276c92544dSBjoern A. Zeeb 	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
10286c92544dSBjoern A. Zeeb 	wcid = sta ? &msta->wcid : NULL;
10296c92544dSBjoern A. Zeeb 
10306c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
10316c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
10326c92544dSBjoern A. Zeeb 						  WTBL_RESET_AND_SET, tlv,
10336c92544dSBjoern A. Zeeb 						  &skb);
10346c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
10356c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
10366c92544dSBjoern A. Zeeb 
10376c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_generic_tlv(&dev->mt76, skb, vif, sta, tlv,
10386c92544dSBjoern A. Zeeb 					 wtbl_hdr);
10396c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
10406c92544dSBjoern A. Zeeb 	if (sta)
10416c92544dSBjoern A. Zeeb 		mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
10426c92544dSBjoern A. Zeeb 					    wtbl_hdr, mvif->cap.ht_ldpc,
10436c92544dSBjoern A. Zeeb 					    mvif->cap.vht_ldpc);
10446c92544dSBjoern A. Zeeb 
10456c92544dSBjoern A. Zeeb 	return 0;
10466c92544dSBjoern A. Zeeb }
10476c92544dSBjoern A. Zeeb 
10486c92544dSBjoern A. Zeeb static inline bool
mt7915_is_ebf_supported(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool bfee)10496c92544dSBjoern A. Zeeb mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
10506c92544dSBjoern A. Zeeb 			struct ieee80211_sta *sta, bool bfee)
10516c92544dSBjoern A. Zeeb {
10526c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1053*8ba4d145SBjoern A. Zeeb 	int sts = hweight16(phy->mt76->chainmask);
10546c92544dSBjoern A. Zeeb 
10556c92544dSBjoern A. Zeeb 	if (vif->type != NL80211_IFTYPE_STATION &&
10566c92544dSBjoern A. Zeeb 	    vif->type != NL80211_IFTYPE_AP)
10576c92544dSBjoern A. Zeeb 		return false;
10586c92544dSBjoern A. Zeeb 
1059*8ba4d145SBjoern A. Zeeb 	if (!bfee && sts < 2)
10606c92544dSBjoern A. Zeeb 		return false;
10616c92544dSBjoern A. Zeeb 
10626c92544dSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he) {
10636c92544dSBjoern A. Zeeb 		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
10646c92544dSBjoern A. Zeeb 
10656c92544dSBjoern A. Zeeb 		if (bfee)
10666c92544dSBjoern A. Zeeb 			return mvif->cap.he_su_ebfee &&
10676c92544dSBjoern A. Zeeb 			       HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
10686c92544dSBjoern A. Zeeb 		else
10696c92544dSBjoern A. Zeeb 			return mvif->cap.he_su_ebfer &&
10706c92544dSBjoern A. Zeeb 			       HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
10716c92544dSBjoern A. Zeeb 	}
10726c92544dSBjoern A. Zeeb 
10736c92544dSBjoern A. Zeeb 	if (sta->deflink.vht_cap.vht_supported) {
10746c92544dSBjoern A. Zeeb 		u32 cap = sta->deflink.vht_cap.cap;
10756c92544dSBjoern A. Zeeb 
10766c92544dSBjoern A. Zeeb 		if (bfee)
10776c92544dSBjoern A. Zeeb 			return mvif->cap.vht_su_ebfee &&
10786c92544dSBjoern A. Zeeb 			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
10796c92544dSBjoern A. Zeeb 		else
10806c92544dSBjoern A. Zeeb 			return mvif->cap.vht_su_ebfer &&
10816c92544dSBjoern A. Zeeb 			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
10826c92544dSBjoern A. Zeeb 	}
10836c92544dSBjoern A. Zeeb 
10846c92544dSBjoern A. Zeeb 	return false;
10856c92544dSBjoern A. Zeeb }
10866c92544dSBjoern A. Zeeb 
10876c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_sounding_rate(struct sta_rec_bf * bf)10886c92544dSBjoern A. Zeeb mt7915_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
10896c92544dSBjoern A. Zeeb {
10906c92544dSBjoern A. Zeeb 	bf->sounding_phy = MT_PHY_TYPE_OFDM;
10916c92544dSBjoern A. Zeeb 	bf->ndp_rate = 0;				/* mcs0 */
10926c92544dSBjoern A. Zeeb 	bf->ndpa_rate = MT7915_CFEND_RATE_DEFAULT;	/* ofdm 24m */
10936c92544dSBjoern A. Zeeb 	bf->rept_poll_rate = MT7915_CFEND_RATE_DEFAULT;	/* ofdm 24m */
10946c92544dSBjoern A. Zeeb }
10956c92544dSBjoern A. Zeeb 
10966c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_bfer_ht(struct ieee80211_sta * sta,struct mt7915_phy * phy,struct sta_rec_bf * bf)10976c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
10986c92544dSBjoern A. Zeeb 		       struct sta_rec_bf *bf)
10996c92544dSBjoern A. Zeeb {
11006c92544dSBjoern A. Zeeb 	struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
11016c92544dSBjoern A. Zeeb 	u8 n = 0;
11026c92544dSBjoern A. Zeeb 
11036c92544dSBjoern A. Zeeb 	bf->tx_mode = MT_PHY_TYPE_HT;
11046c92544dSBjoern A. Zeeb 
11056c92544dSBjoern A. Zeeb 	if ((mcs->tx_params & IEEE80211_HT_MCS_TX_RX_DIFF) &&
11066c92544dSBjoern A. Zeeb 	    (mcs->tx_params & IEEE80211_HT_MCS_TX_DEFINED))
11076c92544dSBjoern A. Zeeb 		n = FIELD_GET(IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK,
11086c92544dSBjoern A. Zeeb 			      mcs->tx_params);
11096c92544dSBjoern A. Zeeb 	else if (mcs->rx_mask[3])
11106c92544dSBjoern A. Zeeb 		n = 3;
11116c92544dSBjoern A. Zeeb 	else if (mcs->rx_mask[2])
11126c92544dSBjoern A. Zeeb 		n = 2;
11136c92544dSBjoern A. Zeeb 	else if (mcs->rx_mask[1])
11146c92544dSBjoern A. Zeeb 		n = 1;
11156c92544dSBjoern A. Zeeb 
11166c92544dSBjoern A. Zeeb 	bf->nrow = hweight8(phy->mt76->chainmask) - 1;
11176c92544dSBjoern A. Zeeb 	bf->ncol = min_t(u8, bf->nrow, n);
11186c92544dSBjoern A. Zeeb 	bf->ibf_ncol = n;
11196c92544dSBjoern A. Zeeb }
11206c92544dSBjoern A. Zeeb 
11216c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_bfer_vht(struct ieee80211_sta * sta,struct mt7915_phy * phy,struct sta_rec_bf * bf,bool explicit)11226c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
11236c92544dSBjoern A. Zeeb 			struct sta_rec_bf *bf, bool explicit)
11246c92544dSBjoern A. Zeeb {
11256c92544dSBjoern A. Zeeb 	struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
11266c92544dSBjoern A. Zeeb 	struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
11276c92544dSBjoern A. Zeeb 	u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
11286c92544dSBjoern A. Zeeb 	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
11296c92544dSBjoern A. Zeeb 	u8 tx_ant = hweight8(phy->mt76->chainmask) - 1;
11306c92544dSBjoern A. Zeeb 
11316c92544dSBjoern A. Zeeb 	bf->tx_mode = MT_PHY_TYPE_VHT;
11326c92544dSBjoern A. Zeeb 
11336c92544dSBjoern A. Zeeb 	if (explicit) {
11346c92544dSBjoern A. Zeeb 		u8 sts, snd_dim;
11356c92544dSBjoern A. Zeeb 
11366c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_sounding_rate(bf);
11376c92544dSBjoern A. Zeeb 
11386c92544dSBjoern A. Zeeb 		sts = FIELD_GET(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK,
11396c92544dSBjoern A. Zeeb 				pc->cap);
11406c92544dSBjoern A. Zeeb 		snd_dim = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
11416c92544dSBjoern A. Zeeb 				    vc->cap);
11426c92544dSBjoern A. Zeeb 		bf->nrow = min_t(u8, min_t(u8, snd_dim, sts), tx_ant);
11436c92544dSBjoern A. Zeeb 		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
11446c92544dSBjoern A. Zeeb 		bf->ibf_ncol = bf->ncol;
11456c92544dSBjoern A. Zeeb 
11466c92544dSBjoern A. Zeeb 		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
11476c92544dSBjoern A. Zeeb 			bf->nrow = 1;
11486c92544dSBjoern A. Zeeb 	} else {
11496c92544dSBjoern A. Zeeb 		bf->nrow = tx_ant;
11506c92544dSBjoern A. Zeeb 		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
11516c92544dSBjoern A. Zeeb 		bf->ibf_ncol = nss_mcs;
11526c92544dSBjoern A. Zeeb 
11536c92544dSBjoern A. Zeeb 		if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
11546c92544dSBjoern A. Zeeb 			bf->ibf_nrow = 1;
11556c92544dSBjoern A. Zeeb 	}
11566c92544dSBjoern A. Zeeb }
11576c92544dSBjoern A. Zeeb 
11586c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_bfer_he(struct ieee80211_sta * sta,struct ieee80211_vif * vif,struct mt7915_phy * phy,struct sta_rec_bf * bf)11596c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
11606c92544dSBjoern A. Zeeb 		       struct mt7915_phy *phy, struct sta_rec_bf *bf)
11616c92544dSBjoern A. Zeeb {
11626c92544dSBjoern A. Zeeb 	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
11636c92544dSBjoern A. Zeeb 	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
11646c92544dSBjoern A. Zeeb 	const struct ieee80211_sta_he_cap *vc =
11656c92544dSBjoern A. Zeeb 		mt76_connac_get_he_phy_cap(phy->mt76, vif);
11666c92544dSBjoern A. Zeeb 	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
11676c92544dSBjoern A. Zeeb 	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
11686c92544dSBjoern A. Zeeb 	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
11696c92544dSBjoern A. Zeeb 	u8 snd_dim, sts;
11706c92544dSBjoern A. Zeeb 
11716c92544dSBjoern A. Zeeb 	bf->tx_mode = MT_PHY_TYPE_HE_SU;
11726c92544dSBjoern A. Zeeb 
11736c92544dSBjoern A. Zeeb 	mt7915_mcu_sta_sounding_rate(bf);
11746c92544dSBjoern A. Zeeb 
11756c92544dSBjoern A. Zeeb 	bf->trigger_su = HE_PHY(CAP6_TRIG_SU_BEAMFORMING_FB,
11766c92544dSBjoern A. Zeeb 				pe->phy_cap_info[6]);
11776c92544dSBjoern A. Zeeb 	bf->trigger_mu = HE_PHY(CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB,
11786c92544dSBjoern A. Zeeb 				pe->phy_cap_info[6]);
11796c92544dSBjoern A. Zeeb 	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
11806c92544dSBjoern A. Zeeb 			 ve->phy_cap_info[5]);
11816c92544dSBjoern A. Zeeb 	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK,
11826c92544dSBjoern A. Zeeb 		     pe->phy_cap_info[4]);
11836c92544dSBjoern A. Zeeb 	bf->nrow = min_t(u8, snd_dim, sts);
11846c92544dSBjoern A. Zeeb 	bf->ncol = min_t(u8, nss_mcs, bf->nrow);
11856c92544dSBjoern A. Zeeb 	bf->ibf_ncol = bf->ncol;
11866c92544dSBjoern A. Zeeb 
11876c92544dSBjoern A. Zeeb 	if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
11886c92544dSBjoern A. Zeeb 		return;
11896c92544dSBjoern A. Zeeb 
11906c92544dSBjoern A. Zeeb 	/* go over for 160MHz and 80p80 */
11916c92544dSBjoern A. Zeeb 	if (pe->phy_cap_info[0] &
11926c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) {
11936c92544dSBjoern A. Zeeb 		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_160);
11946c92544dSBjoern A. Zeeb 		nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
11956c92544dSBjoern A. Zeeb 
1196cbb3ec25SBjoern A. Zeeb 		bf->ncol_gt_bw80 = nss_mcs;
11976c92544dSBjoern A. Zeeb 	}
11986c92544dSBjoern A. Zeeb 
11996c92544dSBjoern A. Zeeb 	if (pe->phy_cap_info[0] &
12006c92544dSBjoern A. Zeeb 	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
12016c92544dSBjoern A. Zeeb 		mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80p80);
12026c92544dSBjoern A. Zeeb 		nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
12036c92544dSBjoern A. Zeeb 
1204cbb3ec25SBjoern A. Zeeb 		if (bf->ncol_gt_bw80)
1205cbb3ec25SBjoern A. Zeeb 			bf->ncol_gt_bw80 = min_t(u8, bf->ncol_gt_bw80, nss_mcs);
12066c92544dSBjoern A. Zeeb 		else
1207cbb3ec25SBjoern A. Zeeb 			bf->ncol_gt_bw80 = nss_mcs;
12086c92544dSBjoern A. Zeeb 	}
12096c92544dSBjoern A. Zeeb 
12106c92544dSBjoern A. Zeeb 	snd_dim = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK,
12116c92544dSBjoern A. Zeeb 			 ve->phy_cap_info[5]);
12126c92544dSBjoern A. Zeeb 	sts = HE_PHY(CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK,
12136c92544dSBjoern A. Zeeb 		     pe->phy_cap_info[4]);
12146c92544dSBjoern A. Zeeb 
1215cbb3ec25SBjoern A. Zeeb 	bf->nrow_gt_bw80 = min_t(int, snd_dim, sts);
12166c92544dSBjoern A. Zeeb }
12176c92544dSBjoern A. Zeeb 
12186c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_bfer_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)12196c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
12206c92544dSBjoern A. Zeeb 			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
12216c92544dSBjoern A. Zeeb {
12226c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
12236c92544dSBjoern A. Zeeb 	struct mt7915_phy *phy = mvif->phy;
12246c92544dSBjoern A. Zeeb 	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
12256c92544dSBjoern A. Zeeb 	struct sta_rec_bf *bf;
12266c92544dSBjoern A. Zeeb 	struct tlv *tlv;
1227*8ba4d145SBjoern A. Zeeb 	static const u8 matrix[4][4] = {
12286c92544dSBjoern A. Zeeb 		{0, 0, 0, 0},
12296c92544dSBjoern A. Zeeb 		{1, 1, 0, 0},	/* 2x1, 2x2, 2x3, 2x4 */
12306c92544dSBjoern A. Zeeb 		{2, 4, 4, 0},	/* 3x1, 3x2, 3x3, 3x4 */
12316c92544dSBjoern A. Zeeb 		{3, 5, 6, 0}	/* 4x1, 4x2, 4x3, 4x4 */
12326c92544dSBjoern A. Zeeb 	};
12336c92544dSBjoern A. Zeeb 	bool ebf;
12346c92544dSBjoern A. Zeeb 
12356c92544dSBjoern A. Zeeb 	if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
12366c92544dSBjoern A. Zeeb 		return;
12376c92544dSBjoern A. Zeeb 
12386c92544dSBjoern A. Zeeb 	ebf = mt7915_is_ebf_supported(phy, vif, sta, false);
12396c92544dSBjoern A. Zeeb 	if (!ebf && !dev->ibf)
12406c92544dSBjoern A. Zeeb 		return;
12416c92544dSBjoern A. Zeeb 
12426c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
12436c92544dSBjoern A. Zeeb 	bf = (struct sta_rec_bf *)tlv;
12446c92544dSBjoern A. Zeeb 
12456c92544dSBjoern A. Zeeb 	/* he: eBF only, in accordance with spec
12466c92544dSBjoern A. Zeeb 	 * vht: support eBF and iBF
12476c92544dSBjoern A. Zeeb 	 * ht: iBF only, since mac80211 lacks of eBF support
12486c92544dSBjoern A. Zeeb 	 */
12496c92544dSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he && ebf)
12506c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
12516c92544dSBjoern A. Zeeb 	else if (sta->deflink.vht_cap.vht_supported)
12526c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
12536c92544dSBjoern A. Zeeb 	else if (sta->deflink.ht_cap.ht_supported)
12546c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_bfer_ht(sta, phy, bf);
12556c92544dSBjoern A. Zeeb 	else
12566c92544dSBjoern A. Zeeb 		return;
12576c92544dSBjoern A. Zeeb 
12586c92544dSBjoern A. Zeeb 	bf->bf_cap = ebf ? ebf : dev->ibf << 1;
12596c92544dSBjoern A. Zeeb 	bf->bw = sta->deflink.bandwidth;
12606c92544dSBjoern A. Zeeb 	bf->ibf_dbw = sta->deflink.bandwidth;
12616c92544dSBjoern A. Zeeb 	bf->ibf_nrow = tx_ant;
12626c92544dSBjoern A. Zeeb 
12636c92544dSBjoern A. Zeeb 	if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
12646c92544dSBjoern A. Zeeb 		bf->ibf_timeout = 0x48;
12656c92544dSBjoern A. Zeeb 	else
12666c92544dSBjoern A. Zeeb 		bf->ibf_timeout = 0x18;
12676c92544dSBjoern A. Zeeb 
12686c92544dSBjoern A. Zeeb 	if (ebf && bf->nrow != tx_ant)
12696c92544dSBjoern A. Zeeb 		bf->mem_20m = matrix[tx_ant][bf->ncol];
12706c92544dSBjoern A. Zeeb 	else
12716c92544dSBjoern A. Zeeb 		bf->mem_20m = matrix[bf->nrow][bf->ncol];
12726c92544dSBjoern A. Zeeb 
12736c92544dSBjoern A. Zeeb 	switch (sta->deflink.bandwidth) {
12746c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_160:
12756c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_80:
12766c92544dSBjoern A. Zeeb 		bf->mem_total = bf->mem_20m * 2;
12776c92544dSBjoern A. Zeeb 		break;
12786c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_40:
12796c92544dSBjoern A. Zeeb 		bf->mem_total = bf->mem_20m;
12806c92544dSBjoern A. Zeeb 		break;
12816c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_20:
12826c92544dSBjoern A. Zeeb 	default:
12836c92544dSBjoern A. Zeeb 		break;
12846c92544dSBjoern A. Zeeb 	}
12856c92544dSBjoern A. Zeeb }
12866c92544dSBjoern A. Zeeb 
12876c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_bfee_tlv(struct mt7915_dev * dev,struct sk_buff * skb,struct ieee80211_vif * vif,struct ieee80211_sta * sta)12886c92544dSBjoern A. Zeeb mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
12896c92544dSBjoern A. Zeeb 			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
12906c92544dSBjoern A. Zeeb {
12916c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
12926c92544dSBjoern A. Zeeb 	struct mt7915_phy *phy = mvif->phy;
12936c92544dSBjoern A. Zeeb 	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
12946c92544dSBjoern A. Zeeb 	struct sta_rec_bfee *bfee;
12956c92544dSBjoern A. Zeeb 	struct tlv *tlv;
12966c92544dSBjoern A. Zeeb 	u8 nrow = 0;
12976c92544dSBjoern A. Zeeb 
12986c92544dSBjoern A. Zeeb 	if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
12996c92544dSBjoern A. Zeeb 		return;
13006c92544dSBjoern A. Zeeb 
13016c92544dSBjoern A. Zeeb 	if (!mt7915_is_ebf_supported(phy, vif, sta, true))
13026c92544dSBjoern A. Zeeb 		return;
13036c92544dSBjoern A. Zeeb 
13046c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
13056c92544dSBjoern A. Zeeb 	bfee = (struct sta_rec_bfee *)tlv;
13066c92544dSBjoern A. Zeeb 
13076c92544dSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he) {
13086c92544dSBjoern A. Zeeb 		struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
13096c92544dSBjoern A. Zeeb 
13106c92544dSBjoern A. Zeeb 		nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
13116c92544dSBjoern A. Zeeb 			      pe->phy_cap_info[5]);
13126c92544dSBjoern A. Zeeb 	} else if (sta->deflink.vht_cap.vht_supported) {
13136c92544dSBjoern A. Zeeb 		struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
13146c92544dSBjoern A. Zeeb 
13156c92544dSBjoern A. Zeeb 		nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
13166c92544dSBjoern A. Zeeb 				 pc->cap);
13176c92544dSBjoern A. Zeeb 	}
13186c92544dSBjoern A. Zeeb 
13196c92544dSBjoern A. Zeeb 	/* reply with identity matrix to avoid 2x2 BF negative gain */
13206c92544dSBjoern A. Zeeb 	bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
13216c92544dSBjoern A. Zeeb }
13226c92544dSBjoern A. Zeeb 
13236c92544dSBjoern A. Zeeb static enum mcu_mmps_mode
mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)13246c92544dSBjoern A. Zeeb mt7915_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
13256c92544dSBjoern A. Zeeb {
13266c92544dSBjoern A. Zeeb 	switch (smps) {
13276c92544dSBjoern A. Zeeb 	case IEEE80211_SMPS_OFF:
13286c92544dSBjoern A. Zeeb 		return MCU_MMPS_DISABLE;
13296c92544dSBjoern A. Zeeb 	case IEEE80211_SMPS_STATIC:
13306c92544dSBjoern A. Zeeb 		return MCU_MMPS_STATIC;
13316c92544dSBjoern A. Zeeb 	case IEEE80211_SMPS_DYNAMIC:
13326c92544dSBjoern A. Zeeb 		return MCU_MMPS_DYNAMIC;
13336c92544dSBjoern A. Zeeb 	default:
13346c92544dSBjoern A. Zeeb 		return MCU_MMPS_DISABLE;
13356c92544dSBjoern A. Zeeb 	}
13366c92544dSBjoern A. Zeeb }
13376c92544dSBjoern A. Zeeb 
mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,void * data,u32 field)13386c92544dSBjoern A. Zeeb int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
13396c92544dSBjoern A. Zeeb 				   struct ieee80211_vif *vif,
13406c92544dSBjoern A. Zeeb 				   struct ieee80211_sta *sta,
13416c92544dSBjoern A. Zeeb 				   void *data, u32 field)
13426c92544dSBjoern A. Zeeb {
13436c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
13446c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
13456c92544dSBjoern A. Zeeb 	struct sta_phy *phy = data;
13466c92544dSBjoern A. Zeeb 	struct sta_rec_ra_fixed *ra;
13476c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
13486c92544dSBjoern A. Zeeb 	struct tlv *tlv;
13496c92544dSBjoern A. Zeeb 
13506c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
13516c92544dSBjoern A. Zeeb 					    &msta->wcid);
13526c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
13536c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
13546c92544dSBjoern A. Zeeb 
13556c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
13566c92544dSBjoern A. Zeeb 	ra = (struct sta_rec_ra_fixed *)tlv;
13576c92544dSBjoern A. Zeeb 
13586c92544dSBjoern A. Zeeb 	switch (field) {
13596c92544dSBjoern A. Zeeb 	case RATE_PARAM_AUTO:
13606c92544dSBjoern A. Zeeb 		break;
13616c92544dSBjoern A. Zeeb 	case RATE_PARAM_FIXED:
13626c92544dSBjoern A. Zeeb 	case RATE_PARAM_FIXED_MCS:
13636c92544dSBjoern A. Zeeb 	case RATE_PARAM_FIXED_GI:
13646c92544dSBjoern A. Zeeb 	case RATE_PARAM_FIXED_HE_LTF:
13656c92544dSBjoern A. Zeeb 		if (phy)
13666c92544dSBjoern A. Zeeb 			ra->phy = *phy;
13676c92544dSBjoern A. Zeeb 		break;
13686c92544dSBjoern A. Zeeb 	case RATE_PARAM_MMPS_UPDATE:
13696c92544dSBjoern A. Zeeb 		ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
13706c92544dSBjoern A. Zeeb 		break;
1371cbb3ec25SBjoern A. Zeeb 	case RATE_PARAM_SPE_UPDATE:
1372cbb3ec25SBjoern A. Zeeb 		ra->spe_idx = *(u8 *)data;
1373cbb3ec25SBjoern A. Zeeb 		break;
13746c92544dSBjoern A. Zeeb 	default:
13756c92544dSBjoern A. Zeeb 		break;
13766c92544dSBjoern A. Zeeb 	}
13776c92544dSBjoern A. Zeeb 	ra->field = cpu_to_le32(field);
13786c92544dSBjoern A. Zeeb 
13796c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
13806c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
13816c92544dSBjoern A. Zeeb }
13826c92544dSBjoern A. Zeeb 
mt7915_mcu_add_smps(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)13836c92544dSBjoern A. Zeeb int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
13846c92544dSBjoern A. Zeeb 			struct ieee80211_sta *sta)
13856c92544dSBjoern A. Zeeb {
13866c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
13876c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
13886c92544dSBjoern A. Zeeb 	struct wtbl_req_hdr *wtbl_hdr;
13896c92544dSBjoern A. Zeeb 	struct tlv *sta_wtbl;
13906c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
13916c92544dSBjoern A. Zeeb 	int ret;
13926c92544dSBjoern A. Zeeb 
13936c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
13946c92544dSBjoern A. Zeeb 					    &msta->wcid);
13956c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
13966c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
13976c92544dSBjoern A. Zeeb 
13986c92544dSBjoern A. Zeeb 	sta_wtbl = mt76_connac_mcu_add_tlv(skb, STA_REC_WTBL,
13996c92544dSBjoern A. Zeeb 					   sizeof(struct tlv));
14006c92544dSBjoern A. Zeeb 	wtbl_hdr = mt76_connac_mcu_alloc_wtbl_req(&dev->mt76, &msta->wcid,
14016c92544dSBjoern A. Zeeb 						  WTBL_SET, sta_wtbl, &skb);
14026c92544dSBjoern A. Zeeb 	if (IS_ERR(wtbl_hdr))
14036c92544dSBjoern A. Zeeb 		return PTR_ERR(wtbl_hdr);
14046c92544dSBjoern A. Zeeb 
14056c92544dSBjoern A. Zeeb 	mt76_connac_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr);
14066c92544dSBjoern A. Zeeb 
14076c92544dSBjoern A. Zeeb 	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
14086c92544dSBjoern A. Zeeb 				    MCU_EXT_CMD(STA_REC_UPDATE), true);
14096c92544dSBjoern A. Zeeb 	if (ret)
14106c92544dSBjoern A. Zeeb 		return ret;
14116c92544dSBjoern A. Zeeb 
14126c92544dSBjoern A. Zeeb 	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, NULL,
14136c92544dSBjoern A. Zeeb 					      RATE_PARAM_MMPS_UPDATE);
14146c92544dSBjoern A. Zeeb }
14156c92544dSBjoern A. Zeeb 
14166c92544dSBjoern A. Zeeb static int
mt7915_mcu_set_spe_idx(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)1417cbb3ec25SBjoern A. Zeeb mt7915_mcu_set_spe_idx(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1418cbb3ec25SBjoern A. Zeeb 		       struct ieee80211_sta *sta)
1419cbb3ec25SBjoern A. Zeeb {
1420cbb3ec25SBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1421cbb3ec25SBjoern A. Zeeb 	struct mt76_phy *mphy = mvif->phy->mt76;
1422cbb3ec25SBjoern A. Zeeb 	u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
1423cbb3ec25SBjoern A. Zeeb 
1424cbb3ec25SBjoern A. Zeeb 	return mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &spe_idx,
1425cbb3ec25SBjoern A. Zeeb 					      RATE_PARAM_SPE_UPDATE);
1426cbb3ec25SBjoern A. Zeeb }
1427cbb3ec25SBjoern A. Zeeb 
1428cbb3ec25SBjoern A. Zeeb static int
mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)14296c92544dSBjoern A. Zeeb mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
14306c92544dSBjoern A. Zeeb 			       struct ieee80211_vif *vif,
14316c92544dSBjoern A. Zeeb 			       struct ieee80211_sta *sta)
14326c92544dSBjoern A. Zeeb {
14336c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
14346c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
14356c92544dSBjoern A. Zeeb 	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
14366c92544dSBjoern A. Zeeb 	enum nl80211_band band = chandef->chan->band;
14376c92544dSBjoern A. Zeeb 	struct sta_phy phy = {};
14386c92544dSBjoern A. Zeeb 	int ret, nrates = 0;
14396c92544dSBjoern A. Zeeb 
14406c92544dSBjoern A. Zeeb #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he)			\
14416c92544dSBjoern A. Zeeb 	do {									\
14426c92544dSBjoern A. Zeeb 		u8 i, gi = mask->control[band]._gi;				\
14436c92544dSBjoern A. Zeeb 		gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;		\
14446c92544dSBjoern A. Zeeb 		for (i = 0; i <= sta->deflink.bandwidth; i++) {			\
14456c92544dSBjoern A. Zeeb 			phy.sgi |= gi << (i << (_he));				\
14466c92544dSBjoern A. Zeeb 			phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\
14476c92544dSBjoern A. Zeeb 		}								\
14486c92544dSBjoern A. Zeeb 		for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) {	\
14496c92544dSBjoern A. Zeeb 			if (!mask->control[band]._mcs[i])			\
14506c92544dSBjoern A. Zeeb 				continue;					\
14516c92544dSBjoern A. Zeeb 			nrates += hweight16(mask->control[band]._mcs[i]);	\
14526c92544dSBjoern A. Zeeb 			phy.mcs = ffs(mask->control[band]._mcs[i]) - 1;		\
14536c92544dSBjoern A. Zeeb 			if (_ht)						\
14546c92544dSBjoern A. Zeeb 				phy.mcs += 8 * i;				\
14556c92544dSBjoern A. Zeeb 		}								\
14566c92544dSBjoern A. Zeeb 	} while (0)
14576c92544dSBjoern A. Zeeb 
14586c92544dSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he) {
14596c92544dSBjoern A. Zeeb 		__sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
14606c92544dSBjoern A. Zeeb 	} else if (sta->deflink.vht_cap.vht_supported) {
14616c92544dSBjoern A. Zeeb 		__sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
14626c92544dSBjoern A. Zeeb 	} else if (sta->deflink.ht_cap.ht_supported) {
14636c92544dSBjoern A. Zeeb 		__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
14646c92544dSBjoern A. Zeeb 	} else {
14656c92544dSBjoern A. Zeeb 		nrates = hweight32(mask->control[band].legacy);
14666c92544dSBjoern A. Zeeb 		phy.mcs = ffs(mask->control[band].legacy) - 1;
14676c92544dSBjoern A. Zeeb 	}
14686c92544dSBjoern A. Zeeb #undef __sta_phy_bitrate_mask_check
14696c92544dSBjoern A. Zeeb 
14706c92544dSBjoern A. Zeeb 	/* fall back to auto rate control */
14716c92544dSBjoern A. Zeeb 	if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
14726c92544dSBjoern A. Zeeb 	    mask->control[band].he_gi == GENMASK(7, 0) &&
14736c92544dSBjoern A. Zeeb 	    mask->control[band].he_ltf == GENMASK(7, 0) &&
14746c92544dSBjoern A. Zeeb 	    nrates != 1)
14756c92544dSBjoern A. Zeeb 		return 0;
14766c92544dSBjoern A. Zeeb 
14776c92544dSBjoern A. Zeeb 	/* fixed single rate */
14786c92544dSBjoern A. Zeeb 	if (nrates == 1) {
14796c92544dSBjoern A. Zeeb 		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
14806c92544dSBjoern A. Zeeb 						     RATE_PARAM_FIXED_MCS);
14816c92544dSBjoern A. Zeeb 		if (ret)
14826c92544dSBjoern A. Zeeb 			return ret;
14836c92544dSBjoern A. Zeeb 	}
14846c92544dSBjoern A. Zeeb 
14856c92544dSBjoern A. Zeeb 	/* fixed GI */
14866c92544dSBjoern A. Zeeb 	if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
14876c92544dSBjoern A. Zeeb 	    mask->control[band].he_gi != GENMASK(7, 0)) {
14886c92544dSBjoern A. Zeeb 		struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
14896c92544dSBjoern A. Zeeb 		u32 addr;
14906c92544dSBjoern A. Zeeb 
14916c92544dSBjoern A. Zeeb 		/* firmware updates only TXCMD but doesn't take WTBL into
14926c92544dSBjoern A. Zeeb 		 * account, so driver should update here to reflect the
14936c92544dSBjoern A. Zeeb 		 * actual txrate hardware sends out.
14946c92544dSBjoern A. Zeeb 		 */
14956c92544dSBjoern A. Zeeb 		addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
14966c92544dSBjoern A. Zeeb 		if (sta->deflink.he_cap.has_he)
14976c92544dSBjoern A. Zeeb 			mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
14986c92544dSBjoern A. Zeeb 		else
14996c92544dSBjoern A. Zeeb 			mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
15006c92544dSBjoern A. Zeeb 
15016c92544dSBjoern A. Zeeb 		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
15026c92544dSBjoern A. Zeeb 						     RATE_PARAM_FIXED_GI);
15036c92544dSBjoern A. Zeeb 		if (ret)
15046c92544dSBjoern A. Zeeb 			return ret;
15056c92544dSBjoern A. Zeeb 	}
15066c92544dSBjoern A. Zeeb 
15076c92544dSBjoern A. Zeeb 	/* fixed HE_LTF */
15086c92544dSBjoern A. Zeeb 	if (mask->control[band].he_ltf != GENMASK(7, 0)) {
15096c92544dSBjoern A. Zeeb 		ret = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
15106c92544dSBjoern A. Zeeb 						     RATE_PARAM_FIXED_HE_LTF);
15116c92544dSBjoern A. Zeeb 		if (ret)
15126c92544dSBjoern A. Zeeb 			return ret;
15136c92544dSBjoern A. Zeeb 	}
15146c92544dSBjoern A. Zeeb 
1515cbb3ec25SBjoern A. Zeeb 	return mt7915_mcu_set_spe_idx(dev, vif, sta);
15166c92544dSBjoern A. Zeeb }
15176c92544dSBjoern A. Zeeb 
15186c92544dSBjoern A. Zeeb static void
mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff * skb,struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)15196c92544dSBjoern A. Zeeb mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
15206c92544dSBjoern A. Zeeb 			     struct ieee80211_vif *vif, struct ieee80211_sta *sta)
15216c92544dSBjoern A. Zeeb {
15226c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
15236c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = mvif->phy->mt76;
15246c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &mphy->chandef;
15256c92544dSBjoern A. Zeeb 	struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
15266c92544dSBjoern A. Zeeb 	enum nl80211_band band = chandef->chan->band;
15276c92544dSBjoern A. Zeeb 	struct sta_rec_ra *ra;
15286c92544dSBjoern A. Zeeb 	struct tlv *tlv;
15296c92544dSBjoern A. Zeeb 	u32 supp_rate = sta->deflink.supp_rates[band];
15306c92544dSBjoern A. Zeeb 	u32 cap = sta->wme ? STA_CAP_WMM : 0;
15316c92544dSBjoern A. Zeeb 
15326c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
15336c92544dSBjoern A. Zeeb 	ra = (struct sta_rec_ra *)tlv;
15346c92544dSBjoern A. Zeeb 
15356c92544dSBjoern A. Zeeb 	ra->valid = true;
15366c92544dSBjoern A. Zeeb 	ra->auto_rate = true;
1537*8ba4d145SBjoern A. Zeeb 	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink);
15386c92544dSBjoern A. Zeeb 	ra->channel = chandef->chan->hw_value;
15396c92544dSBjoern A. Zeeb 	ra->bw = sta->deflink.bandwidth;
15406c92544dSBjoern A. Zeeb 	ra->phy.bw = sta->deflink.bandwidth;
15416c92544dSBjoern A. Zeeb 	ra->mmps_mode = mt7915_mcu_get_mmps_mode(sta->deflink.smps_mode);
15426c92544dSBjoern A. Zeeb 
15436c92544dSBjoern A. Zeeb 	if (supp_rate) {
15446c92544dSBjoern A. Zeeb 		supp_rate &= mask->control[band].legacy;
15456c92544dSBjoern A. Zeeb 		ra->rate_len = hweight32(supp_rate);
15466c92544dSBjoern A. Zeeb 
15476c92544dSBjoern A. Zeeb 		if (band == NL80211_BAND_2GHZ) {
15486c92544dSBjoern A. Zeeb 			ra->supp_mode = MODE_CCK;
15496c92544dSBjoern A. Zeeb 			ra->supp_cck_rate = supp_rate & GENMASK(3, 0);
15506c92544dSBjoern A. Zeeb 
15516c92544dSBjoern A. Zeeb 			if (ra->rate_len > 4) {
15526c92544dSBjoern A. Zeeb 				ra->supp_mode |= MODE_OFDM;
15536c92544dSBjoern A. Zeeb 				ra->supp_ofdm_rate = supp_rate >> 4;
15546c92544dSBjoern A. Zeeb 			}
15556c92544dSBjoern A. Zeeb 		} else {
15566c92544dSBjoern A. Zeeb 			ra->supp_mode = MODE_OFDM;
15576c92544dSBjoern A. Zeeb 			ra->supp_ofdm_rate = supp_rate;
15586c92544dSBjoern A. Zeeb 		}
15596c92544dSBjoern A. Zeeb 	}
15606c92544dSBjoern A. Zeeb 
15616c92544dSBjoern A. Zeeb 	if (sta->deflink.ht_cap.ht_supported) {
15626c92544dSBjoern A. Zeeb 		ra->supp_mode |= MODE_HT;
15636c92544dSBjoern A. Zeeb 		ra->af = sta->deflink.ht_cap.ampdu_factor;
15646c92544dSBjoern A. Zeeb 		ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
15656c92544dSBjoern A. Zeeb 
15666c92544dSBjoern A. Zeeb 		cap |= STA_CAP_HT;
15676c92544dSBjoern A. Zeeb 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
15686c92544dSBjoern A. Zeeb 			cap |= STA_CAP_SGI_20;
15696c92544dSBjoern A. Zeeb 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
15706c92544dSBjoern A. Zeeb 			cap |= STA_CAP_SGI_40;
15716c92544dSBjoern A. Zeeb 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
15726c92544dSBjoern A. Zeeb 			cap |= STA_CAP_TX_STBC;
15736c92544dSBjoern A. Zeeb 		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
15746c92544dSBjoern A. Zeeb 			cap |= STA_CAP_RX_STBC;
15756c92544dSBjoern A. Zeeb 		if (mvif->cap.ht_ldpc &&
15766c92544dSBjoern A. Zeeb 		    (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
15776c92544dSBjoern A. Zeeb 			cap |= STA_CAP_LDPC;
15786c92544dSBjoern A. Zeeb 
15796c92544dSBjoern A. Zeeb 		mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
15806c92544dSBjoern A. Zeeb 					  mask->control[band].ht_mcs);
15816c92544dSBjoern A. Zeeb 		ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
15826c92544dSBjoern A. Zeeb 	}
15836c92544dSBjoern A. Zeeb 
15846c92544dSBjoern A. Zeeb 	if (sta->deflink.vht_cap.vht_supported) {
15856c92544dSBjoern A. Zeeb 		u8 af;
15866c92544dSBjoern A. Zeeb 
15876c92544dSBjoern A. Zeeb 		ra->supp_mode |= MODE_VHT;
15886c92544dSBjoern A. Zeeb 		af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
15896c92544dSBjoern A. Zeeb 			       sta->deflink.vht_cap.cap);
15906c92544dSBjoern A. Zeeb 		ra->af = max_t(u8, ra->af, af);
15916c92544dSBjoern A. Zeeb 
15926c92544dSBjoern A. Zeeb 		cap |= STA_CAP_VHT;
15936c92544dSBjoern A. Zeeb 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
15946c92544dSBjoern A. Zeeb 			cap |= STA_CAP_VHT_SGI_80;
15956c92544dSBjoern A. Zeeb 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
15966c92544dSBjoern A. Zeeb 			cap |= STA_CAP_VHT_SGI_160;
15976c92544dSBjoern A. Zeeb 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
15986c92544dSBjoern A. Zeeb 			cap |= STA_CAP_VHT_TX_STBC;
15996c92544dSBjoern A. Zeeb 		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
16006c92544dSBjoern A. Zeeb 			cap |= STA_CAP_VHT_RX_STBC;
16016c92544dSBjoern A. Zeeb 		if (mvif->cap.vht_ldpc &&
16026c92544dSBjoern A. Zeeb 		    (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
16036c92544dSBjoern A. Zeeb 			cap |= STA_CAP_VHT_LDPC;
16046c92544dSBjoern A. Zeeb 
16056c92544dSBjoern A. Zeeb 		mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
16066c92544dSBjoern A. Zeeb 					   mask->control[band].vht_mcs);
16076c92544dSBjoern A. Zeeb 	}
16086c92544dSBjoern A. Zeeb 
16096c92544dSBjoern A. Zeeb 	if (sta->deflink.he_cap.has_he) {
16106c92544dSBjoern A. Zeeb 		ra->supp_mode |= MODE_HE;
16116c92544dSBjoern A. Zeeb 		cap |= STA_CAP_HE;
16126c92544dSBjoern A. Zeeb 
16136c92544dSBjoern A. Zeeb 		if (sta->deflink.he_6ghz_capa.capa)
16146c92544dSBjoern A. Zeeb 			ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
16156c92544dSBjoern A. Zeeb 					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
16166c92544dSBjoern A. Zeeb 	}
16176c92544dSBjoern A. Zeeb 
16186c92544dSBjoern A. Zeeb 	ra->sta_cap = cpu_to_le32(cap);
16196c92544dSBjoern A. Zeeb }
16206c92544dSBjoern A. Zeeb 
mt7915_mcu_add_rate_ctrl(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,bool changed)16216c92544dSBjoern A. Zeeb int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
16226c92544dSBjoern A. Zeeb 			     struct ieee80211_sta *sta, bool changed)
16236c92544dSBjoern A. Zeeb {
16246c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
16256c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
16266c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
16276c92544dSBjoern A. Zeeb 	int ret;
16286c92544dSBjoern A. Zeeb 
16296c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
16306c92544dSBjoern A. Zeeb 					    &msta->wcid);
16316c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
16326c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
16336c92544dSBjoern A. Zeeb 
16346c92544dSBjoern A. Zeeb 	/* firmware rc algorithm refers to sta_rec_he for HE control.
16356c92544dSBjoern A. Zeeb 	 * once dev->rc_work changes the settings driver should also
16366c92544dSBjoern A. Zeeb 	 * update sta_rec_he here.
16376c92544dSBjoern A. Zeeb 	 */
16386c92544dSBjoern A. Zeeb 	if (changed)
16396c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_he_tlv(skb, sta, vif);
16406c92544dSBjoern A. Zeeb 
16416c92544dSBjoern A. Zeeb 	/* sta_rec_ra accommodates BW, NSS and only MCS range format
16426c92544dSBjoern A. Zeeb 	 * i.e 0-{7,8,9} for VHT.
16436c92544dSBjoern A. Zeeb 	 */
16446c92544dSBjoern A. Zeeb 	mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
16456c92544dSBjoern A. Zeeb 
16466c92544dSBjoern A. Zeeb 	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
16476c92544dSBjoern A. Zeeb 				    MCU_EXT_CMD(STA_REC_UPDATE), true);
16486c92544dSBjoern A. Zeeb 	if (ret)
16496c92544dSBjoern A. Zeeb 		return ret;
16506c92544dSBjoern A. Zeeb 
16516c92544dSBjoern A. Zeeb 	/* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE,
16526c92544dSBjoern A. Zeeb 	 * and updates as peer fixed rate parameters, which overrides
16536c92544dSBjoern A. Zeeb 	 * sta_rec_ra and firmware rate control algorithm.
16546c92544dSBjoern A. Zeeb 	 */
16556c92544dSBjoern A. Zeeb 	return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
16566c92544dSBjoern A. Zeeb }
16576c92544dSBjoern A. Zeeb 
16586c92544dSBjoern A. Zeeb static int
mt7915_mcu_add_group(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta)16596c92544dSBjoern A. Zeeb mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
16606c92544dSBjoern A. Zeeb 		     struct ieee80211_sta *sta)
16616c92544dSBjoern A. Zeeb {
16626c92544dSBjoern A. Zeeb #define MT_STA_BSS_GROUP		1
16636c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
16646c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta;
16656c92544dSBjoern A. Zeeb 	struct {
16666c92544dSBjoern A. Zeeb 		__le32 action;
16676c92544dSBjoern A. Zeeb 		u8 wlan_idx_lo;
16686c92544dSBjoern A. Zeeb 		u8 status;
16696c92544dSBjoern A. Zeeb 		u8 wlan_idx_hi;
16706c92544dSBjoern A. Zeeb 		u8 rsv0[5];
16716c92544dSBjoern A. Zeeb 		__le32 val;
16726c92544dSBjoern A. Zeeb 		u8 rsv1[8];
16736c92544dSBjoern A. Zeeb 	} __packed req = {
16746c92544dSBjoern A. Zeeb 		.action = cpu_to_le32(MT_STA_BSS_GROUP),
16756c92544dSBjoern A. Zeeb 		.val = cpu_to_le32(mvif->mt76.idx % 16),
16766c92544dSBjoern A. Zeeb 	};
16776c92544dSBjoern A. Zeeb 
16786c92544dSBjoern A. Zeeb 	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
16796c92544dSBjoern A. Zeeb 	req.wlan_idx_lo = to_wcid_lo(msta->wcid.idx);
16806c92544dSBjoern A. Zeeb 	req.wlan_idx_hi = to_wcid_hi(msta->wcid.idx);
16816c92544dSBjoern A. Zeeb 
16826c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_DRR_CTRL), &req,
16836c92544dSBjoern A. Zeeb 				 sizeof(req), true);
16846c92544dSBjoern A. Zeeb }
16856c92544dSBjoern A. Zeeb 
mt7915_mcu_add_sta(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct ieee80211_sta * sta,int conn_state,bool newly)16866c92544dSBjoern A. Zeeb int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
1687*8ba4d145SBjoern A. Zeeb 		       struct ieee80211_sta *sta, int conn_state, bool newly)
16886c92544dSBjoern A. Zeeb {
16896c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
1690*8ba4d145SBjoern A. Zeeb 	struct ieee80211_link_sta *link_sta;
16916c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta;
16926c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
16936c92544dSBjoern A. Zeeb 	int ret;
16946c92544dSBjoern A. Zeeb 
16956c92544dSBjoern A. Zeeb 	msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
1696*8ba4d145SBjoern A. Zeeb 	link_sta = sta ? &sta->deflink : NULL;
16976c92544dSBjoern A. Zeeb 
16986c92544dSBjoern A. Zeeb 	skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
16996c92544dSBjoern A. Zeeb 					    &msta->wcid);
17006c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
17016c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
17026c92544dSBjoern A. Zeeb 
17036c92544dSBjoern A. Zeeb 	/* starec basic */
1704*8ba4d145SBjoern A. Zeeb 	mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf, link_sta,
1705*8ba4d145SBjoern A. Zeeb 				      conn_state, newly);
17066c92544dSBjoern A. Zeeb 	/* tag order is in accordance with firmware dependency. */
1707*8ba4d145SBjoern A. Zeeb 	if (sta && conn_state != CONN_STATE_DISCONNECT) {
17086c92544dSBjoern A. Zeeb 		/* starec bfer */
17096c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_bfer_tlv(dev, skb, vif, sta);
17106c92544dSBjoern A. Zeeb 		/* starec ht */
17116c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_ht_tlv(skb, sta);
17126c92544dSBjoern A. Zeeb 		/* starec vht */
17136c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_vht_tlv(skb, sta);
17146c92544dSBjoern A. Zeeb 		/* starec uapsd */
17156c92544dSBjoern A. Zeeb 		mt76_connac_mcu_sta_uapsd(skb, vif, sta);
17166c92544dSBjoern A. Zeeb 	}
17176c92544dSBjoern A. Zeeb 
1718*8ba4d145SBjoern A. Zeeb 	if (newly || conn_state != CONN_STATE_DISCONNECT) {
17196c92544dSBjoern A. Zeeb 		ret = mt7915_mcu_sta_wtbl_tlv(dev, skb, vif, sta);
17206c92544dSBjoern A. Zeeb 		if (ret) {
17216c92544dSBjoern A. Zeeb 			dev_kfree_skb(skb);
17226c92544dSBjoern A. Zeeb 			return ret;
17236c92544dSBjoern A. Zeeb 		}
1724*8ba4d145SBjoern A. Zeeb 	}
1725*8ba4d145SBjoern A. Zeeb 
1726*8ba4d145SBjoern A. Zeeb 	if (conn_state == CONN_STATE_DISCONNECT)
1727*8ba4d145SBjoern A. Zeeb 		goto out;
17286c92544dSBjoern A. Zeeb 
17296c92544dSBjoern A. Zeeb 	if (sta) {
17306c92544dSBjoern A. Zeeb 		/* starec amsdu */
17316c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
17326c92544dSBjoern A. Zeeb 		/* starec he */
17336c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_he_tlv(skb, sta, vif);
17346c92544dSBjoern A. Zeeb 		/* starec muru */
17356c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_muru_tlv(dev, skb, sta, vif);
17366c92544dSBjoern A. Zeeb 		/* starec bfee */
17376c92544dSBjoern A. Zeeb 		mt7915_mcu_sta_bfee_tlv(dev, skb, vif, sta);
17386c92544dSBjoern A. Zeeb 	}
17396c92544dSBjoern A. Zeeb 
17406c92544dSBjoern A. Zeeb 	ret = mt7915_mcu_add_group(dev, vif, sta);
17416c92544dSBjoern A. Zeeb 	if (ret) {
17426c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
17436c92544dSBjoern A. Zeeb 		return ret;
17446c92544dSBjoern A. Zeeb 	}
17456c92544dSBjoern A. Zeeb out:
1746cbb3ec25SBjoern A. Zeeb 	ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb);
1747cbb3ec25SBjoern A. Zeeb 	if (ret)
1748cbb3ec25SBjoern A. Zeeb 		return ret;
1749cbb3ec25SBjoern A. Zeeb 
17506c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
17516c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(STA_REC_UPDATE), true);
17526c92544dSBjoern A. Zeeb }
17536c92544dSBjoern A. Zeeb 
mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev * dev)1754cbb3ec25SBjoern A. Zeeb int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev)
1755cbb3ec25SBjoern A. Zeeb {
1756cbb3ec25SBjoern A. Zeeb #ifdef CONFIG_NET_MEDIATEK_SOC_WED
1757cbb3ec25SBjoern A. Zeeb 	struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
1758cbb3ec25SBjoern A. Zeeb 	struct {
1759cbb3ec25SBjoern A. Zeeb 		__le32 args[2];
1760cbb3ec25SBjoern A. Zeeb 	} req = {
1761cbb3ec25SBjoern A. Zeeb 		.args[0] = cpu_to_le32(1),
1762cbb3ec25SBjoern A. Zeeb 		.args[1] = cpu_to_le32(6),
1763cbb3ec25SBjoern A. Zeeb 	};
1764cbb3ec25SBjoern A. Zeeb 
1765cbb3ec25SBjoern A. Zeeb 	return mtk_wed_device_update_msg(wed, MTK_WED_WO_CMD_RXCNT_CTRL,
1766cbb3ec25SBjoern A. Zeeb 					 &req, sizeof(req));
1767cbb3ec25SBjoern A. Zeeb #else
1768cbb3ec25SBjoern A. Zeeb 	return 0;
1769cbb3ec25SBjoern A. Zeeb #endif
1770cbb3ec25SBjoern A. Zeeb }
1771cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_add_dev_info(struct mt7915_phy * phy,struct ieee80211_vif * vif,bool enable)17726c92544dSBjoern A. Zeeb int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
17736c92544dSBjoern A. Zeeb 			    struct ieee80211_vif *vif, bool enable)
17746c92544dSBjoern A. Zeeb {
17756c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
17766c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
17776c92544dSBjoern A. Zeeb 	struct {
17786c92544dSBjoern A. Zeeb 		struct req_hdr {
17796c92544dSBjoern A. Zeeb 			u8 omac_idx;
1780cbb3ec25SBjoern A. Zeeb 			u8 band_idx;
17816c92544dSBjoern A. Zeeb 			__le16 tlv_num;
17826c92544dSBjoern A. Zeeb 			u8 is_tlv_append;
17836c92544dSBjoern A. Zeeb 			u8 rsv[3];
17846c92544dSBjoern A. Zeeb 		} __packed hdr;
17856c92544dSBjoern A. Zeeb 		struct req_tlv {
17866c92544dSBjoern A. Zeeb 			__le16 tag;
17876c92544dSBjoern A. Zeeb 			__le16 len;
17886c92544dSBjoern A. Zeeb 			u8 active;
1789cbb3ec25SBjoern A. Zeeb 			u8 band_idx;
17906c92544dSBjoern A. Zeeb 			u8 omac_addr[ETH_ALEN];
17916c92544dSBjoern A. Zeeb 		} __packed tlv;
17926c92544dSBjoern A. Zeeb 	} data = {
17936c92544dSBjoern A. Zeeb 		.hdr = {
17946c92544dSBjoern A. Zeeb 			.omac_idx = mvif->mt76.omac_idx,
1795cbb3ec25SBjoern A. Zeeb 			.band_idx = mvif->mt76.band_idx,
17966c92544dSBjoern A. Zeeb 			.tlv_num = cpu_to_le16(1),
17976c92544dSBjoern A. Zeeb 			.is_tlv_append = 1,
17986c92544dSBjoern A. Zeeb 		},
17996c92544dSBjoern A. Zeeb 		.tlv = {
18006c92544dSBjoern A. Zeeb 			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
18016c92544dSBjoern A. Zeeb 			.len = cpu_to_le16(sizeof(struct req_tlv)),
18026c92544dSBjoern A. Zeeb 			.active = enable,
1803cbb3ec25SBjoern A. Zeeb 			.band_idx = mvif->mt76.band_idx,
18046c92544dSBjoern A. Zeeb 		},
18056c92544dSBjoern A. Zeeb 	};
18066c92544dSBjoern A. Zeeb 
18076c92544dSBjoern A. Zeeb 	if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
18086c92544dSBjoern A. Zeeb 		return mt7915_mcu_muar_config(phy, vif, false, enable);
18096c92544dSBjoern A. Zeeb 
18106c92544dSBjoern A. Zeeb 	memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
18116c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(DEV_INFO_UPDATE),
18126c92544dSBjoern A. Zeeb 				 &data, sizeof(data), true);
18136c92544dSBjoern A. Zeeb }
18146c92544dSBjoern A. Zeeb 
18156c92544dSBjoern A. Zeeb 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)18166c92544dSBjoern A. Zeeb mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
18176c92544dSBjoern A. Zeeb 			 struct sk_buff *skb, struct bss_info_bcn *bcn,
18186c92544dSBjoern A. Zeeb 			 struct ieee80211_mutable_offsets *offs)
18196c92544dSBjoern A. Zeeb {
18206c92544dSBjoern A. Zeeb 	struct bss_info_bcn_cntdwn *info;
18216c92544dSBjoern A. Zeeb 	struct tlv *tlv;
18226c92544dSBjoern A. Zeeb 	int sub_tag;
18236c92544dSBjoern A. Zeeb 
18246c92544dSBjoern A. Zeeb 	if (!offs->cntdwn_counter_offs[0])
18256c92544dSBjoern A. Zeeb 		return;
18266c92544dSBjoern A. Zeeb 
18276c92544dSBjoern A. Zeeb 	sub_tag = vif->bss_conf.csa_active ? BSS_INFO_BCN_CSA : BSS_INFO_BCN_BCC;
18286c92544dSBjoern A. Zeeb 	tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info),
18296c92544dSBjoern A. Zeeb 					   &bcn->sub_ntlv, &bcn->len);
18306c92544dSBjoern A. Zeeb 	info = (struct bss_info_bcn_cntdwn *)tlv;
18316c92544dSBjoern A. Zeeb 	info->cnt = skb->data[offs->cntdwn_counter_offs[0]];
18326c92544dSBjoern A. Zeeb }
18336c92544dSBjoern A. Zeeb 
18346c92544dSBjoern A. Zeeb 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)18356c92544dSBjoern A. Zeeb mt7915_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
18366c92544dSBjoern A. Zeeb 		       struct ieee80211_vif *vif, struct bss_info_bcn *bcn,
18376c92544dSBjoern A. Zeeb 		       struct ieee80211_mutable_offsets *offs)
18386c92544dSBjoern A. Zeeb {
18396c92544dSBjoern A. Zeeb 	struct bss_info_bcn_mbss *mbss;
18406c92544dSBjoern A. Zeeb 	const struct element *elem;
18416c92544dSBjoern A. Zeeb 	struct tlv *tlv;
18426c92544dSBjoern A. Zeeb 
18436c92544dSBjoern A. Zeeb 	if (!vif->bss_conf.bssid_indicator)
18446c92544dSBjoern A. Zeeb 		return;
18456c92544dSBjoern A. Zeeb 
18466c92544dSBjoern A. Zeeb 	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_MBSSID,
18476c92544dSBjoern A. Zeeb 					   sizeof(*mbss), &bcn->sub_ntlv,
18486c92544dSBjoern A. Zeeb 					   &bcn->len);
18496c92544dSBjoern A. Zeeb 
18506c92544dSBjoern A. Zeeb 	mbss = (struct bss_info_bcn_mbss *)tlv;
18516c92544dSBjoern A. Zeeb 	mbss->offset[0] = cpu_to_le16(offs->tim_offset);
18526c92544dSBjoern A. Zeeb 	mbss->bitmap = cpu_to_le32(1);
18536c92544dSBjoern A. Zeeb 
18546c92544dSBjoern A. Zeeb 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID,
18556c92544dSBjoern A. Zeeb 			    &skb->data[offs->mbssid_off],
18566c92544dSBjoern A. Zeeb 			    skb->len - offs->mbssid_off) {
18576c92544dSBjoern A. Zeeb 		const struct element *sub_elem;
18586c92544dSBjoern A. Zeeb 
18596c92544dSBjoern A. Zeeb 		if (elem->datalen < 2)
18606c92544dSBjoern A. Zeeb 			continue;
18616c92544dSBjoern A. Zeeb 
18626c92544dSBjoern A. Zeeb 		for_each_element(sub_elem, elem->data + 1, elem->datalen - 1) {
18636c92544dSBjoern A. Zeeb 			const struct ieee80211_bssid_index *idx;
18646c92544dSBjoern A. Zeeb 			const u8 *idx_ie;
18656c92544dSBjoern A. Zeeb 
18666c92544dSBjoern A. Zeeb 			if (sub_elem->id || sub_elem->datalen < 4)
18676c92544dSBjoern A. Zeeb 				continue; /* not a valid BSS profile */
18686c92544dSBjoern A. Zeeb 
18696c92544dSBjoern A. Zeeb 			/* Find WLAN_EID_MULTI_BSSID_IDX
18706c92544dSBjoern A. Zeeb 			 * in the merged nontransmitted profile
18716c92544dSBjoern A. Zeeb 			 */
18726c92544dSBjoern A. Zeeb 			idx_ie = cfg80211_find_ie(WLAN_EID_MULTI_BSSID_IDX,
18736c92544dSBjoern A. Zeeb 						  sub_elem->data,
18746c92544dSBjoern A. Zeeb 						  sub_elem->datalen);
18756c92544dSBjoern A. Zeeb 			if (!idx_ie || idx_ie[1] < sizeof(*idx))
18766c92544dSBjoern A. Zeeb 				continue;
18776c92544dSBjoern A. Zeeb 
18786c92544dSBjoern A. Zeeb #if defined(__linux__)
18796c92544dSBjoern A. Zeeb 			idx = (void *)(idx_ie + 2);
18806c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
18816c92544dSBjoern A. Zeeb 			idx = (const void *)(idx_ie + 2);
18826c92544dSBjoern A. Zeeb #endif
18836c92544dSBjoern A. Zeeb 			if (!idx->bssid_index || idx->bssid_index > 31)
18846c92544dSBjoern A. Zeeb 				continue;
18856c92544dSBjoern A. Zeeb 
18866c92544dSBjoern A. Zeeb 			mbss->offset[idx->bssid_index] =
18876c92544dSBjoern A. Zeeb 				cpu_to_le16(idx_ie - skb->data);
18886c92544dSBjoern A. Zeeb 			mbss->bitmap |= cpu_to_le32(BIT(idx->bssid_index));
18896c92544dSBjoern A. Zeeb 		}
18906c92544dSBjoern A. Zeeb 	}
18916c92544dSBjoern A. Zeeb }
18926c92544dSBjoern A. Zeeb 
18936c92544dSBjoern A. Zeeb 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)18946c92544dSBjoern A. Zeeb mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
18956c92544dSBjoern A. Zeeb 		       struct sk_buff *rskb, struct sk_buff *skb,
18966c92544dSBjoern A. Zeeb 		       struct bss_info_bcn *bcn,
18976c92544dSBjoern A. Zeeb 		       struct ieee80211_mutable_offsets *offs)
18986c92544dSBjoern A. Zeeb {
18996c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
19006c92544dSBjoern A. Zeeb 	struct bss_info_bcn_cont *cont;
19016c92544dSBjoern A. Zeeb 	struct tlv *tlv;
19026c92544dSBjoern A. Zeeb 	u8 *buf;
19036c92544dSBjoern A. Zeeb 	int len = sizeof(*cont) + MT_TXD_SIZE + skb->len;
19046c92544dSBjoern A. Zeeb 
19056c92544dSBjoern A. Zeeb 	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
19066c92544dSBjoern A. Zeeb 	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT,
19076c92544dSBjoern A. Zeeb 					   len, &bcn->sub_ntlv, &bcn->len);
19086c92544dSBjoern A. Zeeb 
19096c92544dSBjoern A. Zeeb 	cont = (struct bss_info_bcn_cont *)tlv;
19106c92544dSBjoern A. Zeeb 	cont->pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
19116c92544dSBjoern A. Zeeb 	cont->tim_ofs = cpu_to_le16(offs->tim_offset);
19126c92544dSBjoern A. Zeeb 
19136c92544dSBjoern A. Zeeb 	if (offs->cntdwn_counter_offs[0]) {
19146c92544dSBjoern A. Zeeb 		u16 offset = offs->cntdwn_counter_offs[0];
19156c92544dSBjoern A. Zeeb 
19166c92544dSBjoern A. Zeeb 		if (vif->bss_conf.csa_active)
19176c92544dSBjoern A. Zeeb 			cont->csa_ofs = cpu_to_le16(offset - 4);
19186c92544dSBjoern A. Zeeb 		if (vif->bss_conf.color_change_active)
19196c92544dSBjoern A. Zeeb 			cont->bcc_ofs = cpu_to_le16(offset - 3);
19206c92544dSBjoern A. Zeeb 	}
19216c92544dSBjoern A. Zeeb 
19226c92544dSBjoern A. Zeeb 	buf = (u8 *)tlv + sizeof(*cont);
19236c92544dSBjoern A. Zeeb 	mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
19246c92544dSBjoern A. Zeeb 			      0, BSS_CHANGED_BEACON);
19256c92544dSBjoern A. Zeeb 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
19266c92544dSBjoern A. Zeeb }
19276c92544dSBjoern A. Zeeb 
1928*8ba4d145SBjoern A. Zeeb int
mt7915_mcu_add_inband_discov(struct mt7915_dev * dev,struct ieee80211_vif * vif,u32 changed)1929*8ba4d145SBjoern A. Zeeb mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
19306c92544dSBjoern A. Zeeb 			     u32 changed)
19316c92544dSBjoern A. Zeeb {
19326c92544dSBjoern A. Zeeb #define OFFLOAD_TX_MODE_SU	BIT(0)
19336c92544dSBjoern A. Zeeb #define OFFLOAD_TX_MODE_MU	BIT(1)
19346c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = mt76_hw(dev);
19356c92544dSBjoern A. Zeeb 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
19366c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
19376c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
19386c92544dSBjoern A. Zeeb 	enum nl80211_band band = chandef->chan->band;
19396c92544dSBjoern A. Zeeb 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1940*8ba4d145SBjoern A. Zeeb 	struct bss_info_bcn *bcn;
19416c92544dSBjoern A. Zeeb 	struct bss_info_inband_discovery *discov;
19426c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info;
1943*8ba4d145SBjoern A. Zeeb 	struct sk_buff *rskb, *skb = NULL;
1944*8ba4d145SBjoern A. Zeeb 	struct tlv *tlv, *sub_tlv;
19456c92544dSBjoern A. Zeeb 	bool ext_phy = phy != &dev->phy;
19466c92544dSBjoern A. Zeeb 	u8 *buf, interval;
19476c92544dSBjoern A. Zeeb 	int len;
19486c92544dSBjoern A. Zeeb 
1949*8ba4d145SBjoern A. Zeeb 	if (vif->bss_conf.nontransmitted)
1950*8ba4d145SBjoern A. Zeeb 		return 0;
1951*8ba4d145SBjoern A. Zeeb 
1952*8ba4d145SBjoern A. Zeeb 	rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, NULL,
1953*8ba4d145SBjoern A. Zeeb 					       MT7915_MAX_BSS_OFFLOAD_SIZE);
1954*8ba4d145SBjoern A. Zeeb 	if (IS_ERR(rskb))
1955*8ba4d145SBjoern A. Zeeb 		return PTR_ERR(rskb);
1956*8ba4d145SBjoern A. Zeeb 
1957*8ba4d145SBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
1958*8ba4d145SBjoern A. Zeeb 	bcn = (struct bss_info_bcn *)tlv;
1959*8ba4d145SBjoern A. Zeeb 	bcn->enable = true;
1960*8ba4d145SBjoern A. Zeeb 
1961*8ba4d145SBjoern A. Zeeb 	if (changed & BSS_CHANGED_FILS_DISCOVERY) {
19626c92544dSBjoern A. Zeeb 		interval = vif->bss_conf.fils_discovery.max_interval;
19636c92544dSBjoern A. Zeeb 		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
19646c92544dSBjoern A. Zeeb 	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
19656c92544dSBjoern A. Zeeb 		   vif->bss_conf.unsol_bcast_probe_resp_interval) {
19666c92544dSBjoern A. Zeeb 		interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
19676c92544dSBjoern A. Zeeb 		skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
19686c92544dSBjoern A. Zeeb 	}
19696c92544dSBjoern A. Zeeb 
1970*8ba4d145SBjoern A. Zeeb 	if (!skb) {
1971*8ba4d145SBjoern A. Zeeb 		dev_kfree_skb(rskb);
1972*8ba4d145SBjoern A. Zeeb 		return -EINVAL;
1973*8ba4d145SBjoern A. Zeeb 	}
19746c92544dSBjoern A. Zeeb 
19756c92544dSBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
19766c92544dSBjoern A. Zeeb 	info->control.vif = vif;
19776c92544dSBjoern A. Zeeb 	info->band = band;
19786c92544dSBjoern A. Zeeb 	info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
19796c92544dSBjoern A. Zeeb 
19806c92544dSBjoern A. Zeeb 	len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
19816c92544dSBjoern A. Zeeb 	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
19826c92544dSBjoern A. Zeeb 
1983*8ba4d145SBjoern A. Zeeb 	if (skb->len > MT7915_MAX_BEACON_SIZE) {
19846c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "inband discovery size limit exceed\n");
1985*8ba4d145SBjoern A. Zeeb 		dev_kfree_skb(rskb);
19866c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
1987*8ba4d145SBjoern A. Zeeb 		return -EINVAL;
19886c92544dSBjoern A. Zeeb 	}
19896c92544dSBjoern A. Zeeb 
1990*8ba4d145SBjoern A. Zeeb 	sub_tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
19916c92544dSBjoern A. Zeeb 					       len, &bcn->sub_ntlv, &bcn->len);
1992*8ba4d145SBjoern A. Zeeb 	discov = (struct bss_info_inband_discovery *)sub_tlv;
19936c92544dSBjoern A. Zeeb 	discov->tx_mode = OFFLOAD_TX_MODE_SU;
19946c92544dSBjoern A. Zeeb 	/* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
19956c92544dSBjoern A. Zeeb 	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
19966c92544dSBjoern A. Zeeb 	discov->tx_interval = interval;
19976c92544dSBjoern A. Zeeb 	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1998*8ba4d145SBjoern A. Zeeb 	discov->enable = !!interval;
19996c92544dSBjoern A. Zeeb 
2000*8ba4d145SBjoern A. Zeeb 	buf = (u8 *)sub_tlv + sizeof(*discov);
20016c92544dSBjoern A. Zeeb 
20026c92544dSBjoern A. Zeeb 	mt7915_mac_write_txwi(&dev->mt76, (__le32 *)buf, skb, wcid, 0, NULL,
20036c92544dSBjoern A. Zeeb 			      0, changed);
20046c92544dSBjoern A. Zeeb 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
20056c92544dSBjoern A. Zeeb 
20066c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
2007*8ba4d145SBjoern A. Zeeb 
2008*8ba4d145SBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
2009*8ba4d145SBjoern A. Zeeb 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
20106c92544dSBjoern A. Zeeb }
20116c92544dSBjoern A. Zeeb 
mt7915_mcu_add_beacon(struct ieee80211_hw * hw,struct ieee80211_vif * vif,int en,u32 changed)20126c92544dSBjoern A. Zeeb int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
20136c92544dSBjoern A. Zeeb 			  int en, u32 changed)
20146c92544dSBjoern A. Zeeb {
20156c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
20166c92544dSBjoern A. Zeeb 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
20176c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
20186c92544dSBjoern A. Zeeb 	struct ieee80211_mutable_offsets offs;
20196c92544dSBjoern A. Zeeb 	struct ieee80211_tx_info *info;
20206c92544dSBjoern A. Zeeb 	struct sk_buff *skb, *rskb;
20216c92544dSBjoern A. Zeeb 	struct tlv *tlv;
20226c92544dSBjoern A. Zeeb 	struct bss_info_bcn *bcn;
20236c92544dSBjoern A. Zeeb 	int len = MT7915_MAX_BSS_OFFLOAD_SIZE;
20246c92544dSBjoern A. Zeeb 	bool ext_phy = phy != &dev->phy;
20256c92544dSBjoern A. Zeeb 
20266c92544dSBjoern A. Zeeb 	if (vif->bss_conf.nontransmitted)
20276c92544dSBjoern A. Zeeb 		return 0;
20286c92544dSBjoern A. Zeeb 
20296c92544dSBjoern A. Zeeb 	rskb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
20306c92544dSBjoern A. Zeeb 					       NULL, len);
20316c92544dSBjoern A. Zeeb 	if (IS_ERR(rskb))
20326c92544dSBjoern A. Zeeb 		return PTR_ERR(rskb);
20336c92544dSBjoern A. Zeeb 
20346c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
20356c92544dSBjoern A. Zeeb 	bcn = (struct bss_info_bcn *)tlv;
20366c92544dSBjoern A. Zeeb 	bcn->enable = en;
20376c92544dSBjoern A. Zeeb 
20386c92544dSBjoern A. Zeeb 	if (!en)
20396c92544dSBjoern A. Zeeb 		goto out;
20406c92544dSBjoern A. Zeeb 
20416c92544dSBjoern A. Zeeb 	skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
2042*8ba4d145SBjoern A. Zeeb 	if (!skb) {
2043*8ba4d145SBjoern A. Zeeb 		dev_kfree_skb(rskb);
20446c92544dSBjoern A. Zeeb 		return -EINVAL;
2045*8ba4d145SBjoern A. Zeeb 	}
20466c92544dSBjoern A. Zeeb 
2047*8ba4d145SBjoern A. Zeeb 	if (skb->len > MT7915_MAX_BEACON_SIZE) {
20486c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
2049*8ba4d145SBjoern A. Zeeb 		dev_kfree_skb(rskb);
20506c92544dSBjoern A. Zeeb 		dev_kfree_skb(skb);
20516c92544dSBjoern A. Zeeb 		return -EINVAL;
20526c92544dSBjoern A. Zeeb 	}
20536c92544dSBjoern A. Zeeb 
20546c92544dSBjoern A. Zeeb 	info = IEEE80211_SKB_CB(skb);
20556c92544dSBjoern A. Zeeb 	info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
20566c92544dSBjoern A. Zeeb 
20576c92544dSBjoern A. Zeeb 	mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
20586c92544dSBjoern A. Zeeb 	mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
20596c92544dSBjoern A. Zeeb 	mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
20606c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
20616c92544dSBjoern A. Zeeb 
20626c92544dSBjoern A. Zeeb out:
20636c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
20646c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
20656c92544dSBjoern A. Zeeb }
20666c92544dSBjoern A. Zeeb 
mt7915_driver_own(struct mt7915_dev * dev,u8 band)20676c92544dSBjoern A. Zeeb static int mt7915_driver_own(struct mt7915_dev *dev, u8 band)
20686c92544dSBjoern A. Zeeb {
20696c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(band), MT_TOP_LPCR_HOST_DRV_OWN);
20706c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_TOP_LPCR_HOST_BAND(band),
20716c92544dSBjoern A. Zeeb 			    MT_TOP_LPCR_HOST_FW_OWN_STAT, 0, 500)) {
20726c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout for driver own\n");
20736c92544dSBjoern A. Zeeb 		return -EIO;
20746c92544dSBjoern A. Zeeb 	}
20756c92544dSBjoern A. Zeeb 
20766c92544dSBjoern A. Zeeb 	/* clear irq when the driver own success */
20776c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND_IRQ_STAT(band),
20786c92544dSBjoern A. Zeeb 		MT_TOP_LPCR_HOST_BAND_STAT);
20796c92544dSBjoern A. Zeeb 
20806c92544dSBjoern A. Zeeb 	return 0;
20816c92544dSBjoern A. Zeeb }
20826c92544dSBjoern A. Zeeb 
20836c92544dSBjoern A. Zeeb static int
mt7915_firmware_state(struct mt7915_dev * dev,bool wa)20846c92544dSBjoern A. Zeeb mt7915_firmware_state(struct mt7915_dev *dev, bool wa)
20856c92544dSBjoern A. Zeeb {
20866c92544dSBjoern A. Zeeb 	u32 state = FIELD_PREP(MT_TOP_MISC_FW_STATE,
20876c92544dSBjoern A. Zeeb 			       wa ? FW_STATE_RDY : FW_STATE_FW_DOWNLOAD);
20886c92544dSBjoern A. Zeeb 
20896c92544dSBjoern A. Zeeb 	if (!mt76_poll_msec(dev, MT_TOP_MISC, MT_TOP_MISC_FW_STATE,
20906c92544dSBjoern A. Zeeb 			    state, 1000)) {
20916c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
20926c92544dSBjoern A. Zeeb 		return -EIO;
20936c92544dSBjoern A. Zeeb 	}
20946c92544dSBjoern A. Zeeb 	return 0;
20956c92544dSBjoern A. Zeeb }
20966c92544dSBjoern A. Zeeb 
mt7915_load_firmware(struct mt7915_dev * dev)20976c92544dSBjoern A. Zeeb static int mt7915_load_firmware(struct mt7915_dev *dev)
20986c92544dSBjoern A. Zeeb {
20996c92544dSBjoern A. Zeeb 	int ret;
21006c92544dSBjoern A. Zeeb 
21016c92544dSBjoern A. Zeeb 	/* make sure fw is download state */
21026c92544dSBjoern A. Zeeb 	if (mt7915_firmware_state(dev, false)) {
21036c92544dSBjoern A. Zeeb 		/* restart firmware once */
2104cbb3ec25SBjoern A. Zeeb 		mt76_connac_mcu_restart(&dev->mt76);
21056c92544dSBjoern A. Zeeb 		ret = mt7915_firmware_state(dev, false);
21066c92544dSBjoern A. Zeeb 		if (ret) {
21076c92544dSBjoern A. Zeeb 			dev_err(dev->mt76.dev,
21086c92544dSBjoern A. Zeeb 				"Firmware is not ready for download\n");
21096c92544dSBjoern A. Zeeb 			return ret;
21106c92544dSBjoern A. Zeeb 		}
21116c92544dSBjoern A. Zeeb 	}
21126c92544dSBjoern A. Zeeb 
21136c92544dSBjoern A. Zeeb 	ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH));
21146c92544dSBjoern A. Zeeb 	if (ret)
21156c92544dSBjoern A. Zeeb 		return ret;
21166c92544dSBjoern A. Zeeb 
21176c92544dSBjoern A. Zeeb 	ret = mt76_connac2_load_ram(&dev->mt76, fw_name_var(dev, FIRMWARE_WM),
21186c92544dSBjoern A. Zeeb 				    fw_name(dev, FIRMWARE_WA));
21196c92544dSBjoern A. Zeeb 	if (ret)
21206c92544dSBjoern A. Zeeb 		return ret;
21216c92544dSBjoern A. Zeeb 
21226c92544dSBjoern A. Zeeb 	ret = mt7915_firmware_state(dev, true);
21236c92544dSBjoern A. Zeeb 	if (ret)
21246c92544dSBjoern A. Zeeb 		return ret;
21256c92544dSBjoern A. Zeeb 
21266c92544dSBjoern A. Zeeb 	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
21276c92544dSBjoern A. Zeeb 
21286c92544dSBjoern A. Zeeb 	dev_dbg(dev->mt76.dev, "Firmware init done\n");
21296c92544dSBjoern A. Zeeb 
21306c92544dSBjoern A. Zeeb 	return 0;
21316c92544dSBjoern A. Zeeb }
21326c92544dSBjoern A. Zeeb 
mt7915_mcu_fw_log_2_host(struct mt7915_dev * dev,u8 type,u8 ctrl)21336c92544dSBjoern A. Zeeb int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl)
21346c92544dSBjoern A. Zeeb {
21356c92544dSBjoern A. Zeeb 	struct {
21366c92544dSBjoern A. Zeeb 		u8 ctrl_val;
21376c92544dSBjoern A. Zeeb 		u8 pad[3];
21386c92544dSBjoern A. Zeeb 	} data = {
21396c92544dSBjoern A. Zeeb 		.ctrl_val = ctrl
21406c92544dSBjoern A. Zeeb 	};
21416c92544dSBjoern A. Zeeb 
21426c92544dSBjoern A. Zeeb 	if (type == MCU_FW_LOG_WA)
21436c92544dSBjoern A. Zeeb 		return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(FW_LOG_2_HOST),
21446c92544dSBjoern A. Zeeb 					 &data, sizeof(data), true);
21456c92544dSBjoern A. Zeeb 
21466c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_LOG_2_HOST), &data,
21476c92544dSBjoern A. Zeeb 				 sizeof(data), true);
21486c92544dSBjoern A. Zeeb }
21496c92544dSBjoern A. Zeeb 
mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev * dev,u32 module,u8 level)21506c92544dSBjoern A. Zeeb int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
21516c92544dSBjoern A. Zeeb {
21526c92544dSBjoern A. Zeeb 	struct {
21536c92544dSBjoern A. Zeeb 		u8 ver;
21546c92544dSBjoern A. Zeeb 		u8 pad;
21556c92544dSBjoern A. Zeeb 		__le16 len;
21566c92544dSBjoern A. Zeeb 		u8 level;
21576c92544dSBjoern A. Zeeb 		u8 rsv[3];
21586c92544dSBjoern A. Zeeb 		__le32 module_idx;
21596c92544dSBjoern A. Zeeb 	} data = {
21606c92544dSBjoern A. Zeeb 		.module_idx = cpu_to_le32(module),
21616c92544dSBjoern A. Zeeb 		.level = level,
21626c92544dSBjoern A. Zeeb 	};
21636c92544dSBjoern A. Zeeb 
21646c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(FW_DBG_CTRL), &data,
21656c92544dSBjoern A. Zeeb 				 sizeof(data), false);
21666c92544dSBjoern A. Zeeb }
21676c92544dSBjoern A. Zeeb 
mt7915_mcu_muru_debug_set(struct mt7915_dev * dev,bool enabled)21686c92544dSBjoern A. Zeeb int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled)
21696c92544dSBjoern A. Zeeb {
21706c92544dSBjoern A. Zeeb 	struct {
21716c92544dSBjoern A. Zeeb 		__le32 cmd;
21726c92544dSBjoern A. Zeeb 		u8 enable;
21736c92544dSBjoern A. Zeeb 	} data = {
21746c92544dSBjoern A. Zeeb 		.cmd = cpu_to_le32(MURU_SET_TXC_TX_STATS_EN),
21756c92544dSBjoern A. Zeeb 		.enable = enabled,
21766c92544dSBjoern A. Zeeb 	};
21776c92544dSBjoern A. Zeeb 
21786c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &data,
21796c92544dSBjoern A. Zeeb 				sizeof(data), false);
21806c92544dSBjoern A. Zeeb }
21816c92544dSBjoern A. Zeeb 
mt7915_mcu_muru_debug_get(struct mt7915_phy * phy)2182cbb3ec25SBjoern A. Zeeb int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy)
21836c92544dSBjoern A. Zeeb {
21846c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
21856c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
2186cbb3ec25SBjoern A. Zeeb 	struct mt7915_mcu_muru_stats *mu_stats;
21876c92544dSBjoern A. Zeeb 	int ret;
21886c92544dSBjoern A. Zeeb 
21896c92544dSBjoern A. Zeeb 	struct {
21906c92544dSBjoern A. Zeeb 		__le32 cmd;
21916c92544dSBjoern A. Zeeb 		u8 band_idx;
21926c92544dSBjoern A. Zeeb 	} req = {
21936c92544dSBjoern A. Zeeb 		.cmd = cpu_to_le32(MURU_GET_TXC_TX_STATS),
2194cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
21956c92544dSBjoern A. Zeeb 	};
21966c92544dSBjoern A. Zeeb 
21976c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL),
21986c92544dSBjoern A. Zeeb 					&req, sizeof(req), true, &skb);
21996c92544dSBjoern A. Zeeb 	if (ret)
22006c92544dSBjoern A. Zeeb 		return ret;
22016c92544dSBjoern A. Zeeb 
2202cbb3ec25SBjoern A. Zeeb 	mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data);
2203cbb3ec25SBjoern A. Zeeb 
2204cbb3ec25SBjoern A. Zeeb 	/* accumulate stats, these are clear-on-read */
2205cbb3ec25SBjoern A. Zeeb #define __dl_u32(s)	 phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s)
2206cbb3ec25SBjoern A. Zeeb #define __ul_u32(s)	 phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s)
2207cbb3ec25SBjoern A. Zeeb 	__dl_u32(cck_cnt);
2208cbb3ec25SBjoern A. Zeeb 	__dl_u32(ofdm_cnt);
2209cbb3ec25SBjoern A. Zeeb 	__dl_u32(htmix_cnt);
2210cbb3ec25SBjoern A. Zeeb 	__dl_u32(htgf_cnt);
2211cbb3ec25SBjoern A. Zeeb 	__dl_u32(vht_su_cnt);
2212cbb3ec25SBjoern A. Zeeb 	__dl_u32(vht_2mu_cnt);
2213cbb3ec25SBjoern A. Zeeb 	__dl_u32(vht_3mu_cnt);
2214cbb3ec25SBjoern A. Zeeb 	__dl_u32(vht_4mu_cnt);
2215cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_su_cnt);
2216cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_2ru_cnt);
2217cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_2mu_cnt);
2218cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_3ru_cnt);
2219cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_3mu_cnt);
2220cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_4ru_cnt);
2221cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_4mu_cnt);
2222cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_5to8ru_cnt);
2223cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_9to16ru_cnt);
2224cbb3ec25SBjoern A. Zeeb 	__dl_u32(he_gtr16ru_cnt);
2225cbb3ec25SBjoern A. Zeeb 
2226cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_su_cnt);
2227cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_2ru_cnt);
2228cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_3ru_cnt);
2229cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_4ru_cnt);
2230cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_5to8ru_cnt);
2231cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_9to16ru_cnt);
2232cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_gtr16ru_cnt);
2233cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_2mu_cnt);
2234cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_3mu_cnt);
2235cbb3ec25SBjoern A. Zeeb 	__ul_u32(hetrig_4mu_cnt);
2236cbb3ec25SBjoern A. Zeeb #undef __dl_u32
2237cbb3ec25SBjoern A. Zeeb #undef __ul_u32
2238cbb3ec25SBjoern A. Zeeb 
22396c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
22406c92544dSBjoern A. Zeeb 
22416c92544dSBjoern A. Zeeb 	return 0;
22426c92544dSBjoern A. Zeeb }
22436c92544dSBjoern A. Zeeb 
mt7915_mcu_set_mwds(struct mt7915_dev * dev,bool enabled)22446c92544dSBjoern A. Zeeb static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled)
22456c92544dSBjoern A. Zeeb {
22466c92544dSBjoern A. Zeeb 	struct {
22476c92544dSBjoern A. Zeeb 		u8 enable;
22486c92544dSBjoern A. Zeeb 		u8 _rsv[3];
22496c92544dSBjoern A. Zeeb 	} __packed req = {
22506c92544dSBjoern A. Zeeb 		.enable = enabled
22516c92544dSBjoern A. Zeeb 	};
22526c92544dSBjoern A. Zeeb 
22536c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(MWDS_SUPPORT), &req,
22546c92544dSBjoern A. Zeeb 				 sizeof(req), false);
22556c92544dSBjoern A. Zeeb }
22566c92544dSBjoern A. Zeeb 
mt7915_mcu_set_muru_ctrl(struct mt7915_dev * dev,u32 cmd,u32 val)22576c92544dSBjoern A. Zeeb int mt7915_mcu_set_muru_ctrl(struct mt7915_dev *dev, u32 cmd, u32 val)
22586c92544dSBjoern A. Zeeb {
22596c92544dSBjoern A. Zeeb 	struct {
22606c92544dSBjoern A. Zeeb 		__le32 cmd;
22616c92544dSBjoern A. Zeeb 		u8 val[4];
22626c92544dSBjoern A. Zeeb 	} __packed req = {
22636c92544dSBjoern A. Zeeb 		.cmd = cpu_to_le32(cmd),
22646c92544dSBjoern A. Zeeb 	};
22656c92544dSBjoern A. Zeeb 
22666c92544dSBjoern A. Zeeb 	put_unaligned_le32(val, req.val);
22676c92544dSBjoern A. Zeeb 
22686c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MURU_CTRL), &req,
22696c92544dSBjoern A. Zeeb 				 sizeof(req), false);
22706c92544dSBjoern A. Zeeb }
22716c92544dSBjoern A. Zeeb 
22726c92544dSBjoern A. Zeeb static int
mt7915_mcu_init_rx_airtime(struct mt7915_dev * dev)22736c92544dSBjoern A. Zeeb mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
22746c92544dSBjoern A. Zeeb {
22756c92544dSBjoern A. Zeeb #define RX_AIRTIME_FEATURE_CTRL		1
22766c92544dSBjoern A. Zeeb #define RX_AIRTIME_BITWISE_CTRL		2
22776c92544dSBjoern A. Zeeb #define RX_AIRTIME_CLEAR_EN	1
22786c92544dSBjoern A. Zeeb 	struct {
22796c92544dSBjoern A. Zeeb 		__le16 field;
22806c92544dSBjoern A. Zeeb 		__le16 sub_field;
22816c92544dSBjoern A. Zeeb 		__le32 set_status;
22826c92544dSBjoern A. Zeeb 		__le32 get_status;
22836c92544dSBjoern A. Zeeb 		u8 _rsv[12];
22846c92544dSBjoern A. Zeeb 
22856c92544dSBjoern A. Zeeb 		bool airtime_en;
22866c92544dSBjoern A. Zeeb 		bool mibtime_en;
22876c92544dSBjoern A. Zeeb 		bool earlyend_en;
22886c92544dSBjoern A. Zeeb 		u8 _rsv1[9];
22896c92544dSBjoern A. Zeeb 
22906c92544dSBjoern A. Zeeb 		bool airtime_clear;
22916c92544dSBjoern A. Zeeb 		bool mibtime_clear;
22926c92544dSBjoern A. Zeeb 		u8 _rsv2[98];
22936c92544dSBjoern A. Zeeb 	} __packed req = {
22946c92544dSBjoern A. Zeeb 		.field = cpu_to_le16(RX_AIRTIME_BITWISE_CTRL),
22956c92544dSBjoern A. Zeeb 		.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN),
22966c92544dSBjoern A. Zeeb 		.airtime_clear = true,
22976c92544dSBjoern A. Zeeb 	};
22986c92544dSBjoern A. Zeeb 	int ret;
22996c92544dSBjoern A. Zeeb 
23006c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
23016c92544dSBjoern A. Zeeb 				sizeof(req), true);
23026c92544dSBjoern A. Zeeb 	if (ret)
23036c92544dSBjoern A. Zeeb 		return ret;
23046c92544dSBjoern A. Zeeb 
23056c92544dSBjoern A. Zeeb 	req.field = cpu_to_le16(RX_AIRTIME_FEATURE_CTRL);
23066c92544dSBjoern A. Zeeb 	req.sub_field = cpu_to_le16(RX_AIRTIME_CLEAR_EN);
23076c92544dSBjoern A. Zeeb 	req.airtime_en = true;
23086c92544dSBjoern A. Zeeb 
23096c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_AIRTIME_CTRL), &req,
23106c92544dSBjoern A. Zeeb 				 sizeof(req), true);
23116c92544dSBjoern A. Zeeb }
23126c92544dSBjoern A. Zeeb 
mt7915_red_set_watermark(struct mt7915_dev * dev)2313cbb3ec25SBjoern A. Zeeb static int mt7915_red_set_watermark(struct mt7915_dev *dev)
23146c92544dSBjoern A. Zeeb {
2315cbb3ec25SBjoern A. Zeeb #define RED_GLOBAL_TOKEN_WATERMARK 2
2316cbb3ec25SBjoern A. Zeeb 	struct {
2317cbb3ec25SBjoern A. Zeeb 		__le32 args[3];
2318cbb3ec25SBjoern A. Zeeb 		u8 cmd;
2319cbb3ec25SBjoern A. Zeeb 		u8 version;
2320cbb3ec25SBjoern A. Zeeb 		u8 __rsv1[4];
2321cbb3ec25SBjoern A. Zeeb 		__le16 len;
2322cbb3ec25SBjoern A. Zeeb 		__le16 high_mark;
2323cbb3ec25SBjoern A. Zeeb 		__le16 low_mark;
2324cbb3ec25SBjoern A. Zeeb 		u8 __rsv2[12];
2325cbb3ec25SBjoern A. Zeeb 	} __packed req = {
2326cbb3ec25SBjoern A. Zeeb 		.args[0] = cpu_to_le32(MCU_WA_PARAM_RED_SETTING),
2327cbb3ec25SBjoern A. Zeeb 		.cmd = RED_GLOBAL_TOKEN_WATERMARK,
2328cbb3ec25SBjoern A. Zeeb 		.len = cpu_to_le16(sizeof(req) - sizeof(req.args)),
2329cbb3ec25SBjoern A. Zeeb 		.high_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256),
2330cbb3ec25SBjoern A. Zeeb 		.low_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256 - 1536),
23316c92544dSBjoern A. Zeeb 	};
23326c92544dSBjoern A. Zeeb 
2333cbb3ec25SBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET), &req,
2334cbb3ec25SBjoern A. Zeeb 				 sizeof(req), false);
2335cbb3ec25SBjoern A. Zeeb }
2336cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_set_red(struct mt7915_dev * dev,bool enabled)2337cbb3ec25SBjoern A. Zeeb static int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
2338cbb3ec25SBjoern A. Zeeb {
2339cbb3ec25SBjoern A. Zeeb #define RED_DISABLE		0
2340cbb3ec25SBjoern A. Zeeb #define RED_BY_WA_ENABLE	2
2341cbb3ec25SBjoern A. Zeeb 	int ret;
2342cbb3ec25SBjoern A. Zeeb 	u32 red_type = enabled ? RED_BY_WA_ENABLE : RED_DISABLE;
2343cbb3ec25SBjoern A. Zeeb 	__le32 req = cpu_to_le32(red_type);
2344cbb3ec25SBjoern A. Zeeb 
2345cbb3ec25SBjoern A. Zeeb 	if (enabled) {
2346cbb3ec25SBjoern A. Zeeb 		ret = mt7915_red_set_watermark(dev);
2347cbb3ec25SBjoern A. Zeeb 		if (ret < 0)
2348cbb3ec25SBjoern A. Zeeb 			return ret;
2349cbb3ec25SBjoern A. Zeeb 	}
2350cbb3ec25SBjoern A. Zeeb 
2351cbb3ec25SBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RED_ENABLE), &req,
2352cbb3ec25SBjoern A. Zeeb 				sizeof(req), false);
2353cbb3ec25SBjoern A. Zeeb 	if (ret < 0)
2354cbb3ec25SBjoern A. Zeeb 		return ret;
2355cbb3ec25SBjoern A. Zeeb 
2356cbb3ec25SBjoern A. Zeeb 	return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
2357cbb3ec25SBjoern A. Zeeb 				 MCU_WA_PARAM_RED, enabled, 0);
2358cbb3ec25SBjoern A. Zeeb }
2359cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_init_firmware(struct mt7915_dev * dev)2360cbb3ec25SBjoern A. Zeeb int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
2361cbb3ec25SBjoern A. Zeeb {
2362cbb3ec25SBjoern A. Zeeb 	int ret;
23636c92544dSBjoern A. Zeeb 
23646c92544dSBjoern A. Zeeb 	/* force firmware operation mode into normal state,
23656c92544dSBjoern A. Zeeb 	 * which should be set before firmware download stage.
23666c92544dSBjoern A. Zeeb 	 */
23676c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
23686c92544dSBjoern A. Zeeb 
23696c92544dSBjoern A. Zeeb 	ret = mt7915_driver_own(dev, 0);
23706c92544dSBjoern A. Zeeb 	if (ret)
23716c92544dSBjoern A. Zeeb 		return ret;
23726c92544dSBjoern A. Zeeb 	/* set driver own for band1 when two hif exist */
23736c92544dSBjoern A. Zeeb 	if (dev->hif2) {
23746c92544dSBjoern A. Zeeb 		ret = mt7915_driver_own(dev, 1);
23756c92544dSBjoern A. Zeeb 		if (ret)
23766c92544dSBjoern A. Zeeb 			return ret;
23776c92544dSBjoern A. Zeeb 	}
23786c92544dSBjoern A. Zeeb 
23796c92544dSBjoern A. Zeeb 	ret = mt7915_load_firmware(dev);
23806c92544dSBjoern A. Zeeb 	if (ret)
23816c92544dSBjoern A. Zeeb 		return ret;
23826c92544dSBjoern A. Zeeb 
23836c92544dSBjoern A. Zeeb 	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
23846c92544dSBjoern A. Zeeb 	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0);
23856c92544dSBjoern A. Zeeb 	if (ret)
23866c92544dSBjoern A. Zeeb 		return ret;
23876c92544dSBjoern A. Zeeb 
23886c92544dSBjoern A. Zeeb 	ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WA, 0);
23896c92544dSBjoern A. Zeeb 	if (ret)
23906c92544dSBjoern A. Zeeb 		return ret;
23916c92544dSBjoern A. Zeeb 
2392*8ba4d145SBjoern A. Zeeb 	mt76_connac_mcu_del_wtbl_all(&dev->mt76);
2393*8ba4d145SBjoern A. Zeeb 
2394cbb3ec25SBjoern A. Zeeb 	if ((mtk_wed_device_active(&dev->mt76.mmio.wed) &&
2395cbb3ec25SBjoern A. Zeeb 	     is_mt7915(&dev->mt76)) ||
2396cbb3ec25SBjoern A. Zeeb 	    !mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
23976c92544dSBjoern A. Zeeb 		mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(CAPABILITY), 0, 0, 0);
23986c92544dSBjoern A. Zeeb 
23996c92544dSBjoern A. Zeeb 	ret = mt7915_mcu_set_mwds(dev, 1);
24006c92544dSBjoern A. Zeeb 	if (ret)
24016c92544dSBjoern A. Zeeb 		return ret;
24026c92544dSBjoern A. Zeeb 
24036c92544dSBjoern A. Zeeb 	ret = mt7915_mcu_set_muru_ctrl(dev, MURU_SET_PLATFORM_TYPE,
24046c92544dSBjoern A. Zeeb 				       MURU_PLATFORM_TYPE_PERF_LEVEL_2);
24056c92544dSBjoern A. Zeeb 	if (ret)
24066c92544dSBjoern A. Zeeb 		return ret;
24076c92544dSBjoern A. Zeeb 
24086c92544dSBjoern A. Zeeb 	ret = mt7915_mcu_init_rx_airtime(dev);
24096c92544dSBjoern A. Zeeb 	if (ret)
24106c92544dSBjoern A. Zeeb 		return ret;
24116c92544dSBjoern A. Zeeb 
2412cbb3ec25SBjoern A. Zeeb 	return mt7915_mcu_set_red(dev, mtk_wed_device_active(&dev->mt76.mmio.wed));
2413cbb3ec25SBjoern A. Zeeb }
2414cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_init(struct mt7915_dev * dev)2415cbb3ec25SBjoern A. Zeeb int mt7915_mcu_init(struct mt7915_dev *dev)
2416cbb3ec25SBjoern A. Zeeb {
2417cbb3ec25SBjoern A. Zeeb 	static const struct mt76_mcu_ops mt7915_mcu_ops = {
2418*8ba4d145SBjoern A. Zeeb 		.max_retry = 1,
2419cbb3ec25SBjoern A. Zeeb 		.headroom = sizeof(struct mt76_connac2_mcu_txd),
2420*8ba4d145SBjoern A. Zeeb 		.mcu_skb_prepare_msg = mt76_connac2_mcu_fill_message,
2421cbb3ec25SBjoern A. Zeeb 		.mcu_skb_send_msg = mt7915_mcu_send_message,
2422cbb3ec25SBjoern A. Zeeb 		.mcu_parse_response = mt7915_mcu_parse_response,
2423cbb3ec25SBjoern A. Zeeb 	};
2424cbb3ec25SBjoern A. Zeeb 
2425cbb3ec25SBjoern A. Zeeb 	dev->mt76.mcu_ops = &mt7915_mcu_ops;
2426cbb3ec25SBjoern A. Zeeb 
2427cbb3ec25SBjoern A. Zeeb 	return mt7915_mcu_init_firmware(dev);
24286c92544dSBjoern A. Zeeb }
24296c92544dSBjoern A. Zeeb 
mt7915_mcu_exit(struct mt7915_dev * dev)24306c92544dSBjoern A. Zeeb void mt7915_mcu_exit(struct mt7915_dev *dev)
24316c92544dSBjoern A. Zeeb {
2432cbb3ec25SBjoern A. Zeeb 	mt76_connac_mcu_restart(&dev->mt76);
24336c92544dSBjoern A. Zeeb 	if (mt7915_firmware_state(dev, false)) {
24346c92544dSBjoern A. Zeeb 		dev_err(dev->mt76.dev, "Failed to exit mcu\n");
2435cbb3ec25SBjoern A. Zeeb 		goto out;
24366c92544dSBjoern A. Zeeb 	}
24376c92544dSBjoern A. Zeeb 
24386c92544dSBjoern A. Zeeb 	mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
24396c92544dSBjoern A. Zeeb 	if (dev->hif2)
24406c92544dSBjoern A. Zeeb 		mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
24416c92544dSBjoern A. Zeeb 			MT_TOP_LPCR_HOST_FW_OWN);
2442cbb3ec25SBjoern A. Zeeb out:
24436c92544dSBjoern A. Zeeb 	skb_queue_purge(&dev->mt76.mcu.res_q);
24446c92544dSBjoern A. Zeeb }
24456c92544dSBjoern A. Zeeb 
24466c92544dSBjoern A. Zeeb static int
mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev * dev,int band)24476c92544dSBjoern A. Zeeb mt7915_mcu_set_rx_hdr_trans_blacklist(struct mt7915_dev *dev, int band)
24486c92544dSBjoern A. Zeeb {
24496c92544dSBjoern A. Zeeb 	struct {
24506c92544dSBjoern A. Zeeb 		u8 operation;
24516c92544dSBjoern A. Zeeb 		u8 count;
24526c92544dSBjoern A. Zeeb 		u8 _rsv[2];
24536c92544dSBjoern A. Zeeb 		u8 index;
24546c92544dSBjoern A. Zeeb 		u8 enable;
24556c92544dSBjoern A. Zeeb 		__le16 etype;
24566c92544dSBjoern A. Zeeb 	} req = {
24576c92544dSBjoern A. Zeeb 		.operation = 1,
24586c92544dSBjoern A. Zeeb 		.count = 1,
24596c92544dSBjoern A. Zeeb 		.enable = 1,
24606c92544dSBjoern A. Zeeb 		.etype = cpu_to_le16(ETH_P_PAE),
24616c92544dSBjoern A. Zeeb 	};
24626c92544dSBjoern A. Zeeb 
24636c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
24646c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
24656c92544dSBjoern A. Zeeb }
24666c92544dSBjoern A. Zeeb 
mt7915_mcu_set_mac(struct mt7915_dev * dev,int band,bool enable,bool hdr_trans)24676c92544dSBjoern A. Zeeb int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
24686c92544dSBjoern A. Zeeb 		       bool enable, bool hdr_trans)
24696c92544dSBjoern A. Zeeb {
24706c92544dSBjoern A. Zeeb 	struct {
24716c92544dSBjoern A. Zeeb 		u8 operation;
24726c92544dSBjoern A. Zeeb 		u8 enable;
24736c92544dSBjoern A. Zeeb 		u8 check_bssid;
24746c92544dSBjoern A. Zeeb 		u8 insert_vlan;
24756c92544dSBjoern A. Zeeb 		u8 remove_vlan;
24766c92544dSBjoern A. Zeeb 		u8 tid;
24776c92544dSBjoern A. Zeeb 		u8 mode;
24786c92544dSBjoern A. Zeeb 		u8 rsv;
24796c92544dSBjoern A. Zeeb 	} __packed req_trans = {
24806c92544dSBjoern A. Zeeb 		.enable = hdr_trans,
24816c92544dSBjoern A. Zeeb 	};
24826c92544dSBjoern A. Zeeb 	struct {
24836c92544dSBjoern A. Zeeb 		u8 enable;
24846c92544dSBjoern A. Zeeb 		u8 band;
24856c92544dSBjoern A. Zeeb 		u8 rsv[2];
24866c92544dSBjoern A. Zeeb 	} __packed req_mac = {
24876c92544dSBjoern A. Zeeb 		.enable = enable,
24886c92544dSBjoern A. Zeeb 		.band = band,
24896c92544dSBjoern A. Zeeb 	};
24906c92544dSBjoern A. Zeeb 	int ret;
24916c92544dSBjoern A. Zeeb 
24926c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RX_HDR_TRANS),
24936c92544dSBjoern A. Zeeb 				&req_trans, sizeof(req_trans), false);
24946c92544dSBjoern A. Zeeb 	if (ret)
24956c92544dSBjoern A. Zeeb 		return ret;
24966c92544dSBjoern A. Zeeb 
24976c92544dSBjoern A. Zeeb 	if (hdr_trans)
24986c92544dSBjoern A. Zeeb 		mt7915_mcu_set_rx_hdr_trans_blacklist(dev, band);
24996c92544dSBjoern A. Zeeb 
25006c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MAC_INIT_CTRL),
25016c92544dSBjoern A. Zeeb 				 &req_mac, sizeof(req_mac), true);
25026c92544dSBjoern A. Zeeb }
25036c92544dSBjoern A. Zeeb 
mt7915_mcu_update_edca(struct mt7915_dev * dev,void * param)25046c92544dSBjoern A. Zeeb int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *param)
25056c92544dSBjoern A. Zeeb {
25066c92544dSBjoern A. Zeeb 	struct mt7915_mcu_tx *req = (struct mt7915_mcu_tx *)param;
25076c92544dSBjoern A. Zeeb 	u8 num = req->total;
25086c92544dSBjoern A. Zeeb 	size_t len = sizeof(*req) -
25096c92544dSBjoern A. Zeeb 		     (IEEE80211_NUM_ACS - num) * sizeof(struct edca);
25106c92544dSBjoern A. Zeeb 
25116c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EDCA_UPDATE), req,
25126c92544dSBjoern A. Zeeb 				 len, true);
25136c92544dSBjoern A. Zeeb }
25146c92544dSBjoern A. Zeeb 
mt7915_mcu_set_tx(struct mt7915_dev * dev,struct ieee80211_vif * vif)25156c92544dSBjoern A. Zeeb int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
25166c92544dSBjoern A. Zeeb {
25176c92544dSBjoern A. Zeeb #define TX_CMD_MODE		1
25186c92544dSBjoern A. Zeeb 	struct mt7915_mcu_tx req = {
25196c92544dSBjoern A. Zeeb 		.valid = true,
25206c92544dSBjoern A. Zeeb 		.mode = TX_CMD_MODE,
25216c92544dSBjoern A. Zeeb 		.total = IEEE80211_NUM_ACS,
25226c92544dSBjoern A. Zeeb 	};
25236c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
25246c92544dSBjoern A. Zeeb 	int ac;
25256c92544dSBjoern A. Zeeb 
25266c92544dSBjoern A. Zeeb 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
25276c92544dSBjoern A. Zeeb 		struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
25286c92544dSBjoern A. Zeeb 		struct edca *e = &req.edca[ac];
25296c92544dSBjoern A. Zeeb 
25306c92544dSBjoern A. Zeeb 		e->set = WMM_PARAM_SET;
25316c92544dSBjoern A. Zeeb 		e->queue = ac + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS;
25326c92544dSBjoern A. Zeeb 		e->aifs = q->aifs;
25336c92544dSBjoern A. Zeeb 		e->txop = cpu_to_le16(q->txop);
25346c92544dSBjoern A. Zeeb 
25356c92544dSBjoern A. Zeeb 		if (q->cw_min)
25366c92544dSBjoern A. Zeeb 			e->cw_min = fls(q->cw_min);
25376c92544dSBjoern A. Zeeb 		else
25386c92544dSBjoern A. Zeeb 			e->cw_min = 5;
25396c92544dSBjoern A. Zeeb 
25406c92544dSBjoern A. Zeeb 		if (q->cw_max)
25416c92544dSBjoern A. Zeeb 			e->cw_max = cpu_to_le16(fls(q->cw_max));
25426c92544dSBjoern A. Zeeb 		else
25436c92544dSBjoern A. Zeeb 			e->cw_max = cpu_to_le16(10);
25446c92544dSBjoern A. Zeeb 	}
25456c92544dSBjoern A. Zeeb 
25466c92544dSBjoern A. Zeeb 	return mt7915_mcu_update_edca(dev, &req);
25476c92544dSBjoern A. Zeeb }
25486c92544dSBjoern A. Zeeb 
mt7915_mcu_set_fcc5_lpn(struct mt7915_dev * dev,int val)25496c92544dSBjoern A. Zeeb int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val)
25506c92544dSBjoern A. Zeeb {
25516c92544dSBjoern A. Zeeb 	struct {
25526c92544dSBjoern A. Zeeb 		__le32 tag;
25536c92544dSBjoern A. Zeeb 		__le16 min_lpn;
25546c92544dSBjoern A. Zeeb 		u8 rsv[2];
25556c92544dSBjoern A. Zeeb 	} __packed req = {
25566c92544dSBjoern A. Zeeb 		.tag = cpu_to_le32(0x1),
25576c92544dSBjoern A. Zeeb 		.min_lpn = cpu_to_le16(val),
25586c92544dSBjoern A. Zeeb 	};
25596c92544dSBjoern A. Zeeb 
25606c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
25616c92544dSBjoern A. Zeeb 				 sizeof(req), true);
25626c92544dSBjoern A. Zeeb }
25636c92544dSBjoern A. Zeeb 
mt7915_mcu_set_pulse_th(struct mt7915_dev * dev,const struct mt7915_dfs_pulse * pulse)25646c92544dSBjoern A. Zeeb int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
25656c92544dSBjoern A. Zeeb 			    const struct mt7915_dfs_pulse *pulse)
25666c92544dSBjoern A. Zeeb {
25676c92544dSBjoern A. Zeeb 	struct {
25686c92544dSBjoern A. Zeeb 		__le32 tag;
25696c92544dSBjoern A. Zeeb 
25706c92544dSBjoern A. Zeeb 		__le32 max_width;		/* us */
25716c92544dSBjoern A. Zeeb 		__le32 max_pwr;			/* dbm */
25726c92544dSBjoern A. Zeeb 		__le32 min_pwr;			/* dbm */
25736c92544dSBjoern A. Zeeb 		__le32 min_stgr_pri;		/* us */
25746c92544dSBjoern A. Zeeb 		__le32 max_stgr_pri;		/* us */
25756c92544dSBjoern A. Zeeb 		__le32 min_cr_pri;		/* us */
25766c92544dSBjoern A. Zeeb 		__le32 max_cr_pri;		/* us */
25776c92544dSBjoern A. Zeeb 	} __packed req = {
25786c92544dSBjoern A. Zeeb 		.tag = cpu_to_le32(0x3),
25796c92544dSBjoern A. Zeeb 
25806c92544dSBjoern A. Zeeb #define __req_field(field) .field = cpu_to_le32(pulse->field)
25816c92544dSBjoern A. Zeeb 		__req_field(max_width),
25826c92544dSBjoern A. Zeeb 		__req_field(max_pwr),
25836c92544dSBjoern A. Zeeb 		__req_field(min_pwr),
25846c92544dSBjoern A. Zeeb 		__req_field(min_stgr_pri),
25856c92544dSBjoern A. Zeeb 		__req_field(max_stgr_pri),
25866c92544dSBjoern A. Zeeb 		__req_field(min_cr_pri),
25876c92544dSBjoern A. Zeeb 		__req_field(max_cr_pri),
25886c92544dSBjoern A. Zeeb #undef __req_field
25896c92544dSBjoern A. Zeeb 	};
25906c92544dSBjoern A. Zeeb 
25916c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
25926c92544dSBjoern A. Zeeb 				 sizeof(req), true);
25936c92544dSBjoern A. Zeeb }
25946c92544dSBjoern A. Zeeb 
mt7915_mcu_set_radar_th(struct mt7915_dev * dev,int index,const struct mt7915_dfs_pattern * pattern)25956c92544dSBjoern A. Zeeb int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
25966c92544dSBjoern A. Zeeb 			    const struct mt7915_dfs_pattern *pattern)
25976c92544dSBjoern A. Zeeb {
25986c92544dSBjoern A. Zeeb 	struct {
25996c92544dSBjoern A. Zeeb 		__le32 tag;
26006c92544dSBjoern A. Zeeb 		__le16 radar_type;
26016c92544dSBjoern A. Zeeb 
26026c92544dSBjoern A. Zeeb 		u8 enb;
26036c92544dSBjoern A. Zeeb 		u8 stgr;
26046c92544dSBjoern A. Zeeb 		u8 min_crpn;
26056c92544dSBjoern A. Zeeb 		u8 max_crpn;
26066c92544dSBjoern A. Zeeb 		u8 min_crpr;
26076c92544dSBjoern A. Zeeb 		u8 min_pw;
26086c92544dSBjoern A. Zeeb 		__le32 min_pri;
26096c92544dSBjoern A. Zeeb 		__le32 max_pri;
26106c92544dSBjoern A. Zeeb 		u8 max_pw;
26116c92544dSBjoern A. Zeeb 		u8 min_crbn;
26126c92544dSBjoern A. Zeeb 		u8 max_crbn;
26136c92544dSBjoern A. Zeeb 		u8 min_stgpn;
26146c92544dSBjoern A. Zeeb 		u8 max_stgpn;
26156c92544dSBjoern A. Zeeb 		u8 min_stgpr;
26166c92544dSBjoern A. Zeeb 		u8 rsv[2];
26176c92544dSBjoern A. Zeeb 		__le32 min_stgpr_diff;
26186c92544dSBjoern A. Zeeb 	} __packed req = {
26196c92544dSBjoern A. Zeeb 		.tag = cpu_to_le32(0x2),
26206c92544dSBjoern A. Zeeb 		.radar_type = cpu_to_le16(index),
26216c92544dSBjoern A. Zeeb 
26226c92544dSBjoern A. Zeeb #define __req_field_u8(field) .field = pattern->field
26236c92544dSBjoern A. Zeeb #define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
26246c92544dSBjoern A. Zeeb 		__req_field_u8(enb),
26256c92544dSBjoern A. Zeeb 		__req_field_u8(stgr),
26266c92544dSBjoern A. Zeeb 		__req_field_u8(min_crpn),
26276c92544dSBjoern A. Zeeb 		__req_field_u8(max_crpn),
26286c92544dSBjoern A. Zeeb 		__req_field_u8(min_crpr),
26296c92544dSBjoern A. Zeeb 		__req_field_u8(min_pw),
26306c92544dSBjoern A. Zeeb 		__req_field_u32(min_pri),
26316c92544dSBjoern A. Zeeb 		__req_field_u32(max_pri),
26326c92544dSBjoern A. Zeeb 		__req_field_u8(max_pw),
26336c92544dSBjoern A. Zeeb 		__req_field_u8(min_crbn),
26346c92544dSBjoern A. Zeeb 		__req_field_u8(max_crbn),
26356c92544dSBjoern A. Zeeb 		__req_field_u8(min_stgpn),
26366c92544dSBjoern A. Zeeb 		__req_field_u8(max_stgpn),
26376c92544dSBjoern A. Zeeb 		__req_field_u8(min_stgpr),
26386c92544dSBjoern A. Zeeb 		__req_field_u32(min_stgpr_diff),
26396c92544dSBjoern A. Zeeb #undef __req_field_u8
26406c92544dSBjoern A. Zeeb #undef __req_field_u32
26416c92544dSBjoern A. Zeeb 	};
26426c92544dSBjoern A. Zeeb 
26436c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_RDD_TH), &req,
26446c92544dSBjoern A. Zeeb 				 sizeof(req), true);
26456c92544dSBjoern A. Zeeb }
26466c92544dSBjoern A. Zeeb 
26476c92544dSBjoern A. Zeeb static int
mt7915_mcu_background_chain_ctrl(struct mt7915_phy * phy,struct cfg80211_chan_def * chandef,int cmd)26486c92544dSBjoern A. Zeeb mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
26496c92544dSBjoern A. Zeeb 				 struct cfg80211_chan_def *chandef,
26506c92544dSBjoern A. Zeeb 				 int cmd)
26516c92544dSBjoern A. Zeeb {
26526c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
26536c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = phy->mt76;
26546c92544dSBjoern A. Zeeb 	struct ieee80211_channel *chan = mphy->chandef.chan;
26556c92544dSBjoern A. Zeeb 	int freq = mphy->chandef.center_freq1;
26566c92544dSBjoern A. Zeeb 	struct mt7915_mcu_background_chain_ctrl req = {
26576c92544dSBjoern A. Zeeb 		.monitor_scan_type = 2, /* simple rx */
26586c92544dSBjoern A. Zeeb 	};
26596c92544dSBjoern A. Zeeb 
26606c92544dSBjoern A. Zeeb 	if (!chandef && cmd != CH_SWITCH_BACKGROUND_SCAN_STOP)
26616c92544dSBjoern A. Zeeb 		return -EINVAL;
26626c92544dSBjoern A. Zeeb 
26636c92544dSBjoern A. Zeeb 	if (!cfg80211_chandef_valid(&mphy->chandef))
26646c92544dSBjoern A. Zeeb 		return -EINVAL;
26656c92544dSBjoern A. Zeeb 
26666c92544dSBjoern A. Zeeb 	switch (cmd) {
26676c92544dSBjoern A. Zeeb 	case CH_SWITCH_BACKGROUND_SCAN_START: {
26686c92544dSBjoern A. Zeeb 		req.chan = chan->hw_value;
26696c92544dSBjoern A. Zeeb 		req.central_chan = ieee80211_frequency_to_channel(freq);
26706c92544dSBjoern A. Zeeb 		req.bw = mt76_connac_chan_bw(&mphy->chandef);
26716c92544dSBjoern A. Zeeb 		req.monitor_chan = chandef->chan->hw_value;
26726c92544dSBjoern A. Zeeb 		req.monitor_central_chan =
26736c92544dSBjoern A. Zeeb 			ieee80211_frequency_to_channel(chandef->center_freq1);
26746c92544dSBjoern A. Zeeb 		req.monitor_bw = mt76_connac_chan_bw(chandef);
2675cbb3ec25SBjoern A. Zeeb 		req.band_idx = phy->mt76->band_idx;
26766c92544dSBjoern A. Zeeb 		req.scan_mode = 1;
26776c92544dSBjoern A. Zeeb 		break;
26786c92544dSBjoern A. Zeeb 	}
26796c92544dSBjoern A. Zeeb 	case CH_SWITCH_BACKGROUND_SCAN_RUNNING:
26806c92544dSBjoern A. Zeeb 		req.monitor_chan = chandef->chan->hw_value;
26816c92544dSBjoern A. Zeeb 		req.monitor_central_chan =
26826c92544dSBjoern A. Zeeb 			ieee80211_frequency_to_channel(chandef->center_freq1);
2683cbb3ec25SBjoern A. Zeeb 		req.band_idx = phy->mt76->band_idx;
26846c92544dSBjoern A. Zeeb 		req.scan_mode = 2;
26856c92544dSBjoern A. Zeeb 		break;
26866c92544dSBjoern A. Zeeb 	case CH_SWITCH_BACKGROUND_SCAN_STOP:
26876c92544dSBjoern A. Zeeb 		req.chan = chan->hw_value;
26886c92544dSBjoern A. Zeeb 		req.central_chan = ieee80211_frequency_to_channel(freq);
26896c92544dSBjoern A. Zeeb 		req.bw = mt76_connac_chan_bw(&mphy->chandef);
26906c92544dSBjoern A. Zeeb 		req.tx_stream = hweight8(mphy->antenna_mask);
26916c92544dSBjoern A. Zeeb 		req.rx_stream = mphy->antenna_mask;
26926c92544dSBjoern A. Zeeb 		break;
26936c92544dSBjoern A. Zeeb 	default:
26946c92544dSBjoern A. Zeeb 		return -EINVAL;
26956c92544dSBjoern A. Zeeb 	}
26966c92544dSBjoern A. Zeeb 	req.band = chandef ? chandef->chan->band == NL80211_BAND_5GHZ : 1;
26976c92544dSBjoern A. Zeeb 
26986c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL),
26996c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
27006c92544dSBjoern A. Zeeb }
27016c92544dSBjoern A. Zeeb 
mt7915_mcu_rdd_background_enable(struct mt7915_phy * phy,struct cfg80211_chan_def * chandef)27026c92544dSBjoern A. Zeeb int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
27036c92544dSBjoern A. Zeeb 				     struct cfg80211_chan_def *chandef)
27046c92544dSBjoern A. Zeeb {
27056c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
27066c92544dSBjoern A. Zeeb 	int err, region;
27076c92544dSBjoern A. Zeeb 
27086c92544dSBjoern A. Zeeb 	if (!chandef) { /* disable offchain */
27096c92544dSBjoern A. Zeeb 		err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, MT_RX_SEL2,
27106c92544dSBjoern A. Zeeb 					      0, 0);
27116c92544dSBjoern A. Zeeb 		if (err)
27126c92544dSBjoern A. Zeeb 			return err;
27136c92544dSBjoern A. Zeeb 
27146c92544dSBjoern A. Zeeb 		return mt7915_mcu_background_chain_ctrl(phy, NULL,
27156c92544dSBjoern A. Zeeb 				CH_SWITCH_BACKGROUND_SCAN_STOP);
27166c92544dSBjoern A. Zeeb 	}
27176c92544dSBjoern A. Zeeb 
27186c92544dSBjoern A. Zeeb 	err = mt7915_mcu_background_chain_ctrl(phy, chandef,
27196c92544dSBjoern A. Zeeb 					       CH_SWITCH_BACKGROUND_SCAN_START);
27206c92544dSBjoern A. Zeeb 	if (err)
27216c92544dSBjoern A. Zeeb 		return err;
27226c92544dSBjoern A. Zeeb 
27236c92544dSBjoern A. Zeeb 	switch (dev->mt76.region) {
27246c92544dSBjoern A. Zeeb 	case NL80211_DFS_ETSI:
27256c92544dSBjoern A. Zeeb 		region = 0;
27266c92544dSBjoern A. Zeeb 		break;
27276c92544dSBjoern A. Zeeb 	case NL80211_DFS_JP:
27286c92544dSBjoern A. Zeeb 		region = 2;
27296c92544dSBjoern A. Zeeb 		break;
27306c92544dSBjoern A. Zeeb 	case NL80211_DFS_FCC:
27316c92544dSBjoern A. Zeeb 	default:
27326c92544dSBjoern A. Zeeb 		region = 1;
27336c92544dSBjoern A. Zeeb 		break;
27346c92544dSBjoern A. Zeeb 	}
27356c92544dSBjoern A. Zeeb 
27366c92544dSBjoern A. Zeeb 	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, MT_RX_SEL2,
27376c92544dSBjoern A. Zeeb 				       0, region);
27386c92544dSBjoern A. Zeeb }
27396c92544dSBjoern A. Zeeb 
mt7915_mcu_set_chan_info(struct mt7915_phy * phy,int cmd)27406c92544dSBjoern A. Zeeb int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
27416c92544dSBjoern A. Zeeb {
27426c92544dSBjoern A. Zeeb 	static const u8 ch_band[] = {
27436c92544dSBjoern A. Zeeb 		[NL80211_BAND_2GHZ] = 0,
27446c92544dSBjoern A. Zeeb 		[NL80211_BAND_5GHZ] = 1,
27456c92544dSBjoern A. Zeeb 		[NL80211_BAND_6GHZ] = 2,
27466c92544dSBjoern A. Zeeb 	};
27476c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
27486c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
27496c92544dSBjoern A. Zeeb 	int freq1 = chandef->center_freq1;
2750cbb3ec25SBjoern A. Zeeb 	u8 band = phy->mt76->band_idx;
27516c92544dSBjoern A. Zeeb 	struct {
27526c92544dSBjoern A. Zeeb 		u8 control_ch;
27536c92544dSBjoern A. Zeeb 		u8 center_ch;
27546c92544dSBjoern A. Zeeb 		u8 bw;
2755cbb3ec25SBjoern A. Zeeb 		u8 tx_path_num;
2756cbb3ec25SBjoern A. Zeeb 		u8 rx_path;	/* mask or num */
27576c92544dSBjoern A. Zeeb 		u8 switch_reason;
27586c92544dSBjoern A. Zeeb 		u8 band_idx;
27596c92544dSBjoern A. Zeeb 		u8 center_ch2;	/* for 80+80 only */
27606c92544dSBjoern A. Zeeb 		__le16 cac_case;
27616c92544dSBjoern A. Zeeb 		u8 channel_band;
27626c92544dSBjoern A. Zeeb 		u8 rsv0;
27636c92544dSBjoern A. Zeeb 		__le32 outband_freq;
27646c92544dSBjoern A. Zeeb 		u8 txpower_drop;
27656c92544dSBjoern A. Zeeb 		u8 ap_bw;
27666c92544dSBjoern A. Zeeb 		u8 ap_center_ch;
27676c92544dSBjoern A. Zeeb 		u8 rsv1[57];
27686c92544dSBjoern A. Zeeb 	} __packed req = {
27696c92544dSBjoern A. Zeeb 		.control_ch = chandef->chan->hw_value,
27706c92544dSBjoern A. Zeeb 		.center_ch = ieee80211_frequency_to_channel(freq1),
27716c92544dSBjoern A. Zeeb 		.bw = mt76_connac_chan_bw(chandef),
2772cbb3ec25SBjoern A. Zeeb 		.tx_path_num = hweight16(phy->mt76->chainmask),
2773cbb3ec25SBjoern A. Zeeb 		.rx_path = phy->mt76->chainmask >> (dev->chainshift * band),
2774cbb3ec25SBjoern A. Zeeb 		.band_idx = band,
27756c92544dSBjoern A. Zeeb 		.channel_band = ch_band[chandef->chan->band],
27766c92544dSBjoern A. Zeeb 	};
27776c92544dSBjoern A. Zeeb 
27786c92544dSBjoern A. Zeeb #ifdef CONFIG_NL80211_TESTMODE
27796c92544dSBjoern A. Zeeb 	if (phy->mt76->test.tx_antenna_mask &&
2780cbb3ec25SBjoern A. Zeeb 	    mt76_testmode_enabled(phy->mt76)) {
2781cbb3ec25SBjoern A. Zeeb 		req.tx_path_num = fls(phy->mt76->test.tx_antenna_mask);
2782cbb3ec25SBjoern A. Zeeb 		req.rx_path = phy->mt76->test.tx_antenna_mask;
27836c92544dSBjoern A. Zeeb 	}
27846c92544dSBjoern A. Zeeb #endif
27856c92544dSBjoern A. Zeeb 
2786cbb3ec25SBjoern A. Zeeb 	if (mt76_connac_spe_idx(phy->mt76->antenna_mask))
2787cbb3ec25SBjoern A. Zeeb 		req.tx_path_num = fls(phy->mt76->antenna_mask);
2788cbb3ec25SBjoern A. Zeeb 
2789*8ba4d145SBjoern A. Zeeb 	if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
27906c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_NORMAL;
2791*8ba4d145SBjoern A. Zeeb 	else if (phy->mt76->offchannel ||
2792*8ba4d145SBjoern A. Zeeb 		 phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
27936c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
27946c92544dSBjoern A. Zeeb 	else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
27956c92544dSBjoern A. Zeeb 					  NL80211_IFTYPE_AP))
27966c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_DFS;
27976c92544dSBjoern A. Zeeb 	else
27986c92544dSBjoern A. Zeeb 		req.switch_reason = CH_SWITCH_NORMAL;
27996c92544dSBjoern A. Zeeb 
28006c92544dSBjoern A. Zeeb 	if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
2801cbb3ec25SBjoern A. Zeeb 		req.rx_path = hweight8(req.rx_path);
28026c92544dSBjoern A. Zeeb 
28036c92544dSBjoern A. Zeeb 	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
28046c92544dSBjoern A. Zeeb 		int freq2 = chandef->center_freq2;
28056c92544dSBjoern A. Zeeb 
28066c92544dSBjoern A. Zeeb 		req.center_ch2 = ieee80211_frequency_to_channel(freq2);
28076c92544dSBjoern A. Zeeb 	}
28086c92544dSBjoern A. Zeeb 
28096c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
28106c92544dSBjoern A. Zeeb }
28116c92544dSBjoern A. Zeeb 
mt7915_mcu_set_eeprom_flash(struct mt7915_dev * dev)28126c92544dSBjoern A. Zeeb static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev)
28136c92544dSBjoern A. Zeeb {
28146c92544dSBjoern A. Zeeb #define MAX_PAGE_IDX_MASK	GENMASK(7, 5)
28156c92544dSBjoern A. Zeeb #define PAGE_IDX_MASK		GENMASK(4, 2)
28166c92544dSBjoern A. Zeeb #define PER_PAGE_SIZE		0x400
28176c92544dSBjoern A. Zeeb 	struct mt7915_mcu_eeprom req = { .buffer_mode = EE_MODE_BUFFER };
28186c92544dSBjoern A. Zeeb 	u16 eeprom_size = mt7915_eeprom_size(dev);
28196c92544dSBjoern A. Zeeb 	u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE);
28206c92544dSBjoern A. Zeeb 	u8 *eep = (u8 *)dev->mt76.eeprom.data;
28216c92544dSBjoern A. Zeeb 	int eep_len;
28226c92544dSBjoern A. Zeeb 	int i;
28236c92544dSBjoern A. Zeeb 
28246c92544dSBjoern A. Zeeb 	for (i = 0; i < total; i++, eep += eep_len) {
28256c92544dSBjoern A. Zeeb 		struct sk_buff *skb;
28266c92544dSBjoern A. Zeeb 		int ret;
28276c92544dSBjoern A. Zeeb 
28286c92544dSBjoern A. Zeeb 		if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE))
28296c92544dSBjoern A. Zeeb 			eep_len = eeprom_size % PER_PAGE_SIZE;
28306c92544dSBjoern A. Zeeb 		else
28316c92544dSBjoern A. Zeeb 			eep_len = PER_PAGE_SIZE;
28326c92544dSBjoern A. Zeeb 
28336c92544dSBjoern A. Zeeb 		skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
28346c92544dSBjoern A. Zeeb 					 sizeof(req) + eep_len);
28356c92544dSBjoern A. Zeeb 		if (!skb)
28366c92544dSBjoern A. Zeeb 			return -ENOMEM;
28376c92544dSBjoern A. Zeeb 
28386c92544dSBjoern A. Zeeb 		req.format = FIELD_PREP(MAX_PAGE_IDX_MASK, total - 1) |
28396c92544dSBjoern A. Zeeb 			     FIELD_PREP(PAGE_IDX_MASK, i) | EE_FORMAT_WHOLE;
28406c92544dSBjoern A. Zeeb 		req.len = cpu_to_le16(eep_len);
28416c92544dSBjoern A. Zeeb 
28426c92544dSBjoern A. Zeeb 		skb_put_data(skb, &req, sizeof(req));
28436c92544dSBjoern A. Zeeb 		skb_put_data(skb, eep, eep_len);
28446c92544dSBjoern A. Zeeb 
28456c92544dSBjoern A. Zeeb 		ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
28466c92544dSBjoern A. Zeeb 					    MCU_EXT_CMD(EFUSE_BUFFER_MODE), true);
28476c92544dSBjoern A. Zeeb 		if (ret)
28486c92544dSBjoern A. Zeeb 			return ret;
28496c92544dSBjoern A. Zeeb 	}
28506c92544dSBjoern A. Zeeb 
28516c92544dSBjoern A. Zeeb 	return 0;
28526c92544dSBjoern A. Zeeb }
28536c92544dSBjoern A. Zeeb 
mt7915_mcu_set_eeprom(struct mt7915_dev * dev)28546c92544dSBjoern A. Zeeb int mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
28556c92544dSBjoern A. Zeeb {
28566c92544dSBjoern A. Zeeb 	struct mt7915_mcu_eeprom req = {
28576c92544dSBjoern A. Zeeb 		.buffer_mode = EE_MODE_EFUSE,
28586c92544dSBjoern A. Zeeb 		.format = EE_FORMAT_WHOLE,
28596c92544dSBjoern A. Zeeb 	};
28606c92544dSBjoern A. Zeeb 
28616c92544dSBjoern A. Zeeb 	if (dev->flash_mode)
28626c92544dSBjoern A. Zeeb 		return mt7915_mcu_set_eeprom_flash(dev);
28636c92544dSBjoern A. Zeeb 
28646c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
28656c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
28666c92544dSBjoern A. Zeeb }
28676c92544dSBjoern A. Zeeb 
mt7915_mcu_get_eeprom(struct mt7915_dev * dev,u32 offset)28686c92544dSBjoern A. Zeeb int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
28696c92544dSBjoern A. Zeeb {
28706c92544dSBjoern A. Zeeb 	struct mt7915_mcu_eeprom_info req = {
28716c92544dSBjoern A. Zeeb 		.addr = cpu_to_le32(round_down(offset,
28726c92544dSBjoern A. Zeeb 				    MT7915_EEPROM_BLOCK_SIZE)),
28736c92544dSBjoern A. Zeeb 	};
28746c92544dSBjoern A. Zeeb 	struct mt7915_mcu_eeprom_info *res;
28756c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
28766c92544dSBjoern A. Zeeb 	int ret;
28776c92544dSBjoern A. Zeeb 	u8 *buf;
28786c92544dSBjoern A. Zeeb 
2879cbb3ec25SBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
2880cbb3ec25SBjoern A. Zeeb 					MCU_EXT_QUERY(EFUSE_ACCESS),
2881cbb3ec25SBjoern A. Zeeb 					&req, sizeof(req), true, &skb);
28826c92544dSBjoern A. Zeeb 	if (ret)
28836c92544dSBjoern A. Zeeb 		return ret;
28846c92544dSBjoern A. Zeeb 
28856c92544dSBjoern A. Zeeb 	res = (struct mt7915_mcu_eeprom_info *)skb->data;
28866c92544dSBjoern A. Zeeb #if defined(__linux__)
28876c92544dSBjoern A. Zeeb 	buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
28886c92544dSBjoern A. Zeeb #elif defined(__FreeBSD__)
28896c92544dSBjoern A. Zeeb 	buf = (u8 *)dev->mt76.eeprom.data + le32_to_cpu(res->addr);
28906c92544dSBjoern A. Zeeb #endif
28916c92544dSBjoern A. Zeeb 	memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE);
28926c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
28936c92544dSBjoern A. Zeeb 
28946c92544dSBjoern A. Zeeb 	return 0;
28956c92544dSBjoern A. Zeeb }
28966c92544dSBjoern A. Zeeb 
mt7915_mcu_get_eeprom_free_block(struct mt7915_dev * dev,u8 * block_num)28976c92544dSBjoern A. Zeeb int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num)
28986c92544dSBjoern A. Zeeb {
28996c92544dSBjoern A. Zeeb 	struct {
29006c92544dSBjoern A. Zeeb 		u8 _rsv;
29016c92544dSBjoern A. Zeeb 		u8 version;
29026c92544dSBjoern A. Zeeb 		u8 die_idx;
29036c92544dSBjoern A. Zeeb 		u8 _rsv2;
29046c92544dSBjoern A. Zeeb 	} __packed req = {
29056c92544dSBjoern A. Zeeb 		.version = 1,
29066c92544dSBjoern A. Zeeb 	};
29076c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
29086c92544dSBjoern A. Zeeb 	int ret;
29096c92544dSBjoern A. Zeeb 
2910cbb3ec25SBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
2911cbb3ec25SBjoern A. Zeeb 					MCU_EXT_QUERY(EFUSE_FREE_BLOCK),
2912cbb3ec25SBjoern A. Zeeb 					&req, sizeof(req), true, &skb);
29136c92544dSBjoern A. Zeeb 	if (ret)
29146c92544dSBjoern A. Zeeb 		return ret;
29156c92544dSBjoern A. Zeeb 
29166c92544dSBjoern A. Zeeb 	*block_num = *(u8 *)skb->data;
29176c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
29186c92544dSBjoern A. Zeeb 
29196c92544dSBjoern A. Zeeb 	return 0;
29206c92544dSBjoern A. Zeeb }
29216c92544dSBjoern A. Zeeb 
mt7915_mcu_set_pre_cal(struct mt7915_dev * dev,u8 idx,u8 * data,u32 len,int cmd)29226c92544dSBjoern A. Zeeb static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
29236c92544dSBjoern A. Zeeb 				  u8 *data, u32 len, int cmd)
29246c92544dSBjoern A. Zeeb {
29256c92544dSBjoern A. Zeeb 	struct {
29266c92544dSBjoern A. Zeeb 		u8 dir;
29276c92544dSBjoern A. Zeeb 		u8 valid;
29286c92544dSBjoern A. Zeeb 		__le16 bitmap;
29296c92544dSBjoern A. Zeeb 		s8 precal;
29306c92544dSBjoern A. Zeeb 		u8 action;
29316c92544dSBjoern A. Zeeb 		u8 band;
29326c92544dSBjoern A. Zeeb 		u8 idx;
29336c92544dSBjoern A. Zeeb 		u8 rsv[4];
29346c92544dSBjoern A. Zeeb 		__le32 len;
29356c92544dSBjoern A. Zeeb 	} req = {};
29366c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
29376c92544dSBjoern A. Zeeb 
29386c92544dSBjoern A. Zeeb 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
29396c92544dSBjoern A. Zeeb 	if (!skb)
29406c92544dSBjoern A. Zeeb 		return -ENOMEM;
29416c92544dSBjoern A. Zeeb 
29426c92544dSBjoern A. Zeeb 	req.idx = idx;
29436c92544dSBjoern A. Zeeb 	req.len = cpu_to_le32(len);
29446c92544dSBjoern A. Zeeb 	skb_put_data(skb, &req, sizeof(req));
29456c92544dSBjoern A. Zeeb 	skb_put_data(skb, data, len);
29466c92544dSBjoern A. Zeeb 
29476c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false);
29486c92544dSBjoern A. Zeeb }
29496c92544dSBjoern A. Zeeb 
mt7915_mcu_apply_group_cal(struct mt7915_dev * dev)29506c92544dSBjoern A. Zeeb int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
29516c92544dSBjoern A. Zeeb {
29526c92544dSBjoern A. Zeeb 	u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
2953*8ba4d145SBjoern A. Zeeb 	u32 total = mt7915_get_cal_group_size(dev);
2954*8ba4d145SBjoern A. Zeeb 	u32 offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2;
29556c92544dSBjoern A. Zeeb 
2956*8ba4d145SBjoern A. Zeeb 	if (!(eep[offs] & MT_EE_WIFI_CAL_GROUP))
29576c92544dSBjoern A. Zeeb 		return 0;
29586c92544dSBjoern A. Zeeb 
29596c92544dSBjoern A. Zeeb 	/*
29606c92544dSBjoern A. Zeeb 	 * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG
29616c92544dSBjoern A. Zeeb 	 * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC
29626c92544dSBjoern A. Zeeb 	 */
29636c92544dSBjoern A. Zeeb 	while (total > 0) {
29646c92544dSBjoern A. Zeeb 		int ret, len;
29656c92544dSBjoern A. Zeeb 
29666c92544dSBjoern A. Zeeb 		len = min_t(u32, total, MT_EE_CAL_UNIT);
29676c92544dSBjoern A. Zeeb 
29686c92544dSBjoern A. Zeeb 		ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len,
29696c92544dSBjoern A. Zeeb 					     MCU_EXT_CMD(GROUP_PRE_CAL_INFO));
29706c92544dSBjoern A. Zeeb 		if (ret)
29716c92544dSBjoern A. Zeeb 			return ret;
29726c92544dSBjoern A. Zeeb 
29736c92544dSBjoern A. Zeeb 		total -= len;
29746c92544dSBjoern A. Zeeb 		cal += len;
29756c92544dSBjoern A. Zeeb 		idx++;
29766c92544dSBjoern A. Zeeb 	}
29776c92544dSBjoern A. Zeeb 
29786c92544dSBjoern A. Zeeb 	return 0;
29796c92544dSBjoern A. Zeeb }
29806c92544dSBjoern A. Zeeb 
mt7915_find_freq_idx(const u16 * freqs,int n_freqs,u16 cur)29816c92544dSBjoern A. Zeeb static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
29826c92544dSBjoern A. Zeeb {
29836c92544dSBjoern A. Zeeb 	int i;
29846c92544dSBjoern A. Zeeb 
29856c92544dSBjoern A. Zeeb 	for (i = 0; i < n_freqs; i++)
29866c92544dSBjoern A. Zeeb 		if (cur == freqs[i])
29876c92544dSBjoern A. Zeeb 			return i;
29886c92544dSBjoern A. Zeeb 
29896c92544dSBjoern A. Zeeb 	return -1;
29906c92544dSBjoern A. Zeeb }
29916c92544dSBjoern A. Zeeb 
mt7915_dpd_freq_idx(struct mt7915_dev * dev,u16 freq,u8 bw)2992*8ba4d145SBjoern A. Zeeb static int mt7915_dpd_freq_idx(struct mt7915_dev *dev, u16 freq, u8 bw)
29936c92544dSBjoern A. Zeeb {
2994*8ba4d145SBjoern A. Zeeb 	static const u16 freq_list_v1[] = {
29956c92544dSBjoern A. Zeeb 		5180, 5200, 5220, 5240,
29966c92544dSBjoern A. Zeeb 		5260, 5280, 5300, 5320,
29976c92544dSBjoern A. Zeeb 		5500, 5520, 5540, 5560,
29986c92544dSBjoern A. Zeeb 		5580, 5600, 5620, 5640,
29996c92544dSBjoern A. Zeeb 		5660, 5680, 5700, 5745,
30006c92544dSBjoern A. Zeeb 		5765, 5785, 5805, 5825
30016c92544dSBjoern A. Zeeb 	};
3002*8ba4d145SBjoern A. Zeeb 	static const u16 freq_list_v2[] = {
3003*8ba4d145SBjoern A. Zeeb 		/* 6G BW20*/
3004*8ba4d145SBjoern A. Zeeb 		5955, 5975, 5995, 6015,
3005*8ba4d145SBjoern A. Zeeb 		6035, 6055, 6075, 6095,
3006*8ba4d145SBjoern A. Zeeb 		6115, 6135, 6155, 6175,
3007*8ba4d145SBjoern A. Zeeb 		6195, 6215, 6235, 6255,
3008*8ba4d145SBjoern A. Zeeb 		6275, 6295, 6315, 6335,
3009*8ba4d145SBjoern A. Zeeb 		6355, 6375, 6395, 6415,
3010*8ba4d145SBjoern A. Zeeb 		6435, 6455, 6475, 6495,
3011*8ba4d145SBjoern A. Zeeb 		6515, 6535, 6555, 6575,
3012*8ba4d145SBjoern A. Zeeb 		6595, 6615, 6635, 6655,
3013*8ba4d145SBjoern A. Zeeb 		6675, 6695, 6715, 6735,
3014*8ba4d145SBjoern A. Zeeb 		6755, 6775, 6795, 6815,
3015*8ba4d145SBjoern A. Zeeb 		6835, 6855, 6875, 6895,
3016*8ba4d145SBjoern A. Zeeb 		6915, 6935, 6955, 6975,
3017*8ba4d145SBjoern A. Zeeb 		6995, 7015, 7035, 7055,
3018*8ba4d145SBjoern A. Zeeb 		7075, 7095, 7115,
3019*8ba4d145SBjoern A. Zeeb 		/* 6G BW160 */
3020*8ba4d145SBjoern A. Zeeb 		6025, 6185, 6345, 6505,
3021*8ba4d145SBjoern A. Zeeb 		6665, 6825, 6985,
3022*8ba4d145SBjoern A. Zeeb 		/* 5G BW20 */
3023*8ba4d145SBjoern A. Zeeb 		5180, 5200, 5220, 5240,
3024*8ba4d145SBjoern A. Zeeb 		5260, 5280, 5300, 5320,
3025*8ba4d145SBjoern A. Zeeb 		5500, 5520, 5540, 5560,
3026*8ba4d145SBjoern A. Zeeb 		5580, 5600, 5620, 5640,
3027*8ba4d145SBjoern A. Zeeb 		5660, 5680, 5700, 5720,
3028*8ba4d145SBjoern A. Zeeb 		5745, 5765, 5785, 5805,
3029*8ba4d145SBjoern A. Zeeb 		5825, 5845, 5865, 5885,
3030*8ba4d145SBjoern A. Zeeb 		/* 5G BW160 */
3031*8ba4d145SBjoern A. Zeeb 		5250, 5570, 5815
3032*8ba4d145SBjoern A. Zeeb 	};
3033*8ba4d145SBjoern A. Zeeb 	static const u16 freq_list_v2_7981[] = {
3034*8ba4d145SBjoern A. Zeeb 		/* 5G BW20 */
3035*8ba4d145SBjoern A. Zeeb 		5180, 5200, 5220, 5240,
3036*8ba4d145SBjoern A. Zeeb 		5260, 5280, 5300, 5320,
3037*8ba4d145SBjoern A. Zeeb 		5500, 5520, 5540, 5560,
3038*8ba4d145SBjoern A. Zeeb 		5580, 5600, 5620, 5640,
3039*8ba4d145SBjoern A. Zeeb 		5660, 5680, 5700, 5720,
3040*8ba4d145SBjoern A. Zeeb 		5745, 5765, 5785, 5805,
3041*8ba4d145SBjoern A. Zeeb 		5825, 5845, 5865, 5885,
3042*8ba4d145SBjoern A. Zeeb 		/* 5G BW160 */
3043*8ba4d145SBjoern A. Zeeb 		5250, 5570, 5815
3044*8ba4d145SBjoern A. Zeeb 	};
3045*8ba4d145SBjoern A. Zeeb 	const u16 *freq_list = freq_list_v1;
3046*8ba4d145SBjoern A. Zeeb 	int n_freqs = ARRAY_SIZE(freq_list_v1);
30476c92544dSBjoern A. Zeeb 	int idx;
30486c92544dSBjoern A. Zeeb 
3049*8ba4d145SBjoern A. Zeeb 	if (!is_mt7915(&dev->mt76)) {
3050*8ba4d145SBjoern A. Zeeb 		if (is_mt7981(&dev->mt76)) {
3051*8ba4d145SBjoern A. Zeeb 			freq_list = freq_list_v2_7981;
3052*8ba4d145SBjoern A. Zeeb 			n_freqs = ARRAY_SIZE(freq_list_v2_7981);
3053*8ba4d145SBjoern A. Zeeb 		} else {
3054*8ba4d145SBjoern A. Zeeb 			freq_list = freq_list_v2;
3055*8ba4d145SBjoern A. Zeeb 			n_freqs = ARRAY_SIZE(freq_list_v2);
3056*8ba4d145SBjoern A. Zeeb 		}
3057*8ba4d145SBjoern A. Zeeb 	}
3058*8ba4d145SBjoern A. Zeeb 
30596c92544dSBjoern A. Zeeb 	if (freq < 4000) {
30606c92544dSBjoern A. Zeeb 		if (freq < 2432)
3061*8ba4d145SBjoern A. Zeeb 			return n_freqs;
30626c92544dSBjoern A. Zeeb 		if (freq < 2457)
3063*8ba4d145SBjoern A. Zeeb 			return n_freqs + 1;
30646c92544dSBjoern A. Zeeb 
3065*8ba4d145SBjoern A. Zeeb 		return n_freqs + 2;
30666c92544dSBjoern A. Zeeb 	}
30676c92544dSBjoern A. Zeeb 
3068*8ba4d145SBjoern A. Zeeb 	if (bw == NL80211_CHAN_WIDTH_80P80)
30696c92544dSBjoern A. Zeeb 		return -1;
30706c92544dSBjoern A. Zeeb 
30716c92544dSBjoern A. Zeeb 	if (bw != NL80211_CHAN_WIDTH_20) {
3072*8ba4d145SBjoern A. Zeeb 		idx = mt7915_find_freq_idx(freq_list, n_freqs, freq + 10);
30736c92544dSBjoern A. Zeeb 		if (idx >= 0)
30746c92544dSBjoern A. Zeeb 			return idx;
30756c92544dSBjoern A. Zeeb 
3076*8ba4d145SBjoern A. Zeeb 		idx = mt7915_find_freq_idx(freq_list, n_freqs, freq - 10);
30776c92544dSBjoern A. Zeeb 		if (idx >= 0)
30786c92544dSBjoern A. Zeeb 			return idx;
30796c92544dSBjoern A. Zeeb 	}
30806c92544dSBjoern A. Zeeb 
3081*8ba4d145SBjoern A. Zeeb 	return mt7915_find_freq_idx(freq_list, n_freqs, freq);
30826c92544dSBjoern A. Zeeb }
30836c92544dSBjoern A. Zeeb 
mt7915_mcu_apply_tx_dpd(struct mt7915_phy * phy)30846c92544dSBjoern A. Zeeb int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
30856c92544dSBjoern A. Zeeb {
30866c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
30876c92544dSBjoern A. Zeeb 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
3088*8ba4d145SBjoern A. Zeeb 	enum nl80211_band band = chandef->chan->band;
3089*8ba4d145SBjoern A. Zeeb 	u32 offs = is_mt7915(&dev->mt76) ? MT_EE_DO_PRE_CAL : MT_EE_DO_PRE_CAL_V2;
3090*8ba4d145SBjoern A. Zeeb 	u16 center_freq = chandef->center_freq1;
30916c92544dSBjoern A. Zeeb 	u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
3092*8ba4d145SBjoern A. Zeeb 	u8 dpd_mask, cal_num = is_mt7915(&dev->mt76) ? 2 : 3;
30936c92544dSBjoern A. Zeeb 	int idx;
30946c92544dSBjoern A. Zeeb 
3095*8ba4d145SBjoern A. Zeeb 	switch (band) {
3096*8ba4d145SBjoern A. Zeeb 	case NL80211_BAND_2GHZ:
3097*8ba4d145SBjoern A. Zeeb 		dpd_mask = MT_EE_WIFI_CAL_DPD_2G;
3098*8ba4d145SBjoern A. Zeeb 		break;
3099*8ba4d145SBjoern A. Zeeb 	case NL80211_BAND_5GHZ:
3100*8ba4d145SBjoern A. Zeeb 		dpd_mask = MT_EE_WIFI_CAL_DPD_5G;
3101*8ba4d145SBjoern A. Zeeb 		break;
3102*8ba4d145SBjoern A. Zeeb 	case NL80211_BAND_6GHZ:
3103*8ba4d145SBjoern A. Zeeb 		dpd_mask = MT_EE_WIFI_CAL_DPD_6G;
3104*8ba4d145SBjoern A. Zeeb 		break;
3105*8ba4d145SBjoern A. Zeeb 	default:
3106*8ba4d145SBjoern A. Zeeb 		dpd_mask = 0;
3107*8ba4d145SBjoern A. Zeeb 		break;
3108*8ba4d145SBjoern A. Zeeb 	}
3109*8ba4d145SBjoern A. Zeeb 
3110*8ba4d145SBjoern A. Zeeb 	if (!(eep[offs] & dpd_mask))
31116c92544dSBjoern A. Zeeb 		return 0;
31126c92544dSBjoern A. Zeeb 
3113*8ba4d145SBjoern A. Zeeb 	idx = mt7915_dpd_freq_idx(dev, center_freq, chandef->width);
31146c92544dSBjoern A. Zeeb 	if (idx < 0)
31156c92544dSBjoern A. Zeeb 		return -EINVAL;
31166c92544dSBjoern A. Zeeb 
31176c92544dSBjoern A. Zeeb 	/* Items: Tx DPD, Tx Flatness */
3118*8ba4d145SBjoern A. Zeeb 	idx = idx * cal_num;
3119*8ba4d145SBjoern A. Zeeb 	cal += mt7915_get_cal_group_size(dev) + (idx * MT_EE_CAL_UNIT);
31206c92544dSBjoern A. Zeeb 
3121*8ba4d145SBjoern A. Zeeb 	while (cal_num--) {
31226c92544dSBjoern A. Zeeb 		int ret;
31236c92544dSBjoern A. Zeeb 
31246c92544dSBjoern A. Zeeb 		ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT,
31256c92544dSBjoern A. Zeeb 					     MCU_EXT_CMD(DPD_PRE_CAL_INFO));
31266c92544dSBjoern A. Zeeb 		if (ret)
31276c92544dSBjoern A. Zeeb 			return ret;
31286c92544dSBjoern A. Zeeb 
31296c92544dSBjoern A. Zeeb 		idx++;
3130*8ba4d145SBjoern A. Zeeb 		cal += MT_EE_CAL_UNIT;
31316c92544dSBjoern A. Zeeb 	}
31326c92544dSBjoern A. Zeeb 
31336c92544dSBjoern A. Zeeb 	return 0;
31346c92544dSBjoern A. Zeeb }
31356c92544dSBjoern A. Zeeb 
mt7915_mcu_get_chan_mib_info(struct mt7915_phy * phy,bool chan_switch)31366c92544dSBjoern A. Zeeb int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch)
31376c92544dSBjoern A. Zeeb {
31386c92544dSBjoern A. Zeeb 	struct mt76_channel_state *state = phy->mt76->chan_state;
31396c92544dSBjoern A. Zeeb 	struct mt76_channel_state *state_ts = &phy->state_ts;
31406c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3141cbb3ec25SBjoern A. Zeeb 	struct mt7915_mcu_mib *res, req[5];
31426c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
3143cbb3ec25SBjoern A. Zeeb 	static const u32 *offs;
3144cbb3ec25SBjoern A. Zeeb 	int i, ret, len, offs_cc;
3145cbb3ec25SBjoern A. Zeeb 	u64 cc_tx;
31466c92544dSBjoern A. Zeeb 
3147cbb3ec25SBjoern A. Zeeb 	/* strict order */
3148cbb3ec25SBjoern A. Zeeb 	if (is_mt7915(&dev->mt76)) {
3149cbb3ec25SBjoern A. Zeeb 		static const u32 chip_offs[] = {
3150cbb3ec25SBjoern A. Zeeb 			MIB_NON_WIFI_TIME,
3151cbb3ec25SBjoern A. Zeeb 			MIB_TX_TIME,
3152cbb3ec25SBjoern A. Zeeb 			MIB_RX_TIME,
3153cbb3ec25SBjoern A. Zeeb 			MIB_OBSS_AIRTIME,
3154cbb3ec25SBjoern A. Zeeb 			MIB_TXOP_INIT_COUNT,
3155cbb3ec25SBjoern A. Zeeb 		};
3156cbb3ec25SBjoern A. Zeeb 		len = ARRAY_SIZE(chip_offs);
3157cbb3ec25SBjoern A. Zeeb 		offs = chip_offs;
3158cbb3ec25SBjoern A. Zeeb 		offs_cc = 20;
3159cbb3ec25SBjoern A. Zeeb 	} else {
3160cbb3ec25SBjoern A. Zeeb 		static const u32 chip_offs[] = {
3161cbb3ec25SBjoern A. Zeeb 			MIB_NON_WIFI_TIME_V2,
3162cbb3ec25SBjoern A. Zeeb 			MIB_TX_TIME_V2,
3163cbb3ec25SBjoern A. Zeeb 			MIB_RX_TIME_V2,
3164cbb3ec25SBjoern A. Zeeb 			MIB_OBSS_AIRTIME_V2
3165cbb3ec25SBjoern A. Zeeb 		};
3166cbb3ec25SBjoern A. Zeeb 		len = ARRAY_SIZE(chip_offs);
3167cbb3ec25SBjoern A. Zeeb 		offs = chip_offs;
3168cbb3ec25SBjoern A. Zeeb 		offs_cc = 0;
31696c92544dSBjoern A. Zeeb 	}
31706c92544dSBjoern A. Zeeb 
3171cbb3ec25SBjoern A. Zeeb 	for (i = 0; i < len; i++) {
3172cbb3ec25SBjoern A. Zeeb 		req[i].band = cpu_to_le32(phy->mt76->band_idx);
3173cbb3ec25SBjoern A. Zeeb 		req[i].offs = cpu_to_le32(offs[i]);
31746c92544dSBjoern A. Zeeb 	}
31756c92544dSBjoern A. Zeeb 
31766c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(GET_MIB_INFO),
3177cbb3ec25SBjoern A. Zeeb 					req, len * sizeof(req[0]), true, &skb);
31786c92544dSBjoern A. Zeeb 	if (ret)
31796c92544dSBjoern A. Zeeb 		return ret;
31806c92544dSBjoern A. Zeeb 
3181cbb3ec25SBjoern A. Zeeb 	res = (struct mt7915_mcu_mib *)(skb->data + offs_cc);
3182cbb3ec25SBjoern A. Zeeb 
3183cbb3ec25SBjoern A. Zeeb #define __res_u64(s) le64_to_cpu(res[s].data)
3184*8ba4d145SBjoern A. Zeeb 	/* subtract Tx backoff time from Tx duration for MT7915 */
3185*8ba4d145SBjoern A. Zeeb 	if (is_mt7915(&dev->mt76)) {
3186*8ba4d145SBjoern A. Zeeb 		u64 backoff = (__res_u64(4) & 0xffff) * 79;  /* 16us + 9us * 7 */
3187*8ba4d145SBjoern A. Zeeb 		cc_tx = __res_u64(1) - backoff;
3188*8ba4d145SBjoern A. Zeeb 	} else {
3189*8ba4d145SBjoern A. Zeeb 		cc_tx = __res_u64(1);
3190*8ba4d145SBjoern A. Zeeb 	}
31916c92544dSBjoern A. Zeeb 
31926c92544dSBjoern A. Zeeb 	if (chan_switch)
31936c92544dSBjoern A. Zeeb 		goto out;
31946c92544dSBjoern A. Zeeb 
3195cbb3ec25SBjoern A. Zeeb 	state->cc_tx += cc_tx - state_ts->cc_tx;
31966c92544dSBjoern A. Zeeb 	state->cc_bss_rx += __res_u64(2) - state_ts->cc_bss_rx;
31976c92544dSBjoern A. Zeeb 	state->cc_rx += __res_u64(2) + __res_u64(3) - state_ts->cc_rx;
3198cbb3ec25SBjoern A. Zeeb 	state->cc_busy += __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3) -
3199cbb3ec25SBjoern A. Zeeb 			  state_ts->cc_busy;
32006c92544dSBjoern A. Zeeb 
32016c92544dSBjoern A. Zeeb out:
3202cbb3ec25SBjoern A. Zeeb 	state_ts->cc_tx = cc_tx;
32036c92544dSBjoern A. Zeeb 	state_ts->cc_bss_rx = __res_u64(2);
32046c92544dSBjoern A. Zeeb 	state_ts->cc_rx = __res_u64(2) + __res_u64(3);
3205cbb3ec25SBjoern A. Zeeb 	state_ts->cc_busy = __res_u64(0) + cc_tx + __res_u64(2) + __res_u64(3);
32066c92544dSBjoern A. Zeeb #undef __res_u64
32076c92544dSBjoern A. Zeeb 
32086c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
32096c92544dSBjoern A. Zeeb 
32106c92544dSBjoern A. Zeeb 	return 0;
32116c92544dSBjoern A. Zeeb }
32126c92544dSBjoern A. Zeeb 
mt7915_mcu_get_temperature(struct mt7915_phy * phy)32136c92544dSBjoern A. Zeeb int mt7915_mcu_get_temperature(struct mt7915_phy *phy)
32146c92544dSBjoern A. Zeeb {
32156c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
32166c92544dSBjoern A. Zeeb 	struct {
32176c92544dSBjoern A. Zeeb 		u8 ctrl_id;
32186c92544dSBjoern A. Zeeb 		u8 action;
3219cbb3ec25SBjoern A. Zeeb 		u8 band_idx;
32206c92544dSBjoern A. Zeeb 		u8 rsv[5];
32216c92544dSBjoern A. Zeeb 	} req = {
32226c92544dSBjoern A. Zeeb 		.ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
3223cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
32246c92544dSBjoern A. Zeeb 	};
32256c92544dSBjoern A. Zeeb 
32266c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
32276c92544dSBjoern A. Zeeb 				 sizeof(req), true);
32286c92544dSBjoern A. Zeeb }
32296c92544dSBjoern A. Zeeb 
mt7915_mcu_set_thermal_throttling(struct mt7915_phy * phy,u8 state)32306c92544dSBjoern A. Zeeb int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
32316c92544dSBjoern A. Zeeb {
32326c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3233cbb3ec25SBjoern A. Zeeb 	struct mt7915_mcu_thermal_ctrl req = {
3234cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
3235cbb3ec25SBjoern A. Zeeb 		.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG,
3236cbb3ec25SBjoern A. Zeeb 	};
3237cbb3ec25SBjoern A. Zeeb 	int level, ret;
3238cbb3ec25SBjoern A. Zeeb 
3239cbb3ec25SBjoern A. Zeeb 	/* set duty cycle and level */
3240cbb3ec25SBjoern A. Zeeb 	for (level = 0; level < 4; level++) {
3241cbb3ec25SBjoern A. Zeeb 		req.duty.duty_level = level;
3242cbb3ec25SBjoern A. Zeeb 		req.duty.duty_cycle = state;
3243cbb3ec25SBjoern A. Zeeb 		state /= 2;
3244cbb3ec25SBjoern A. Zeeb 
3245cbb3ec25SBjoern A. Zeeb 		ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
3246cbb3ec25SBjoern A. Zeeb 					&req, sizeof(req), false);
3247cbb3ec25SBjoern A. Zeeb 		if (ret)
3248cbb3ec25SBjoern A. Zeeb 			return ret;
3249cbb3ec25SBjoern A. Zeeb 	}
3250cbb3ec25SBjoern A. Zeeb 	return 0;
3251cbb3ec25SBjoern A. Zeeb }
3252cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_set_thermal_protect(struct mt7915_phy * phy)3253cbb3ec25SBjoern A. Zeeb int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy)
3254cbb3ec25SBjoern A. Zeeb {
3255cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
32566c92544dSBjoern A. Zeeb 	struct {
32576c92544dSBjoern A. Zeeb 		struct mt7915_mcu_thermal_ctrl ctrl;
32586c92544dSBjoern A. Zeeb 
32596c92544dSBjoern A. Zeeb 		__le32 trigger_temp;
32606c92544dSBjoern A. Zeeb 		__le32 restore_temp;
32616c92544dSBjoern A. Zeeb 		__le16 sustain_time;
32626c92544dSBjoern A. Zeeb 		u8 rsv[2];
32636c92544dSBjoern A. Zeeb 	} __packed req = {
32646c92544dSBjoern A. Zeeb 		.ctrl = {
3265cbb3ec25SBjoern A. Zeeb 			.band_idx = phy->mt76->band_idx,
3266cbb3ec25SBjoern A. Zeeb 			.type.protect_type = 1,
3267cbb3ec25SBjoern A. Zeeb 			.type.trigger_type = 1,
32686c92544dSBjoern A. Zeeb 		},
32696c92544dSBjoern A. Zeeb 	};
32706c92544dSBjoern A. Zeeb 	int ret;
32716c92544dSBjoern A. Zeeb 
3272cbb3ec25SBjoern A. Zeeb 	req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
32736c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
32746c92544dSBjoern A. Zeeb 				&req, sizeof(req.ctrl), false);
3275cbb3ec25SBjoern A. Zeeb 
32766c92544dSBjoern A. Zeeb 	if (ret)
32776c92544dSBjoern A. Zeeb 		return ret;
32786c92544dSBjoern A. Zeeb 
32796c92544dSBjoern A. Zeeb 	/* set high-temperature trigger threshold */
32806c92544dSBjoern A. Zeeb 	req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
32816c92544dSBjoern A. Zeeb 	/* add a safety margin ~10 */
32826c92544dSBjoern A. Zeeb 	req.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
32836c92544dSBjoern A. Zeeb 	req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
32846c92544dSBjoern A. Zeeb 	req.sustain_time = cpu_to_le16(10);
32856c92544dSBjoern A. Zeeb 
32866c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
32876c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
32886c92544dSBjoern A. Zeeb }
32896c92544dSBjoern A. Zeeb 
mt7915_mcu_set_txpower_frame_min(struct mt7915_phy * phy,s8 txpower)3290cbb3ec25SBjoern A. Zeeb int mt7915_mcu_set_txpower_frame_min(struct mt7915_phy *phy, s8 txpower)
3291cbb3ec25SBjoern A. Zeeb {
3292cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3293cbb3ec25SBjoern A. Zeeb 	struct {
3294cbb3ec25SBjoern A. Zeeb 		u8 format_id;
3295cbb3ec25SBjoern A. Zeeb 		u8 rsv;
3296cbb3ec25SBjoern A. Zeeb 		u8 band_idx;
3297cbb3ec25SBjoern A. Zeeb 		s8 txpower_min;
3298cbb3ec25SBjoern A. Zeeb 	} __packed req = {
3299cbb3ec25SBjoern A. Zeeb 		.format_id = TX_POWER_LIMIT_FRAME_MIN,
3300cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
3301cbb3ec25SBjoern A. Zeeb 		.txpower_min = txpower * 2, /* 0.5db */
3302cbb3ec25SBjoern A. Zeeb 	};
3303cbb3ec25SBjoern A. Zeeb 
3304cbb3ec25SBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76,
3305cbb3ec25SBjoern A. Zeeb 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
3306cbb3ec25SBjoern A. Zeeb 				 sizeof(req), true);
3307cbb3ec25SBjoern A. Zeeb }
3308cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_set_txpower_frame(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,s8 txpower)3309cbb3ec25SBjoern A. Zeeb int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
3310cbb3ec25SBjoern A. Zeeb 				 struct ieee80211_vif *vif,
3311cbb3ec25SBjoern A. Zeeb 				 struct ieee80211_sta *sta, s8 txpower)
3312cbb3ec25SBjoern A. Zeeb {
3313cbb3ec25SBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
3314cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3315cbb3ec25SBjoern A. Zeeb 	struct mt76_phy *mphy = phy->mt76;
3316cbb3ec25SBjoern A. Zeeb 	struct {
3317cbb3ec25SBjoern A. Zeeb 		u8 format_id;
3318cbb3ec25SBjoern A. Zeeb 		u8 rsv[3];
3319cbb3ec25SBjoern A. Zeeb 		u8 band_idx;
3320cbb3ec25SBjoern A. Zeeb 		s8 txpower_max;
3321cbb3ec25SBjoern A. Zeeb 		__le16 wcid;
3322cbb3ec25SBjoern A. Zeeb 		s8 txpower_offs[48];
3323cbb3ec25SBjoern A. Zeeb 	} __packed req = {
3324cbb3ec25SBjoern A. Zeeb 		.format_id = TX_POWER_LIMIT_FRAME,
3325cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
3326cbb3ec25SBjoern A. Zeeb 		.txpower_max = DIV_ROUND_UP(mphy->txpower_cur, 2),
3327cbb3ec25SBjoern A. Zeeb 		.wcid = cpu_to_le16(msta->wcid.idx),
3328cbb3ec25SBjoern A. Zeeb 	};
3329cbb3ec25SBjoern A. Zeeb 	int ret;
3330cbb3ec25SBjoern A. Zeeb 	s8 txpower_sku[MT7915_SKU_RATE_NUM];
3331cbb3ec25SBjoern A. Zeeb 
3332cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_get_txpower_sku(phy, txpower_sku, sizeof(txpower_sku));
3333cbb3ec25SBjoern A. Zeeb 	if (ret)
3334cbb3ec25SBjoern A. Zeeb 		return ret;
3335cbb3ec25SBjoern A. Zeeb 
3336cbb3ec25SBjoern A. Zeeb 	txpower = mt7915_get_power_bound(phy, txpower);
3337cbb3ec25SBjoern A. Zeeb 	if (txpower > mphy->txpower_cur || txpower < 0)
3338cbb3ec25SBjoern A. Zeeb 		return -EINVAL;
3339cbb3ec25SBjoern A. Zeeb 
3340cbb3ec25SBjoern A. Zeeb 	if (txpower) {
3341cbb3ec25SBjoern A. Zeeb 		u32 offs, len, i;
3342cbb3ec25SBjoern A. Zeeb 
3343cbb3ec25SBjoern A. Zeeb 		if (sta->deflink.ht_cap.ht_supported) {
3344cbb3ec25SBjoern A. Zeeb 			const u8 *sku_len = mt7915_sku_group_len;
3345cbb3ec25SBjoern A. Zeeb 
3346cbb3ec25SBjoern A. Zeeb 			offs = sku_len[SKU_CCK] + sku_len[SKU_OFDM];
3347cbb3ec25SBjoern A. Zeeb 			len = sku_len[SKU_HT_BW20] + sku_len[SKU_HT_BW40];
3348cbb3ec25SBjoern A. Zeeb 
3349cbb3ec25SBjoern A. Zeeb 			if (sta->deflink.vht_cap.vht_supported) {
3350cbb3ec25SBjoern A. Zeeb 				offs += len;
3351cbb3ec25SBjoern A. Zeeb 				len = sku_len[SKU_VHT_BW20] * 4;
3352cbb3ec25SBjoern A. Zeeb 
3353cbb3ec25SBjoern A. Zeeb 				if (sta->deflink.he_cap.has_he) {
3354cbb3ec25SBjoern A. Zeeb 					offs += len + sku_len[SKU_HE_RU26] * 3;
3355cbb3ec25SBjoern A. Zeeb 					len = sku_len[SKU_HE_RU242] * 4;
3356cbb3ec25SBjoern A. Zeeb 				}
3357cbb3ec25SBjoern A. Zeeb 			}
3358cbb3ec25SBjoern A. Zeeb 		} else {
3359cbb3ec25SBjoern A. Zeeb 			return -EINVAL;
3360cbb3ec25SBjoern A. Zeeb 		}
3361cbb3ec25SBjoern A. Zeeb 
3362cbb3ec25SBjoern A. Zeeb 		for (i = 0; i < len; i++, offs++)
3363cbb3ec25SBjoern A. Zeeb 			req.txpower_offs[i] =
3364cbb3ec25SBjoern A. Zeeb 				DIV_ROUND_UP(txpower - txpower_sku[offs], 2);
3365cbb3ec25SBjoern A. Zeeb 	}
3366cbb3ec25SBjoern A. Zeeb 
3367cbb3ec25SBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76,
3368cbb3ec25SBjoern A. Zeeb 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
3369cbb3ec25SBjoern A. Zeeb 				 sizeof(req), true);
3370cbb3ec25SBjoern A. Zeeb }
3371cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_set_txpower_sku(struct mt7915_phy * phy)33726c92544dSBjoern A. Zeeb int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
33736c92544dSBjoern A. Zeeb {
33746c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
33756c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = phy->mt76;
33766c92544dSBjoern A. Zeeb 	struct ieee80211_hw *hw = mphy->hw;
3377cbb3ec25SBjoern A. Zeeb 	struct mt7915_mcu_txpower_sku req = {
3378cbb3ec25SBjoern A. Zeeb 		.format_id = TX_POWER_LIMIT_TABLE,
3379cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
33806c92544dSBjoern A. Zeeb 	};
33816c92544dSBjoern A. Zeeb 	struct mt76_power_limits limits_array;
33826c92544dSBjoern A. Zeeb 	s8 *la = (s8 *)&limits_array;
3383cbb3ec25SBjoern A. Zeeb 	int i, idx;
3384cbb3ec25SBjoern A. Zeeb 	int tx_power;
33856c92544dSBjoern A. Zeeb 
3386cbb3ec25SBjoern A. Zeeb 	tx_power = mt7915_get_power_bound(phy, hw->conf.power_level);
33876c92544dSBjoern A. Zeeb 	tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
33886c92544dSBjoern A. Zeeb 					      &limits_array, tx_power);
33896c92544dSBjoern A. Zeeb 	mphy->txpower_cur = tx_power;
33906c92544dSBjoern A. Zeeb 
33916c92544dSBjoern A. Zeeb 	for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
33926c92544dSBjoern A. Zeeb 		u8 mcs_num, len = mt7915_sku_group_len[i];
33936c92544dSBjoern A. Zeeb 		int j;
33946c92544dSBjoern A. Zeeb 
33956c92544dSBjoern A. Zeeb 		if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) {
33966c92544dSBjoern A. Zeeb 			mcs_num = 10;
33976c92544dSBjoern A. Zeeb 
33986c92544dSBjoern A. Zeeb 			if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
33996c92544dSBjoern A. Zeeb 				la = (s8 *)&limits_array + 12;
34006c92544dSBjoern A. Zeeb 		} else {
34016c92544dSBjoern A. Zeeb 			mcs_num = len;
34026c92544dSBjoern A. Zeeb 		}
34036c92544dSBjoern A. Zeeb 
34046c92544dSBjoern A. Zeeb 		for (j = 0; j < min_t(u8, mcs_num, len); j++)
3405cbb3ec25SBjoern A. Zeeb 			req.txpower_sku[idx + j] = la[j];
34066c92544dSBjoern A. Zeeb 
34076c92544dSBjoern A. Zeeb 		la += mcs_num;
34086c92544dSBjoern A. Zeeb 		idx += len;
34096c92544dSBjoern A. Zeeb 	}
34106c92544dSBjoern A. Zeeb 
34116c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76,
34126c92544dSBjoern A. Zeeb 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
34136c92544dSBjoern A. Zeeb 				 sizeof(req), true);
34146c92544dSBjoern A. Zeeb }
34156c92544dSBjoern A. Zeeb 
mt7915_mcu_get_txpower_sku(struct mt7915_phy * phy,s8 * txpower,int len)34166c92544dSBjoern A. Zeeb int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
34176c92544dSBjoern A. Zeeb {
34186c92544dSBjoern A. Zeeb #define RATE_POWER_INFO	2
34196c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
34206c92544dSBjoern A. Zeeb 	struct {
34216c92544dSBjoern A. Zeeb 		u8 format_id;
34226c92544dSBjoern A. Zeeb 		u8 category;
3423cbb3ec25SBjoern A. Zeeb 		u8 band_idx;
34246c92544dSBjoern A. Zeeb 		u8 _rsv;
34256c92544dSBjoern A. Zeeb 	} __packed req = {
3426cbb3ec25SBjoern A. Zeeb 		.format_id = TX_POWER_LIMIT_INFO,
34276c92544dSBjoern A. Zeeb 		.category = RATE_POWER_INFO,
3428cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
34296c92544dSBjoern A. Zeeb 	};
3430cbb3ec25SBjoern A. Zeeb 	s8 txpower_sku[MT7915_SKU_RATE_NUM][2];
34316c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
34326c92544dSBjoern A. Zeeb 	int ret, i;
34336c92544dSBjoern A. Zeeb 
34346c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76,
34356c92544dSBjoern A. Zeeb 					MCU_EXT_CMD(TX_POWER_FEATURE_CTRL),
34366c92544dSBjoern A. Zeeb 					&req, sizeof(req), true, &skb);
34376c92544dSBjoern A. Zeeb 	if (ret)
34386c92544dSBjoern A. Zeeb 		return ret;
34396c92544dSBjoern A. Zeeb 
3440cbb3ec25SBjoern A. Zeeb 	memcpy(txpower_sku, skb->data + 4, sizeof(txpower_sku));
34416c92544dSBjoern A. Zeeb 	for (i = 0; i < len; i++)
3442cbb3ec25SBjoern A. Zeeb 		txpower[i] = txpower_sku[i][req.band_idx];
34436c92544dSBjoern A. Zeeb 
34446c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
34456c92544dSBjoern A. Zeeb 
34466c92544dSBjoern A. Zeeb 	return 0;
34476c92544dSBjoern A. Zeeb }
34486c92544dSBjoern A. Zeeb 
mt7915_mcu_set_test_param(struct mt7915_dev * dev,u8 param,bool test_mode,u8 en)34496c92544dSBjoern A. Zeeb int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
34506c92544dSBjoern A. Zeeb 			      u8 en)
34516c92544dSBjoern A. Zeeb {
34526c92544dSBjoern A. Zeeb 	struct {
34536c92544dSBjoern A. Zeeb 		u8 test_mode_en;
34546c92544dSBjoern A. Zeeb 		u8 param_idx;
34556c92544dSBjoern A. Zeeb 		u8 _rsv[2];
34566c92544dSBjoern A. Zeeb 
34576c92544dSBjoern A. Zeeb 		u8 enable;
34586c92544dSBjoern A. Zeeb 		u8 _rsv2[3];
34596c92544dSBjoern A. Zeeb 
34606c92544dSBjoern A. Zeeb 		u8 pad[8];
34616c92544dSBjoern A. Zeeb 	} __packed req = {
34626c92544dSBjoern A. Zeeb 		.test_mode_en = test_mode,
34636c92544dSBjoern A. Zeeb 		.param_idx = param,
34646c92544dSBjoern A. Zeeb 		.enable = en,
34656c92544dSBjoern A. Zeeb 	};
34666c92544dSBjoern A. Zeeb 
34676c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req,
34686c92544dSBjoern A. Zeeb 				 sizeof(req), false);
34696c92544dSBjoern A. Zeeb }
34706c92544dSBjoern A. Zeeb 
mt7915_mcu_set_sku_en(struct mt7915_phy * phy,bool enable)34716c92544dSBjoern A. Zeeb int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
34726c92544dSBjoern A. Zeeb {
34736c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
34746c92544dSBjoern A. Zeeb 	struct mt7915_sku {
34756c92544dSBjoern A. Zeeb 		u8 format_id;
34766c92544dSBjoern A. Zeeb 		u8 sku_enable;
3477cbb3ec25SBjoern A. Zeeb 		u8 band_idx;
34786c92544dSBjoern A. Zeeb 		u8 rsv;
34796c92544dSBjoern A. Zeeb 	} __packed req = {
3480cbb3ec25SBjoern A. Zeeb 		.format_id = TX_POWER_LIMIT_ENABLE,
3481cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
34826c92544dSBjoern A. Zeeb 		.sku_enable = enable,
34836c92544dSBjoern A. Zeeb 	};
34846c92544dSBjoern A. Zeeb 
34856c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76,
34866c92544dSBjoern A. Zeeb 				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
34876c92544dSBjoern A. Zeeb 				 sizeof(req), true);
34886c92544dSBjoern A. Zeeb }
34896c92544dSBjoern A. Zeeb 
mt7915_mcu_set_ser(struct mt7915_dev * dev,u8 action,u8 set,u8 band)34906c92544dSBjoern A. Zeeb int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
34916c92544dSBjoern A. Zeeb {
34926c92544dSBjoern A. Zeeb 	struct {
34936c92544dSBjoern A. Zeeb 		u8 action;
34946c92544dSBjoern A. Zeeb 		u8 set;
34956c92544dSBjoern A. Zeeb 		u8 band;
34966c92544dSBjoern A. Zeeb 		u8 rsv;
34976c92544dSBjoern A. Zeeb 	} req = {
34986c92544dSBjoern A. Zeeb 		.action = action,
34996c92544dSBjoern A. Zeeb 		.set = set,
35006c92544dSBjoern A. Zeeb 		.band = band,
35016c92544dSBjoern A. Zeeb 	};
35026c92544dSBjoern A. Zeeb 
35036c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SER_TRIGGER),
35046c92544dSBjoern A. Zeeb 				 &req, sizeof(req), false);
35056c92544dSBjoern A. Zeeb }
35066c92544dSBjoern A. Zeeb 
mt7915_mcu_set_txbf(struct mt7915_dev * dev,u8 action)35076c92544dSBjoern A. Zeeb int mt7915_mcu_set_txbf(struct mt7915_dev *dev, u8 action)
35086c92544dSBjoern A. Zeeb {
35096c92544dSBjoern A. Zeeb 	struct {
35106c92544dSBjoern A. Zeeb 		u8 action;
35116c92544dSBjoern A. Zeeb 		union {
35126c92544dSBjoern A. Zeeb 			struct {
35136c92544dSBjoern A. Zeeb 				u8 snd_mode;
35146c92544dSBjoern A. Zeeb 				u8 sta_num;
35156c92544dSBjoern A. Zeeb 				u8 rsv;
35166c92544dSBjoern A. Zeeb 				u8 wlan_idx[4];
35176c92544dSBjoern A. Zeeb 				__le32 snd_period;	/* ms */
35186c92544dSBjoern A. Zeeb 			} __packed snd;
35196c92544dSBjoern A. Zeeb 			struct {
35206c92544dSBjoern A. Zeeb 				bool ebf;
35216c92544dSBjoern A. Zeeb 				bool ibf;
35226c92544dSBjoern A. Zeeb 				u8 rsv;
35236c92544dSBjoern A. Zeeb 			} __packed type;
35246c92544dSBjoern A. Zeeb 			struct {
35256c92544dSBjoern A. Zeeb 				u8 bf_num;
35266c92544dSBjoern A. Zeeb 				u8 bf_bitmap;
35276c92544dSBjoern A. Zeeb 				u8 bf_sel[8];
35286c92544dSBjoern A. Zeeb 				u8 rsv[5];
35296c92544dSBjoern A. Zeeb 			} __packed mod;
35306c92544dSBjoern A. Zeeb 		};
35316c92544dSBjoern A. Zeeb 	} __packed req = {
35326c92544dSBjoern A. Zeeb 		.action = action,
35336c92544dSBjoern A. Zeeb 	};
35346c92544dSBjoern A. Zeeb 
35356c92544dSBjoern A. Zeeb #define MT_BF_PROCESSING	4
35366c92544dSBjoern A. Zeeb 	switch (action) {
35376c92544dSBjoern A. Zeeb 	case MT_BF_SOUNDING_ON:
35386c92544dSBjoern A. Zeeb 		req.snd.snd_mode = MT_BF_PROCESSING;
35396c92544dSBjoern A. Zeeb 		break;
35406c92544dSBjoern A. Zeeb 	case MT_BF_TYPE_UPDATE:
35416c92544dSBjoern A. Zeeb 		req.type.ebf = true;
35426c92544dSBjoern A. Zeeb 		req.type.ibf = dev->ibf;
35436c92544dSBjoern A. Zeeb 		break;
35446c92544dSBjoern A. Zeeb 	case MT_BF_MODULE_UPDATE:
35456c92544dSBjoern A. Zeeb 		req.mod.bf_num = 2;
35466c92544dSBjoern A. Zeeb 		req.mod.bf_bitmap = GENMASK(1, 0);
35476c92544dSBjoern A. Zeeb 		break;
35486c92544dSBjoern A. Zeeb 	default:
35496c92544dSBjoern A. Zeeb 		return -EINVAL;
35506c92544dSBjoern A. Zeeb 	}
35516c92544dSBjoern A. Zeeb 
35526c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TXBF_ACTION), &req,
35536c92544dSBjoern A. Zeeb 				 sizeof(req), true);
35546c92544dSBjoern A. Zeeb }
35556c92544dSBjoern A. Zeeb 
3556cbb3ec25SBjoern A. Zeeb static int
mt7915_mcu_enable_obss_spr(struct mt7915_phy * phy,u8 action,u8 val)3557cbb3ec25SBjoern A. Zeeb mt7915_mcu_enable_obss_spr(struct mt7915_phy *phy, u8 action, u8 val)
35586c92544dSBjoern A. Zeeb {
3559cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3560cbb3ec25SBjoern A. Zeeb 	struct mt7915_mcu_sr_ctrl req = {
3561cbb3ec25SBjoern A. Zeeb 		.action = action,
3562cbb3ec25SBjoern A. Zeeb 		.argnum = 1,
3563cbb3ec25SBjoern A. Zeeb 		.band_idx = phy->mt76->band_idx,
3564cbb3ec25SBjoern A. Zeeb 		.val = cpu_to_le32(val),
35656c92544dSBjoern A. Zeeb 	};
35666c92544dSBjoern A. Zeeb 
35676c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
35686c92544dSBjoern A. Zeeb 				 sizeof(req), true);
35696c92544dSBjoern A. Zeeb }
35706c92544dSBjoern A. Zeeb 
3571cbb3ec25SBjoern A. Zeeb static int
mt7915_mcu_set_obss_spr_pd(struct mt7915_phy * phy,struct ieee80211_he_obss_pd * he_obss_pd)3572cbb3ec25SBjoern A. Zeeb mt7915_mcu_set_obss_spr_pd(struct mt7915_phy *phy,
3573cbb3ec25SBjoern A. Zeeb 			   struct ieee80211_he_obss_pd *he_obss_pd)
3574cbb3ec25SBjoern A. Zeeb {
3575cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3576cbb3ec25SBjoern A. Zeeb 	struct {
3577cbb3ec25SBjoern A. Zeeb 		struct mt7915_mcu_sr_ctrl ctrl;
3578cbb3ec25SBjoern A. Zeeb 		struct {
3579cbb3ec25SBjoern A. Zeeb 			u8 pd_th_non_srg;
3580cbb3ec25SBjoern A. Zeeb 			u8 pd_th_srg;
3581cbb3ec25SBjoern A. Zeeb 			u8 period_offs;
3582cbb3ec25SBjoern A. Zeeb 			u8 rcpi_src;
3583cbb3ec25SBjoern A. Zeeb 			__le16 obss_pd_min;
3584cbb3ec25SBjoern A. Zeeb 			__le16 obss_pd_min_srg;
3585cbb3ec25SBjoern A. Zeeb 			u8 resp_txpwr_mode;
3586cbb3ec25SBjoern A. Zeeb 			u8 txpwr_restrict_mode;
3587cbb3ec25SBjoern A. Zeeb 			u8 txpwr_ref;
3588cbb3ec25SBjoern A. Zeeb 			u8 rsv[3];
3589cbb3ec25SBjoern A. Zeeb 		} __packed param;
3590cbb3ec25SBjoern A. Zeeb 	} __packed req = {
3591cbb3ec25SBjoern A. Zeeb 		.ctrl = {
3592cbb3ec25SBjoern A. Zeeb 			.action = SPR_SET_PARAM,
3593cbb3ec25SBjoern A. Zeeb 			.argnum = 9,
3594cbb3ec25SBjoern A. Zeeb 			.band_idx = phy->mt76->band_idx,
3595cbb3ec25SBjoern A. Zeeb 		},
3596cbb3ec25SBjoern A. Zeeb 	};
3597cbb3ec25SBjoern A. Zeeb 	int ret;
3598cbb3ec25SBjoern A. Zeeb 	u8 max_th = 82, non_srg_max_th = 62;
3599cbb3ec25SBjoern A. Zeeb 
3600cbb3ec25SBjoern A. Zeeb 	/* disable firmware dynamical PD asjustment */
3601cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_DPD, false);
3602cbb3ec25SBjoern A. Zeeb 	if (ret)
3603cbb3ec25SBjoern A. Zeeb 		return ret;
3604cbb3ec25SBjoern A. Zeeb 
3605cbb3ec25SBjoern A. Zeeb 	if (he_obss_pd->sr_ctrl &
3606cbb3ec25SBjoern A. Zeeb 	    IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)
3607cbb3ec25SBjoern A. Zeeb 		req.param.pd_th_non_srg = max_th;
3608cbb3ec25SBjoern A. Zeeb 	else if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
3609cbb3ec25SBjoern A. Zeeb 		req.param.pd_th_non_srg  = max_th - he_obss_pd->non_srg_max_offset;
3610cbb3ec25SBjoern A. Zeeb 	else
3611cbb3ec25SBjoern A. Zeeb 		req.param.pd_th_non_srg  = non_srg_max_th;
3612cbb3ec25SBjoern A. Zeeb 
3613cbb3ec25SBjoern A. Zeeb 	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
3614cbb3ec25SBjoern A. Zeeb 		req.param.pd_th_srg = max_th - he_obss_pd->max_offset;
3615cbb3ec25SBjoern A. Zeeb 
3616cbb3ec25SBjoern A. Zeeb 	req.param.obss_pd_min = cpu_to_le16(82);
3617cbb3ec25SBjoern A. Zeeb 	req.param.obss_pd_min_srg = cpu_to_le16(82);
3618cbb3ec25SBjoern A. Zeeb 	req.param.txpwr_restrict_mode = 2;
3619cbb3ec25SBjoern A. Zeeb 	req.param.txpwr_ref = 21;
3620cbb3ec25SBjoern A. Zeeb 
3621cbb3ec25SBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
3622cbb3ec25SBjoern A. Zeeb 				 sizeof(req), true);
3623cbb3ec25SBjoern A. Zeeb }
3624cbb3ec25SBjoern A. Zeeb 
3625cbb3ec25SBjoern A. Zeeb static int
mt7915_mcu_set_obss_spr_siga(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_he_obss_pd * he_obss_pd)3626cbb3ec25SBjoern A. Zeeb mt7915_mcu_set_obss_spr_siga(struct mt7915_phy *phy, struct ieee80211_vif *vif,
3627cbb3ec25SBjoern A. Zeeb 			     struct ieee80211_he_obss_pd *he_obss_pd)
3628cbb3ec25SBjoern A. Zeeb {
3629cbb3ec25SBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
3630cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3631cbb3ec25SBjoern A. Zeeb 	u8 omac = mvif->mt76.omac_idx;
3632cbb3ec25SBjoern A. Zeeb 	struct {
3633cbb3ec25SBjoern A. Zeeb 		struct mt7915_mcu_sr_ctrl ctrl;
3634cbb3ec25SBjoern A. Zeeb 		struct {
3635cbb3ec25SBjoern A. Zeeb 			u8 omac;
3636cbb3ec25SBjoern A. Zeeb 			u8 rsv[3];
3637cbb3ec25SBjoern A. Zeeb 			u8 flag[20];
3638cbb3ec25SBjoern A. Zeeb 		} __packed siga;
3639cbb3ec25SBjoern A. Zeeb 	} __packed req = {
3640cbb3ec25SBjoern A. Zeeb 		.ctrl = {
3641cbb3ec25SBjoern A. Zeeb 			.action = SPR_SET_SIGA,
3642cbb3ec25SBjoern A. Zeeb 			.argnum = 1,
3643cbb3ec25SBjoern A. Zeeb 			.band_idx = phy->mt76->band_idx,
3644cbb3ec25SBjoern A. Zeeb 		},
3645cbb3ec25SBjoern A. Zeeb 		.siga = {
3646cbb3ec25SBjoern A. Zeeb 			.omac = omac > HW_BSSID_MAX ? omac - 12 : omac,
3647cbb3ec25SBjoern A. Zeeb 		},
3648cbb3ec25SBjoern A. Zeeb 	};
3649cbb3ec25SBjoern A. Zeeb 	int ret;
3650cbb3ec25SBjoern A. Zeeb 
3651cbb3ec25SBjoern A. Zeeb 	if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED)
3652cbb3ec25SBjoern A. Zeeb 		req.siga.flag[req.siga.omac] = 0xf;
3653cbb3ec25SBjoern A. Zeeb 	else
3654cbb3ec25SBjoern A. Zeeb 		return 0;
3655cbb3ec25SBjoern A. Zeeb 
3656cbb3ec25SBjoern A. Zeeb 	/* switch to normal AP mode */
3657cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_MODE, 0);
3658cbb3ec25SBjoern A. Zeeb 	if (ret)
3659cbb3ec25SBjoern A. Zeeb 		return ret;
3660cbb3ec25SBjoern A. Zeeb 
3661cbb3ec25SBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
3662cbb3ec25SBjoern A. Zeeb 				 sizeof(req), true);
3663cbb3ec25SBjoern A. Zeeb }
3664cbb3ec25SBjoern A. Zeeb 
3665cbb3ec25SBjoern A. Zeeb static int
mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy * phy,struct ieee80211_he_obss_pd * he_obss_pd)3666cbb3ec25SBjoern A. Zeeb mt7915_mcu_set_obss_spr_bitmap(struct mt7915_phy *phy,
3667cbb3ec25SBjoern A. Zeeb 			       struct ieee80211_he_obss_pd *he_obss_pd)
3668cbb3ec25SBjoern A. Zeeb {
3669cbb3ec25SBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
3670cbb3ec25SBjoern A. Zeeb 	struct {
3671cbb3ec25SBjoern A. Zeeb 		struct mt7915_mcu_sr_ctrl ctrl;
3672cbb3ec25SBjoern A. Zeeb 		struct {
3673cbb3ec25SBjoern A. Zeeb 			__le32 color_l[2];
3674cbb3ec25SBjoern A. Zeeb 			__le32 color_h[2];
3675cbb3ec25SBjoern A. Zeeb 			__le32 bssid_l[2];
3676cbb3ec25SBjoern A. Zeeb 			__le32 bssid_h[2];
3677cbb3ec25SBjoern A. Zeeb 		} __packed bitmap;
3678cbb3ec25SBjoern A. Zeeb 	} __packed req = {
3679cbb3ec25SBjoern A. Zeeb 		.ctrl = {
3680cbb3ec25SBjoern A. Zeeb 			.action = SPR_SET_SRG_BITMAP,
3681cbb3ec25SBjoern A. Zeeb 			.argnum = 4,
3682cbb3ec25SBjoern A. Zeeb 			.band_idx = phy->mt76->band_idx,
3683cbb3ec25SBjoern A. Zeeb 		},
3684cbb3ec25SBjoern A. Zeeb 	};
3685cbb3ec25SBjoern A. Zeeb 	u32 bitmap;
3686cbb3ec25SBjoern A. Zeeb 
3687cbb3ec25SBjoern A. Zeeb 	memcpy(&bitmap, he_obss_pd->bss_color_bitmap, sizeof(bitmap));
3688cbb3ec25SBjoern A. Zeeb 	req.bitmap.color_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
3689cbb3ec25SBjoern A. Zeeb 
3690cbb3ec25SBjoern A. Zeeb 	memcpy(&bitmap, he_obss_pd->bss_color_bitmap + 4, sizeof(bitmap));
3691cbb3ec25SBjoern A. Zeeb 	req.bitmap.color_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
3692cbb3ec25SBjoern A. Zeeb 
3693cbb3ec25SBjoern A. Zeeb 	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(bitmap));
3694cbb3ec25SBjoern A. Zeeb 	req.bitmap.bssid_l[req.ctrl.band_idx] = cpu_to_le32(bitmap);
3695cbb3ec25SBjoern A. Zeeb 
3696cbb3ec25SBjoern A. Zeeb 	memcpy(&bitmap, he_obss_pd->partial_bssid_bitmap + 4, sizeof(bitmap));
3697cbb3ec25SBjoern A. Zeeb 	req.bitmap.bssid_h[req.ctrl.band_idx] = cpu_to_le32(bitmap);
3698cbb3ec25SBjoern A. Zeeb 
3699cbb3ec25SBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(SET_SPR), &req,
3700cbb3ec25SBjoern A. Zeeb 				 sizeof(req), true);
3701cbb3ec25SBjoern A. Zeeb }
3702cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_add_obss_spr(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_he_obss_pd * he_obss_pd)3703cbb3ec25SBjoern A. Zeeb int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
3704cbb3ec25SBjoern A. Zeeb 			    struct ieee80211_he_obss_pd *he_obss_pd)
3705cbb3ec25SBjoern A. Zeeb {
3706cbb3ec25SBjoern A. Zeeb 	int ret;
3707cbb3ec25SBjoern A. Zeeb 
3708cbb3ec25SBjoern A. Zeeb 	/* enable firmware scene detection algorithms */
3709cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_SD, sr_scene_detect);
3710cbb3ec25SBjoern A. Zeeb 	if (ret)
3711cbb3ec25SBjoern A. Zeeb 		return ret;
3712cbb3ec25SBjoern A. Zeeb 
3713cbb3ec25SBjoern A. Zeeb 	/* firmware dynamically adjusts PD threshold so skip manual control */
3714cbb3ec25SBjoern A. Zeeb 	if (sr_scene_detect && !he_obss_pd->enable)
3715cbb3ec25SBjoern A. Zeeb 		return 0;
3716cbb3ec25SBjoern A. Zeeb 
3717cbb3ec25SBjoern A. Zeeb 	/* enable spatial reuse */
3718cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE, he_obss_pd->enable);
3719cbb3ec25SBjoern A. Zeeb 	if (ret)
3720cbb3ec25SBjoern A. Zeeb 		return ret;
3721cbb3ec25SBjoern A. Zeeb 
3722cbb3ec25SBjoern A. Zeeb 	if (sr_scene_detect || !he_obss_pd->enable)
3723cbb3ec25SBjoern A. Zeeb 		return 0;
3724cbb3ec25SBjoern A. Zeeb 
3725cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_enable_obss_spr(phy, SPR_ENABLE_TX, true);
3726cbb3ec25SBjoern A. Zeeb 	if (ret)
3727cbb3ec25SBjoern A. Zeeb 		return ret;
3728cbb3ec25SBjoern A. Zeeb 
3729cbb3ec25SBjoern A. Zeeb 	/* set SRG/non-SRG OBSS PD threshold */
3730cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_set_obss_spr_pd(phy, he_obss_pd);
3731cbb3ec25SBjoern A. Zeeb 	if (ret)
3732cbb3ec25SBjoern A. Zeeb 		return ret;
3733cbb3ec25SBjoern A. Zeeb 
3734cbb3ec25SBjoern A. Zeeb 	/* Set SR prohibit */
3735cbb3ec25SBjoern A. Zeeb 	ret = mt7915_mcu_set_obss_spr_siga(phy, vif, he_obss_pd);
3736cbb3ec25SBjoern A. Zeeb 	if (ret)
3737cbb3ec25SBjoern A. Zeeb 		return ret;
3738cbb3ec25SBjoern A. Zeeb 
3739cbb3ec25SBjoern A. Zeeb 	/* set SRG BSS color/BSSID bitmap */
3740cbb3ec25SBjoern A. Zeeb 	return mt7915_mcu_set_obss_spr_bitmap(phy, he_obss_pd);
3741cbb3ec25SBjoern A. Zeeb }
3742cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_get_rx_rate(struct mt7915_phy * phy,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct rate_info * rate)37436c92544dSBjoern A. Zeeb int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
37446c92544dSBjoern A. Zeeb 			   struct ieee80211_sta *sta, struct rate_info *rate)
37456c92544dSBjoern A. Zeeb {
37466c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
37476c92544dSBjoern A. Zeeb 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
37486c92544dSBjoern A. Zeeb 	struct mt7915_dev *dev = phy->dev;
37496c92544dSBjoern A. Zeeb 	struct mt76_phy *mphy = phy->mt76;
37506c92544dSBjoern A. Zeeb 	struct {
37516c92544dSBjoern A. Zeeb 		u8 category;
37526c92544dSBjoern A. Zeeb 		u8 band;
37536c92544dSBjoern A. Zeeb 		__le16 wcid;
37546c92544dSBjoern A. Zeeb 	} __packed req = {
37556c92544dSBjoern A. Zeeb 		.category = MCU_PHY_STATE_CONTENTION_RX_RATE,
37566c92544dSBjoern A. Zeeb 		.band = mvif->mt76.band_idx,
37576c92544dSBjoern A. Zeeb 		.wcid = cpu_to_le16(msta->wcid.idx),
37586c92544dSBjoern A. Zeeb 	};
37596c92544dSBjoern A. Zeeb 	struct ieee80211_supported_band *sband;
37606c92544dSBjoern A. Zeeb 	struct mt7915_mcu_phy_rx_info *res;
37616c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
37626c92544dSBjoern A. Zeeb 	int ret;
37636c92544dSBjoern A. Zeeb 	bool cck = false;
37646c92544dSBjoern A. Zeeb 
37656c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(PHY_STAT_INFO),
37666c92544dSBjoern A. Zeeb 					&req, sizeof(req), true, &skb);
37676c92544dSBjoern A. Zeeb 	if (ret)
37686c92544dSBjoern A. Zeeb 		return ret;
37696c92544dSBjoern A. Zeeb 
37706c92544dSBjoern A. Zeeb 	res = (struct mt7915_mcu_phy_rx_info *)skb->data;
37716c92544dSBjoern A. Zeeb 
37726c92544dSBjoern A. Zeeb 	rate->mcs = res->rate;
37736c92544dSBjoern A. Zeeb 	rate->nss = res->nsts + 1;
37746c92544dSBjoern A. Zeeb 
37756c92544dSBjoern A. Zeeb 	switch (res->mode) {
37766c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_CCK:
37776c92544dSBjoern A. Zeeb 		cck = true;
37786c92544dSBjoern A. Zeeb 		fallthrough;
37796c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_OFDM:
37806c92544dSBjoern A. Zeeb 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
37816c92544dSBjoern A. Zeeb 			sband = &mphy->sband_5g.sband;
37826c92544dSBjoern A. Zeeb 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
37836c92544dSBjoern A. Zeeb 			sband = &mphy->sband_6g.sband;
37846c92544dSBjoern A. Zeeb 		else
37856c92544dSBjoern A. Zeeb 			sband = &mphy->sband_2g.sband;
37866c92544dSBjoern A. Zeeb 
37876c92544dSBjoern A. Zeeb 		rate->mcs = mt76_get_rate(&dev->mt76, sband, rate->mcs, cck);
37886c92544dSBjoern A. Zeeb 		rate->legacy = sband->bitrates[rate->mcs].bitrate;
37896c92544dSBjoern A. Zeeb 		break;
37906c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_HT:
37916c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_HT_GF:
37926c92544dSBjoern A. Zeeb 		if (rate->mcs > 31) {
37936c92544dSBjoern A. Zeeb 			ret = -EINVAL;
37946c92544dSBjoern A. Zeeb 			goto out;
37956c92544dSBjoern A. Zeeb 		}
37966c92544dSBjoern A. Zeeb 
37976c92544dSBjoern A. Zeeb 		rate->flags = RATE_INFO_FLAGS_MCS;
37986c92544dSBjoern A. Zeeb 		if (res->gi)
37996c92544dSBjoern A. Zeeb 			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
38006c92544dSBjoern A. Zeeb 		break;
38016c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_VHT:
38026c92544dSBjoern A. Zeeb 		if (rate->mcs > 9) {
38036c92544dSBjoern A. Zeeb 			ret = -EINVAL;
38046c92544dSBjoern A. Zeeb 			goto out;
38056c92544dSBjoern A. Zeeb 		}
38066c92544dSBjoern A. Zeeb 
38076c92544dSBjoern A. Zeeb 		rate->flags = RATE_INFO_FLAGS_VHT_MCS;
38086c92544dSBjoern A. Zeeb 		if (res->gi)
38096c92544dSBjoern A. Zeeb 			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
38106c92544dSBjoern A. Zeeb 		break;
38116c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_HE_SU:
38126c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_HE_EXT_SU:
38136c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_HE_TB:
38146c92544dSBjoern A. Zeeb 	case MT_PHY_TYPE_HE_MU:
38156c92544dSBjoern A. Zeeb 		if (res->gi > NL80211_RATE_INFO_HE_GI_3_2 || rate->mcs > 11) {
38166c92544dSBjoern A. Zeeb 			ret = -EINVAL;
38176c92544dSBjoern A. Zeeb 			goto out;
38186c92544dSBjoern A. Zeeb 		}
38196c92544dSBjoern A. Zeeb 		rate->he_gi = res->gi;
38206c92544dSBjoern A. Zeeb 		rate->flags = RATE_INFO_FLAGS_HE_MCS;
38216c92544dSBjoern A. Zeeb 		break;
38226c92544dSBjoern A. Zeeb 	default:
38236c92544dSBjoern A. Zeeb 		ret = -EINVAL;
38246c92544dSBjoern A. Zeeb 		goto out;
38256c92544dSBjoern A. Zeeb 	}
38266c92544dSBjoern A. Zeeb 
38276c92544dSBjoern A. Zeeb 	switch (res->bw) {
38286c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_160:
38296c92544dSBjoern A. Zeeb 		rate->bw = RATE_INFO_BW_160;
38306c92544dSBjoern A. Zeeb 		break;
38316c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_80:
38326c92544dSBjoern A. Zeeb 		rate->bw = RATE_INFO_BW_80;
38336c92544dSBjoern A. Zeeb 		break;
38346c92544dSBjoern A. Zeeb 	case IEEE80211_STA_RX_BW_40:
38356c92544dSBjoern A. Zeeb 		rate->bw = RATE_INFO_BW_40;
38366c92544dSBjoern A. Zeeb 		break;
38376c92544dSBjoern A. Zeeb 	default:
38386c92544dSBjoern A. Zeeb 		rate->bw = RATE_INFO_BW_20;
38396c92544dSBjoern A. Zeeb 		break;
38406c92544dSBjoern A. Zeeb 	}
38416c92544dSBjoern A. Zeeb 
38426c92544dSBjoern A. Zeeb out:
38436c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
38446c92544dSBjoern A. Zeeb 
38456c92544dSBjoern A. Zeeb 	return ret;
38466c92544dSBjoern A. Zeeb }
38476c92544dSBjoern A. Zeeb 
mt7915_mcu_update_bss_color(struct mt7915_dev * dev,struct ieee80211_vif * vif,struct cfg80211_he_bss_color * he_bss_color)38486c92544dSBjoern A. Zeeb int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
38496c92544dSBjoern A. Zeeb 				struct cfg80211_he_bss_color *he_bss_color)
38506c92544dSBjoern A. Zeeb {
38516c92544dSBjoern A. Zeeb 	int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_color);
38526c92544dSBjoern A. Zeeb 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
38536c92544dSBjoern A. Zeeb 	struct bss_info_color *bss_color;
38546c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
38556c92544dSBjoern A. Zeeb 	struct tlv *tlv;
38566c92544dSBjoern A. Zeeb 
38576c92544dSBjoern A. Zeeb 	skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
38586c92544dSBjoern A. Zeeb 					      NULL, len);
38596c92544dSBjoern A. Zeeb 	if (IS_ERR(skb))
38606c92544dSBjoern A. Zeeb 		return PTR_ERR(skb);
38616c92544dSBjoern A. Zeeb 
38626c92544dSBjoern A. Zeeb 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_BSS_COLOR,
38636c92544dSBjoern A. Zeeb 				      sizeof(*bss_color));
38646c92544dSBjoern A. Zeeb 	bss_color = (struct bss_info_color *)tlv;
38656c92544dSBjoern A. Zeeb 	bss_color->disable = !he_bss_color->enabled;
38666c92544dSBjoern A. Zeeb 	bss_color->color = he_bss_color->color;
38676c92544dSBjoern A. Zeeb 
38686c92544dSBjoern A. Zeeb 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
38696c92544dSBjoern A. Zeeb 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
38706c92544dSBjoern A. Zeeb }
38716c92544dSBjoern A. Zeeb 
38726c92544dSBjoern A. Zeeb #define TWT_AGRT_TRIGGER	BIT(0)
38736c92544dSBjoern A. Zeeb #define TWT_AGRT_ANNOUNCE	BIT(1)
38746c92544dSBjoern A. Zeeb #define TWT_AGRT_PROTECT	BIT(2)
38756c92544dSBjoern A. Zeeb 
mt7915_mcu_twt_agrt_update(struct mt7915_dev * dev,struct mt7915_vif * mvif,struct mt7915_twt_flow * flow,int cmd)38766c92544dSBjoern A. Zeeb int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
38776c92544dSBjoern A. Zeeb 			       struct mt7915_vif *mvif,
38786c92544dSBjoern A. Zeeb 			       struct mt7915_twt_flow *flow,
38796c92544dSBjoern A. Zeeb 			       int cmd)
38806c92544dSBjoern A. Zeeb {
38816c92544dSBjoern A. Zeeb 	struct {
38826c92544dSBjoern A. Zeeb 		u8 tbl_idx;
38836c92544dSBjoern A. Zeeb 		u8 cmd;
38846c92544dSBjoern A. Zeeb 		u8 own_mac_idx;
38856c92544dSBjoern A. Zeeb 		u8 flowid; /* 0xff for group id */
38866c92544dSBjoern A. Zeeb 		__le16 peer_id; /* specify the peer_id (msb=0)
38876c92544dSBjoern A. Zeeb 				 * or group_id (msb=1)
38886c92544dSBjoern A. Zeeb 				 */
38896c92544dSBjoern A. Zeeb 		u8 duration; /* 256 us */
38906c92544dSBjoern A. Zeeb 		u8 bss_idx;
38916c92544dSBjoern A. Zeeb 		__le64 start_tsf;
38926c92544dSBjoern A. Zeeb 		__le16 mantissa;
38936c92544dSBjoern A. Zeeb 		u8 exponent;
38946c92544dSBjoern A. Zeeb 		u8 is_ap;
38956c92544dSBjoern A. Zeeb 		u8 agrt_params;
38966c92544dSBjoern A. Zeeb 		u8 rsv[23];
38976c92544dSBjoern A. Zeeb 	} __packed req = {
38986c92544dSBjoern A. Zeeb 		.tbl_idx = flow->table_id,
38996c92544dSBjoern A. Zeeb 		.cmd = cmd,
39006c92544dSBjoern A. Zeeb 		.own_mac_idx = mvif->mt76.omac_idx,
39016c92544dSBjoern A. Zeeb 		.flowid = flow->id,
39026c92544dSBjoern A. Zeeb 		.peer_id = cpu_to_le16(flow->wcid),
39036c92544dSBjoern A. Zeeb 		.duration = flow->duration,
39046c92544dSBjoern A. Zeeb 		.bss_idx = mvif->mt76.idx,
39056c92544dSBjoern A. Zeeb 		.start_tsf = cpu_to_le64(flow->tsf),
39066c92544dSBjoern A. Zeeb 		.mantissa = flow->mantissa,
39076c92544dSBjoern A. Zeeb 		.exponent = flow->exp,
39086c92544dSBjoern A. Zeeb 		.is_ap = true,
39096c92544dSBjoern A. Zeeb 	};
39106c92544dSBjoern A. Zeeb 
39116c92544dSBjoern A. Zeeb 	if (flow->protection)
39126c92544dSBjoern A. Zeeb 		req.agrt_params |= TWT_AGRT_PROTECT;
39136c92544dSBjoern A. Zeeb 	if (!flow->flowtype)
39146c92544dSBjoern A. Zeeb 		req.agrt_params |= TWT_AGRT_ANNOUNCE;
39156c92544dSBjoern A. Zeeb 	if (flow->trigger)
39166c92544dSBjoern A. Zeeb 		req.agrt_params |= TWT_AGRT_TRIGGER;
39176c92544dSBjoern A. Zeeb 
39186c92544dSBjoern A. Zeeb 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(TWT_AGRT_UPDATE),
39196c92544dSBjoern A. Zeeb 				 &req, sizeof(req), true);
39206c92544dSBjoern A. Zeeb }
39216c92544dSBjoern A. Zeeb 
mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev * dev,u16 wlan_idx)3922cbb3ec25SBjoern A. Zeeb int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
3923cbb3ec25SBjoern A. Zeeb {
3924cbb3ec25SBjoern A. Zeeb 	struct {
3925cbb3ec25SBjoern A. Zeeb 		__le32 cmd;
3926*8ba4d145SBjoern A. Zeeb 		__le32 arg0;
3927*8ba4d145SBjoern A. Zeeb 		__le32 arg1;
3928*8ba4d145SBjoern A. Zeeb 		__le16 arg2;
3929*8ba4d145SBjoern A. Zeeb 	} __packed req = {
3930cbb3ec25SBjoern A. Zeeb 		.cmd = cpu_to_le32(0x15),
3931cbb3ec25SBjoern A. Zeeb 	};
3932cbb3ec25SBjoern A. Zeeb 	struct mt7915_mcu_wa_tx_stat {
3933*8ba4d145SBjoern A. Zeeb 		__le16 wcid;
3934*8ba4d145SBjoern A. Zeeb 		u8 __rsv2[2];
3935cbb3ec25SBjoern A. Zeeb 
3936cbb3ec25SBjoern A. Zeeb 		/* tx_bytes is deprecated since WA byte counter uses u32,
3937cbb3ec25SBjoern A. Zeeb 		 * which easily leads to overflow.
3938cbb3ec25SBjoern A. Zeeb 		 */
3939cbb3ec25SBjoern A. Zeeb 		__le32 tx_bytes;
3940cbb3ec25SBjoern A. Zeeb 		__le32 tx_packets;
3941*8ba4d145SBjoern A. Zeeb 	} __packed *res;
3942cbb3ec25SBjoern A. Zeeb 	struct mt76_wcid *wcid;
3943cbb3ec25SBjoern A. Zeeb 	struct sk_buff *skb;
3944*8ba4d145SBjoern A. Zeeb 	int ret, len;
3945*8ba4d145SBjoern A. Zeeb 	u16 ret_wcid;
3946*8ba4d145SBjoern A. Zeeb 
3947*8ba4d145SBjoern A. Zeeb 	if (is_mt7915(&dev->mt76)) {
3948*8ba4d145SBjoern A. Zeeb 		req.arg0 = cpu_to_le32(wlan_idx);
3949*8ba4d145SBjoern A. Zeeb 		len = sizeof(req) - sizeof(req.arg2);
3950*8ba4d145SBjoern A. Zeeb 	} else {
3951*8ba4d145SBjoern A. Zeeb 		req.arg0 = cpu_to_le32(1);
3952*8ba4d145SBjoern A. Zeeb 		req.arg2 = cpu_to_le16(wlan_idx);
3953*8ba4d145SBjoern A. Zeeb 		len = sizeof(req);
3954*8ba4d145SBjoern A. Zeeb 	}
3955cbb3ec25SBjoern A. Zeeb 
3956cbb3ec25SBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY),
3957*8ba4d145SBjoern A. Zeeb 					&req, len, true, &skb);
3958cbb3ec25SBjoern A. Zeeb 	if (ret)
3959cbb3ec25SBjoern A. Zeeb 		return ret;
3960cbb3ec25SBjoern A. Zeeb 
3961cbb3ec25SBjoern A. Zeeb 	if (!is_mt7915(&dev->mt76))
3962cbb3ec25SBjoern A. Zeeb 		skb_pull(skb, 4);
3963cbb3ec25SBjoern A. Zeeb 
3964cbb3ec25SBjoern A. Zeeb 	res = (struct mt7915_mcu_wa_tx_stat *)skb->data;
3965cbb3ec25SBjoern A. Zeeb 
3966*8ba4d145SBjoern A. Zeeb 	ret_wcid = le16_to_cpu(res->wcid);
3967*8ba4d145SBjoern A. Zeeb 	if (is_mt7915(&dev->mt76))
3968*8ba4d145SBjoern A. Zeeb 		ret_wcid &= 0xff;
3969*8ba4d145SBjoern A. Zeeb 
3970*8ba4d145SBjoern A. Zeeb 	if (ret_wcid != wlan_idx) {
3971cbb3ec25SBjoern A. Zeeb 		ret = -EINVAL;
3972cbb3ec25SBjoern A. Zeeb 		goto out;
3973cbb3ec25SBjoern A. Zeeb 	}
3974cbb3ec25SBjoern A. Zeeb 
3975cbb3ec25SBjoern A. Zeeb 	rcu_read_lock();
3976cbb3ec25SBjoern A. Zeeb 
3977cbb3ec25SBjoern A. Zeeb 	wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
3978cbb3ec25SBjoern A. Zeeb 	if (wcid)
3979cbb3ec25SBjoern A. Zeeb 		wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
3980cbb3ec25SBjoern A. Zeeb 	else
3981cbb3ec25SBjoern A. Zeeb 		ret = -EINVAL;
3982cbb3ec25SBjoern A. Zeeb 
3983cbb3ec25SBjoern A. Zeeb 	rcu_read_unlock();
3984cbb3ec25SBjoern A. Zeeb out:
3985cbb3ec25SBjoern A. Zeeb 	dev_kfree_skb(skb);
3986cbb3ec25SBjoern A. Zeeb 
3987cbb3ec25SBjoern A. Zeeb 	return ret;
3988cbb3ec25SBjoern A. Zeeb }
3989cbb3ec25SBjoern A. Zeeb 
mt7915_mcu_rf_regval(struct mt7915_dev * dev,u32 regidx,u32 * val,bool set)39906c92544dSBjoern A. Zeeb int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
39916c92544dSBjoern A. Zeeb {
39926c92544dSBjoern A. Zeeb 	struct {
39936c92544dSBjoern A. Zeeb 		__le32 idx;
39946c92544dSBjoern A. Zeeb 		__le32 ofs;
39956c92544dSBjoern A. Zeeb 		__le32 data;
39966c92544dSBjoern A. Zeeb 	} __packed req = {
3997cbb3ec25SBjoern A. Zeeb 		.idx = cpu_to_le32(u32_get_bits(regidx, GENMASK(31, 24))),
3998cbb3ec25SBjoern A. Zeeb 		.ofs = cpu_to_le32(u32_get_bits(regidx, GENMASK(23, 0))),
39996c92544dSBjoern A. Zeeb 		.data = set ? cpu_to_le32(*val) : 0,
40006c92544dSBjoern A. Zeeb 	};
40016c92544dSBjoern A. Zeeb 	struct sk_buff *skb;
40026c92544dSBjoern A. Zeeb 	int ret;
40036c92544dSBjoern A. Zeeb 
40046c92544dSBjoern A. Zeeb 	if (set)
40056c92544dSBjoern A. Zeeb 		return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_REG_ACCESS),
40066c92544dSBjoern A. Zeeb 					 &req, sizeof(req), false);
40076c92544dSBjoern A. Zeeb 
40086c92544dSBjoern A. Zeeb 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(RF_REG_ACCESS),
40096c92544dSBjoern A. Zeeb 					&req, sizeof(req), true, &skb);
40106c92544dSBjoern A. Zeeb 	if (ret)
40116c92544dSBjoern A. Zeeb 		return ret;
40126c92544dSBjoern A. Zeeb 
40136c92544dSBjoern A. Zeeb 	*val = le32_to_cpu(*(__le32 *)(skb->data + 8));
40146c92544dSBjoern A. Zeeb 	dev_kfree_skb(skb);
40156c92544dSBjoern A. Zeeb 
40166c92544dSBjoern A. Zeeb 	return 0;
40176c92544dSBjoern A. Zeeb }
4018