11c099ab4SSean Wang // SPDX-License-Identifier: ISC
21c099ab4SSean Wang /* Copyright (C) 2020 MediaTek Inc. */
31c099ab4SSean Wang 
41c099ab4SSean Wang #include <linux/firmware.h>
51c099ab4SSean Wang #include <linux/fs.h>
61c099ab4SSean Wang #include "mt7921.h"
71c099ab4SSean Wang #include "mcu.h"
81c099ab4SSean Wang #include "mac.h"
91c099ab4SSean Wang 
101c099ab4SSean Wang struct mt7921_patch_hdr {
111c099ab4SSean Wang 	char build_date[16];
121c099ab4SSean Wang 	char platform[4];
131c099ab4SSean Wang 	__be32 hw_sw_ver;
141c099ab4SSean Wang 	__be32 patch_ver;
151c099ab4SSean Wang 	__be16 checksum;
161c099ab4SSean Wang 	u16 reserved;
171c099ab4SSean Wang 	struct {
181c099ab4SSean Wang 		__be32 patch_ver;
191c099ab4SSean Wang 		__be32 subsys;
201c099ab4SSean Wang 		__be32 feature;
211c099ab4SSean Wang 		__be32 n_region;
221c099ab4SSean Wang 		__be32 crc;
231c099ab4SSean Wang 		u32 reserved[11];
241c099ab4SSean Wang 	} desc;
251c099ab4SSean Wang } __packed;
261c099ab4SSean Wang 
271c099ab4SSean Wang struct mt7921_patch_sec {
281c099ab4SSean Wang 	__be32 type;
291c099ab4SSean Wang 	__be32 offs;
301c099ab4SSean Wang 	__be32 size;
311c099ab4SSean Wang 	union {
321c099ab4SSean Wang 		__be32 spec[13];
331c099ab4SSean Wang 		struct {
341c099ab4SSean Wang 			__be32 addr;
351c099ab4SSean Wang 			__be32 len;
361c099ab4SSean Wang 			__be32 sec_key_idx;
371c099ab4SSean Wang 			__be32 align_len;
381c099ab4SSean Wang 			u32 reserved[9];
391c099ab4SSean Wang 		} info;
401c099ab4SSean Wang 	};
411c099ab4SSean Wang } __packed;
421c099ab4SSean Wang 
431c099ab4SSean Wang struct mt7921_fw_trailer {
441c099ab4SSean Wang 	u8 chip_id;
451c099ab4SSean Wang 	u8 eco_code;
461c099ab4SSean Wang 	u8 n_region;
471c099ab4SSean Wang 	u8 format_ver;
481c099ab4SSean Wang 	u8 format_flag;
491c099ab4SSean Wang 	u8 reserved[2];
501c099ab4SSean Wang 	char fw_ver[10];
511c099ab4SSean Wang 	char build_date[15];
521c099ab4SSean Wang 	u32 crc;
531c099ab4SSean Wang } __packed;
541c099ab4SSean Wang 
551c099ab4SSean Wang struct mt7921_fw_region {
561c099ab4SSean Wang 	__le32 decomp_crc;
571c099ab4SSean Wang 	__le32 decomp_len;
581c099ab4SSean Wang 	__le32 decomp_blk_sz;
591c099ab4SSean Wang 	u8 reserved[4];
601c099ab4SSean Wang 	__le32 addr;
611c099ab4SSean Wang 	__le32 len;
621c099ab4SSean Wang 	u8 feature_set;
631c099ab4SSean Wang 	u8 reserved1[15];
641c099ab4SSean Wang } __packed;
651c099ab4SSean Wang 
661c099ab4SSean Wang #define MCU_PATCH_ADDRESS		0x200000
671c099ab4SSean Wang 
681c099ab4SSean Wang #define MT_STA_BFER			BIT(0)
691c099ab4SSean Wang #define MT_STA_BFEE			BIT(1)
701c099ab4SSean Wang 
711c099ab4SSean Wang #define FW_FEATURE_SET_ENCRYPT		BIT(0)
721c099ab4SSean Wang #define FW_FEATURE_SET_KEY_IDX		GENMASK(2, 1)
731c099ab4SSean Wang #define FW_FEATURE_ENCRY_MODE		BIT(4)
741c099ab4SSean Wang #define FW_FEATURE_OVERRIDE_ADDR	BIT(5)
751c099ab4SSean Wang 
761c099ab4SSean Wang #define DL_MODE_ENCRYPT			BIT(0)
771c099ab4SSean Wang #define DL_MODE_KEY_IDX			GENMASK(2, 1)
781c099ab4SSean Wang #define DL_MODE_RESET_SEC_IV		BIT(3)
791c099ab4SSean Wang #define DL_MODE_WORKING_PDA_CR4		BIT(4)
801c099ab4SSean Wang #define DL_CONFIG_ENCRY_MODE_SEL	BIT(6)
811c099ab4SSean Wang #define DL_MODE_NEED_RSP		BIT(31)
821c099ab4SSean Wang 
831c099ab4SSean Wang #define FW_START_OVERRIDE		BIT(0)
841c099ab4SSean Wang #define FW_START_WORKING_PDA_CR4	BIT(2)
851c099ab4SSean Wang 
861c099ab4SSean Wang #define PATCH_SEC_TYPE_MASK		GENMASK(15, 0)
871c099ab4SSean Wang #define PATCH_SEC_TYPE_INFO		0x2
881c099ab4SSean Wang 
891c099ab4SSean Wang #define to_wcid_lo(id)			FIELD_GET(GENMASK(7, 0), (u16)id)
901c099ab4SSean Wang #define to_wcid_hi(id)			FIELD_GET(GENMASK(9, 8), (u16)id)
911c099ab4SSean Wang 
921c099ab4SSean Wang #define HE_PHY(p, c)			u8_get_bits(c, IEEE80211_HE_PHY_##p)
931c099ab4SSean Wang #define HE_MAC(m, c)			u8_get_bits(c, IEEE80211_HE_MAC_##m)
941c099ab4SSean Wang 
951c099ab4SSean Wang static enum mt7921_cipher_type
961c099ab4SSean Wang mt7921_mcu_get_cipher(int cipher)
971c099ab4SSean Wang {
981c099ab4SSean Wang 	switch (cipher) {
991c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_WEP40:
1001c099ab4SSean Wang 		return MT_CIPHER_WEP40;
1011c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_WEP104:
1021c099ab4SSean Wang 		return MT_CIPHER_WEP104;
1031c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_TKIP:
1041c099ab4SSean Wang 		return MT_CIPHER_TKIP;
1051c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_AES_CMAC:
1061c099ab4SSean Wang 		return MT_CIPHER_BIP_CMAC_128;
1071c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_CCMP:
1081c099ab4SSean Wang 		return MT_CIPHER_AES_CCMP;
1091c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_CCMP_256:
1101c099ab4SSean Wang 		return MT_CIPHER_CCMP_256;
1111c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_GCMP:
1121c099ab4SSean Wang 		return MT_CIPHER_GCMP;
1131c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_GCMP_256:
1141c099ab4SSean Wang 		return MT_CIPHER_GCMP_256;
1151c099ab4SSean Wang 	case WLAN_CIPHER_SUITE_SMS4:
1161c099ab4SSean Wang 		return MT_CIPHER_WAPI;
1171c099ab4SSean Wang 	default:
1181c099ab4SSean Wang 		return MT_CIPHER_NONE;
1191c099ab4SSean Wang 	}
1201c099ab4SSean Wang }
1211c099ab4SSean Wang 
1221c099ab4SSean Wang static u8 mt7921_mcu_chan_bw(struct cfg80211_chan_def *chandef)
1231c099ab4SSean Wang {
1241c099ab4SSean Wang 	static const u8 width_to_bw[] = {
1251c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_40] = CMD_CBW_40MHZ,
1261c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_80] = CMD_CBW_80MHZ,
1271c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_80P80] = CMD_CBW_8080MHZ,
1281c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_160] = CMD_CBW_160MHZ,
1291c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_5] = CMD_CBW_5MHZ,
1301c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
1311c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
1321c099ab4SSean Wang 		[NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
1331c099ab4SSean Wang 	};
1341c099ab4SSean Wang 
1351c099ab4SSean Wang 	if (chandef->width >= ARRAY_SIZE(width_to_bw))
1361c099ab4SSean Wang 		return 0;
1371c099ab4SSean Wang 
1381c099ab4SSean Wang 	return width_to_bw[chandef->width];
1391c099ab4SSean Wang }
1401c099ab4SSean Wang 
1411c099ab4SSean Wang static const struct ieee80211_sta_he_cap *
1421c099ab4SSean Wang mt7921_get_he_phy_cap(struct mt7921_phy *phy, struct ieee80211_vif *vif)
1431c099ab4SSean Wang {
1441c099ab4SSean Wang 	struct ieee80211_supported_band *sband;
1451c099ab4SSean Wang 	enum nl80211_band band;
1461c099ab4SSean Wang 
1471c099ab4SSean Wang 	band = phy->mt76->chandef.chan->band;
1481c099ab4SSean Wang 	sband = phy->mt76->hw->wiphy->bands[band];
1491c099ab4SSean Wang 
1501c099ab4SSean Wang 	return ieee80211_get_he_iftype_cap(sband, vif->type);
1511c099ab4SSean Wang }
1521c099ab4SSean Wang 
1531c099ab4SSean Wang static u8
1541c099ab4SSean Wang mt7921_get_phy_mode(struct mt7921_dev *dev, struct ieee80211_vif *vif,
1551c099ab4SSean Wang 		    enum nl80211_band band, struct ieee80211_sta *sta)
1561c099ab4SSean Wang {
1571c099ab4SSean Wang 	struct ieee80211_sta_ht_cap *ht_cap;
1581c099ab4SSean Wang 	struct ieee80211_sta_vht_cap *vht_cap;
1591c099ab4SSean Wang 	const struct ieee80211_sta_he_cap *he_cap;
1601c099ab4SSean Wang 	u8 mode = 0;
1611c099ab4SSean Wang 
1621c099ab4SSean Wang 	if (sta) {
1631c099ab4SSean Wang 		ht_cap = &sta->ht_cap;
1641c099ab4SSean Wang 		vht_cap = &sta->vht_cap;
1651c099ab4SSean Wang 		he_cap = &sta->he_cap;
1661c099ab4SSean Wang 	} else {
1671c099ab4SSean Wang 		struct ieee80211_supported_band *sband;
1681c099ab4SSean Wang 		struct mt7921_phy *phy = &dev->phy;
1691c099ab4SSean Wang 
1701c099ab4SSean Wang 		sband = phy->mt76->hw->wiphy->bands[band];
1711c099ab4SSean Wang 		ht_cap = &sband->ht_cap;
1721c099ab4SSean Wang 		vht_cap = &sband->vht_cap;
1731c099ab4SSean Wang 		he_cap = ieee80211_get_he_iftype_cap(sband, vif->type);
1741c099ab4SSean Wang 	}
1751c099ab4SSean Wang 
1761c099ab4SSean Wang 	if (band == NL80211_BAND_2GHZ) {
1771c099ab4SSean Wang 		mode |= PHY_MODE_B | PHY_MODE_G;
1781c099ab4SSean Wang 
1791c099ab4SSean Wang 		if (ht_cap->ht_supported)
1801c099ab4SSean Wang 			mode |= PHY_MODE_GN;
1811c099ab4SSean Wang 
1821c099ab4SSean Wang 		if (he_cap->has_he)
1831c099ab4SSean Wang 			mode |= PHY_MODE_AX_24G;
1841c099ab4SSean Wang 	} else if (band == NL80211_BAND_5GHZ) {
1851c099ab4SSean Wang 		mode |= PHY_MODE_A;
1861c099ab4SSean Wang 
1871c099ab4SSean Wang 		if (ht_cap->ht_supported)
1881c099ab4SSean Wang 			mode |= PHY_MODE_AN;
1891c099ab4SSean Wang 
1901c099ab4SSean Wang 		if (vht_cap->vht_supported)
1911c099ab4SSean Wang 			mode |= PHY_MODE_AC;
1921c099ab4SSean Wang 
1931c099ab4SSean Wang 		if (he_cap->has_he)
1941c099ab4SSean Wang 			mode |= PHY_MODE_AX_5G;
1951c099ab4SSean Wang 	}
1961c099ab4SSean Wang 
1971c099ab4SSean Wang 	return mode;
1981c099ab4SSean Wang }
1991c099ab4SSean Wang 
2001c099ab4SSean Wang static u8
2011c099ab4SSean Wang mt7921_get_phy_mode_v2(struct mt7921_dev *dev, struct ieee80211_vif *vif,
2021c099ab4SSean Wang 		       enum nl80211_band band, struct ieee80211_sta *sta)
2031c099ab4SSean Wang {
2041c099ab4SSean Wang 	struct ieee80211_sta_ht_cap *ht_cap;
2051c099ab4SSean Wang 	struct ieee80211_sta_vht_cap *vht_cap;
2061c099ab4SSean Wang 	const struct ieee80211_sta_he_cap *he_cap;
2071c099ab4SSean Wang 	u8 mode = 0;
2081c099ab4SSean Wang 
2091c099ab4SSean Wang 	if (sta) {
2101c099ab4SSean Wang 		ht_cap = &sta->ht_cap;
2111c099ab4SSean Wang 		vht_cap = &sta->vht_cap;
2121c099ab4SSean Wang 		he_cap = &sta->he_cap;
2131c099ab4SSean Wang 	} else {
2141c099ab4SSean Wang 		struct ieee80211_supported_band *sband;
2151c099ab4SSean Wang 		struct mt7921_phy *phy = &dev->phy;
2161c099ab4SSean Wang 
2171c099ab4SSean Wang 		sband = phy->mt76->hw->wiphy->bands[band];
2181c099ab4SSean Wang 		ht_cap = &sband->ht_cap;
2191c099ab4SSean Wang 		vht_cap = &sband->vht_cap;
2201c099ab4SSean Wang 		he_cap = ieee80211_get_he_iftype_cap(sband, vif->type);
2211c099ab4SSean Wang 	}
2221c099ab4SSean Wang 
2231c099ab4SSean Wang 	if (band == NL80211_BAND_2GHZ) {
2241c099ab4SSean Wang 		mode |= PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP;
2251c099ab4SSean Wang 
2261c099ab4SSean Wang 		if (ht_cap->ht_supported)
2271c099ab4SSean Wang 			mode |= PHY_TYPE_BIT_HT;
2281c099ab4SSean Wang 
2291c099ab4SSean Wang 		if (he_cap->has_he)
2301c099ab4SSean Wang 			mode |= PHY_TYPE_BIT_HE;
2311c099ab4SSean Wang 	} else if (band == NL80211_BAND_5GHZ) {
2321c099ab4SSean Wang 		mode |= PHY_TYPE_BIT_OFDM;
2331c099ab4SSean Wang 
2341c099ab4SSean Wang 		if (ht_cap->ht_supported)
2351c099ab4SSean Wang 			mode |= PHY_TYPE_BIT_HT;
2361c099ab4SSean Wang 
2371c099ab4SSean Wang 		if (vht_cap->vht_supported)
2381c099ab4SSean Wang 			mode |= PHY_TYPE_BIT_VHT;
2391c099ab4SSean Wang 
2401c099ab4SSean Wang 		if (he_cap->has_he)
2411c099ab4SSean Wang 			mode |= PHY_TYPE_BIT_HE;
2421c099ab4SSean Wang 	}
2431c099ab4SSean Wang 
2441c099ab4SSean Wang 	return mode;
2451c099ab4SSean Wang }
2461c099ab4SSean Wang 
2471c099ab4SSean Wang static int
2481c099ab4SSean Wang mt7921_mcu_parse_eeprom(struct mt76_dev *dev, struct sk_buff *skb)
2491c099ab4SSean Wang {
2501c099ab4SSean Wang 	struct mt7921_mcu_eeprom_info *res;
2511c099ab4SSean Wang 	u8 *buf;
2521c099ab4SSean Wang 
2531c099ab4SSean Wang 	if (!skb)
2541c099ab4SSean Wang 		return -EINVAL;
2551c099ab4SSean Wang 
2561c099ab4SSean Wang 	skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
2571c099ab4SSean Wang 
2581c099ab4SSean Wang 	res = (struct mt7921_mcu_eeprom_info *)skb->data;
2591c099ab4SSean Wang 	buf = dev->eeprom.data + le32_to_cpu(res->addr);
2601c099ab4SSean Wang 	memcpy(buf, res->data, 16);
2611c099ab4SSean Wang 
2621c099ab4SSean Wang 	return 0;
2631c099ab4SSean Wang }
2641c099ab4SSean Wang 
2651c099ab4SSean Wang static int
2661c099ab4SSean Wang mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
2671c099ab4SSean Wang 			  struct sk_buff *skb, int seq)
2681c099ab4SSean Wang {
2691c099ab4SSean Wang 	struct mt7921_mcu_rxd *rxd;
2701c099ab4SSean Wang 	int ret = 0;
2711c099ab4SSean Wang 
2721c099ab4SSean Wang 	if (!skb) {
2731c099ab4SSean Wang 		dev_err(mdev->dev, "Message %d (seq %d) timeout\n",
2741c099ab4SSean Wang 			cmd, seq);
2751c099ab4SSean Wang 		return -ETIMEDOUT;
2761c099ab4SSean Wang 	}
2771c099ab4SSean Wang 
2781c099ab4SSean Wang 	rxd = (struct mt7921_mcu_rxd *)skb->data;
2791c099ab4SSean Wang 	if (seq != rxd->seq)
2801c099ab4SSean Wang 		return -EAGAIN;
2811c099ab4SSean Wang 
2821c099ab4SSean Wang 	switch (cmd) {
2831c099ab4SSean Wang 	case MCU_CMD_PATCH_SEM_CONTROL:
2841c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd) - 4);
2851c099ab4SSean Wang 		ret = *skb->data;
2861c099ab4SSean Wang 		break;
2871c099ab4SSean Wang 	case MCU_EXT_CMD_THERMAL_CTRL:
2881c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd) + 4);
2891c099ab4SSean Wang 		ret = le32_to_cpu(*(__le32 *)skb->data);
2901c099ab4SSean Wang 		break;
2911c099ab4SSean Wang 	case MCU_EXT_CMD_EFUSE_ACCESS:
2921c099ab4SSean Wang 		ret = mt7921_mcu_parse_eeprom(mdev, skb);
2931c099ab4SSean Wang 		break;
2941c099ab4SSean Wang 	case MCU_UNI_CMD_DEV_INFO_UPDATE:
2951c099ab4SSean Wang 	case MCU_UNI_CMD_BSS_INFO_UPDATE:
2961c099ab4SSean Wang 	case MCU_UNI_CMD_STA_REC_UPDATE:
2971c099ab4SSean Wang 	case MCU_UNI_CMD_HIF_CTRL:
2981c099ab4SSean Wang 	case MCU_UNI_CMD_OFFLOAD:
2991c099ab4SSean Wang 	case MCU_UNI_CMD_SUSPEND: {
3001c099ab4SSean Wang 		struct mt7921_mcu_uni_event *event;
3011c099ab4SSean Wang 
3021c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd));
3031c099ab4SSean Wang 		event = (struct mt7921_mcu_uni_event *)skb->data;
3041c099ab4SSean Wang 		ret = le32_to_cpu(event->status);
3051c099ab4SSean Wang 		break;
3061c099ab4SSean Wang 	}
3071c099ab4SSean Wang 	case MCU_CMD_REG_READ: {
3081c099ab4SSean Wang 		struct mt7921_mcu_reg_event *event;
3091c099ab4SSean Wang 
3101c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd));
3111c099ab4SSean Wang 		event = (struct mt7921_mcu_reg_event *)skb->data;
3121c099ab4SSean Wang 		ret = (int)le32_to_cpu(event->val);
3131c099ab4SSean Wang 		break;
3141c099ab4SSean Wang 	}
3151c099ab4SSean Wang 	default:
3161c099ab4SSean Wang 		skb_pull(skb, sizeof(struct mt7921_mcu_rxd));
3171c099ab4SSean Wang 		break;
3181c099ab4SSean Wang 	}
3191c099ab4SSean Wang 
3201c099ab4SSean Wang 	return ret;
3211c099ab4SSean Wang }
3221c099ab4SSean Wang 
3231c099ab4SSean Wang static int
3241c099ab4SSean Wang mt7921_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
3251c099ab4SSean Wang 			int cmd, int *wait_seq)
3261c099ab4SSean Wang {
3271c099ab4SSean Wang 	struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
3281c099ab4SSean Wang 	int txd_len, mcu_cmd = cmd & MCU_CMD_MASK;
3291c099ab4SSean Wang 	enum mt76_mcuq_id txq = MT_MCUQ_WM;
3301c099ab4SSean Wang 	struct mt7921_uni_txd *uni_txd;
3311c099ab4SSean Wang 	struct mt7921_mcu_txd *mcu_txd;
3321c099ab4SSean Wang 	__le32 *txd;
3331c099ab4SSean Wang 	u32 val;
3341c099ab4SSean Wang 	u8 seq;
3351c099ab4SSean Wang 
3361c099ab4SSean Wang 	/* TODO: make dynamic based on msg type */
3371c099ab4SSean Wang 	mdev->mcu.timeout = 20 * HZ;
3381c099ab4SSean Wang 
3391c099ab4SSean Wang 	seq = ++dev->mt76.mcu.msg_seq & 0xf;
3401c099ab4SSean Wang 	if (!seq)
3411c099ab4SSean Wang 		seq = ++dev->mt76.mcu.msg_seq & 0xf;
3421c099ab4SSean Wang 
3431c099ab4SSean Wang 	if (cmd == MCU_CMD_FW_SCATTER) {
3441c099ab4SSean Wang 		txq = MT_MCUQ_FWDL;
3451c099ab4SSean Wang 		goto exit;
3461c099ab4SSean Wang 	}
3471c099ab4SSean Wang 
3481c099ab4SSean Wang 	txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd);
3491c099ab4SSean Wang 	txd = (__le32 *)skb_push(skb, txd_len);
3501c099ab4SSean Wang 
3511c099ab4SSean Wang 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
3521c099ab4SSean Wang 	      FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CMD) |
3531c099ab4SSean Wang 	      FIELD_PREP(MT_TXD0_Q_IDX, MT_TX_MCU_PORT_RX_Q0);
3541c099ab4SSean Wang 	txd[0] = cpu_to_le32(val);
3551c099ab4SSean Wang 
3561c099ab4SSean Wang 	val = MT_TXD1_LONG_FORMAT |
3571c099ab4SSean Wang 	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_CMD);
3581c099ab4SSean Wang 	txd[1] = cpu_to_le32(val);
3591c099ab4SSean Wang 
3601c099ab4SSean Wang 	if (cmd & MCU_UNI_PREFIX) {
3611c099ab4SSean Wang 		uni_txd = (struct mt7921_uni_txd *)txd;
3621c099ab4SSean Wang 		uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
3631c099ab4SSean Wang 		uni_txd->option = MCU_CMD_UNI_EXT_ACK;
3641c099ab4SSean Wang 		uni_txd->cid = cpu_to_le16(mcu_cmd);
3651c099ab4SSean Wang 		uni_txd->s2d_index = MCU_S2D_H2N;
3661c099ab4SSean Wang 		uni_txd->pkt_type = MCU_PKT_ID;
3671c099ab4SSean Wang 		uni_txd->seq = seq;
3681c099ab4SSean Wang 
3691c099ab4SSean Wang 		goto exit;
3701c099ab4SSean Wang 	}
3711c099ab4SSean Wang 
3721c099ab4SSean Wang 	mcu_txd = (struct mt7921_mcu_txd *)txd;
3731c099ab4SSean Wang 	mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
3741c099ab4SSean Wang 	mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU,
3751c099ab4SSean Wang 					       MT_TX_MCU_PORT_RX_Q0));
3761c099ab4SSean Wang 	mcu_txd->pkt_type = MCU_PKT_ID;
3771c099ab4SSean Wang 	mcu_txd->seq = seq;
3781c099ab4SSean Wang 
3791c099ab4SSean Wang 	switch (cmd & ~MCU_CMD_MASK) {
3801c099ab4SSean Wang 	case MCU_FW_PREFIX:
3811c099ab4SSean Wang 		mcu_txd->set_query = MCU_Q_NA;
3821c099ab4SSean Wang 		mcu_txd->cid = mcu_cmd;
3831c099ab4SSean Wang 		break;
3841c099ab4SSean Wang 	case MCU_CE_PREFIX:
3851c099ab4SSean Wang 		if (cmd & MCU_QUERY_MASK)
3861c099ab4SSean Wang 			mcu_txd->set_query = MCU_Q_QUERY;
3871c099ab4SSean Wang 		else
3881c099ab4SSean Wang 			mcu_txd->set_query = MCU_Q_SET;
3891c099ab4SSean Wang 		mcu_txd->cid = mcu_cmd;
3901c099ab4SSean Wang 		break;
3911c099ab4SSean Wang 	default:
3921c099ab4SSean Wang 		mcu_txd->cid = MCU_CMD_EXT_CID;
3931c099ab4SSean Wang 		if (cmd & MCU_QUERY_PREFIX || cmd == MCU_EXT_CMD_EFUSE_ACCESS)
3941c099ab4SSean Wang 			mcu_txd->set_query = MCU_Q_QUERY;
3951c099ab4SSean Wang 		else
3961c099ab4SSean Wang 			mcu_txd->set_query = MCU_Q_SET;
3971c099ab4SSean Wang 		mcu_txd->ext_cid = mcu_cmd;
3981c099ab4SSean Wang 		mcu_txd->ext_cid_ack = 1;
3991c099ab4SSean Wang 		break;
4001c099ab4SSean Wang 	}
4011c099ab4SSean Wang 
4021c099ab4SSean Wang 	mcu_txd->s2d_index = MCU_S2D_H2N;
4031c099ab4SSean Wang 	WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS &&
4041c099ab4SSean Wang 		mcu_txd->set_query != MCU_Q_QUERY);
4051c099ab4SSean Wang 
4061c099ab4SSean Wang exit:
4071c099ab4SSean Wang 	if (wait_seq)
4081c099ab4SSean Wang 		*wait_seq = seq;
4091c099ab4SSean Wang 
4101c099ab4SSean Wang 	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
4111c099ab4SSean Wang }
4121c099ab4SSean Wang 
4131c099ab4SSean Wang static void
4141c099ab4SSean Wang mt7921_mcu_tx_rate_parse(struct mt76_phy *mphy,
4151c099ab4SSean Wang 			 struct mt7921_mcu_peer_cap *peer,
4161c099ab4SSean Wang 			 struct rate_info *rate, u16 r)
4171c099ab4SSean Wang {
4181c099ab4SSean Wang 	struct ieee80211_supported_band *sband;
4191c099ab4SSean Wang 	u16 flags = 0;
4201c099ab4SSean Wang 	u8 txmode = FIELD_GET(MT_WTBL_RATE_TX_MODE, r);
4211c099ab4SSean Wang 	u8 gi = 0;
4221c099ab4SSean Wang 	u8 bw = 0;
4231c099ab4SSean Wang 
4241c099ab4SSean Wang 	rate->mcs = FIELD_GET(MT_WTBL_RATE_MCS, r);
4251c099ab4SSean Wang 	rate->nss = FIELD_GET(MT_WTBL_RATE_NSS, r) + 1;
4261c099ab4SSean Wang 
4271c099ab4SSean Wang 	switch (peer->bw) {
4281c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_160:
4291c099ab4SSean Wang 		gi = peer->g16;
4301c099ab4SSean Wang 		break;
4311c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_80:
4321c099ab4SSean Wang 		gi = peer->g8;
4331c099ab4SSean Wang 		break;
4341c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_40:
4351c099ab4SSean Wang 		gi = peer->g4;
4361c099ab4SSean Wang 		break;
4371c099ab4SSean Wang 	default:
4381c099ab4SSean Wang 		gi = peer->g2;
4391c099ab4SSean Wang 		break;
4401c099ab4SSean Wang 	}
4411c099ab4SSean Wang 
4421c099ab4SSean Wang 	gi = txmode >= MT_PHY_TYPE_HE_SU ?
4431c099ab4SSean Wang 		FIELD_GET(MT_WTBL_RATE_HE_GI, gi) :
4441c099ab4SSean Wang 		FIELD_GET(MT_WTBL_RATE_GI, gi);
4451c099ab4SSean Wang 
4461c099ab4SSean Wang 	switch (txmode) {
4471c099ab4SSean Wang 	case MT_PHY_TYPE_CCK:
4481c099ab4SSean Wang 	case MT_PHY_TYPE_OFDM:
4491c099ab4SSean Wang 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
4501c099ab4SSean Wang 			sband = &mphy->sband_5g.sband;
4511c099ab4SSean Wang 		else
4521c099ab4SSean Wang 			sband = &mphy->sband_2g.sband;
4531c099ab4SSean Wang 
4541c099ab4SSean Wang 		rate->legacy = sband->bitrates[rate->mcs].bitrate;
4551c099ab4SSean Wang 		break;
4561c099ab4SSean Wang 	case MT_PHY_TYPE_HT:
4571c099ab4SSean Wang 	case MT_PHY_TYPE_HT_GF:
4581c099ab4SSean Wang 		flags |= RATE_INFO_FLAGS_MCS;
4591c099ab4SSean Wang 
4601c099ab4SSean Wang 		if (gi)
4611c099ab4SSean Wang 			flags |= RATE_INFO_FLAGS_SHORT_GI;
4621c099ab4SSean Wang 		break;
4631c099ab4SSean Wang 	case MT_PHY_TYPE_VHT:
4641c099ab4SSean Wang 		flags |= RATE_INFO_FLAGS_VHT_MCS;
4651c099ab4SSean Wang 
4661c099ab4SSean Wang 		if (gi)
4671c099ab4SSean Wang 			flags |= RATE_INFO_FLAGS_SHORT_GI;
4681c099ab4SSean Wang 		break;
4691c099ab4SSean Wang 	case MT_PHY_TYPE_HE_SU:
4701c099ab4SSean Wang 	case MT_PHY_TYPE_HE_EXT_SU:
4711c099ab4SSean Wang 	case MT_PHY_TYPE_HE_TB:
4721c099ab4SSean Wang 	case MT_PHY_TYPE_HE_MU:
4731c099ab4SSean Wang 		rate->he_gi = gi;
4741c099ab4SSean Wang 		rate->he_dcm = FIELD_GET(MT_RA_RATE_DCM_EN, r);
4751c099ab4SSean Wang 
4761c099ab4SSean Wang 		flags |= RATE_INFO_FLAGS_HE_MCS;
4771c099ab4SSean Wang 		break;
4781c099ab4SSean Wang 	default:
4791c099ab4SSean Wang 		break;
4801c099ab4SSean Wang 	}
4811c099ab4SSean Wang 	rate->flags = flags;
4821c099ab4SSean Wang 
4831c099ab4SSean Wang 	bw = mt7921_mcu_chan_bw(&mphy->chandef) - FIELD_GET(MT_RA_RATE_BW, r);
4841c099ab4SSean Wang 
4851c099ab4SSean Wang 	switch (bw) {
4861c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_160:
4871c099ab4SSean Wang 		rate->bw = RATE_INFO_BW_160;
4881c099ab4SSean Wang 		break;
4891c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_80:
4901c099ab4SSean Wang 		rate->bw = RATE_INFO_BW_80;
4911c099ab4SSean Wang 		break;
4921c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_40:
4931c099ab4SSean Wang 		rate->bw = RATE_INFO_BW_40;
4941c099ab4SSean Wang 		break;
4951c099ab4SSean Wang 	default:
4961c099ab4SSean Wang 		rate->bw = RATE_INFO_BW_20;
4971c099ab4SSean Wang 		break;
4981c099ab4SSean Wang 	}
4991c099ab4SSean Wang }
5001c099ab4SSean Wang 
5011c099ab4SSean Wang static void
5021c099ab4SSean Wang mt7921_mcu_tx_rate_report(struct mt7921_dev *dev, struct sk_buff *skb,
5031c099ab4SSean Wang 			  u16 wlan_idx)
5041c099ab4SSean Wang {
5051c099ab4SSean Wang 	struct mt7921_mcu_wlan_info_event *wtbl_info =
5061c099ab4SSean Wang 		(struct mt7921_mcu_wlan_info_event *)(skb->data);
5071c099ab4SSean Wang 	struct rate_info rate = {};
5081c099ab4SSean Wang 	u8 curr_idx = wtbl_info->rate_info.rate_idx;
5091c099ab4SSean Wang 	u16 curr = le16_to_cpu(wtbl_info->rate_info.rate[curr_idx]);
5101c099ab4SSean Wang 	struct mt7921_mcu_peer_cap peer = wtbl_info->peer_cap;
5111c099ab4SSean Wang 	struct mt76_phy *mphy = &dev->mphy;
5121c099ab4SSean Wang 	struct mt7921_sta_stats *stats;
5131c099ab4SSean Wang 	struct mt7921_sta *msta;
5141c099ab4SSean Wang 	struct mt76_wcid *wcid;
5151c099ab4SSean Wang 
5161c099ab4SSean Wang 	if (wlan_idx >= MT76_N_WCIDS)
5171c099ab4SSean Wang 		return;
5181c099ab4SSean Wang 	wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
5191c099ab4SSean Wang 	if (!wcid) {
5201c099ab4SSean Wang 		stats->tx_rate = rate;
5211c099ab4SSean Wang 		return;
5221c099ab4SSean Wang 	}
5231c099ab4SSean Wang 
5241c099ab4SSean Wang 	msta = container_of(wcid, struct mt7921_sta, wcid);
5251c099ab4SSean Wang 	stats = &msta->stats;
5261c099ab4SSean Wang 
5271c099ab4SSean Wang 	/* current rate */
5281c099ab4SSean Wang 	mt7921_mcu_tx_rate_parse(mphy, &peer, &rate, curr);
5291c099ab4SSean Wang 	stats->tx_rate = rate;
5301c099ab4SSean Wang }
5311c099ab4SSean Wang 
5321c099ab4SSean Wang static void
5331c099ab4SSean Wang mt7921_mcu_scan_event(struct mt7921_dev *dev, struct sk_buff *skb)
5341c099ab4SSean Wang {
5351c099ab4SSean Wang 	struct mt76_phy *mphy = &dev->mt76.phy;
5361c099ab4SSean Wang 	struct mt7921_phy *phy = (struct mt7921_phy *)mphy->priv;
5371c099ab4SSean Wang 
5381c099ab4SSean Wang 	spin_lock_bh(&dev->mt76.lock);
5391c099ab4SSean Wang 	__skb_queue_tail(&phy->scan_event_list, skb);
5401c099ab4SSean Wang 	spin_unlock_bh(&dev->mt76.lock);
5411c099ab4SSean Wang 
5421c099ab4SSean Wang 	ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
5431c099ab4SSean Wang 				     MT7921_HW_SCAN_TIMEOUT);
5441c099ab4SSean Wang }
5451c099ab4SSean Wang 
5461c099ab4SSean Wang static void
5471c099ab4SSean Wang mt7921_mcu_bss_event(struct mt7921_dev *dev, struct sk_buff *skb)
5481c099ab4SSean Wang {
5491c099ab4SSean Wang 	struct mt76_phy *mphy = &dev->mt76.phy;
5501c099ab4SSean Wang 	struct mt7921_mcu_bss_event *event;
5511c099ab4SSean Wang 
5521c099ab4SSean Wang 	event = (struct mt7921_mcu_bss_event *)(skb->data +
5531c099ab4SSean Wang 						sizeof(struct mt7921_mcu_rxd));
5541c099ab4SSean Wang 	if (event->is_absent)
5551c099ab4SSean Wang 		ieee80211_stop_queues(mphy->hw);
5561c099ab4SSean Wang 	else
5571c099ab4SSean Wang 		ieee80211_wake_queues(mphy->hw);
5581c099ab4SSean Wang }
5591c099ab4SSean Wang 
5601c099ab4SSean Wang static void
5611c099ab4SSean Wang mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb)
5621c099ab4SSean Wang {
5631c099ab4SSean Wang 	struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
5641c099ab4SSean Wang 	struct debug_msg {
5651c099ab4SSean Wang 		__le16 id;
5661c099ab4SSean Wang 		u8 type;
5671c099ab4SSean Wang 		u8 flag;
5681c099ab4SSean Wang 		__le32 value;
5691c099ab4SSean Wang 		__le16 len;
5701c099ab4SSean Wang 		u8 content[512];
5711c099ab4SSean Wang 	} __packed * debug_msg;
5721c099ab4SSean Wang 	u16 cur_len;
5731c099ab4SSean Wang 	int i;
5741c099ab4SSean Wang 
5751c099ab4SSean Wang 	skb_pull(skb, sizeof(*rxd));
5761c099ab4SSean Wang 	debug_msg = (struct debug_msg *)skb->data;
5771c099ab4SSean Wang 
5781c099ab4SSean Wang 	cur_len = min_t(u16, le16_to_cpu(debug_msg->len), 512);
5791c099ab4SSean Wang 
5801c099ab4SSean Wang 	if (debug_msg->type == 0x3) {
5811c099ab4SSean Wang 		for (i = 0 ; i < cur_len; i++)
5821c099ab4SSean Wang 			if (!debug_msg->content[i])
5831c099ab4SSean Wang 				debug_msg->content[i] = ' ';
5841c099ab4SSean Wang 
5851c099ab4SSean Wang 		dev_dbg(dev->mt76.dev, "%s", debug_msg->content);
5861c099ab4SSean Wang 	}
5871c099ab4SSean Wang }
5881c099ab4SSean Wang 
5891c099ab4SSean Wang static void
5901c099ab4SSean Wang mt7921_mcu_rx_unsolicited_event(struct mt7921_dev *dev, struct sk_buff *skb)
5911c099ab4SSean Wang {
5921c099ab4SSean Wang 	struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
5931c099ab4SSean Wang 
5941c099ab4SSean Wang 	switch (rxd->eid) {
5951c099ab4SSean Wang 	case MCU_EVENT_BSS_BEACON_LOSS:
5961c099ab4SSean Wang 		break;
5971c099ab4SSean Wang 	case MCU_EVENT_SCHED_SCAN_DONE:
5981c099ab4SSean Wang 	case MCU_EVENT_SCAN_DONE:
5991c099ab4SSean Wang 		mt7921_mcu_scan_event(dev, skb);
6001c099ab4SSean Wang 		return;
6011c099ab4SSean Wang 	case MCU_EVENT_BSS_ABSENCE:
6021c099ab4SSean Wang 		mt7921_mcu_bss_event(dev, skb);
6031c099ab4SSean Wang 		break;
6041c099ab4SSean Wang 	case MCU_EVENT_DBG_MSG:
6051c099ab4SSean Wang 		mt7921_mcu_debug_msg_event(dev, skb);
6061c099ab4SSean Wang 		break;
6071c099ab4SSean Wang 	default:
6081c099ab4SSean Wang 		break;
6091c099ab4SSean Wang 	}
6101c099ab4SSean Wang 	dev_kfree_skb(skb);
6111c099ab4SSean Wang }
6121c099ab4SSean Wang 
6131c099ab4SSean Wang void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb)
6141c099ab4SSean Wang {
6151c099ab4SSean Wang 	struct mt7921_mcu_rxd *rxd = (struct mt7921_mcu_rxd *)skb->data;
6161c099ab4SSean Wang 
6171c099ab4SSean Wang 	if (rxd->eid == 0x6) {
6181c099ab4SSean Wang 		mt76_mcu_rx_event(&dev->mt76, skb);
6191c099ab4SSean Wang 		return;
6201c099ab4SSean Wang 	}
6211c099ab4SSean Wang 
6221c099ab4SSean Wang 	if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT ||
6231c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
6241c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
6251c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_BSS_ABSENCE ||
6261c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_SCAN_DONE ||
6271c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_DBG_MSG ||
6281c099ab4SSean Wang 	    !rxd->seq)
6291c099ab4SSean Wang 		mt7921_mcu_rx_unsolicited_event(dev, skb);
6301c099ab4SSean Wang 	else
6311c099ab4SSean Wang 		mt76_mcu_rx_event(&dev->mt76, skb);
6321c099ab4SSean Wang }
6331c099ab4SSean Wang 
6341c099ab4SSean Wang static struct sk_buff *
6351c099ab4SSean Wang mt7921_mcu_alloc_sta_req(struct mt7921_dev *dev, struct mt7921_vif *mvif,
6361c099ab4SSean Wang 			 struct mt7921_sta *msta, int len)
6371c099ab4SSean Wang {
6381c099ab4SSean Wang 	struct sta_req_hdr hdr = {
6391c099ab4SSean Wang 		.bss_idx = mvif->mt76.idx,
6401c099ab4SSean Wang 		.wlan_idx_lo = msta ? to_wcid_lo(msta->wcid.idx) : 0,
6411c099ab4SSean Wang 		.wlan_idx_hi = msta ? to_wcid_hi(msta->wcid.idx) : 0,
6421c099ab4SSean Wang 		.muar_idx = msta ? mvif->mt76.omac_idx : 0,
6431c099ab4SSean Wang 		.is_tlv_append = 1,
6441c099ab4SSean Wang 	};
6451c099ab4SSean Wang 	struct sk_buff *skb;
6461c099ab4SSean Wang 
6471c099ab4SSean Wang 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
6481c099ab4SSean Wang 	if (!skb)
6491c099ab4SSean Wang 		return ERR_PTR(-ENOMEM);
6501c099ab4SSean Wang 
6511c099ab4SSean Wang 	skb_put_data(skb, &hdr, sizeof(hdr));
6521c099ab4SSean Wang 
6531c099ab4SSean Wang 	return skb;
6541c099ab4SSean Wang }
6551c099ab4SSean Wang 
6561c099ab4SSean Wang static struct wtbl_req_hdr *
6571c099ab4SSean Wang mt7921_mcu_alloc_wtbl_req(struct mt7921_dev *dev, struct mt7921_sta *msta,
6581c099ab4SSean Wang 			  int cmd, void *sta_wtbl, struct sk_buff **skb)
6591c099ab4SSean Wang {
6601c099ab4SSean Wang 	struct tlv *sta_hdr = sta_wtbl;
6611c099ab4SSean Wang 	struct wtbl_req_hdr hdr = {
6621c099ab4SSean Wang 		.wlan_idx_lo = to_wcid_lo(msta->wcid.idx),
6631c099ab4SSean Wang 		.wlan_idx_hi = to_wcid_hi(msta->wcid.idx),
6641c099ab4SSean Wang 		.operation = cmd,
6651c099ab4SSean Wang 	};
6661c099ab4SSean Wang 	struct sk_buff *nskb = *skb;
6671c099ab4SSean Wang 
6681c099ab4SSean Wang 	if (!nskb) {
6691c099ab4SSean Wang 		nskb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
6701c099ab4SSean Wang 					  MT7921_WTBL_UPDATE_BA_SIZE);
6711c099ab4SSean Wang 		if (!nskb)
6721c099ab4SSean Wang 			return ERR_PTR(-ENOMEM);
6731c099ab4SSean Wang 
6741c099ab4SSean Wang 		*skb = nskb;
6751c099ab4SSean Wang 	}
6761c099ab4SSean Wang 
6771c099ab4SSean Wang 	if (sta_hdr)
6781c099ab4SSean Wang 		sta_hdr->len = cpu_to_le16(sizeof(hdr));
6791c099ab4SSean Wang 
6801c099ab4SSean Wang 	return skb_put_data(nskb, &hdr, sizeof(hdr));
6811c099ab4SSean Wang }
6821c099ab4SSean Wang 
6831c099ab4SSean Wang static struct tlv *
6841c099ab4SSean Wang mt7921_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len,
6851c099ab4SSean Wang 			  void *sta_ntlv, void *sta_wtbl)
6861c099ab4SSean Wang {
6871c099ab4SSean Wang 	struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv;
6881c099ab4SSean Wang 	struct tlv *sta_hdr = sta_wtbl;
6891c099ab4SSean Wang 	struct tlv *ptlv, tlv = {
6901c099ab4SSean Wang 		.tag = cpu_to_le16(tag),
6911c099ab4SSean Wang 		.len = cpu_to_le16(len),
6921c099ab4SSean Wang 	};
6931c099ab4SSean Wang 	u16 ntlv;
6941c099ab4SSean Wang 
6951c099ab4SSean Wang 	ptlv = skb_put(skb, len);
6961c099ab4SSean Wang 	memcpy(ptlv, &tlv, sizeof(tlv));
6971c099ab4SSean Wang 
6981c099ab4SSean Wang 	ntlv = le16_to_cpu(ntlv_hdr->tlv_num);
6991c099ab4SSean Wang 	ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1);
7001c099ab4SSean Wang 
7011c099ab4SSean Wang 	if (sta_hdr) {
7021c099ab4SSean Wang 		u16 size = le16_to_cpu(sta_hdr->len);
7031c099ab4SSean Wang 
7041c099ab4SSean Wang 		sta_hdr->len = cpu_to_le16(size + len);
7051c099ab4SSean Wang 	}
7061c099ab4SSean Wang 
7071c099ab4SSean Wang 	return ptlv;
7081c099ab4SSean Wang }
7091c099ab4SSean Wang 
7101c099ab4SSean Wang static struct tlv *
7111c099ab4SSean Wang mt7921_mcu_add_tlv(struct sk_buff *skb, int tag, int len)
7121c099ab4SSean Wang {
7131c099ab4SSean Wang 	return mt7921_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL);
7141c099ab4SSean Wang }
7151c099ab4SSean Wang 
7161c099ab4SSean Wang static void
7171c099ab4SSean Wang mt7921_mcu_uni_bss_he_tlv(struct tlv *tlv, struct ieee80211_vif *vif,
7181c099ab4SSean Wang 			  struct mt7921_phy *phy)
7191c099ab4SSean Wang {
7201c099ab4SSean Wang #define DEFAULT_HE_PE_DURATION		4
7211c099ab4SSean Wang #define DEFAULT_HE_DURATION_RTS_THRES	1023
7221c099ab4SSean Wang 	const struct ieee80211_sta_he_cap *cap;
7231c099ab4SSean Wang 	struct bss_info_uni_he *he;
7241c099ab4SSean Wang 
7251c099ab4SSean Wang 	cap = mt7921_get_he_phy_cap(phy, vif);
7261c099ab4SSean Wang 
7271c099ab4SSean Wang 	he = (struct bss_info_uni_he *)tlv;
7281c099ab4SSean Wang 	he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
7291c099ab4SSean Wang 	if (!he->he_pe_duration)
7301c099ab4SSean Wang 		he->he_pe_duration = DEFAULT_HE_PE_DURATION;
7311c099ab4SSean Wang 
7321c099ab4SSean Wang 	he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
7331c099ab4SSean Wang 	if (!he->he_rts_thres)
7341c099ab4SSean Wang 		he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
7351c099ab4SSean Wang 
7361c099ab4SSean Wang 	he->max_nss_mcs[CMD_HE_MCS_BW80] = cap->he_mcs_nss_supp.tx_mcs_80;
7371c099ab4SSean Wang 	he->max_nss_mcs[CMD_HE_MCS_BW160] = cap->he_mcs_nss_supp.tx_mcs_160;
7381c099ab4SSean Wang 	he->max_nss_mcs[CMD_HE_MCS_BW8080] = cap->he_mcs_nss_supp.tx_mcs_80p80;
7391c099ab4SSean Wang }
7401c099ab4SSean Wang 
7411c099ab4SSean Wang /** starec & wtbl **/
7421c099ab4SSean Wang static int
7431c099ab4SSean Wang mt7921_mcu_sta_key_tlv(struct mt7921_sta *msta, struct sk_buff *skb,
7441c099ab4SSean Wang 		       struct ieee80211_key_conf *key, enum set_key_cmd cmd)
7451c099ab4SSean Wang {
7461c099ab4SSean Wang 	struct mt7921_sta_key_conf *bip = &msta->bip;
7471c099ab4SSean Wang 	struct sta_rec_sec *sec;
7481c099ab4SSean Wang 	struct tlv *tlv;
7491c099ab4SSean Wang 	u32 len = sizeof(*sec);
7501c099ab4SSean Wang 
7511c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec));
7521c099ab4SSean Wang 
7531c099ab4SSean Wang 	sec = (struct sta_rec_sec *)tlv;
7541c099ab4SSean Wang 	sec->add = cmd;
7551c099ab4SSean Wang 
7561c099ab4SSean Wang 	if (cmd == SET_KEY) {
7571c099ab4SSean Wang 		struct sec_key *sec_key;
7581c099ab4SSean Wang 		u8 cipher;
7591c099ab4SSean Wang 
7601c099ab4SSean Wang 		cipher = mt7921_mcu_get_cipher(key->cipher);
7611c099ab4SSean Wang 		if (cipher == MT_CIPHER_NONE)
7621c099ab4SSean Wang 			return -EOPNOTSUPP;
7631c099ab4SSean Wang 
7641c099ab4SSean Wang 		sec_key = &sec->key[0];
7651c099ab4SSean Wang 		sec_key->cipher_len = sizeof(*sec_key);
7661c099ab4SSean Wang 
7671c099ab4SSean Wang 		if (cipher == MT_CIPHER_BIP_CMAC_128) {
7681c099ab4SSean Wang 			sec_key->cipher_id = MT_CIPHER_AES_CCMP;
7691c099ab4SSean Wang 			sec_key->key_id = bip->keyidx;
7701c099ab4SSean Wang 			sec_key->key_len = 16;
7711c099ab4SSean Wang 			memcpy(sec_key->key, bip->key, 16);
7721c099ab4SSean Wang 
7731c099ab4SSean Wang 			sec_key = &sec->key[1];
7741c099ab4SSean Wang 			sec_key->cipher_id = MT_CIPHER_BIP_CMAC_128;
7751c099ab4SSean Wang 			sec_key->cipher_len = sizeof(*sec_key);
7761c099ab4SSean Wang 			sec_key->key_len = 16;
7771c099ab4SSean Wang 			memcpy(sec_key->key, key->key, 16);
7781c099ab4SSean Wang 
7791c099ab4SSean Wang 			sec->n_cipher = 2;
7801c099ab4SSean Wang 		} else {
7811c099ab4SSean Wang 			sec_key->cipher_id = cipher;
7821c099ab4SSean Wang 			sec_key->key_id = key->keyidx;
7831c099ab4SSean Wang 			sec_key->key_len = key->keylen;
7841c099ab4SSean Wang 			memcpy(sec_key->key, key->key, key->keylen);
7851c099ab4SSean Wang 
7861c099ab4SSean Wang 			if (cipher == MT_CIPHER_TKIP) {
7871c099ab4SSean Wang 				/* Rx/Tx MIC keys are swapped */
7881c099ab4SSean Wang 				memcpy(sec_key->key + 16, key->key + 24, 8);
7891c099ab4SSean Wang 				memcpy(sec_key->key + 24, key->key + 16, 8);
7901c099ab4SSean Wang 			}
7911c099ab4SSean Wang 
7921c099ab4SSean Wang 			/* store key_conf for BIP batch update */
7931c099ab4SSean Wang 			if (cipher == MT_CIPHER_AES_CCMP) {
7941c099ab4SSean Wang 				memcpy(bip->key, key->key, key->keylen);
7951c099ab4SSean Wang 				bip->keyidx = key->keyidx;
7961c099ab4SSean Wang 			}
7971c099ab4SSean Wang 
7981c099ab4SSean Wang 			len -= sizeof(*sec_key);
7991c099ab4SSean Wang 			sec->n_cipher = 1;
8001c099ab4SSean Wang 		}
8011c099ab4SSean Wang 	} else {
8021c099ab4SSean Wang 		len -= sizeof(sec->key);
8031c099ab4SSean Wang 		sec->n_cipher = 0;
8041c099ab4SSean Wang 	}
8051c099ab4SSean Wang 	sec->len = cpu_to_le16(len);
8061c099ab4SSean Wang 
8071c099ab4SSean Wang 	return 0;
8081c099ab4SSean Wang }
8091c099ab4SSean Wang 
8101c099ab4SSean Wang int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif,
8111c099ab4SSean Wang 		       struct mt7921_sta *msta, struct ieee80211_key_conf *key,
8121c099ab4SSean Wang 		       enum set_key_cmd cmd)
8131c099ab4SSean Wang {
8141c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
8151c099ab4SSean Wang 	struct sk_buff *skb;
8161c099ab4SSean Wang 	int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_sec);
8171c099ab4SSean Wang 	int ret;
8181c099ab4SSean Wang 
8191c099ab4SSean Wang 	skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta, len);
8201c099ab4SSean Wang 	if (IS_ERR(skb))
8211c099ab4SSean Wang 		return PTR_ERR(skb);
8221c099ab4SSean Wang 
8231c099ab4SSean Wang 	ret = mt7921_mcu_sta_key_tlv(msta, skb, key, cmd);
8241c099ab4SSean Wang 	if (ret)
8251c099ab4SSean Wang 		return ret;
8261c099ab4SSean Wang 
8271c099ab4SSean Wang 	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
8281c099ab4SSean Wang 				     MCU_UNI_CMD_STA_REC_UPDATE, true);
8291c099ab4SSean Wang }
8301c099ab4SSean Wang 
8311c099ab4SSean Wang static void
8321c099ab4SSean Wang mt7921_mcu_sta_ba_tlv(struct sk_buff *skb,
8331c099ab4SSean Wang 		      struct ieee80211_ampdu_params *params,
8341c099ab4SSean Wang 		      bool enable, bool tx)
8351c099ab4SSean Wang {
8361c099ab4SSean Wang 	struct sta_rec_ba *ba;
8371c099ab4SSean Wang 	struct tlv *tlv;
8381c099ab4SSean Wang 
8391c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));
8401c099ab4SSean Wang 
8411c099ab4SSean Wang 	ba = (struct sta_rec_ba *)tlv;
8421c099ab4SSean Wang 	ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT,
8431c099ab4SSean Wang 	ba->winsize = cpu_to_le16(params->buf_size);
8441c099ab4SSean Wang 	ba->ssn = cpu_to_le16(params->ssn);
8451c099ab4SSean Wang 	ba->ba_en = enable << params->tid;
8461c099ab4SSean Wang 	ba->amsdu = params->amsdu;
8471c099ab4SSean Wang 	ba->tid = params->tid;
8481c099ab4SSean Wang }
8491c099ab4SSean Wang 
8501c099ab4SSean Wang static void
8511c099ab4SSean Wang mt7921_mcu_wtbl_ba_tlv(struct sk_buff *skb,
8521c099ab4SSean Wang 		       struct ieee80211_ampdu_params *params,
8531c099ab4SSean Wang 		       bool enable, bool tx, void *sta_wtbl,
8541c099ab4SSean Wang 		       void *wtbl_tlv)
8551c099ab4SSean Wang {
8561c099ab4SSean Wang 	struct wtbl_ba *ba;
8571c099ab4SSean Wang 	struct tlv *tlv;
8581c099ab4SSean Wang 
8591c099ab4SSean Wang 	tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba),
8601c099ab4SSean Wang 					wtbl_tlv, sta_wtbl);
8611c099ab4SSean Wang 
8621c099ab4SSean Wang 	ba = (struct wtbl_ba *)tlv;
8631c099ab4SSean Wang 	ba->tid = params->tid;
8641c099ab4SSean Wang 
8651c099ab4SSean Wang 	if (tx) {
8661c099ab4SSean Wang 		ba->ba_type = MT_BA_TYPE_ORIGINATOR;
8671c099ab4SSean Wang 		ba->sn = enable ? cpu_to_le16(params->ssn) : 0;
8681c099ab4SSean Wang 		ba->ba_en = enable;
8691c099ab4SSean Wang 	} else {
8701c099ab4SSean Wang 		memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN);
8711c099ab4SSean Wang 		ba->ba_type = MT_BA_TYPE_RECIPIENT;
8721c099ab4SSean Wang 		ba->rst_ba_tid = params->tid;
8731c099ab4SSean Wang 		ba->rst_ba_sel = RST_BA_MAC_TID_MATCH;
8741c099ab4SSean Wang 		ba->rst_ba_sb = 1;
8751c099ab4SSean Wang 	}
8761c099ab4SSean Wang 
8771c099ab4SSean Wang 	if (enable && tx)
8781c099ab4SSean Wang 		ba->ba_winsize = cpu_to_le16(params->buf_size);
8791c099ab4SSean Wang }
8801c099ab4SSean Wang 
8811c099ab4SSean Wang static int
8821c099ab4SSean Wang mt7921_mcu_sta_ba(struct mt7921_dev *dev,
8831c099ab4SSean Wang 		  struct ieee80211_ampdu_params *params,
8841c099ab4SSean Wang 		  bool enable, bool tx, int cmd)
8851c099ab4SSean Wang {
8861c099ab4SSean Wang 	struct mt7921_sta *msta = (struct mt7921_sta *)params->sta->drv_priv;
8871c099ab4SSean Wang 	struct mt7921_vif *mvif = msta->vif;
8881c099ab4SSean Wang 	struct wtbl_req_hdr *wtbl_hdr;
8891c099ab4SSean Wang 	struct tlv *sta_wtbl;
8901c099ab4SSean Wang 	struct sk_buff *skb;
8911c099ab4SSean Wang 	int ret;
8921c099ab4SSean Wang 
8931c099ab4SSean Wang 	if (enable && tx && !params->amsdu)
8941c099ab4SSean Wang 		msta->wcid.amsdu = false;
8951c099ab4SSean Wang 
8961c099ab4SSean Wang 	skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta,
8971c099ab4SSean Wang 				       MT7921_STA_UPDATE_MAX_SIZE);
8981c099ab4SSean Wang 	if (IS_ERR(skb))
8991c099ab4SSean Wang 		return PTR_ERR(skb);
9001c099ab4SSean Wang 
9011c099ab4SSean Wang 	sta_wtbl = mt7921_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
9021c099ab4SSean Wang 
9031c099ab4SSean Wang 	wtbl_hdr = mt7921_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl,
9041c099ab4SSean Wang 					     &skb);
9051c099ab4SSean Wang 	mt7921_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr);
9061c099ab4SSean Wang 
9071c099ab4SSean Wang 	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
9081c099ab4SSean Wang 	if (ret)
9091c099ab4SSean Wang 		return ret;
9101c099ab4SSean Wang 
9111c099ab4SSean Wang 	skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta,
9121c099ab4SSean Wang 				       MT7921_STA_UPDATE_MAX_SIZE);
9131c099ab4SSean Wang 	if (IS_ERR(skb))
9141c099ab4SSean Wang 		return PTR_ERR(skb);
9151c099ab4SSean Wang 
9161c099ab4SSean Wang 	mt7921_mcu_sta_ba_tlv(skb, params, enable, tx);
9171c099ab4SSean Wang 
9181c099ab4SSean Wang 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
9191c099ab4SSean Wang }
9201c099ab4SSean Wang 
9211c099ab4SSean Wang int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev,
9221c099ab4SSean Wang 			 struct ieee80211_ampdu_params *params,
9231c099ab4SSean Wang 			 bool enable)
9241c099ab4SSean Wang {
9251c099ab4SSean Wang 	return mt7921_mcu_sta_ba(dev, params, enable, true, MCU_UNI_CMD_STA_REC_UPDATE);
9261c099ab4SSean Wang }
9271c099ab4SSean Wang 
9281c099ab4SSean Wang int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev,
9291c099ab4SSean Wang 			 struct ieee80211_ampdu_params *params,
9301c099ab4SSean Wang 			 bool enable)
9311c099ab4SSean Wang {
9321c099ab4SSean Wang 	return mt7921_mcu_sta_ba(dev, params, enable, false, MCU_UNI_CMD_STA_REC_UPDATE);
9331c099ab4SSean Wang }
9341c099ab4SSean Wang 
9351c099ab4SSean Wang static void
9361c099ab4SSean Wang mt7921_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
9371c099ab4SSean Wang 			    struct ieee80211_sta *sta, void *sta_wtbl,
9381c099ab4SSean Wang 			    void *wtbl_tlv)
9391c099ab4SSean Wang {
9401c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
9411c099ab4SSean Wang 	struct wtbl_generic *generic;
9421c099ab4SSean Wang 	struct wtbl_rx *rx;
9431c099ab4SSean Wang 	struct tlv *tlv;
9441c099ab4SSean Wang 
9451c099ab4SSean Wang 	tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic),
9461c099ab4SSean Wang 					wtbl_tlv, sta_wtbl);
9471c099ab4SSean Wang 
9481c099ab4SSean Wang 	generic = (struct wtbl_generic *)tlv;
9491c099ab4SSean Wang 
9501c099ab4SSean Wang 	if (sta) {
9511c099ab4SSean Wang 		if (vif->type == NL80211_IFTYPE_STATION)
9521c099ab4SSean Wang 			generic->partial_aid = cpu_to_le16(vif->bss_conf.aid);
9531c099ab4SSean Wang 		else
9541c099ab4SSean Wang 			generic->partial_aid = cpu_to_le16(sta->aid);
9551c099ab4SSean Wang 		memcpy(generic->peer_addr, sta->addr, ETH_ALEN);
9561c099ab4SSean Wang 		generic->muar_idx = mvif->mt76.omac_idx;
9571c099ab4SSean Wang 		generic->qos = sta->wme;
9581c099ab4SSean Wang 	} else {
9591c099ab4SSean Wang 		/* use BSSID in station mode */
9601c099ab4SSean Wang 		if (vif->type == NL80211_IFTYPE_STATION)
9611c099ab4SSean Wang 			memcpy(generic->peer_addr, vif->bss_conf.bssid,
9621c099ab4SSean Wang 			       ETH_ALEN);
9631c099ab4SSean Wang 		else
9641c099ab4SSean Wang 			eth_broadcast_addr(generic->peer_addr);
9651c099ab4SSean Wang 
9661c099ab4SSean Wang 		generic->muar_idx = 0xe;
9671c099ab4SSean Wang 	}
9681c099ab4SSean Wang 
9691c099ab4SSean Wang 	tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx),
9701c099ab4SSean Wang 					wtbl_tlv, sta_wtbl);
9711c099ab4SSean Wang 
9721c099ab4SSean Wang 	rx = (struct wtbl_rx *)tlv;
9731c099ab4SSean Wang 	rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1;
9741c099ab4SSean Wang 	rx->rca2 = 1;
9751c099ab4SSean Wang 	rx->rv = 1;
9761c099ab4SSean Wang }
9771c099ab4SSean Wang 
9781c099ab4SSean Wang static void
9791c099ab4SSean Wang mt7921_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
9801c099ab4SSean Wang 			 struct ieee80211_sta *sta, bool enable)
9811c099ab4SSean Wang {
9821c099ab4SSean Wang #define EXTRA_INFO_VER          BIT(0)
9831c099ab4SSean Wang #define EXTRA_INFO_NEW          BIT(1)
9841c099ab4SSean Wang 	struct sta_rec_basic *basic;
9851c099ab4SSean Wang 	struct tlv *tlv;
9861c099ab4SSean Wang 	int conn_type;
9871c099ab4SSean Wang 
9881c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic));
9891c099ab4SSean Wang 
9901c099ab4SSean Wang 	basic = (struct sta_rec_basic *)tlv;
9911c099ab4SSean Wang 	basic->extra_info = cpu_to_le16(EXTRA_INFO_VER);
9921c099ab4SSean Wang 
9931c099ab4SSean Wang 	if (enable) {
9941c099ab4SSean Wang 		basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);
9951c099ab4SSean Wang 		basic->conn_state = CONN_STATE_PORT_SECURE;
9961c099ab4SSean Wang 	} else {
9971c099ab4SSean Wang 		basic->conn_state = CONN_STATE_DISCONNECT;
9981c099ab4SSean Wang 	}
9991c099ab4SSean Wang 
10001c099ab4SSean Wang 	if (!sta) {
10011c099ab4SSean Wang 		basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
10021c099ab4SSean Wang 		eth_broadcast_addr(basic->peer_addr);
10031c099ab4SSean Wang 		return;
10041c099ab4SSean Wang 	}
10051c099ab4SSean Wang 
10061c099ab4SSean Wang 	switch (vif->type) {
10071c099ab4SSean Wang 	case NL80211_IFTYPE_MESH_POINT:
10081c099ab4SSean Wang 	case NL80211_IFTYPE_AP:
10091c099ab4SSean Wang 		if (vif->p2p)
10101c099ab4SSean Wang 			conn_type = CONNECTION_P2P_GC;
10111c099ab4SSean Wang 		else
10121c099ab4SSean Wang 			conn_type = CONNECTION_INFRA_STA;
10131c099ab4SSean Wang 		basic->conn_type = cpu_to_le32(conn_type);
10141c099ab4SSean Wang 		basic->aid = cpu_to_le16(sta->aid);
10151c099ab4SSean Wang 		break;
10161c099ab4SSean Wang 	case NL80211_IFTYPE_STATION:
10171c099ab4SSean Wang 		if (vif->p2p)
10181c099ab4SSean Wang 			conn_type = CONNECTION_P2P_GO;
10191c099ab4SSean Wang 		else
10201c099ab4SSean Wang 			conn_type = CONNECTION_INFRA_AP;
10211c099ab4SSean Wang 		basic->conn_type = cpu_to_le32(conn_type);
10221c099ab4SSean Wang 		basic->aid = cpu_to_le16(vif->bss_conf.aid);
10231c099ab4SSean Wang 		break;
10241c099ab4SSean Wang 	case NL80211_IFTYPE_ADHOC:
10251c099ab4SSean Wang 		basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
10261c099ab4SSean Wang 		basic->aid = cpu_to_le16(sta->aid);
10271c099ab4SSean Wang 		break;
10281c099ab4SSean Wang 	default:
10291c099ab4SSean Wang 		WARN_ON(1);
10301c099ab4SSean Wang 		break;
10311c099ab4SSean Wang 	}
10321c099ab4SSean Wang 
10331c099ab4SSean Wang 	memcpy(basic->peer_addr, sta->addr, ETH_ALEN);
10341c099ab4SSean Wang 	basic->qos = sta->wme;
10351c099ab4SSean Wang }
10361c099ab4SSean Wang 
10371c099ab4SSean Wang static void
10381c099ab4SSean Wang mt7921_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
10391c099ab4SSean Wang {
10401c099ab4SSean Wang 	struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
10411c099ab4SSean Wang 	struct ieee80211_he_cap_elem *elem = &he_cap->he_cap_elem;
10421c099ab4SSean Wang 	struct sta_rec_he *he;
10431c099ab4SSean Wang 	struct tlv *tlv;
10441c099ab4SSean Wang 	u32 cap = 0;
10451c099ab4SSean Wang 
10461c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
10471c099ab4SSean Wang 
10481c099ab4SSean Wang 	he = (struct sta_rec_he *)tlv;
10491c099ab4SSean Wang 
10501c099ab4SSean Wang 	if (elem->mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_HTC_HE)
10511c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_HTC;
10521c099ab4SSean Wang 
10531c099ab4SSean Wang 	if (elem->mac_cap_info[2] & IEEE80211_HE_MAC_CAP2_BSR)
10541c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_BSR;
10551c099ab4SSean Wang 
10561c099ab4SSean Wang 	if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL)
10571c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_OM;
10581c099ab4SSean Wang 
10591c099ab4SSean Wang 	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU)
10601c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU;
10611c099ab4SSean Wang 
10621c099ab4SSean Wang 	if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR)
10631c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_BQR;
10641c099ab4SSean Wang 
10651c099ab4SSean Wang 	if (elem->phy_cap_info[0] &
10661c099ab4SSean Wang 	    (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G |
10671c099ab4SSean Wang 	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
10681c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
10691c099ab4SSean Wang 
10701c099ab4SSean Wang 	if (elem->phy_cap_info[1] &
10711c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)
10721c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_LDPC;
10731c099ab4SSean Wang 
10741c099ab4SSean Wang 	if (elem->phy_cap_info[1] &
10751c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US)
10761c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_SU_PPDU_1LTF_8US_GI;
10771c099ab4SSean Wang 
10781c099ab4SSean Wang 	if (elem->phy_cap_info[2] &
10791c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US)
10801c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_NDP_4LTF_3DOT2MS_GI;
10811c099ab4SSean Wang 
10821c099ab4SSean Wang 	if (elem->phy_cap_info[2] &
10831c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ)
10841c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_LE_EQ_80M_TX_STBC;
10851c099ab4SSean Wang 
10861c099ab4SSean Wang 	if (elem->phy_cap_info[2] &
10871c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ)
10881c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_LE_EQ_80M_RX_STBC;
10891c099ab4SSean Wang 
10901c099ab4SSean Wang 	if (elem->phy_cap_info[6] &
10911c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE)
10921c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_PARTIAL_BW_EXT_RANGE;
10931c099ab4SSean Wang 
10941c099ab4SSean Wang 	if (elem->phy_cap_info[7] &
10951c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI)
10961c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_SU_MU_PPDU_4LTF_8US_GI;
10971c099ab4SSean Wang 
10981c099ab4SSean Wang 	if (elem->phy_cap_info[7] &
10991c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ)
11001c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_GT_80M_TX_STBC;
11011c099ab4SSean Wang 
11021c099ab4SSean Wang 	if (elem->phy_cap_info[7] &
11031c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)
11041c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_GT_80M_RX_STBC;
11051c099ab4SSean Wang 
11061c099ab4SSean Wang 	if (elem->phy_cap_info[8] &
11071c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI)
11081c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_ER_SU_PPDU_4LTF_8US_GI;
11091c099ab4SSean Wang 
11101c099ab4SSean Wang 	if (elem->phy_cap_info[8] &
11111c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI)
11121c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_ER_SU_PPDU_1LTF_8US_GI;
11131c099ab4SSean Wang 
11141c099ab4SSean Wang 	if (elem->phy_cap_info[9] &
11151c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK)
11161c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_TRIG_CQI_FK;
11171c099ab4SSean Wang 
11181c099ab4SSean Wang 	if (elem->phy_cap_info[9] &
11191c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU)
11201c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_TX_1024QAM_UNDER_RU242;
11211c099ab4SSean Wang 
11221c099ab4SSean Wang 	if (elem->phy_cap_info[9] &
11231c099ab4SSean Wang 	    IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU)
11241c099ab4SSean Wang 		cap |= STA_REC_HE_CAP_RX_1024QAM_UNDER_RU242;
11251c099ab4SSean Wang 
11261c099ab4SSean Wang 	he->he_cap = cpu_to_le32(cap);
11271c099ab4SSean Wang 
11281c099ab4SSean Wang 	switch (sta->bandwidth) {
11291c099ab4SSean Wang 	case IEEE80211_STA_RX_BW_160:
11301c099ab4SSean Wang 		if (elem->phy_cap_info[0] &
11311c099ab4SSean Wang 		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
11321c099ab4SSean Wang 			he->max_nss_mcs[CMD_HE_MCS_BW8080] =
11331c099ab4SSean Wang 				he_cap->he_mcs_nss_supp.rx_mcs_80p80;
11341c099ab4SSean Wang 
11351c099ab4SSean Wang 		he->max_nss_mcs[CMD_HE_MCS_BW160] =
11361c099ab4SSean Wang 				he_cap->he_mcs_nss_supp.rx_mcs_160;
11371c099ab4SSean Wang 		fallthrough;
11381c099ab4SSean Wang 	default:
11391c099ab4SSean Wang 		he->max_nss_mcs[CMD_HE_MCS_BW80] =
11401c099ab4SSean Wang 				he_cap->he_mcs_nss_supp.rx_mcs_80;
11411c099ab4SSean Wang 		break;
11421c099ab4SSean Wang 	}
11431c099ab4SSean Wang 
11441c099ab4SSean Wang 	he->t_frame_dur =
11451c099ab4SSean Wang 		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
11461c099ab4SSean Wang 	he->max_ampdu_exp =
11471c099ab4SSean Wang 		HE_MAC(CAP3_MAX_AMPDU_LEN_EXP_MASK, elem->mac_cap_info[3]);
11481c099ab4SSean Wang 
11491c099ab4SSean Wang 	he->bw_set =
11501c099ab4SSean Wang 		HE_PHY(CAP0_CHANNEL_WIDTH_SET_MASK, elem->phy_cap_info[0]);
11511c099ab4SSean Wang 	he->device_class =
11521c099ab4SSean Wang 		HE_PHY(CAP1_DEVICE_CLASS_A, elem->phy_cap_info[1]);
11531c099ab4SSean Wang 	he->punc_pream_rx =
11541c099ab4SSean Wang 		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
11551c099ab4SSean Wang 
11561c099ab4SSean Wang 	he->dcm_tx_mode =
11571c099ab4SSean Wang 		HE_PHY(CAP3_DCM_MAX_CONST_TX_MASK, elem->phy_cap_info[3]);
11581c099ab4SSean Wang 	he->dcm_tx_max_nss =
11591c099ab4SSean Wang 		HE_PHY(CAP3_DCM_MAX_TX_NSS_2, elem->phy_cap_info[3]);
11601c099ab4SSean Wang 	he->dcm_rx_mode =
11611c099ab4SSean Wang 		HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]);
11621c099ab4SSean Wang 	he->dcm_rx_max_nss =
11631c099ab4SSean Wang 		HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]);
11641c099ab4SSean Wang 	he->dcm_rx_max_nss =
11651c099ab4SSean Wang 		HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]);
11661c099ab4SSean Wang 
11671c099ab4SSean Wang 	he->pkt_ext = 2;
11681c099ab4SSean Wang }
11691c099ab4SSean Wang 
11701c099ab4SSean Wang static void
11711c099ab4SSean Wang mt7921_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
11721c099ab4SSean Wang 			 struct ieee80211_vif *vif)
11731c099ab4SSean Wang {
11741c099ab4SSean Wang 	struct sta_rec_uapsd *uapsd;
11751c099ab4SSean Wang 	struct tlv *tlv;
11761c099ab4SSean Wang 
11771c099ab4SSean Wang 	if (vif->type != NL80211_IFTYPE_AP || !sta->wme)
11781c099ab4SSean Wang 		return;
11791c099ab4SSean Wang 
11801c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd));
11811c099ab4SSean Wang 	uapsd = (struct sta_rec_uapsd *)tlv;
11821c099ab4SSean Wang 
11831c099ab4SSean Wang 	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) {
11841c099ab4SSean Wang 		uapsd->dac_map |= BIT(3);
11851c099ab4SSean Wang 		uapsd->tac_map |= BIT(3);
11861c099ab4SSean Wang 	}
11871c099ab4SSean Wang 	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) {
11881c099ab4SSean Wang 		uapsd->dac_map |= BIT(2);
11891c099ab4SSean Wang 		uapsd->tac_map |= BIT(2);
11901c099ab4SSean Wang 	}
11911c099ab4SSean Wang 	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) {
11921c099ab4SSean Wang 		uapsd->dac_map |= BIT(1);
11931c099ab4SSean Wang 		uapsd->tac_map |= BIT(1);
11941c099ab4SSean Wang 	}
11951c099ab4SSean Wang 	if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) {
11961c099ab4SSean Wang 		uapsd->dac_map |= BIT(0);
11971c099ab4SSean Wang 		uapsd->tac_map |= BIT(0);
11981c099ab4SSean Wang 	}
11991c099ab4SSean Wang 	uapsd->max_sp = sta->max_sp;
12001c099ab4SSean Wang }
12011c099ab4SSean Wang 
12021c099ab4SSean Wang static void
12031c099ab4SSean Wang mt7921_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
12041c099ab4SSean Wang {
12051c099ab4SSean Wang 	struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
12061c099ab4SSean Wang 	struct sta_rec_amsdu *amsdu;
12071c099ab4SSean Wang 	struct tlv *tlv;
12081c099ab4SSean Wang 
12091c099ab4SSean Wang 	if (!sta->max_amsdu_len)
12101c099ab4SSean Wang 		return;
12111c099ab4SSean Wang 
12121c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
12131c099ab4SSean Wang 	amsdu = (struct sta_rec_amsdu *)tlv;
12141c099ab4SSean Wang 	amsdu->max_amsdu_num = 8;
12151c099ab4SSean Wang 	amsdu->amsdu_en = true;
12161c099ab4SSean Wang 	amsdu->max_mpdu_size = sta->max_amsdu_len >=
12171c099ab4SSean Wang 			       IEEE80211_MAX_MPDU_LEN_VHT_7991;
12181c099ab4SSean Wang 	msta->wcid.amsdu = true;
12191c099ab4SSean Wang }
12201c099ab4SSean Wang 
12211c099ab4SSean Wang static bool
12221c099ab4SSean Wang mt7921_hw_amsdu_supported(struct ieee80211_vif *vif)
12231c099ab4SSean Wang {
12241c099ab4SSean Wang 	switch (vif->type) {
12251c099ab4SSean Wang 	case NL80211_IFTYPE_AP:
12261c099ab4SSean Wang 	case NL80211_IFTYPE_STATION:
12271c099ab4SSean Wang 		return true;
12281c099ab4SSean Wang 	default:
12291c099ab4SSean Wang 		return false;
12301c099ab4SSean Wang 	}
12311c099ab4SSean Wang }
12321c099ab4SSean Wang 
12331c099ab4SSean Wang static void
12341c099ab4SSean Wang mt7921_mcu_sta_tlv(struct mt7921_dev *dev, struct sk_buff *skb,
12351c099ab4SSean Wang 		   struct ieee80211_sta *sta, struct ieee80211_vif *vif)
12361c099ab4SSean Wang {
12371c099ab4SSean Wang 	struct tlv *tlv;
12381c099ab4SSean Wang 	struct sta_rec_state *state;
12391c099ab4SSean Wang 	struct sta_rec_phy *phy;
12401c099ab4SSean Wang 	struct sta_rec_ra_info *ra_info;
12411c099ab4SSean Wang 	struct cfg80211_chan_def *chandef = &dev->mphy.chandef;
12421c099ab4SSean Wang 	enum nl80211_band band = chandef->chan->band;
12431c099ab4SSean Wang 
12441c099ab4SSean Wang 	/* starec ht */
12451c099ab4SSean Wang 	if (sta->ht_cap.ht_supported) {
12461c099ab4SSean Wang 		struct sta_rec_ht *ht;
12471c099ab4SSean Wang 
12481c099ab4SSean Wang 		tlv = mt7921_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
12491c099ab4SSean Wang 		ht = (struct sta_rec_ht *)tlv;
12501c099ab4SSean Wang 		ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
12511c099ab4SSean Wang 
12521c099ab4SSean Wang 		if (mt7921_hw_amsdu_supported(vif))
12531c099ab4SSean Wang 			mt7921_mcu_sta_amsdu_tlv(skb, sta);
12541c099ab4SSean Wang 	}
12551c099ab4SSean Wang 
12561c099ab4SSean Wang 	/* starec vht */
12571c099ab4SSean Wang 	if (sta->vht_cap.vht_supported) {
12581c099ab4SSean Wang 		struct sta_rec_vht *vht;
12591c099ab4SSean Wang 
12601c099ab4SSean Wang 		tlv = mt7921_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
12611c099ab4SSean Wang 		vht = (struct sta_rec_vht *)tlv;
12621c099ab4SSean Wang 		vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
12631c099ab4SSean Wang 		vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map;
12641c099ab4SSean Wang 		vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map;
12651c099ab4SSean Wang 	}
12661c099ab4SSean Wang 
12671c099ab4SSean Wang 	/* starec he */
12681c099ab4SSean Wang 	if (sta->he_cap.has_he)
12691c099ab4SSean Wang 		mt7921_mcu_sta_he_tlv(skb, sta);
12701c099ab4SSean Wang 
12711c099ab4SSean Wang 	/* starec uapsd */
12721c099ab4SSean Wang 	mt7921_mcu_sta_uapsd_tlv(skb, sta, vif);
12731c099ab4SSean Wang 
12741c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));
12751c099ab4SSean Wang 	phy = (struct sta_rec_phy *)tlv;
12761c099ab4SSean Wang 	phy->phy_type = mt7921_get_phy_mode_v2(dev, vif, band, sta);
12771c099ab4SSean Wang 	phy->basic_rate = cpu_to_le16((u16)vif->bss_conf.basic_rates);
12781c099ab4SSean Wang 
12791c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info));
12801c099ab4SSean Wang 	ra_info = (struct sta_rec_ra_info *)tlv;
12811c099ab4SSean Wang 	ra_info->legacy = cpu_to_le16((u16)sta->supp_rates[band]);
12821c099ab4SSean Wang 
12831c099ab4SSean Wang 	if (sta->ht_cap.ht_supported) {
12841c099ab4SSean Wang 		memcpy(ra_info->rx_mcs_bitmask, sta->ht_cap.mcs.rx_mask,
12851c099ab4SSean Wang 		       HT_MCS_MASK_NUM);
12861c099ab4SSean Wang 	}
12871c099ab4SSean Wang 
12881c099ab4SSean Wang 	tlv = mt7921_mcu_add_tlv(skb, STA_REC_STATE, sizeof(*state));
12891c099ab4SSean Wang 	state = (struct sta_rec_state *)tlv;
12901c099ab4SSean Wang 	state->state = 2;
12911c099ab4SSean Wang 
12921c099ab4SSean Wang 	if (sta->vht_cap.vht_supported) {
12931c099ab4SSean Wang 		state->vht_opmode = sta->bandwidth;
12941c099ab4SSean Wang 		state->vht_opmode |= (sta->rx_nss - 1) <<
12951c099ab4SSean Wang 			IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
12961c099ab4SSean Wang 	}
12971c099ab4SSean Wang }
12981c099ab4SSean Wang 
12991c099ab4SSean Wang static void
13001c099ab4SSean Wang mt7921_mcu_wtbl_smps_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
13011c099ab4SSean Wang 			 void *sta_wtbl, void *wtbl_tlv)
13021c099ab4SSean Wang {
13031c099ab4SSean Wang 	struct wtbl_smps *smps;
13041c099ab4SSean Wang 	struct tlv *tlv;
13051c099ab4SSean Wang 
13061c099ab4SSean Wang 	tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps),
13071c099ab4SSean Wang 					wtbl_tlv, sta_wtbl);
13081c099ab4SSean Wang 	smps = (struct wtbl_smps *)tlv;
13091c099ab4SSean Wang 
13101c099ab4SSean Wang 	if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
13111c099ab4SSean Wang 		smps->smps = true;
13121c099ab4SSean Wang }
13131c099ab4SSean Wang 
13141c099ab4SSean Wang static void
13151c099ab4SSean Wang mt7921_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
13161c099ab4SSean Wang 		       void *sta_wtbl, void *wtbl_tlv)
13171c099ab4SSean Wang {
13181c099ab4SSean Wang 	struct wtbl_ht *ht = NULL;
13191c099ab4SSean Wang 	struct tlv *tlv;
13201c099ab4SSean Wang 
13211c099ab4SSean Wang 	/* wtbl ht */
13221c099ab4SSean Wang 	if (sta->ht_cap.ht_supported) {
13231c099ab4SSean Wang 		tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),
13241c099ab4SSean Wang 						wtbl_tlv, sta_wtbl);
13251c099ab4SSean Wang 		ht = (struct wtbl_ht *)tlv;
13261c099ab4SSean Wang 		ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);
13271c099ab4SSean Wang 		ht->af = sta->ht_cap.ampdu_factor;
13281c099ab4SSean Wang 		ht->mm = sta->ht_cap.ampdu_density;
13291c099ab4SSean Wang 		ht->ht = true;
13301c099ab4SSean Wang 	}
13311c099ab4SSean Wang 
13321c099ab4SSean Wang 	/* wtbl vht */
13331c099ab4SSean Wang 	if (sta->vht_cap.vht_supported) {
13341c099ab4SSean Wang 		struct wtbl_vht *vht;
13351c099ab4SSean Wang 		u8 af;
13361c099ab4SSean Wang 
13371c099ab4SSean Wang 		tlv = mt7921_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht),
13381c099ab4SSean Wang 						wtbl_tlv, sta_wtbl);
13391c099ab4SSean Wang 		vht = (struct wtbl_vht *)tlv;
13401c099ab4SSean Wang 		vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
13411c099ab4SSean Wang 		vht->vht = true;
13421c099ab4SSean Wang 
13431c099ab4SSean Wang 		af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
13441c099ab4SSean Wang 			       sta->vht_cap.cap);
13451c099ab4SSean Wang 		if (ht)
13461c099ab4SSean Wang 			ht->af = max_t(u8, ht->af, af);
13471c099ab4SSean Wang 	}
13481c099ab4SSean Wang 
13491c099ab4SSean Wang 	mt7921_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv);
13501c099ab4SSean Wang }
13511c099ab4SSean Wang 
13521c099ab4SSean Wang static int mt7921_mcu_start_firmware(struct mt7921_dev *dev, u32 addr,
13531c099ab4SSean Wang 				     u32 option)
13541c099ab4SSean Wang {
13551c099ab4SSean Wang 	struct {
13561c099ab4SSean Wang 		__le32 option;
13571c099ab4SSean Wang 		__le32 addr;
13581c099ab4SSean Wang 	} req = {
13591c099ab4SSean Wang 		.option = cpu_to_le32(option),
13601c099ab4SSean Wang 		.addr = cpu_to_le32(addr),
13611c099ab4SSean Wang 	};
13621c099ab4SSean Wang 
13631c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ, &req,
13641c099ab4SSean Wang 				 sizeof(req), true);
13651c099ab4SSean Wang }
13661c099ab4SSean Wang 
13671c099ab4SSean Wang static int mt7921_mcu_restart(struct mt76_dev *dev)
13681c099ab4SSean Wang {
13691c099ab4SSean Wang 	struct {
13701c099ab4SSean Wang 		u8 power_mode;
13711c099ab4SSean Wang 		u8 rsv[3];
13721c099ab4SSean Wang 	} req = {
13731c099ab4SSean Wang 		.power_mode = 1,
13741c099ab4SSean Wang 	};
13751c099ab4SSean Wang 
13761c099ab4SSean Wang 	return mt76_mcu_send_msg(dev, MCU_CMD_NIC_POWER_CTRL, &req,
13771c099ab4SSean Wang 				 sizeof(req), false);
13781c099ab4SSean Wang }
13791c099ab4SSean Wang 
13801c099ab4SSean Wang static int mt7921_mcu_patch_sem_ctrl(struct mt7921_dev *dev, bool get)
13811c099ab4SSean Wang {
13821c099ab4SSean Wang 	struct {
13831c099ab4SSean Wang 		__le32 op;
13841c099ab4SSean Wang 	} req = {
13851c099ab4SSean Wang 		.op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE),
13861c099ab4SSean Wang 	};
13871c099ab4SSean Wang 
13881c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL, &req,
13891c099ab4SSean Wang 				 sizeof(req), true);
13901c099ab4SSean Wang }
13911c099ab4SSean Wang 
13921c099ab4SSean Wang static int mt7921_mcu_start_patch(struct mt7921_dev *dev)
13931c099ab4SSean Wang {
13941c099ab4SSean Wang 	struct {
13951c099ab4SSean Wang 		u8 check_crc;
13961c099ab4SSean Wang 		u8 reserved[3];
13971c099ab4SSean Wang 	} req = {
13981c099ab4SSean Wang 		.check_crc = 0,
13991c099ab4SSean Wang 	};
14001c099ab4SSean Wang 
14011c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ, &req,
14021c099ab4SSean Wang 				 sizeof(req), true);
14031c099ab4SSean Wang }
14041c099ab4SSean Wang 
14051c099ab4SSean Wang static int mt7921_driver_own(struct mt7921_dev *dev)
14061c099ab4SSean Wang {
14071c099ab4SSean Wang 	u32 reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
14081c099ab4SSean Wang 
14091c099ab4SSean Wang 	mt76_wr(dev, reg, MT_TOP_LPCR_HOST_DRV_OWN);
14101c099ab4SSean Wang 	if (!mt76_poll_msec(dev, reg, MT_TOP_LPCR_HOST_FW_OWN,
14111c099ab4SSean Wang 			    0, 500)) {
14121c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Timeout for driver own\n");
14131c099ab4SSean Wang 		return -EIO;
14141c099ab4SSean Wang 	}
14151c099ab4SSean Wang 
14161c099ab4SSean Wang 	return 0;
14171c099ab4SSean Wang }
14181c099ab4SSean Wang 
14191c099ab4SSean Wang static int mt7921_mcu_init_download(struct mt7921_dev *dev, u32 addr,
14201c099ab4SSean Wang 				    u32 len, u32 mode)
14211c099ab4SSean Wang {
14221c099ab4SSean Wang 	struct {
14231c099ab4SSean Wang 		__le32 addr;
14241c099ab4SSean Wang 		__le32 len;
14251c099ab4SSean Wang 		__le32 mode;
14261c099ab4SSean Wang 	} req = {
14271c099ab4SSean Wang 		.addr = cpu_to_le32(addr),
14281c099ab4SSean Wang 		.len = cpu_to_le32(len),
14291c099ab4SSean Wang 		.mode = cpu_to_le32(mode),
14301c099ab4SSean Wang 	};
14311c099ab4SSean Wang 	int attr;
14321c099ab4SSean Wang 
14331c099ab4SSean Wang 	if (req.addr == cpu_to_le32(MCU_PATCH_ADDRESS) || addr == 0x900000)
14341c099ab4SSean Wang 		attr = MCU_CMD_PATCH_START_REQ;
14351c099ab4SSean Wang 	else
14361c099ab4SSean Wang 		attr = MCU_CMD_TARGET_ADDRESS_LEN_REQ;
14371c099ab4SSean Wang 
14381c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true);
14391c099ab4SSean Wang }
14401c099ab4SSean Wang 
14411c099ab4SSean Wang static int mt7921_load_patch(struct mt7921_dev *dev)
14421c099ab4SSean Wang {
14431c099ab4SSean Wang 	const struct mt7921_patch_hdr *hdr;
14441c099ab4SSean Wang 	const struct firmware *fw = NULL;
14451c099ab4SSean Wang 	int i, ret, sem;
14461c099ab4SSean Wang 
14471c099ab4SSean Wang 	sem = mt7921_mcu_patch_sem_ctrl(dev, 1);
14481c099ab4SSean Wang 	switch (sem) {
14491c099ab4SSean Wang 	case PATCH_IS_DL:
14501c099ab4SSean Wang 		return 0;
14511c099ab4SSean Wang 	case PATCH_NOT_DL_SEM_SUCCESS:
14521c099ab4SSean Wang 		break;
14531c099ab4SSean Wang 	default:
14541c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
14551c099ab4SSean Wang 		return -EAGAIN;
14561c099ab4SSean Wang 	}
14571c099ab4SSean Wang 
14581c099ab4SSean Wang 	ret = request_firmware(&fw, MT7921_ROM_PATCH, dev->mt76.dev);
14591c099ab4SSean Wang 	if (ret)
14601c099ab4SSean Wang 		goto out;
14611c099ab4SSean Wang 
14621c099ab4SSean Wang 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
14631c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Invalid firmware\n");
14641c099ab4SSean Wang 		ret = -EINVAL;
14651c099ab4SSean Wang 		goto out;
14661c099ab4SSean Wang 	}
14671c099ab4SSean Wang 
14681c099ab4SSean Wang 	hdr = (const struct mt7921_patch_hdr *)(fw->data);
14691c099ab4SSean Wang 
14701c099ab4SSean Wang 	dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
14711c099ab4SSean Wang 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
14721c099ab4SSean Wang 
14731c099ab4SSean Wang 	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
14741c099ab4SSean Wang 		struct mt7921_patch_sec *sec;
14751c099ab4SSean Wang 		const u8 *dl;
14761c099ab4SSean Wang 		u32 len, addr;
14771c099ab4SSean Wang 
14781c099ab4SSean Wang 		sec = (struct mt7921_patch_sec *)(fw->data + sizeof(*hdr) +
14791c099ab4SSean Wang 						  i * sizeof(*sec));
14801c099ab4SSean Wang 		if ((be32_to_cpu(sec->type) & PATCH_SEC_TYPE_MASK) !=
14811c099ab4SSean Wang 		    PATCH_SEC_TYPE_INFO) {
14821c099ab4SSean Wang 			ret = -EINVAL;
14831c099ab4SSean Wang 			goto out;
14841c099ab4SSean Wang 		}
14851c099ab4SSean Wang 
14861c099ab4SSean Wang 		addr = be32_to_cpu(sec->info.addr);
14871c099ab4SSean Wang 		len = be32_to_cpu(sec->info.len);
14881c099ab4SSean Wang 		dl = fw->data + be32_to_cpu(sec->offs);
14891c099ab4SSean Wang 
14901c099ab4SSean Wang 		ret = mt7921_mcu_init_download(dev, addr, len,
14911c099ab4SSean Wang 					       DL_MODE_NEED_RSP);
14921c099ab4SSean Wang 		if (ret) {
14931c099ab4SSean Wang 			dev_err(dev->mt76.dev, "Download request failed\n");
14941c099ab4SSean Wang 			goto out;
14951c099ab4SSean Wang 		}
14961c099ab4SSean Wang 
14971c099ab4SSean Wang 		ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
14981c099ab4SSean Wang 					     dl, len);
14991c099ab4SSean Wang 		if (ret) {
15001c099ab4SSean Wang 			dev_err(dev->mt76.dev, "Failed to send patch\n");
15011c099ab4SSean Wang 			goto out;
15021c099ab4SSean Wang 		}
15031c099ab4SSean Wang 	}
15041c099ab4SSean Wang 
15051c099ab4SSean Wang 	ret = mt7921_mcu_start_patch(dev);
15061c099ab4SSean Wang 	if (ret)
15071c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Failed to start patch\n");
15081c099ab4SSean Wang 
15091c099ab4SSean Wang out:
15101c099ab4SSean Wang 	sem = mt7921_mcu_patch_sem_ctrl(dev, 0);
15111c099ab4SSean Wang 	switch (sem) {
15121c099ab4SSean Wang 	case PATCH_REL_SEM_SUCCESS:
15131c099ab4SSean Wang 		break;
15141c099ab4SSean Wang 	default:
15151c099ab4SSean Wang 		ret = -EAGAIN;
15161c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Failed to release patch semaphore\n");
15171c099ab4SSean Wang 		goto out;
15181c099ab4SSean Wang 	}
15191c099ab4SSean Wang 	release_firmware(fw);
15201c099ab4SSean Wang 
15211c099ab4SSean Wang 	return ret;
15221c099ab4SSean Wang }
15231c099ab4SSean Wang 
15241c099ab4SSean Wang static u32 mt7921_mcu_gen_dl_mode(u8 feature_set, bool is_wa)
15251c099ab4SSean Wang {
15261c099ab4SSean Wang 	u32 ret = 0;
15271c099ab4SSean Wang 
15281c099ab4SSean Wang 	ret |= (feature_set & FW_FEATURE_SET_ENCRYPT) ?
15291c099ab4SSean Wang 	       (DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV) : 0;
15301c099ab4SSean Wang 	ret |= (feature_set & FW_FEATURE_ENCRY_MODE) ?
15311c099ab4SSean Wang 	       DL_CONFIG_ENCRY_MODE_SEL : 0;
15321c099ab4SSean Wang 	ret |= FIELD_PREP(DL_MODE_KEY_IDX,
15331c099ab4SSean Wang 			  FIELD_GET(FW_FEATURE_SET_KEY_IDX, feature_set));
15341c099ab4SSean Wang 	ret |= DL_MODE_NEED_RSP;
15351c099ab4SSean Wang 	ret |= is_wa ? DL_MODE_WORKING_PDA_CR4 : 0;
15361c099ab4SSean Wang 
15371c099ab4SSean Wang 	return ret;
15381c099ab4SSean Wang }
15391c099ab4SSean Wang 
15401c099ab4SSean Wang static int
15411c099ab4SSean Wang mt7921_mcu_send_ram_firmware(struct mt7921_dev *dev,
15421c099ab4SSean Wang 			     const struct mt7921_fw_trailer *hdr,
15431c099ab4SSean Wang 			     const u8 *data, bool is_wa)
15441c099ab4SSean Wang {
15451c099ab4SSean Wang 	int i, offset = 0;
15461c099ab4SSean Wang 	u32 override = 0, option = 0;
15471c099ab4SSean Wang 
15481c099ab4SSean Wang 	for (i = 0; i < hdr->n_region; i++) {
15491c099ab4SSean Wang 		const struct mt7921_fw_region *region;
15501c099ab4SSean Wang 		int err;
15511c099ab4SSean Wang 		u32 len, addr, mode;
15521c099ab4SSean Wang 
15531c099ab4SSean Wang 		region = (const struct mt7921_fw_region *)((const u8 *)hdr -
15541c099ab4SSean Wang 			 (hdr->n_region - i) * sizeof(*region));
15551c099ab4SSean Wang 		mode = mt7921_mcu_gen_dl_mode(region->feature_set, is_wa);
15561c099ab4SSean Wang 		len = le32_to_cpu(region->len);
15571c099ab4SSean Wang 		addr = le32_to_cpu(region->addr);
15581c099ab4SSean Wang 
15591c099ab4SSean Wang 		if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR)
15601c099ab4SSean Wang 			override = addr;
15611c099ab4SSean Wang 
15621c099ab4SSean Wang 		err = mt7921_mcu_init_download(dev, addr, len, mode);
15631c099ab4SSean Wang 		if (err) {
15641c099ab4SSean Wang 			dev_err(dev->mt76.dev, "Download request failed\n");
15651c099ab4SSean Wang 			return err;
15661c099ab4SSean Wang 		}
15671c099ab4SSean Wang 
15681c099ab4SSean Wang 		err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
15691c099ab4SSean Wang 					     data + offset, len);
15701c099ab4SSean Wang 		if (err) {
15711c099ab4SSean Wang 			dev_err(dev->mt76.dev, "Failed to send firmware.\n");
15721c099ab4SSean Wang 			return err;
15731c099ab4SSean Wang 		}
15741c099ab4SSean Wang 
15751c099ab4SSean Wang 		offset += len;
15761c099ab4SSean Wang 	}
15771c099ab4SSean Wang 
15781c099ab4SSean Wang 	if (override)
15791c099ab4SSean Wang 		option |= FW_START_OVERRIDE;
15801c099ab4SSean Wang 
15811c099ab4SSean Wang 	if (is_wa)
15821c099ab4SSean Wang 		option |= FW_START_WORKING_PDA_CR4;
15831c099ab4SSean Wang 
15841c099ab4SSean Wang 	return mt7921_mcu_start_firmware(dev, override, option);
15851c099ab4SSean Wang }
15861c099ab4SSean Wang 
15871c099ab4SSean Wang static int mt7921_load_ram(struct mt7921_dev *dev)
15881c099ab4SSean Wang {
15891c099ab4SSean Wang 	const struct mt7921_fw_trailer *hdr;
15901c099ab4SSean Wang 	const struct firmware *fw;
15911c099ab4SSean Wang 	int ret;
15921c099ab4SSean Wang 
15931c099ab4SSean Wang 	ret = request_firmware(&fw, MT7921_FIRMWARE_WM, dev->mt76.dev);
15941c099ab4SSean Wang 	if (ret)
15951c099ab4SSean Wang 		return ret;
15961c099ab4SSean Wang 
15971c099ab4SSean Wang 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
15981c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Invalid firmware\n");
15991c099ab4SSean Wang 		ret = -EINVAL;
16001c099ab4SSean Wang 		goto out;
16011c099ab4SSean Wang 	}
16021c099ab4SSean Wang 
16031c099ab4SSean Wang 	hdr = (const struct mt7921_fw_trailer *)(fw->data + fw->size -
16041c099ab4SSean Wang 					sizeof(*hdr));
16051c099ab4SSean Wang 
16061c099ab4SSean Wang 	dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",
16071c099ab4SSean Wang 		 hdr->fw_ver, hdr->build_date);
16081c099ab4SSean Wang 
16091c099ab4SSean Wang 	ret = mt7921_mcu_send_ram_firmware(dev, hdr, fw->data, false);
16101c099ab4SSean Wang 	if (ret) {
16111c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Failed to start WM firmware\n");
16121c099ab4SSean Wang 		goto out;
16131c099ab4SSean Wang 	}
16141c099ab4SSean Wang 
16151c099ab4SSean Wang 	snprintf(dev->mt76.hw->wiphy->fw_version,
16161c099ab4SSean Wang 		 sizeof(dev->mt76.hw->wiphy->fw_version),
16171c099ab4SSean Wang 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
16181c099ab4SSean Wang 
16191c099ab4SSean Wang out:
16201c099ab4SSean Wang 	release_firmware(fw);
16211c099ab4SSean Wang 
16221c099ab4SSean Wang 	return ret;
16231c099ab4SSean Wang }
16241c099ab4SSean Wang 
16251c099ab4SSean Wang static int mt7921_load_firmware(struct mt7921_dev *dev)
16261c099ab4SSean Wang {
16271c099ab4SSean Wang 	int ret;
16281c099ab4SSean Wang 
16291c099ab4SSean Wang 	ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
16301c099ab4SSean Wang 	if (ret) {
16311c099ab4SSean Wang 		dev_dbg(dev->mt76.dev, "Firmware is already download\n");
16321c099ab4SSean Wang 		return -EIO;
16331c099ab4SSean Wang 	}
16341c099ab4SSean Wang 
16351c099ab4SSean Wang 	ret = mt7921_load_patch(dev);
16361c099ab4SSean Wang 	if (ret)
16371c099ab4SSean Wang 		return ret;
16381c099ab4SSean Wang 
16391c099ab4SSean Wang 	ret = mt7921_load_ram(dev);
16401c099ab4SSean Wang 	if (ret)
16411c099ab4SSean Wang 		return ret;
16421c099ab4SSean Wang 
16431c099ab4SSean Wang 	if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
16441c099ab4SSean Wang 			    MT_TOP_MISC2_FW_N9_RDY, 1500)) {
16451c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
16461c099ab4SSean Wang 
16471c099ab4SSean Wang 		return -EIO;
16481c099ab4SSean Wang 	}
16491c099ab4SSean Wang 
16501c099ab4SSean Wang 	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
16511c099ab4SSean Wang 
16521c099ab4SSean Wang 	dev_err(dev->mt76.dev, "Firmware init done\n");
16531c099ab4SSean Wang 
16541c099ab4SSean Wang 	return 0;
16551c099ab4SSean Wang }
16561c099ab4SSean Wang 
16571c099ab4SSean Wang int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl)
16581c099ab4SSean Wang {
16591c099ab4SSean Wang 	struct {
16601c099ab4SSean Wang 		u8 ctrl_val;
16611c099ab4SSean Wang 		u8 pad[3];
16621c099ab4SSean Wang 	} data = {
16631c099ab4SSean Wang 		.ctrl_val = ctrl
16641c099ab4SSean Wang 	};
16651c099ab4SSean Wang 
16661c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FWLOG_2_HOST, &data,
16671c099ab4SSean Wang 				 sizeof(data), false);
16681c099ab4SSean Wang }
16691c099ab4SSean Wang 
16701c099ab4SSean Wang int mt7921_mcu_init(struct mt7921_dev *dev)
16711c099ab4SSean Wang {
16721c099ab4SSean Wang 	static const struct mt76_mcu_ops mt7921_mcu_ops = {
16731c099ab4SSean Wang 		.headroom = sizeof(struct mt7921_mcu_txd),
16741c099ab4SSean Wang 		.mcu_skb_send_msg = mt7921_mcu_send_message,
16751c099ab4SSean Wang 		.mcu_parse_response = mt7921_mcu_parse_response,
16761c099ab4SSean Wang 		.mcu_restart = mt7921_mcu_restart,
16771c099ab4SSean Wang 	};
16781c099ab4SSean Wang 	int ret;
16791c099ab4SSean Wang 
16801c099ab4SSean Wang 	dev->mt76.mcu_ops = &mt7921_mcu_ops;
16811c099ab4SSean Wang 
16821c099ab4SSean Wang 	ret = mt7921_driver_own(dev);
16831c099ab4SSean Wang 	if (ret)
16841c099ab4SSean Wang 		return ret;
16851c099ab4SSean Wang 
16861c099ab4SSean Wang 	ret = mt7921_load_firmware(dev);
16871c099ab4SSean Wang 	if (ret)
16881c099ab4SSean Wang 		return ret;
16891c099ab4SSean Wang 
16901c099ab4SSean Wang 	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
16911c099ab4SSean Wang 	mt7921_mcu_fw_log_2_host(dev, 1);
16921c099ab4SSean Wang 
16931c099ab4SSean Wang 	return 0;
16941c099ab4SSean Wang }
16951c099ab4SSean Wang 
16961c099ab4SSean Wang void mt7921_mcu_exit(struct mt7921_dev *dev)
16971c099ab4SSean Wang {
16981c099ab4SSean Wang 	u32 reg = mt7921_reg_map_l1(dev, MT_TOP_MISC);
16991c099ab4SSean Wang 
17001c099ab4SSean Wang 	__mt76_mcu_restart(&dev->mt76);
17011c099ab4SSean Wang 	if (!mt76_poll_msec(dev, reg, MT_TOP_MISC_FW_STATE,
17021c099ab4SSean Wang 			    FIELD_PREP(MT_TOP_MISC_FW_STATE,
17031c099ab4SSean Wang 				       FW_STATE_FW_DOWNLOAD), 1000)) {
17041c099ab4SSean Wang 		dev_err(dev->mt76.dev, "Failed to exit mcu\n");
17051c099ab4SSean Wang 		return;
17061c099ab4SSean Wang 	}
17071c099ab4SSean Wang 
17081c099ab4SSean Wang 	reg = mt7921_reg_map_l1(dev, MT_TOP_LPCR_HOST_BAND0);
17091c099ab4SSean Wang 	mt76_wr(dev, reg, MT_TOP_LPCR_HOST_FW_OWN);
17101c099ab4SSean Wang 	skb_queue_purge(&dev->mt76.mcu.res_q);
17111c099ab4SSean Wang }
17121c099ab4SSean Wang 
17131c099ab4SSean Wang int mt7921_mcu_set_mac(struct mt7921_dev *dev, int band,
17141c099ab4SSean Wang 		       bool enable, bool hdr_trans)
17151c099ab4SSean Wang {
17161c099ab4SSean Wang 	struct {
17171c099ab4SSean Wang 		u8 enable;
17181c099ab4SSean Wang 		u8 band;
17191c099ab4SSean Wang 		u8 rsv[2];
17201c099ab4SSean Wang 	} __packed req_mac = {
17211c099ab4SSean Wang 		.enable = enable,
17221c099ab4SSean Wang 		.band = band,
17231c099ab4SSean Wang 	};
17241c099ab4SSean Wang 
17251c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL,
17261c099ab4SSean Wang 				 &req_mac, sizeof(req_mac), true);
17271c099ab4SSean Wang }
17281c099ab4SSean Wang 
17291c099ab4SSean Wang int mt7921_mcu_set_rts_thresh(struct mt7921_phy *phy, u32 val)
17301c099ab4SSean Wang {
17311c099ab4SSean Wang 	struct mt7921_dev *dev = phy->dev;
17321c099ab4SSean Wang 	struct {
17331c099ab4SSean Wang 		u8 prot_idx;
17341c099ab4SSean Wang 		u8 band;
17351c099ab4SSean Wang 		u8 rsv[2];
17361c099ab4SSean Wang 		__le32 len_thresh;
17371c099ab4SSean Wang 		__le32 pkt_thresh;
17381c099ab4SSean Wang 	} __packed req = {
17391c099ab4SSean Wang 		.prot_idx = 1,
17401c099ab4SSean Wang 		.band = phy != &dev->phy,
17411c099ab4SSean Wang 		.len_thresh = cpu_to_le32(val),
17421c099ab4SSean Wang 		.pkt_thresh = cpu_to_le32(0x2),
17431c099ab4SSean Wang 	};
17441c099ab4SSean Wang 
17451c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, &req,
17461c099ab4SSean Wang 				 sizeof(req), true);
17471c099ab4SSean Wang }
17481c099ab4SSean Wang 
17491c099ab4SSean Wang int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif)
17501c099ab4SSean Wang {
17511c099ab4SSean Wang #define WMM_AIFS_SET		BIT(0)
17521c099ab4SSean Wang #define WMM_CW_MIN_SET		BIT(1)
17531c099ab4SSean Wang #define WMM_CW_MAX_SET		BIT(2)
17541c099ab4SSean Wang #define WMM_TXOP_SET		BIT(3)
17551c099ab4SSean Wang #define WMM_PARAM_SET		GENMASK(3, 0)
17561c099ab4SSean Wang #define TX_CMD_MODE		1
17571c099ab4SSean Wang 	struct edca {
17581c099ab4SSean Wang 		u8 queue;
17591c099ab4SSean Wang 		u8 set;
17601c099ab4SSean Wang 		u8 aifs;
17611c099ab4SSean Wang 		u8 cw_min;
17621c099ab4SSean Wang 		__le16 cw_max;
17631c099ab4SSean Wang 		__le16 txop;
17641c099ab4SSean Wang 	};
17651c099ab4SSean Wang 	struct mt7921_mcu_tx {
17661c099ab4SSean Wang 		u8 total;
17671c099ab4SSean Wang 		u8 action;
17681c099ab4SSean Wang 		u8 valid;
17691c099ab4SSean Wang 		u8 mode;
17701c099ab4SSean Wang 
17711c099ab4SSean Wang 		struct edca edca[IEEE80211_NUM_ACS];
17721c099ab4SSean Wang 	} __packed req = {
17731c099ab4SSean Wang 		.valid = true,
17741c099ab4SSean Wang 		.mode = TX_CMD_MODE,
17751c099ab4SSean Wang 		.total = IEEE80211_NUM_ACS,
17761c099ab4SSean Wang 	};
17771c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
17781c099ab4SSean Wang 	int ac;
17791c099ab4SSean Wang 
17801c099ab4SSean Wang 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
17811c099ab4SSean Wang 		struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
17821c099ab4SSean Wang 		struct edca *e = &req.edca[ac];
17831c099ab4SSean Wang 
17841c099ab4SSean Wang 		e->set = WMM_PARAM_SET;
17851c099ab4SSean Wang 		e->queue = ac + mvif->mt76.wmm_idx * MT7921_MAX_WMM_SETS;
17861c099ab4SSean Wang 		e->aifs = q->aifs;
17871c099ab4SSean Wang 		e->txop = cpu_to_le16(q->txop);
17881c099ab4SSean Wang 
17891c099ab4SSean Wang 		if (q->cw_min)
17901c099ab4SSean Wang 			e->cw_min = fls(q->cw_min);
17911c099ab4SSean Wang 		else
17921c099ab4SSean Wang 			e->cw_min = 5;
17931c099ab4SSean Wang 
17941c099ab4SSean Wang 		if (q->cw_max)
17951c099ab4SSean Wang 			e->cw_max = cpu_to_le16(fls(q->cw_max));
17961c099ab4SSean Wang 		else
17971c099ab4SSean Wang 			e->cw_max = cpu_to_le16(10);
17981c099ab4SSean Wang 	}
17991c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req,
18001c099ab4SSean Wang 				 sizeof(req), true);
18011c099ab4SSean Wang }
18021c099ab4SSean Wang 
18031c099ab4SSean Wang int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd)
18041c099ab4SSean Wang {
18051c099ab4SSean Wang 	struct mt7921_dev *dev = phy->dev;
18061c099ab4SSean Wang 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
18071c099ab4SSean Wang 	int freq1 = chandef->center_freq1;
18081c099ab4SSean Wang 	struct {
18091c099ab4SSean Wang 		u8 control_ch;
18101c099ab4SSean Wang 		u8 center_ch;
18111c099ab4SSean Wang 		u8 bw;
18121c099ab4SSean Wang 		u8 tx_streams_num;
18131c099ab4SSean Wang 		u8 rx_streams;	/* mask or num */
18141c099ab4SSean Wang 		u8 switch_reason;
18151c099ab4SSean Wang 		u8 band_idx;
18161c099ab4SSean Wang 		u8 center_ch2;	/* for 80+80 only */
18171c099ab4SSean Wang 		__le16 cac_case;
18181c099ab4SSean Wang 		u8 channel_band;
18191c099ab4SSean Wang 		u8 rsv0;
18201c099ab4SSean Wang 		__le32 outband_freq;
18211c099ab4SSean Wang 		u8 txpower_drop;
18221c099ab4SSean Wang 		u8 ap_bw;
18231c099ab4SSean Wang 		u8 ap_center_ch;
18241c099ab4SSean Wang 		u8 rsv1[57];
18251c099ab4SSean Wang 	} __packed req = {
18261c099ab4SSean Wang 		.control_ch = chandef->chan->hw_value,
18271c099ab4SSean Wang 		.center_ch = ieee80211_frequency_to_channel(freq1),
18281c099ab4SSean Wang 		.bw = mt7921_mcu_chan_bw(chandef),
18291c099ab4SSean Wang 		.tx_streams_num = hweight8(phy->mt76->antenna_mask),
18301c099ab4SSean Wang 		.rx_streams = phy->mt76->antenna_mask,
18311c099ab4SSean Wang 		.band_idx = phy != &dev->phy,
18321c099ab4SSean Wang 		.channel_band = chandef->chan->band,
18331c099ab4SSean Wang 	};
18341c099ab4SSean Wang 
18351c099ab4SSean Wang 	if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
18361c099ab4SSean Wang 		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
18371c099ab4SSean Wang 	else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
18381c099ab4SSean Wang 		 chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
18391c099ab4SSean Wang 		req.switch_reason = CH_SWITCH_DFS;
18401c099ab4SSean Wang 	else
18411c099ab4SSean Wang 		req.switch_reason = CH_SWITCH_NORMAL;
18421c099ab4SSean Wang 
18431c099ab4SSean Wang 	if (cmd == MCU_EXT_CMD_CHANNEL_SWITCH)
18441c099ab4SSean Wang 		req.rx_streams = hweight8(req.rx_streams);
18451c099ab4SSean Wang 
18461c099ab4SSean Wang 	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
18471c099ab4SSean Wang 		int freq2 = chandef->center_freq2;
18481c099ab4SSean Wang 
18491c099ab4SSean Wang 		req.center_ch2 = ieee80211_frequency_to_channel(freq2);
18501c099ab4SSean Wang 	}
18511c099ab4SSean Wang 
18521c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
18531c099ab4SSean Wang }
18541c099ab4SSean Wang 
18551c099ab4SSean Wang int mt7921_mcu_set_eeprom(struct mt7921_dev *dev)
18561c099ab4SSean Wang {
18571c099ab4SSean Wang 	struct req_hdr {
18581c099ab4SSean Wang 		u8 buffer_mode;
18591c099ab4SSean Wang 		u8 format;
18601c099ab4SSean Wang 		__le16 len;
18611c099ab4SSean Wang 	} __packed req = {
18621c099ab4SSean Wang 		.buffer_mode = EE_MODE_EFUSE,
18631c099ab4SSean Wang 		.format = EE_FORMAT_WHOLE,
18641c099ab4SSean Wang 	};
18651c099ab4SSean Wang 
18661c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
18671c099ab4SSean Wang 				 &req, sizeof(req), true);
18681c099ab4SSean Wang }
18691c099ab4SSean Wang 
18701c099ab4SSean Wang int mt7921_mcu_get_eeprom(struct mt7921_dev *dev, u32 offset)
18711c099ab4SSean Wang {
18721c099ab4SSean Wang 	struct mt7921_mcu_eeprom_info req = {
18731c099ab4SSean Wang 		.addr = cpu_to_le32(round_down(offset, 16)),
18741c099ab4SSean Wang 	};
18751c099ab4SSean Wang 	struct mt7921_mcu_eeprom_info *res;
18761c099ab4SSean Wang 	struct sk_buff *skb;
18771c099ab4SSean Wang 	int ret;
18781c099ab4SSean Wang 	u8 *buf;
18791c099ab4SSean Wang 
18801c099ab4SSean Wang 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req,
18811c099ab4SSean Wang 					sizeof(req), true, &skb);
18821c099ab4SSean Wang 	if (ret)
18831c099ab4SSean Wang 		return ret;
18841c099ab4SSean Wang 
18851c099ab4SSean Wang 	res = (struct mt7921_mcu_eeprom_info *)skb->data;
18861c099ab4SSean Wang 	buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
18871c099ab4SSean Wang 	memcpy(buf, res->data, 16);
18881c099ab4SSean Wang 	dev_kfree_skb(skb);
18891c099ab4SSean Wang 
18901c099ab4SSean Wang 	return 0;
18911c099ab4SSean Wang }
18921c099ab4SSean Wang 
18931c099ab4SSean Wang int
18941c099ab4SSean Wang mt7921_mcu_uni_add_dev(struct mt7921_dev *dev,
18951c099ab4SSean Wang 		       struct ieee80211_vif *vif, bool enable)
18961c099ab4SSean Wang {
18971c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
18981c099ab4SSean Wang 	u8 omac_idx = mvif->mt76.omac_idx;
18991c099ab4SSean Wang 	struct {
19001c099ab4SSean Wang 		struct {
19011c099ab4SSean Wang 			u8 omac_idx;
19021c099ab4SSean Wang 			u8 band_idx;
19031c099ab4SSean Wang 			__le16 pad;
19041c099ab4SSean Wang 		} __packed hdr;
19051c099ab4SSean Wang 		struct req_tlv {
19061c099ab4SSean Wang 			__le16 tag;
19071c099ab4SSean Wang 			__le16 len;
19081c099ab4SSean Wang 			u8 active;
19091c099ab4SSean Wang 			u8 pad;
19101c099ab4SSean Wang 			u8 omac_addr[ETH_ALEN];
19111c099ab4SSean Wang 		} __packed tlv;
19121c099ab4SSean Wang 	} dev_req = {
19131c099ab4SSean Wang 		.hdr = {
19141c099ab4SSean Wang 			.omac_idx = omac_idx,
19151c099ab4SSean Wang 			.band_idx = mvif->mt76.band_idx,
19161c099ab4SSean Wang 		},
19171c099ab4SSean Wang 		.tlv = {
19181c099ab4SSean Wang 			.tag = cpu_to_le16(DEV_INFO_ACTIVE),
19191c099ab4SSean Wang 			.len = cpu_to_le16(sizeof(struct req_tlv)),
19201c099ab4SSean Wang 			.active = enable,
19211c099ab4SSean Wang 		},
19221c099ab4SSean Wang 	};
19231c099ab4SSean Wang 	struct {
19241c099ab4SSean Wang 		struct {
19251c099ab4SSean Wang 			u8 bss_idx;
19261c099ab4SSean Wang 			u8 pad[3];
19271c099ab4SSean Wang 		} __packed hdr;
19281c099ab4SSean Wang 		struct mt7921_bss_basic_tlv basic;
19291c099ab4SSean Wang 	} basic_req = {
19301c099ab4SSean Wang 		.hdr = {
19311c099ab4SSean Wang 			.bss_idx = mvif->mt76.idx,
19321c099ab4SSean Wang 		},
19331c099ab4SSean Wang 		.basic = {
19341c099ab4SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_BASIC),
19351c099ab4SSean Wang 			.len = cpu_to_le16(sizeof(struct mt7921_bss_basic_tlv)),
19361c099ab4SSean Wang 			.omac_idx = omac_idx,
19371c099ab4SSean Wang 			.band_idx = mvif->mt76.band_idx,
19381c099ab4SSean Wang 			.wmm_idx = mvif->mt76.wmm_idx,
19391c099ab4SSean Wang 			.active = enable,
19401c099ab4SSean Wang 			.bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx),
19411c099ab4SSean Wang 			.sta_idx = cpu_to_le16(mvif->sta.wcid.idx),
19421c099ab4SSean Wang 			.conn_state = 1,
19431c099ab4SSean Wang 		},
19441c099ab4SSean Wang 	};
19451c099ab4SSean Wang 	int err, idx, cmd, len;
19461c099ab4SSean Wang 	void *data;
19471c099ab4SSean Wang 
19481c099ab4SSean Wang 	switch (vif->type) {
19491c099ab4SSean Wang 	case NL80211_IFTYPE_MESH_POINT:
19501c099ab4SSean Wang 	case NL80211_IFTYPE_AP:
19511c099ab4SSean Wang 		basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
19521c099ab4SSean Wang 		break;
19531c099ab4SSean Wang 	case NL80211_IFTYPE_STATION:
19541c099ab4SSean Wang 		basic_req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA);
19551c099ab4SSean Wang 		break;
19561c099ab4SSean Wang 	case NL80211_IFTYPE_ADHOC:
19571c099ab4SSean Wang 		basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
19581c099ab4SSean Wang 		break;
19591c099ab4SSean Wang 	default:
19601c099ab4SSean Wang 		WARN_ON(1);
19611c099ab4SSean Wang 		break;
19621c099ab4SSean Wang 	}
19631c099ab4SSean Wang 
19641c099ab4SSean Wang 	idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx;
19651c099ab4SSean Wang 	basic_req.basic.hw_bss_idx = idx;
19661c099ab4SSean Wang 
19671c099ab4SSean Wang 	memcpy(dev_req.tlv.omac_addr, vif->addr, ETH_ALEN);
19681c099ab4SSean Wang 
19691c099ab4SSean Wang 	cmd = enable ? MCU_UNI_CMD_DEV_INFO_UPDATE : MCU_UNI_CMD_BSS_INFO_UPDATE;
19701c099ab4SSean Wang 	data = enable ? (void *)&dev_req : (void *)&basic_req;
19711c099ab4SSean Wang 	len = enable ? sizeof(dev_req) : sizeof(basic_req);
19721c099ab4SSean Wang 
19731c099ab4SSean Wang 	err = mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true);
19741c099ab4SSean Wang 	if (err < 0)
19751c099ab4SSean Wang 		return err;
19761c099ab4SSean Wang 
19771c099ab4SSean Wang 	cmd = enable ? MCU_UNI_CMD_BSS_INFO_UPDATE : MCU_UNI_CMD_DEV_INFO_UPDATE;
19781c099ab4SSean Wang 	data = enable ? (void *)&basic_req : (void *)&dev_req;
19791c099ab4SSean Wang 	len = enable ? sizeof(basic_req) : sizeof(dev_req);
19801c099ab4SSean Wang 
19811c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true);
19821c099ab4SSean Wang }
19831c099ab4SSean Wang 
19841c099ab4SSean Wang int
19851c099ab4SSean Wang mt7921_mcu_uni_add_bss(struct mt7921_phy *phy, struct ieee80211_vif *vif,
19861c099ab4SSean Wang 		       bool enable)
19871c099ab4SSean Wang {
19881c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
19891c099ab4SSean Wang 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
19901c099ab4SSean Wang 	int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
19911c099ab4SSean Wang 	struct mt7921_dev *dev = phy->dev;
19921c099ab4SSean Wang 	enum nl80211_band band = chandef->chan->band;
19931c099ab4SSean Wang 	u8 omac_idx = mvif->mt76.omac_idx;
19941c099ab4SSean Wang 	struct {
19951c099ab4SSean Wang 		struct {
19961c099ab4SSean Wang 			u8 bss_idx;
19971c099ab4SSean Wang 			u8 pad[3];
19981c099ab4SSean Wang 		} __packed hdr;
19991c099ab4SSean Wang 		struct mt7921_bss_basic_tlv basic;
20001c099ab4SSean Wang 		struct mt7921_bss_qos_tlv qos;
20011c099ab4SSean Wang 	} basic_req = {
20021c099ab4SSean Wang 		.hdr = {
20031c099ab4SSean Wang 			.bss_idx = mvif->mt76.idx,
20041c099ab4SSean Wang 		},
20051c099ab4SSean Wang 		.basic = {
20061c099ab4SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_BASIC),
20071c099ab4SSean Wang 			.len = cpu_to_le16(sizeof(struct mt7921_bss_basic_tlv)),
20081c099ab4SSean Wang 			.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
20091c099ab4SSean Wang 			.dtim_period = vif->bss_conf.dtim_period,
20101c099ab4SSean Wang 			.omac_idx = omac_idx,
20111c099ab4SSean Wang 			.band_idx = mvif->mt76.band_idx,
20121c099ab4SSean Wang 			.wmm_idx = mvif->mt76.wmm_idx,
20131c099ab4SSean Wang 			.active = true, /* keep bss deactivated */
20141c099ab4SSean Wang 			.phymode = mt7921_get_phy_mode(phy->dev, vif, band, NULL),
20151c099ab4SSean Wang 		},
20161c099ab4SSean Wang 		.qos = {
20171c099ab4SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_QBSS),
20181c099ab4SSean Wang 			.len = cpu_to_le16(sizeof(struct mt7921_bss_qos_tlv)),
20191c099ab4SSean Wang 			.qos = vif->bss_conf.qos,
20201c099ab4SSean Wang 		},
20211c099ab4SSean Wang 	};
20221c099ab4SSean Wang 
20231c099ab4SSean Wang 	struct {
20241c099ab4SSean Wang 		struct {
20251c099ab4SSean Wang 			u8 bss_idx;
20261c099ab4SSean Wang 			u8 pad[3];
20271c099ab4SSean Wang 		} __packed hdr;
20281c099ab4SSean Wang 		struct bss_info_uni_he he;
20291c099ab4SSean Wang 	} he_req = {
20301c099ab4SSean Wang 		.hdr = {
20311c099ab4SSean Wang 			.bss_idx = mvif->mt76.idx,
20321c099ab4SSean Wang 		},
20331c099ab4SSean Wang 		.he = {
20341c099ab4SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_HE_BASIC),
20351c099ab4SSean Wang 			.len = cpu_to_le16(sizeof(struct bss_info_uni_he)),
20361c099ab4SSean Wang 		},
20371c099ab4SSean Wang 	};
20381c099ab4SSean Wang 
20391c099ab4SSean Wang 	struct {
20401c099ab4SSean Wang 		struct {
20411c099ab4SSean Wang 			u8 bss_idx;
20421c099ab4SSean Wang 			u8 pad[3];
20431c099ab4SSean Wang 		} __packed hdr;
20441c099ab4SSean Wang 		struct rlm_tlv {
20451c099ab4SSean Wang 			__le16 tag;
20461c099ab4SSean Wang 			__le16 len;
20471c099ab4SSean Wang 			u8 control_channel;
20481c099ab4SSean Wang 			u8 center_chan;
20491c099ab4SSean Wang 			u8 center_chan2;
20501c099ab4SSean Wang 			u8 bw;
20511c099ab4SSean Wang 			u8 tx_streams;
20521c099ab4SSean Wang 			u8 rx_streams;
20531c099ab4SSean Wang 			u8 short_st;
20541c099ab4SSean Wang 			u8 ht_op_info;
20551c099ab4SSean Wang 			u8 sco;
20561c099ab4SSean Wang 			u8 pad[3];
20571c099ab4SSean Wang 		} __packed rlm;
20581c099ab4SSean Wang 	} __packed rlm_req = {
20591c099ab4SSean Wang 		.hdr = {
20601c099ab4SSean Wang 			.bss_idx = mvif->mt76.idx,
20611c099ab4SSean Wang 		},
20621c099ab4SSean Wang 		.rlm = {
20631c099ab4SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_RLM),
20641c099ab4SSean Wang 			.len = cpu_to_le16(sizeof(struct rlm_tlv)),
20651c099ab4SSean Wang 			.control_channel = chandef->chan->hw_value,
20661c099ab4SSean Wang 			.center_chan = ieee80211_frequency_to_channel(freq1),
20671c099ab4SSean Wang 			.center_chan2 = ieee80211_frequency_to_channel(freq2),
20681c099ab4SSean Wang 			.tx_streams = hweight8(phy->mt76->antenna_mask),
20691c099ab4SSean Wang 			.rx_streams = phy->mt76->chainmask,
20701c099ab4SSean Wang 			.short_st = true,
20711c099ab4SSean Wang 		},
20721c099ab4SSean Wang 	};
20731c099ab4SSean Wang 	int err, conn_type;
20741c099ab4SSean Wang 	u8 idx;
20751c099ab4SSean Wang 
20761c099ab4SSean Wang 	idx = omac_idx > EXT_BSSID_START ? HW_BSSID_0 : omac_idx;
20771c099ab4SSean Wang 	basic_req.basic.hw_bss_idx = idx;
20781c099ab4SSean Wang 
20791c099ab4SSean Wang 	switch (vif->type) {
20801c099ab4SSean Wang 	case NL80211_IFTYPE_MESH_POINT:
20811c099ab4SSean Wang 	case NL80211_IFTYPE_AP:
20821c099ab4SSean Wang 		if (vif->p2p)
20831c099ab4SSean Wang 			conn_type = CONNECTION_P2P_GO;
20841c099ab4SSean Wang 		else
20851c099ab4SSean Wang 			conn_type = CONNECTION_INFRA_AP;
20861c099ab4SSean Wang 		basic_req.basic.conn_type = cpu_to_le32(conn_type);
20871c099ab4SSean Wang 		break;
20881c099ab4SSean Wang 	case NL80211_IFTYPE_STATION:
20891c099ab4SSean Wang 		if (vif->p2p)
20901c099ab4SSean Wang 			conn_type = CONNECTION_P2P_GC;
20911c099ab4SSean Wang 		else
20921c099ab4SSean Wang 			conn_type = CONNECTION_INFRA_STA;
20931c099ab4SSean Wang 		basic_req.basic.conn_type = cpu_to_le32(conn_type);
20941c099ab4SSean Wang 		break;
20951c099ab4SSean Wang 	case NL80211_IFTYPE_ADHOC:
20961c099ab4SSean Wang 		basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
20971c099ab4SSean Wang 		break;
20981c099ab4SSean Wang 	default:
20991c099ab4SSean Wang 		WARN_ON(1);
21001c099ab4SSean Wang 		break;
21011c099ab4SSean Wang 	}
21021c099ab4SSean Wang 
21031c099ab4SSean Wang 	memcpy(basic_req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN);
21041c099ab4SSean Wang 	basic_req.basic.bmc_tx_wlan_idx = cpu_to_le16(mvif->sta.wcid.idx);
21051c099ab4SSean Wang 	basic_req.basic.sta_idx = cpu_to_le16(mvif->sta.wcid.idx);
21061c099ab4SSean Wang 	basic_req.basic.conn_state = !enable;
21071c099ab4SSean Wang 
21081c099ab4SSean Wang 	err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
21091c099ab4SSean Wang 				&basic_req, sizeof(basic_req), true);
21101c099ab4SSean Wang 	if (err < 0)
21111c099ab4SSean Wang 		return err;
21121c099ab4SSean Wang 
21131c099ab4SSean Wang 	if (vif->bss_conf.he_support) {
21141c099ab4SSean Wang 		mt7921_mcu_uni_bss_he_tlv((struct tlv *)&he_req.he, vif, phy);
21151c099ab4SSean Wang 
21161c099ab4SSean Wang 		err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
21171c099ab4SSean Wang 					&he_req, sizeof(he_req), true);
21181c099ab4SSean Wang 		if (err < 0)
21191c099ab4SSean Wang 			return err;
21201c099ab4SSean Wang 	}
21211c099ab4SSean Wang 
21221c099ab4SSean Wang 	switch (chandef->width) {
21231c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_40:
21241c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_40MHZ;
21251c099ab4SSean Wang 		break;
21261c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_80:
21271c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_80MHZ;
21281c099ab4SSean Wang 		break;
21291c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_80P80:
21301c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_8080MHZ;
21311c099ab4SSean Wang 		break;
21321c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_160:
21331c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_160MHZ;
21341c099ab4SSean Wang 		break;
21351c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_5:
21361c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_5MHZ;
21371c099ab4SSean Wang 		break;
21381c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_10:
21391c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_10MHZ;
21401c099ab4SSean Wang 		break;
21411c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_20_NOHT:
21421c099ab4SSean Wang 	case NL80211_CHAN_WIDTH_20:
21431c099ab4SSean Wang 	default:
21441c099ab4SSean Wang 		rlm_req.rlm.bw = CMD_CBW_20MHZ;
21451c099ab4SSean Wang 		break;
21461c099ab4SSean Wang 	}
21471c099ab4SSean Wang 
21481c099ab4SSean Wang 	if (rlm_req.rlm.control_channel < rlm_req.rlm.center_chan)
21491c099ab4SSean Wang 		rlm_req.rlm.sco = 1; /* SCA */
21501c099ab4SSean Wang 	else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan)
21511c099ab4SSean Wang 		rlm_req.rlm.sco = 3; /* SCB */
21521c099ab4SSean Wang 
21531c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
21541c099ab4SSean Wang 				 &rlm_req, sizeof(rlm_req), true);
21551c099ab4SSean Wang }
21561c099ab4SSean Wang 
21571c099ab4SSean Wang static int
21581c099ab4SSean Wang mt7921_mcu_add_sta_cmd(struct mt7921_dev *dev, struct ieee80211_vif *vif,
21591c099ab4SSean Wang 		       struct ieee80211_sta *sta, bool enable, int cmd)
21601c099ab4SSean Wang {
21611c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
21621c099ab4SSean Wang 	struct wtbl_req_hdr *wtbl_hdr;
21631c099ab4SSean Wang 	struct mt7921_sta *msta;
21641c099ab4SSean Wang 	struct tlv *sta_wtbl;
21651c099ab4SSean Wang 	struct sk_buff *skb;
21661c099ab4SSean Wang 
21671c099ab4SSean Wang 	msta = sta ? (struct mt7921_sta *)sta->drv_priv : &mvif->sta;
21681c099ab4SSean Wang 
21691c099ab4SSean Wang 	skb = mt7921_mcu_alloc_sta_req(dev, mvif, msta,
21701c099ab4SSean Wang 				       MT7921_STA_UPDATE_MAX_SIZE);
21711c099ab4SSean Wang 	if (IS_ERR(skb))
21721c099ab4SSean Wang 		return PTR_ERR(skb);
21731c099ab4SSean Wang 
21741c099ab4SSean Wang 	mt7921_mcu_sta_basic_tlv(skb, vif, sta, enable);
21751c099ab4SSean Wang 	if (enable && sta)
21761c099ab4SSean Wang 		mt7921_mcu_sta_tlv(dev, skb, sta, vif);
21771c099ab4SSean Wang 
21781c099ab4SSean Wang 	sta_wtbl = mt7921_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
21791c099ab4SSean Wang 
21801c099ab4SSean Wang 	wtbl_hdr = mt7921_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET,
21811c099ab4SSean Wang 					     sta_wtbl, &skb);
21821c099ab4SSean Wang 	if (enable) {
21831c099ab4SSean Wang 		mt7921_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr);
21841c099ab4SSean Wang 		if (sta)
21851c099ab4SSean Wang 			mt7921_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr);
21861c099ab4SSean Wang 	}
21871c099ab4SSean Wang 
21881c099ab4SSean Wang 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
21891c099ab4SSean Wang }
21901c099ab4SSean Wang 
21911c099ab4SSean Wang int
21921c099ab4SSean Wang mt7921_mcu_uni_add_sta(struct mt7921_dev *dev, struct ieee80211_vif *vif,
21931c099ab4SSean Wang 		       struct ieee80211_sta *sta, bool enable)
21941c099ab4SSean Wang {
21951c099ab4SSean Wang 	return mt7921_mcu_add_sta_cmd(dev, vif, sta, enable,
21961c099ab4SSean Wang 				      MCU_UNI_CMD_STA_REC_UPDATE);
21971c099ab4SSean Wang }
21981c099ab4SSean Wang 
21991c099ab4SSean Wang int mt7921_mcu_set_channel_domain(struct mt7921_phy *phy)
22001c099ab4SSean Wang {
22011c099ab4SSean Wang 	struct mt76_phy *mphy = phy->mt76;
22021c099ab4SSean Wang 	struct mt7921_dev *dev = phy->dev;
22031c099ab4SSean Wang 	struct mt7921_mcu_channel_domain {
22041c099ab4SSean Wang 		__le32 country_code; /* regulatory_request.alpha2 */
22051c099ab4SSean Wang 		u8 bw_2g; /* BW_20_40M		0
22061c099ab4SSean Wang 			   * BW_20M		1
22071c099ab4SSean Wang 			   * BW_20_40_80M	2
22081c099ab4SSean Wang 			   * BW_20_40_80_160M	3
22091c099ab4SSean Wang 			   * BW_20_40_80_8080M	4
22101c099ab4SSean Wang 			   */
22111c099ab4SSean Wang 		u8 bw_5g;
22121c099ab4SSean Wang 		__le16 pad;
22131c099ab4SSean Wang 		u8 n_2ch;
22141c099ab4SSean Wang 		u8 n_5ch;
22151c099ab4SSean Wang 		__le16 pad2;
22161c099ab4SSean Wang 	} __packed hdr = {
22171c099ab4SSean Wang 		.bw_2g = 0,
22181c099ab4SSean Wang 		.bw_5g = 3,
22191c099ab4SSean Wang 		.n_2ch = mphy->sband_2g.sband.n_channels,
22201c099ab4SSean Wang 		.n_5ch = mphy->sband_5g.sband.n_channels,
22211c099ab4SSean Wang 	};
22221c099ab4SSean Wang 	struct mt7921_mcu_chan {
22231c099ab4SSean Wang 		__le16 hw_value;
22241c099ab4SSean Wang 		__le16 pad;
22251c099ab4SSean Wang 		__le32 flags;
22261c099ab4SSean Wang 	} __packed;
22271c099ab4SSean Wang 	int i, n_channels = hdr.n_2ch + hdr.n_5ch;
22281c099ab4SSean Wang 	int len = sizeof(hdr) + n_channels * sizeof(struct mt7921_mcu_chan);
22291c099ab4SSean Wang 	struct sk_buff *skb;
22301c099ab4SSean Wang 
22311c099ab4SSean Wang 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
22321c099ab4SSean Wang 	if (!skb)
22331c099ab4SSean Wang 		return -ENOMEM;
22341c099ab4SSean Wang 
22351c099ab4SSean Wang 	skb_put_data(skb, &hdr, sizeof(hdr));
22361c099ab4SSean Wang 
22371c099ab4SSean Wang 	for (i = 0; i < n_channels; i++) {
22381c099ab4SSean Wang 		struct ieee80211_channel *chan;
22391c099ab4SSean Wang 		struct mt7921_mcu_chan channel;
22401c099ab4SSean Wang 
22411c099ab4SSean Wang 		if (i < hdr.n_2ch)
22421c099ab4SSean Wang 			chan = &mphy->sband_2g.sband.channels[i];
22431c099ab4SSean Wang 		else
22441c099ab4SSean Wang 			chan = &mphy->sband_5g.sband.channels[i - hdr.n_2ch];
22451c099ab4SSean Wang 
22461c099ab4SSean Wang 		channel.hw_value = cpu_to_le16(chan->hw_value);
22471c099ab4SSean Wang 		channel.flags = cpu_to_le32(chan->flags);
22481c099ab4SSean Wang 		channel.pad = 0;
22491c099ab4SSean Wang 
22501c099ab4SSean Wang 		skb_put_data(skb, &channel, sizeof(channel));
22511c099ab4SSean Wang 	}
22521c099ab4SSean Wang 
22531c099ab4SSean Wang 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SET_CHAN_DOMAIN,
22541c099ab4SSean Wang 				     false);
22551c099ab4SSean Wang }
22561c099ab4SSean Wang 
22571c099ab4SSean Wang #define MT7921_SCAN_CHANNEL_TIME	60
22581c099ab4SSean Wang int mt7921_mcu_hw_scan(struct mt7921_phy *phy, struct ieee80211_vif *vif,
22591c099ab4SSean Wang 		       struct ieee80211_scan_request *scan_req)
22601c099ab4SSean Wang {
22611c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
22621c099ab4SSean Wang 	struct cfg80211_scan_request *sreq = &scan_req->req;
22631c099ab4SSean Wang 	int n_ssids = 0, err, i, duration = MT7921_SCAN_CHANNEL_TIME;
22641c099ab4SSean Wang 	int ext_channels_num = max_t(int, sreq->n_channels - 32, 0);
22651c099ab4SSean Wang 	struct ieee80211_channel **scan_list = sreq->channels;
22661c099ab4SSean Wang 	struct mt7921_dev *dev = phy->dev;
22671c099ab4SSean Wang 	struct mt7921_mcu_scan_channel *chan;
22681c099ab4SSean Wang 	struct mt7921_hw_scan_req *req;
22691c099ab4SSean Wang 	struct sk_buff *skb;
22701c099ab4SSean Wang 
22711c099ab4SSean Wang 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(*req));
22721c099ab4SSean Wang 	if (!skb)
22731c099ab4SSean Wang 		return -ENOMEM;
22741c099ab4SSean Wang 
22751c099ab4SSean Wang 	set_bit(MT76_HW_SCANNING, &phy->mt76->state);
22761c099ab4SSean Wang 	mvif->mt76.scan_seq_num = (mvif->mt76.scan_seq_num + 1) & 0x7f;
22771c099ab4SSean Wang 
22781c099ab4SSean Wang 	req = (struct mt7921_hw_scan_req *)skb_put(skb, sizeof(*req));
22791c099ab4SSean Wang 
22801c099ab4SSean Wang 	req->seq_num = mvif->mt76.scan_seq_num;
22811c099ab4SSean Wang 	req->bss_idx = mvif->mt76.idx;
22821c099ab4SSean Wang 	req->scan_type = sreq->n_ssids ? 1 : 0;
22831c099ab4SSean Wang 	req->probe_req_num = sreq->n_ssids ? 2 : 0;
22841c099ab4SSean Wang 	req->version = 1;
22851c099ab4SSean Wang 
22861c099ab4SSean Wang 	for (i = 0; i < sreq->n_ssids; i++) {
22871c099ab4SSean Wang 		if (!sreq->ssids[i].ssid_len)
22881c099ab4SSean Wang 			continue;
22891c099ab4SSean Wang 
22901c099ab4SSean Wang 		req->ssids[i].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len);
22911c099ab4SSean Wang 		memcpy(req->ssids[i].ssid, sreq->ssids[i].ssid,
22921c099ab4SSean Wang 		       sreq->ssids[i].ssid_len);
22931c099ab4SSean Wang 		n_ssids++;
22941c099ab4SSean Wang 	}
22951c099ab4SSean Wang 	req->ssid_type = n_ssids ? BIT(2) : BIT(0);
22961c099ab4SSean Wang 	req->ssid_type_ext = n_ssids ? BIT(0) : 0;
22971c099ab4SSean Wang 	req->ssids_num = n_ssids;
22981c099ab4SSean Wang 
22991c099ab4SSean Wang 	/* increase channel time for passive scan */
23001c099ab4SSean Wang 	if (!sreq->n_ssids)
23011c099ab4SSean Wang 		duration *= 2;
23021c099ab4SSean Wang 	req->timeout_value = cpu_to_le16(sreq->n_channels * duration);
23031c099ab4SSean Wang 	req->channel_min_dwell_time = cpu_to_le16(duration);
23041c099ab4SSean Wang 	req->channel_dwell_time = cpu_to_le16(duration);
23051c099ab4SSean Wang 
23061c099ab4SSean Wang 	req->channels_num = min_t(u8, sreq->n_channels, 32);
23071c099ab4SSean Wang 	req->ext_channels_num = min_t(u8, ext_channels_num, 32);
23081c099ab4SSean Wang 	for (i = 0; i < req->channels_num + req->ext_channels_num; i++) {
23091c099ab4SSean Wang 		if (i >= 32)
23101c099ab4SSean Wang 			chan = &req->ext_channels[i - 32];
23111c099ab4SSean Wang 		else
23121c099ab4SSean Wang 			chan = &req->channels[i];
23131c099ab4SSean Wang 
23141c099ab4SSean Wang 		chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2;
23151c099ab4SSean Wang 		chan->channel_num = scan_list[i]->hw_value;
23161c099ab4SSean Wang 	}
23171c099ab4SSean Wang 	req->channel_type = sreq->n_channels ? 4 : 0;
23181c099ab4SSean Wang 
23191c099ab4SSean Wang 	if (sreq->ie_len > 0) {
23201c099ab4SSean Wang 		memcpy(req->ies, sreq->ie, sreq->ie_len);
23211c099ab4SSean Wang 		req->ies_len = cpu_to_le16(sreq->ie_len);
23221c099ab4SSean Wang 	}
23231c099ab4SSean Wang 
23241c099ab4SSean Wang 	memcpy(req->bssid, sreq->bssid, ETH_ALEN);
23251c099ab4SSean Wang 	if (sreq->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
23261c099ab4SSean Wang 		get_random_mask_addr(req->random_mac, sreq->mac_addr,
23271c099ab4SSean Wang 				     sreq->mac_addr_mask);
23281c099ab4SSean Wang 		req->scan_func = 1;
23291c099ab4SSean Wang 	}
23301c099ab4SSean Wang 
23311c099ab4SSean Wang 	err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN,
23321c099ab4SSean Wang 				    false);
23331c099ab4SSean Wang 	if (err < 0)
23341c099ab4SSean Wang 		clear_bit(MT76_HW_SCANNING, &phy->mt76->state);
23351c099ab4SSean Wang 
23361c099ab4SSean Wang 	return err;
23371c099ab4SSean Wang }
23381c099ab4SSean Wang 
23391c099ab4SSean Wang int mt7921_mcu_cancel_hw_scan(struct mt7921_phy *phy,
23401c099ab4SSean Wang 			      struct ieee80211_vif *vif)
23411c099ab4SSean Wang {
23421c099ab4SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
23431c099ab4SSean Wang 	struct mt7921_dev *dev = phy->dev;
23441c099ab4SSean Wang 	struct {
23451c099ab4SSean Wang 		u8 seq_num;
23461c099ab4SSean Wang 		u8 is_ext_channel;
23471c099ab4SSean Wang 		u8 rsv[2];
23481c099ab4SSean Wang 	} __packed req = {
23491c099ab4SSean Wang 		.seq_num = mvif->mt76.scan_seq_num,
23501c099ab4SSean Wang 	};
23511c099ab4SSean Wang 
23521c099ab4SSean Wang 	if (test_and_clear_bit(MT76_HW_SCANNING, &phy->mt76->state)) {
23531c099ab4SSean Wang 		struct cfg80211_scan_info info = {
23541c099ab4SSean Wang 			.aborted = true,
23551c099ab4SSean Wang 		};
23561c099ab4SSean Wang 
23571c099ab4SSean Wang 		ieee80211_scan_completed(phy->mt76->hw, &info);
23581c099ab4SSean Wang 	}
23591c099ab4SSean Wang 
23601c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76,  MCU_CMD_CANCEL_HW_SCAN, &req,
23611c099ab4SSean Wang 				 sizeof(req), false);
23621c099ab4SSean Wang }
23631c099ab4SSean Wang 
236429f9d8b0SSean Wang int mt7921_mcu_sched_scan_req(struct mt7921_phy *phy,
236529f9d8b0SSean Wang 			      struct ieee80211_vif *vif,
236629f9d8b0SSean Wang 			      struct cfg80211_sched_scan_request *sreq)
236729f9d8b0SSean Wang {
236829f9d8b0SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
236929f9d8b0SSean Wang 	struct ieee80211_channel **scan_list = sreq->channels;
237029f9d8b0SSean Wang 	struct mt7921_dev *dev = phy->dev;
237129f9d8b0SSean Wang 	struct mt7921_mcu_scan_channel *chan;
237229f9d8b0SSean Wang 	struct mt7921_sched_scan_req *req;
237329f9d8b0SSean Wang 	struct cfg80211_match_set *match;
237429f9d8b0SSean Wang 	struct cfg80211_ssid *ssid;
237529f9d8b0SSean Wang 	struct sk_buff *skb;
237629f9d8b0SSean Wang 	int i;
237729f9d8b0SSean Wang 
237829f9d8b0SSean Wang 	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
237929f9d8b0SSean Wang 				 sizeof(*req) + sreq->ie_len);
238029f9d8b0SSean Wang 	if (!skb)
238129f9d8b0SSean Wang 		return -ENOMEM;
238229f9d8b0SSean Wang 
238329f9d8b0SSean Wang 	mvif->mt76.scan_seq_num = (mvif->mt76.scan_seq_num + 1) & 0x7f;
238429f9d8b0SSean Wang 
238529f9d8b0SSean Wang 	req = (struct mt7921_sched_scan_req *)skb_put(skb, sizeof(*req));
238629f9d8b0SSean Wang 	req->version = 1;
238729f9d8b0SSean Wang 	req->seq_num = mvif->mt76.scan_seq_num;
238829f9d8b0SSean Wang 
238929f9d8b0SSean Wang 	req->ssids_num = sreq->n_ssids;
239029f9d8b0SSean Wang 	for (i = 0; i < req->ssids_num; i++) {
239129f9d8b0SSean Wang 		ssid = &sreq->ssids[i];
239229f9d8b0SSean Wang 		memcpy(req->ssids[i].ssid, ssid->ssid, ssid->ssid_len);
239329f9d8b0SSean Wang 		req->ssids[i].ssid_len = cpu_to_le32(ssid->ssid_len);
239429f9d8b0SSean Wang 	}
239529f9d8b0SSean Wang 
239629f9d8b0SSean Wang 	req->match_num = sreq->n_match_sets;
239729f9d8b0SSean Wang 	for (i = 0; i < req->match_num; i++) {
239829f9d8b0SSean Wang 		match = &sreq->match_sets[i];
239929f9d8b0SSean Wang 		memcpy(req->match[i].ssid, match->ssid.ssid,
240029f9d8b0SSean Wang 		       match->ssid.ssid_len);
240129f9d8b0SSean Wang 		req->match[i].rssi_th = cpu_to_le32(match->rssi_thold);
240229f9d8b0SSean Wang 		req->match[i].ssid_len = match->ssid.ssid_len;
240329f9d8b0SSean Wang 	}
240429f9d8b0SSean Wang 
240529f9d8b0SSean Wang 	req->channel_type = sreq->n_channels ? 4 : 0;
240629f9d8b0SSean Wang 	req->channels_num = min_t(u8, sreq->n_channels, 64);
240729f9d8b0SSean Wang 	for (i = 0; i < req->channels_num; i++) {
240829f9d8b0SSean Wang 		chan = &req->channels[i];
240929f9d8b0SSean Wang 		chan->band = scan_list[i]->band == NL80211_BAND_2GHZ ? 1 : 2;
241029f9d8b0SSean Wang 		chan->channel_num = scan_list[i]->hw_value;
241129f9d8b0SSean Wang 	}
241229f9d8b0SSean Wang 
241329f9d8b0SSean Wang 	req->intervals_num = sreq->n_scan_plans;
241429f9d8b0SSean Wang 	for (i = 0; i < req->intervals_num; i++)
241529f9d8b0SSean Wang 		req->intervals[i] = cpu_to_le16(sreq->scan_plans[i].interval);
241629f9d8b0SSean Wang 
241729f9d8b0SSean Wang 	if (sreq->ie_len > 0) {
241829f9d8b0SSean Wang 		req->ie_len = cpu_to_le16(sreq->ie_len);
241929f9d8b0SSean Wang 		memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len);
242029f9d8b0SSean Wang 	}
242129f9d8b0SSean Wang 
242229f9d8b0SSean Wang 	return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SCHED_SCAN_REQ,
242329f9d8b0SSean Wang 				     false);
242429f9d8b0SSean Wang }
242529f9d8b0SSean Wang 
242629f9d8b0SSean Wang int mt7921_mcu_sched_scan_enable(struct mt7921_phy *phy,
242729f9d8b0SSean Wang 				 struct ieee80211_vif *vif,
242829f9d8b0SSean Wang 				 bool enable)
242929f9d8b0SSean Wang {
243029f9d8b0SSean Wang 	struct mt7921_dev *dev = phy->dev;
243129f9d8b0SSean Wang 	struct {
243229f9d8b0SSean Wang 		u8 active; /* 0: enabled 1: disabled */
243329f9d8b0SSean Wang 		u8 rsv[3];
243429f9d8b0SSean Wang 	} __packed req = {
243529f9d8b0SSean Wang 		.active = !enable,
243629f9d8b0SSean Wang 	};
243729f9d8b0SSean Wang 
243829f9d8b0SSean Wang 	if (enable)
243929f9d8b0SSean Wang 		set_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state);
244029f9d8b0SSean Wang 	else
244129f9d8b0SSean Wang 		clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state);
244229f9d8b0SSean Wang 
244329f9d8b0SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, &req,
244429f9d8b0SSean Wang 				 sizeof(req), false);
244529f9d8b0SSean Wang }
244629f9d8b0SSean Wang 
24471c099ab4SSean Wang u32 mt7921_get_wtbl_info(struct mt7921_dev *dev, u16 wlan_idx)
24481c099ab4SSean Wang {
24491c099ab4SSean Wang 	struct mt7921_mcu_wlan_info wtbl_info = {
24501c099ab4SSean Wang 		.wlan_idx = cpu_to_le32(wlan_idx),
24511c099ab4SSean Wang 	};
24521c099ab4SSean Wang 	struct sk_buff *skb;
24531c099ab4SSean Wang 	int ret;
24541c099ab4SSean Wang 
24551c099ab4SSean Wang 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_WTBL,
24561c099ab4SSean Wang 					&wtbl_info, sizeof(wtbl_info), true,
24571c099ab4SSean Wang 					&skb);
24581c099ab4SSean Wang 	if (ret)
24591c099ab4SSean Wang 		return ret;
24601c099ab4SSean Wang 
24611c099ab4SSean Wang 	mt7921_mcu_tx_rate_report(dev, skb, wlan_idx);
24621c099ab4SSean Wang 	dev_kfree_skb(skb);
24631c099ab4SSean Wang 
24641c099ab4SSean Wang 	return 0;
24651c099ab4SSean Wang }
246656d965daSSean Wang 
246756d965daSSean Wang int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif)
246856d965daSSean Wang {
246956d965daSSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
247056d965daSSean Wang 	struct {
247156d965daSSean Wang 		struct {
247256d965daSSean Wang 			u8 bss_idx;
247356d965daSSean Wang 			u8 pad[3];
247456d965daSSean Wang 		} __packed hdr;
247556d965daSSean Wang 		struct ps_tlv {
247656d965daSSean Wang 			__le16 tag;
247756d965daSSean Wang 			__le16 len;
247856d965daSSean Wang 			u8 ps_state; /* 0: device awake
247956d965daSSean Wang 				      * 1: static power save
248056d965daSSean Wang 				      * 2: dynamic power saving
248156d965daSSean Wang 				      * 3: enter TWT power saving
248256d965daSSean Wang 				      * 4: leave TWT power saving
248356d965daSSean Wang 				      */
248456d965daSSean Wang 			u8 pad[3];
248556d965daSSean Wang 		} __packed ps;
248656d965daSSean Wang 	} __packed ps_req = {
248756d965daSSean Wang 		.hdr = {
248856d965daSSean Wang 			.bss_idx = mvif->mt76.idx,
248956d965daSSean Wang 		},
249056d965daSSean Wang 		.ps = {
249156d965daSSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_PS),
249256d965daSSean Wang 			.len = cpu_to_le16(sizeof(struct ps_tlv)),
249356d965daSSean Wang 			.ps_state = vif->bss_conf.ps ? 2 : 0,
249456d965daSSean Wang 		},
249556d965daSSean Wang 	};
249656d965daSSean Wang 
249756d965daSSean Wang 	if (vif->type != NL80211_IFTYPE_STATION)
249856d965daSSean Wang 		return -EOPNOTSUPP;
249956d965daSSean Wang 
250056d965daSSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
250156d965daSSean Wang 				 &ps_req, sizeof(ps_req), true);
250256d965daSSean Wang }
2503*4086ee28SSean Wang 
2504*4086ee28SSean Wang int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
2505*4086ee28SSean Wang 			     bool enable)
2506*4086ee28SSean Wang {
2507*4086ee28SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
2508*4086ee28SSean Wang 	struct {
2509*4086ee28SSean Wang 		struct {
2510*4086ee28SSean Wang 			u8 bss_idx;
2511*4086ee28SSean Wang 			u8 pad[3];
2512*4086ee28SSean Wang 		} __packed hdr;
2513*4086ee28SSean Wang 		struct bcnft_tlv {
2514*4086ee28SSean Wang 			__le16 tag;
2515*4086ee28SSean Wang 			__le16 len;
2516*4086ee28SSean Wang 			__le16 bcn_interval;
2517*4086ee28SSean Wang 			u8 dtim_period;
2518*4086ee28SSean Wang 			u8 pad;
2519*4086ee28SSean Wang 		} __packed bcnft;
2520*4086ee28SSean Wang 	} __packed bcnft_req = {
2521*4086ee28SSean Wang 		.hdr = {
2522*4086ee28SSean Wang 			.bss_idx = mvif->mt76.idx,
2523*4086ee28SSean Wang 		},
2524*4086ee28SSean Wang 		.bcnft = {
2525*4086ee28SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_BCNFT),
2526*4086ee28SSean Wang 			.len = cpu_to_le16(sizeof(struct bcnft_tlv)),
2527*4086ee28SSean Wang 			.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
2528*4086ee28SSean Wang 			.dtim_period = vif->bss_conf.dtim_period,
2529*4086ee28SSean Wang 		},
2530*4086ee28SSean Wang 	};
2531*4086ee28SSean Wang 
2532*4086ee28SSean Wang 	if (vif->type != NL80211_IFTYPE_STATION)
2533*4086ee28SSean Wang 		return 0;
2534*4086ee28SSean Wang 
2535*4086ee28SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
2536*4086ee28SSean Wang 				 &bcnft_req, sizeof(bcnft_req), true);
2537*4086ee28SSean Wang }
2538*4086ee28SSean Wang 
2539*4086ee28SSean Wang int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
2540*4086ee28SSean Wang 			  bool enable)
2541*4086ee28SSean Wang {
2542*4086ee28SSean Wang 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
2543*4086ee28SSean Wang 	struct {
2544*4086ee28SSean Wang 		u8 bss_idx;
2545*4086ee28SSean Wang 		u8 dtim_period;
2546*4086ee28SSean Wang 		__le16 aid;
2547*4086ee28SSean Wang 		__le16 bcn_interval;
2548*4086ee28SSean Wang 		__le16 atim_window;
2549*4086ee28SSean Wang 		u8 uapsd;
2550*4086ee28SSean Wang 		u8 bmc_delivered_ac;
2551*4086ee28SSean Wang 		u8 bmc_triggered_ac;
2552*4086ee28SSean Wang 		u8 pad;
2553*4086ee28SSean Wang 	} req = {
2554*4086ee28SSean Wang 		.bss_idx = mvif->mt76.idx,
2555*4086ee28SSean Wang 		.aid = cpu_to_le16(vif->bss_conf.aid),
2556*4086ee28SSean Wang 		.dtim_period = vif->bss_conf.dtim_period,
2557*4086ee28SSean Wang 		.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
2558*4086ee28SSean Wang 	};
2559*4086ee28SSean Wang 	struct {
2560*4086ee28SSean Wang 		u8 bss_idx;
2561*4086ee28SSean Wang 		u8 pad[3];
2562*4086ee28SSean Wang 	} req_hdr = {
2563*4086ee28SSean Wang 		.bss_idx = mvif->mt76.idx,
2564*4086ee28SSean Wang 	};
2565*4086ee28SSean Wang 	int err;
2566*4086ee28SSean Wang 
2567*4086ee28SSean Wang 	if (vif->type != NL80211_IFTYPE_STATION)
2568*4086ee28SSean Wang 		return 0;
2569*4086ee28SSean Wang 
2570*4086ee28SSean Wang 	err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr,
2571*4086ee28SSean Wang 				sizeof(req_hdr), false);
2572*4086ee28SSean Wang 	if (err < 0 || !enable)
2573*4086ee28SSean Wang 		return err;
2574*4086ee28SSean Wang 
2575*4086ee28SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req,
2576*4086ee28SSean Wang 				 sizeof(req), false);
2577*4086ee28SSean Wang }
2578