11c099ab4SSean Wang // SPDX-License-Identifier: ISC
21c099ab4SSean Wang /* Copyright (C) 2020 MediaTek Inc. */
31c099ab4SSean Wang 
41c099ab4SSean Wang #include <linux/fs.h>
523bdc5d8SMing Yen Hsieh #include <linux/firmware.h>
61c099ab4SSean Wang #include "mt7921.h"
71c099ab4SSean Wang #include "mcu.h"
8140efef3SLorenzo Bianconi #include "../mt76_connac2_mac.h"
9c74df1c0SLorenzo Bianconi #include "../mt792x_trace.h"
101c099ab4SSean Wang 
111c099ab4SSean Wang #define MT_STA_BFER			BIT(0)
121c099ab4SSean Wang #define MT_STA_BFEE			BIT(1)
131c099ab4SSean Wang 
1423bdc5d8SMing Yen Hsieh static bool mt7921_disable_clc;
1523bdc5d8SMing Yen Hsieh module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
1623bdc5d8SMing Yen Hsieh MODULE_PARM_DESC(disable_clc, "disable CLC support");
1723bdc5d8SMing Yen Hsieh 
mt7921_mcu_parse_response(struct mt76_dev * mdev,int cmd,struct sk_buff * skb,int seq)18dfc7743dSSean Wang int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
191c099ab4SSean Wang 			      struct sk_buff *skb, int seq)
201c099ab4SSean Wang {
21680a2eadSLorenzo Bianconi 	int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd);
22fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
231c099ab4SSean Wang 	int ret = 0;
241c099ab4SSean Wang 
251c099ab4SSean Wang 	if (!skb) {
2653d35b1aSLorenzo Bianconi 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
271c099ab4SSean Wang 			cmd, seq);
28311f121cSLorenzo Bianconi 		mt792x_reset(mdev);
29d43b3257SLorenzo Bianconi 
301c099ab4SSean Wang 		return -ETIMEDOUT;
311c099ab4SSean Wang 	}
321c099ab4SSean Wang 
33fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
341c099ab4SSean Wang 	if (seq != rxd->seq)
351c099ab4SSean Wang 		return -EAGAIN;
361c099ab4SSean Wang 
3745b6f9cbSYN Chen 	if (cmd == MCU_CMD(PATCH_SEM_CONTROL) ||
3845b6f9cbSYN Chen 	    cmd == MCU_CMD(PATCH_FINISH_REQ)) {
391c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd) - 4);
401c099ab4SSean Wang 		ret = *skb->data;
419d8d136cSLorenzo Bianconi 	} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
421c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd) + 4);
431c099ab4SSean Wang 		ret = le32_to_cpu(*(__le32 *)skb->data);
4454722402SLorenzo Bianconi 	} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
4554722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) ||
4654722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(STA_REC_UPDATE) ||
4754722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(HIF_CTRL) ||
4854722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(OFFLOAD) ||
4954722402SLorenzo Bianconi 		   cmd == MCU_UNI_CMD(SUSPEND)) {
5061d1f545SLorenzo Bianconi 		struct mt76_connac_mcu_uni_event *event;
511c099ab4SSean Wang 
521c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd));
5361d1f545SLorenzo Bianconi 		event = (struct mt76_connac_mcu_uni_event *)skb->data;
541c099ab4SSean Wang 		ret = le32_to_cpu(event->status);
55cd3f3873SDeren Wu 		/* skip invalid event */
56cd3f3873SDeren Wu 		if (mcu_cmd != event->cid)
57cd3f3873SDeren Wu 			ret = -EAGAIN;
58680a2eadSLorenzo Bianconi 	} else if (cmd == MCU_CE_QUERY(REG_READ)) {
5961d1f545SLorenzo Bianconi 		struct mt76_connac_mcu_reg_event *event;
601c099ab4SSean Wang 
611c099ab4SSean Wang 		skb_pull(skb, sizeof(*rxd));
6261d1f545SLorenzo Bianconi 		event = (struct mt76_connac_mcu_reg_event *)skb->data;
631c099ab4SSean Wang 		ret = (int)le32_to_cpu(event->val);
64e6d2070dSLorenzo Bianconi 	} else {
65fc6ee71aSLorenzo Bianconi 		skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
661c099ab4SSean Wang 	}
671c099ab4SSean Wang 
681c099ab4SSean Wang 	return ret;
691c099ab4SSean Wang }
708910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_parse_response);
711c099ab4SSean Wang 
mt7921_mcu_read_eeprom(struct mt792x_dev * dev,u32 offset,u8 * val)72975e122dSLorenzo Bianconi static int mt7921_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)
7323bdc5d8SMing Yen Hsieh {
7423bdc5d8SMing Yen Hsieh 	struct mt7921_mcu_eeprom_info *res, req = {
7523bdc5d8SMing Yen Hsieh 		.addr = cpu_to_le32(round_down(offset,
7623bdc5d8SMing Yen Hsieh 				    MT7921_EEPROM_BLOCK_SIZE)),
7723bdc5d8SMing Yen Hsieh 	};
7823bdc5d8SMing Yen Hsieh 	struct sk_buff *skb;
7923bdc5d8SMing Yen Hsieh 	int ret;
8023bdc5d8SMing Yen Hsieh 
8123bdc5d8SMing Yen Hsieh 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(EFUSE_ACCESS),
8223bdc5d8SMing Yen Hsieh 					&req, sizeof(req), true, &skb);
8323bdc5d8SMing Yen Hsieh 	if (ret)
8423bdc5d8SMing Yen Hsieh 		return ret;
8523bdc5d8SMing Yen Hsieh 
8623bdc5d8SMing Yen Hsieh 	res = (struct mt7921_mcu_eeprom_info *)skb->data;
8723bdc5d8SMing Yen Hsieh 	*val = res->data[offset % MT7921_EEPROM_BLOCK_SIZE];
8823bdc5d8SMing Yen Hsieh 	dev_kfree_skb(skb);
8923bdc5d8SMing Yen Hsieh 
9023bdc5d8SMing Yen Hsieh 	return 0;
9123bdc5d8SMing Yen Hsieh }
9223bdc5d8SMing Yen Hsieh 
935fc201aaSDeren Wu #ifdef CONFIG_PM
945fc201aaSDeren Wu 
955fc201aaSDeren Wu static int
mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev * dev,struct ieee80211_vif * vif,bool suspend)965fc201aaSDeren Wu mt7921_mcu_set_ipv6_ns_filter(struct mt76_dev *dev,
975fc201aaSDeren Wu 			      struct ieee80211_vif *vif, bool suspend)
985fc201aaSDeren Wu {
9915ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
1005fc201aaSDeren Wu 	struct {
1015fc201aaSDeren Wu 		struct {
1025fc201aaSDeren Wu 			u8 bss_idx;
1035fc201aaSDeren Wu 			u8 pad[3];
1045fc201aaSDeren Wu 		} __packed hdr;
1055fc201aaSDeren Wu 		struct mt76_connac_arpns_tlv arpns;
1065fc201aaSDeren Wu 	} req = {
1075fc201aaSDeren Wu 		.hdr = {
1085fc201aaSDeren Wu 			.bss_idx = mvif->mt76.idx,
1095fc201aaSDeren Wu 		},
1105fc201aaSDeren Wu 		.arpns = {
1115fc201aaSDeren Wu 			.tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ND),
1125fc201aaSDeren Wu 			.len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),
1135fc201aaSDeren Wu 			.mode = suspend,
1145fc201aaSDeren Wu 		},
1155fc201aaSDeren Wu 	};
1165fc201aaSDeren Wu 
1175fc201aaSDeren Wu 	return mt76_mcu_send_msg(dev, MCU_UNI_CMD_OFFLOAD, &req, sizeof(req),
1185fc201aaSDeren Wu 				 true);
1195fc201aaSDeren Wu }
1205fc201aaSDeren Wu 
mt7921_mcu_set_suspend_iter(void * priv,u8 * mac,struct ieee80211_vif * vif)1215fc201aaSDeren Wu void mt7921_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
1225fc201aaSDeren Wu {
1235fc201aaSDeren Wu 	if (IS_ENABLED(CONFIG_IPV6)) {
1245fc201aaSDeren Wu 		struct mt76_phy *phy = priv;
1255fc201aaSDeren Wu 
1265fc201aaSDeren Wu 		mt7921_mcu_set_ipv6_ns_filter(phy->dev, vif,
1275fc201aaSDeren Wu 					      !test_bit(MT76_STATE_RUNNING,
1285fc201aaSDeren Wu 					      &phy->state));
1295fc201aaSDeren Wu 	}
1305fc201aaSDeren Wu 
1315fc201aaSDeren Wu 	mt76_connac_mcu_set_suspend_iter(priv, mac, vif);
1325fc201aaSDeren Wu }
1335fc201aaSDeren Wu 
1345fc201aaSDeren Wu #endif /* CONFIG_PM */
1355fc201aaSDeren Wu 
1361c099ab4SSean Wang static void
mt7921_mcu_uni_roc_event(struct mt792x_dev * dev,struct sk_buff * skb)137975e122dSLorenzo Bianconi mt7921_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb)
138034ae28bSSean Wang {
139034ae28bSSean Wang 	struct mt7921_roc_grant_tlv *grant;
140034ae28bSSean Wang 	struct mt76_connac2_mcu_rxd *rxd;
141034ae28bSSean Wang 	int duration;
142034ae28bSSean Wang 
143034ae28bSSean Wang 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
144034ae28bSSean Wang 	grant = (struct mt7921_roc_grant_tlv *)(rxd->tlv + 4);
145034ae28bSSean Wang 
146034ae28bSSean Wang 	/* should never happen */
147034ae28bSSean Wang 	WARN_ON_ONCE((le16_to_cpu(grant->tag) != UNI_EVENT_ROC_GRANT));
148034ae28bSSean Wang 
149034ae28bSSean Wang 	if (grant->reqtype == MT7921_ROC_REQ_ROC)
150034ae28bSSean Wang 		ieee80211_ready_on_channel(dev->mt76.phy.hw);
151034ae28bSSean Wang 
152034ae28bSSean Wang 	dev->phy.roc_grant = true;
153034ae28bSSean Wang 	wake_up(&dev->phy.roc_wait);
154034ae28bSSean Wang 	duration = le32_to_cpu(grant->max_interval);
155034ae28bSSean Wang 	mod_timer(&dev->phy.roc_timer,
156c36457a8SDeren Wu 		  jiffies + msecs_to_jiffies(duration));
157034ae28bSSean Wang }
158034ae28bSSean Wang 
159034ae28bSSean Wang static void
mt7921_mcu_scan_event(struct mt792x_dev * dev,struct sk_buff * skb)160975e122dSLorenzo Bianconi mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)
1611c099ab4SSean Wang {
1621c099ab4SSean Wang 	struct mt76_phy *mphy = &dev->mt76.phy;
16378562b2cSLorenzo Bianconi 	struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
1641c099ab4SSean Wang 
1651c099ab4SSean Wang 	spin_lock_bh(&dev->mt76.lock);
1661c099ab4SSean Wang 	__skb_queue_tail(&phy->scan_event_list, skb);
1671c099ab4SSean Wang 	spin_unlock_bh(&dev->mt76.lock);
1681c099ab4SSean Wang 
1691c099ab4SSean Wang 	ieee80211_queue_delayed_work(mphy->hw, &phy->scan_work,
1707d403f3aSLorenzo Bianconi 				     MT792x_HW_SCAN_TIMEOUT);
1711c099ab4SSean Wang }
1721c099ab4SSean Wang 
1731c099ab4SSean Wang static void
mt7921_mcu_connection_loss_iter(void * priv,u8 * mac,struct ieee80211_vif * vif)17410de032aSSean Wang mt7921_mcu_connection_loss_iter(void *priv, u8 *mac,
17510de032aSSean Wang 				struct ieee80211_vif *vif)
17610de032aSSean Wang {
17710de032aSSean Wang 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
17810de032aSSean Wang 	struct mt76_connac_beacon_loss_event *event = priv;
17910de032aSSean Wang 
18010de032aSSean Wang 	if (mvif->idx != event->bss_idx)
18110de032aSSean Wang 		return;
18210de032aSSean Wang 
183116c6960SSean Wang 	if (!(vif->driver_flags & IEEE80211_VIF_BEACON_FILTER) ||
184116c6960SSean Wang 	    vif->type != NL80211_IFTYPE_STATION)
18510de032aSSean Wang 		return;
18610de032aSSean Wang 
18710de032aSSean Wang 	ieee80211_connection_loss(vif);
18810de032aSSean Wang }
18910de032aSSean Wang 
19010de032aSSean Wang static void
mt7921_mcu_connection_loss_event(struct mt792x_dev * dev,struct sk_buff * skb)191975e122dSLorenzo Bianconi mt7921_mcu_connection_loss_event(struct mt792x_dev *dev, struct sk_buff *skb)
192b88f5c64SSean Wang {
19367aa2743SLorenzo Bianconi 	struct mt76_connac_beacon_loss_event *event;
19410de032aSSean Wang 	struct mt76_phy *mphy = &dev->mt76.phy;
195b88f5c64SSean Wang 
196fc6ee71aSLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
19767aa2743SLorenzo Bianconi 	event = (struct mt76_connac_beacon_loss_event *)skb->data;
198b88f5c64SSean Wang 
199b88f5c64SSean Wang 	ieee80211_iterate_active_interfaces_atomic(mphy->hw,
200b88f5c64SSean Wang 					IEEE80211_IFACE_ITER_RESUME_ALL,
20110de032aSSean Wang 					mt7921_mcu_connection_loss_iter, event);
202b88f5c64SSean Wang }
203b88f5c64SSean Wang 
204b88f5c64SSean Wang static void
mt7921_mcu_debug_msg_event(struct mt792x_dev * dev,struct sk_buff * skb)205975e122dSLorenzo Bianconi mt7921_mcu_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
2061c099ab4SSean Wang {
207c7cc5ec5SLorenzo Bianconi 	struct mt7921_debug_msg {
2081c099ab4SSean Wang 		__le16 id;
2091c099ab4SSean Wang 		u8 type;
2101c099ab4SSean Wang 		u8 flag;
2111c099ab4SSean Wang 		__le32 value;
2121c099ab4SSean Wang 		__le16 len;
2131c099ab4SSean Wang 		u8 content[512];
214c7cc5ec5SLorenzo Bianconi 	} __packed * msg;
215c7cc5ec5SLorenzo Bianconi 
216fc6ee71aSLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
217c7cc5ec5SLorenzo Bianconi 	msg = (struct mt7921_debug_msg *)skb->data;
218c7cc5ec5SLorenzo Bianconi 
219c7cc5ec5SLorenzo Bianconi 	if (msg->type == 3) { /* fw log */
220c7cc5ec5SLorenzo Bianconi 		u16 len = min_t(u16, le16_to_cpu(msg->len), 512);
2211c099ab4SSean Wang 		int i;
2221c099ab4SSean Wang 
223c7cc5ec5SLorenzo Bianconi 		for (i = 0 ; i < len; i++) {
224c7cc5ec5SLorenzo Bianconi 			if (!msg->content[i])
225c7cc5ec5SLorenzo Bianconi 				msg->content[i] = ' ';
226c7cc5ec5SLorenzo Bianconi 		}
2272bf301bcSDan Carpenter 		wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content);
2281c099ab4SSean Wang 	}
2291c099ab4SSean Wang }
2301c099ab4SSean Wang 
2311c099ab4SSean Wang static void
mt7921_mcu_low_power_event(struct mt792x_dev * dev,struct sk_buff * skb)232975e122dSLorenzo Bianconi mt7921_mcu_low_power_event(struct mt792x_dev *dev, struct sk_buff *skb)
2332afd17b4SLorenzo Bianconi {
2342afd17b4SLorenzo Bianconi 	struct mt7921_mcu_lp_event {
2352afd17b4SLorenzo Bianconi 		u8 state;
2362afd17b4SLorenzo Bianconi 		u8 reserved[3];
2372afd17b4SLorenzo Bianconi 	} __packed * event;
2382afd17b4SLorenzo Bianconi 
239fc6ee71aSLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
2402afd17b4SLorenzo Bianconi 	event = (struct mt7921_mcu_lp_event *)skb->data;
2412afd17b4SLorenzo Bianconi 
2422afd17b4SLorenzo Bianconi 	trace_lp_event(dev, event->state);
2432afd17b4SLorenzo Bianconi }
2442afd17b4SLorenzo Bianconi 
2452afd17b4SLorenzo Bianconi static void
mt7921_mcu_tx_done_event(struct mt792x_dev * dev,struct sk_buff * skb)246975e122dSLorenzo Bianconi mt7921_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb)
247e0bf699aSDeren Wu {
248e0bf699aSDeren Wu 	struct mt7921_mcu_tx_done_event *event;
249e0bf699aSDeren Wu 
250fc6ee71aSLorenzo Bianconi 	skb_pull(skb, sizeof(struct mt76_connac2_mcu_rxd));
251e0bf699aSDeren Wu 	event = (struct mt7921_mcu_tx_done_event *)skb->data;
252e0bf699aSDeren Wu 
253e0bf699aSDeren Wu 	mt7921_mac_add_txs(dev, event->txs);
254e0bf699aSDeren Wu }
255e0bf699aSDeren Wu 
256e0bf699aSDeren Wu static void
mt7921_mcu_rx_unsolicited_event(struct mt792x_dev * dev,struct sk_buff * skb)257975e122dSLorenzo Bianconi mt7921_mcu_rx_unsolicited_event(struct mt792x_dev *dev, struct sk_buff *skb)
2581c099ab4SSean Wang {
259fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
2601c099ab4SSean Wang 
261fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
2621c099ab4SSean Wang 	switch (rxd->eid) {
2631c099ab4SSean Wang 	case MCU_EVENT_BSS_BEACON_LOSS:
26410de032aSSean Wang 		mt7921_mcu_connection_loss_event(dev, skb);
2651c099ab4SSean Wang 		break;
2661c099ab4SSean Wang 	case MCU_EVENT_SCHED_SCAN_DONE:
2671c099ab4SSean Wang 	case MCU_EVENT_SCAN_DONE:
2681c099ab4SSean Wang 		mt7921_mcu_scan_event(dev, skb);
2691c099ab4SSean Wang 		return;
2701c099ab4SSean Wang 	case MCU_EVENT_DBG_MSG:
2711c099ab4SSean Wang 		mt7921_mcu_debug_msg_event(dev, skb);
2721c099ab4SSean Wang 		break;
2730da3c795SSean Wang 	case MCU_EVENT_COREDUMP:
274ca74b9b9SSean Wang 		dev->fw_assert = true;
2750da3c795SSean Wang 		mt76_connac_mcu_coredump_event(&dev->mt76, skb,
2760da3c795SSean Wang 					       &dev->coredump);
2770da3c795SSean Wang 		return;
2782afd17b4SLorenzo Bianconi 	case MCU_EVENT_LP_INFO:
2792afd17b4SLorenzo Bianconi 		mt7921_mcu_low_power_event(dev, skb);
2802afd17b4SLorenzo Bianconi 		break;
281e0bf699aSDeren Wu 	case MCU_EVENT_TX_DONE:
282e0bf699aSDeren Wu 		mt7921_mcu_tx_done_event(dev, skb);
283e0bf699aSDeren Wu 		break;
2841c099ab4SSean Wang 	default:
2851c099ab4SSean Wang 		break;
2861c099ab4SSean Wang 	}
2871c099ab4SSean Wang 	dev_kfree_skb(skb);
2881c099ab4SSean Wang }
2891c099ab4SSean Wang 
2905b55b6daSQuan Zhou static void
mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev * dev,struct sk_buff * skb)291975e122dSLorenzo Bianconi mt7921_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
2925b55b6daSQuan Zhou 				    struct sk_buff *skb)
2935b55b6daSQuan Zhou {
2945b55b6daSQuan Zhou 	struct mt76_connac2_mcu_rxd *rxd;
2955b55b6daSQuan Zhou 
2965b55b6daSQuan Zhou 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
2975b55b6daSQuan Zhou 
2985b55b6daSQuan Zhou 	switch (rxd->eid) {
2995b55b6daSQuan Zhou 	case MCU_UNI_EVENT_ROC:
300034ae28bSSean Wang 		mt7921_mcu_uni_roc_event(dev, skb);
3015b55b6daSQuan Zhou 		break;
3025b55b6daSQuan Zhou 	default:
3035b55b6daSQuan Zhou 		break;
3045b55b6daSQuan Zhou 	}
3055b55b6daSQuan Zhou 	dev_kfree_skb(skb);
3065b55b6daSQuan Zhou }
3075b55b6daSQuan Zhou 
mt7921_mcu_rx_event(struct mt792x_dev * dev,struct sk_buff * skb)308975e122dSLorenzo Bianconi void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb)
3091c099ab4SSean Wang {
310fc6ee71aSLorenzo Bianconi 	struct mt76_connac2_mcu_rxd *rxd;
311f0ff5d3aSSean Wang 
312f0ff5d3aSSean Wang 	if (skb_linearize(skb))
313f0ff5d3aSSean Wang 		return;
314f0ff5d3aSSean Wang 
315fc6ee71aSLorenzo Bianconi 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
3161c099ab4SSean Wang 
3175b55b6daSQuan Zhou 	if (rxd->option & MCU_UNI_CMD_UNSOLICITED_EVENT) {
3185b55b6daSQuan Zhou 		mt7921_mcu_uni_rx_unsolicited_event(dev, skb);
3195b55b6daSQuan Zhou 		return;
3205b55b6daSQuan Zhou 	}
3215b55b6daSQuan Zhou 
3221c099ab4SSean Wang 	if (rxd->eid == 0x6) {
3231c099ab4SSean Wang 		mt76_mcu_rx_event(&dev->mt76, skb);
3241c099ab4SSean Wang 		return;
3251c099ab4SSean Wang 	}
3261c099ab4SSean Wang 
3271c099ab4SSean Wang 	if (rxd->ext_eid == MCU_EXT_EVENT_RATE_REPORT ||
3281c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_BSS_BEACON_LOSS ||
3291c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_SCHED_SCAN_DONE ||
3301c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_SCAN_DONE ||
3313cce2b98SDeren Wu 	    rxd->eid == MCU_EVENT_TX_DONE ||
3321c099ab4SSean Wang 	    rxd->eid == MCU_EVENT_DBG_MSG ||
3330da3c795SSean Wang 	    rxd->eid == MCU_EVENT_COREDUMP ||
3342afd17b4SLorenzo Bianconi 	    rxd->eid == MCU_EVENT_LP_INFO ||
3351c099ab4SSean Wang 	    !rxd->seq)
3361c099ab4SSean Wang 		mt7921_mcu_rx_unsolicited_event(dev, skb);
3371c099ab4SSean Wang 	else
3381c099ab4SSean Wang 		mt76_mcu_rx_event(&dev->mt76, skb);
3391c099ab4SSean Wang }
3401c099ab4SSean Wang 
3411c099ab4SSean Wang /** starec & wtbl **/
mt7921_mcu_uni_tx_ba(struct mt792x_dev * dev,struct ieee80211_ampdu_params * params,bool enable)342975e122dSLorenzo Bianconi int mt7921_mcu_uni_tx_ba(struct mt792x_dev *dev,
3431c099ab4SSean Wang 			 struct ieee80211_ampdu_params *params,
3441c099ab4SSean Wang 			 bool enable)
3451c099ab4SSean Wang {
346b7bfad2cSLorenzo Bianconi 	struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
34767aa2743SLorenzo Bianconi 
34867aa2743SLorenzo Bianconi 	if (enable && !params->amsdu)
34967aa2743SLorenzo Bianconi 		msta->wcid.amsdu = false;
35067aa2743SLorenzo Bianconi 
35167aa2743SLorenzo Bianconi 	return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params,
352b5322e44SLorenzo Bianconi 				      MCU_UNI_CMD(STA_REC_UPDATE),
35367aa2743SLorenzo Bianconi 				      enable, true);
3541c099ab4SSean Wang }
3551c099ab4SSean Wang 
mt7921_mcu_uni_rx_ba(struct mt792x_dev * dev,struct ieee80211_ampdu_params * params,bool enable)356975e122dSLorenzo Bianconi int mt7921_mcu_uni_rx_ba(struct mt792x_dev *dev,
3571c099ab4SSean Wang 			 struct ieee80211_ampdu_params *params,
3581c099ab4SSean Wang 			 bool enable)
3591c099ab4SSean Wang {
360b7bfad2cSLorenzo Bianconi 	struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
3611c099ab4SSean Wang 
36267aa2743SLorenzo Bianconi 	return mt76_connac_mcu_sta_ba(&dev->mt76, &msta->vif->mt76, params,
363b5322e44SLorenzo Bianconi 				      MCU_UNI_CMD(STA_REC_UPDATE),
36467aa2743SLorenzo Bianconi 				      enable, false);
3651c099ab4SSean Wang }
3661c099ab4SSean Wang 
mt7921_load_clc(struct mt792x_dev * dev,const char * fw_name)367975e122dSLorenzo Bianconi static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
36823bdc5d8SMing Yen Hsieh {
36923bdc5d8SMing Yen Hsieh 	const struct mt76_connac2_fw_trailer *hdr;
37023bdc5d8SMing Yen Hsieh 	const struct mt76_connac2_fw_region *region;
37123bdc5d8SMing Yen Hsieh 	const struct mt7921_clc *clc;
37223bdc5d8SMing Yen Hsieh 	struct mt76_dev *mdev = &dev->mt76;
37378562b2cSLorenzo Bianconi 	struct mt792x_phy *phy = &dev->phy;
37423bdc5d8SMing Yen Hsieh 	const struct firmware *fw;
37523bdc5d8SMing Yen Hsieh 	int ret, i, len, offset = 0;
37623bdc5d8SMing Yen Hsieh 	u8 *clc_base = NULL, hw_encap = 0;
37723bdc5d8SMing Yen Hsieh 
37823bdc5d8SMing Yen Hsieh 	if (mt7921_disable_clc ||
37923bdc5d8SMing Yen Hsieh 	    mt76_is_usb(&dev->mt76))
38023bdc5d8SMing Yen Hsieh 		return 0;
38123bdc5d8SMing Yen Hsieh 
38223bdc5d8SMing Yen Hsieh 	if (mt76_is_mmio(&dev->mt76)) {
38323bdc5d8SMing Yen Hsieh 		ret = mt7921_mcu_read_eeprom(dev, MT_EE_HW_TYPE, &hw_encap);
38423bdc5d8SMing Yen Hsieh 		if (ret)
38523bdc5d8SMing Yen Hsieh 			return ret;
38623bdc5d8SMing Yen Hsieh 		hw_encap = u8_get_bits(hw_encap, MT_EE_HW_TYPE_ENCAP);
38723bdc5d8SMing Yen Hsieh 	}
38823bdc5d8SMing Yen Hsieh 
38923bdc5d8SMing Yen Hsieh 	ret = request_firmware(&fw, fw_name, mdev->dev);
39023bdc5d8SMing Yen Hsieh 	if (ret)
39123bdc5d8SMing Yen Hsieh 		return ret;
39223bdc5d8SMing Yen Hsieh 
39323bdc5d8SMing Yen Hsieh 	if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
39423bdc5d8SMing Yen Hsieh 		dev_err(mdev->dev, "Invalid firmware\n");
39523bdc5d8SMing Yen Hsieh 		ret = -EINVAL;
39623bdc5d8SMing Yen Hsieh 		goto out;
39723bdc5d8SMing Yen Hsieh 	}
39823bdc5d8SMing Yen Hsieh 
39923bdc5d8SMing Yen Hsieh 	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
40023bdc5d8SMing Yen Hsieh 	for (i = 0; i < hdr->n_region; i++) {
40123bdc5d8SMing Yen Hsieh 		region = (const void *)((const u8 *)hdr -
40223bdc5d8SMing Yen Hsieh 					(hdr->n_region - i) * sizeof(*region));
40323bdc5d8SMing Yen Hsieh 		len = le32_to_cpu(region->len);
40423bdc5d8SMing Yen Hsieh 
40523bdc5d8SMing Yen Hsieh 		/* check if we have valid buffer size */
40623bdc5d8SMing Yen Hsieh 		if (offset + len > fw->size) {
40723bdc5d8SMing Yen Hsieh 			dev_err(mdev->dev, "Invalid firmware region\n");
40823bdc5d8SMing Yen Hsieh 			ret = -EINVAL;
40923bdc5d8SMing Yen Hsieh 			goto out;
41023bdc5d8SMing Yen Hsieh 		}
41123bdc5d8SMing Yen Hsieh 
41223bdc5d8SMing Yen Hsieh 		if ((region->feature_set & FW_FEATURE_NON_DL) &&
41323bdc5d8SMing Yen Hsieh 		    region->type == FW_TYPE_CLC) {
41423bdc5d8SMing Yen Hsieh 			clc_base = (u8 *)(fw->data + offset);
41523bdc5d8SMing Yen Hsieh 			break;
41623bdc5d8SMing Yen Hsieh 		}
41723bdc5d8SMing Yen Hsieh 		offset += len;
41823bdc5d8SMing Yen Hsieh 	}
41923bdc5d8SMing Yen Hsieh 
42023bdc5d8SMing Yen Hsieh 	if (!clc_base)
42123bdc5d8SMing Yen Hsieh 		goto out;
42223bdc5d8SMing Yen Hsieh 
42323bdc5d8SMing Yen Hsieh 	for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) {
42423bdc5d8SMing Yen Hsieh 		clc = (const struct mt7921_clc *)(clc_base + offset);
42523bdc5d8SMing Yen Hsieh 
42623bdc5d8SMing Yen Hsieh 		/* do not init buf again if chip reset triggered */
42723bdc5d8SMing Yen Hsieh 		if (phy->clc[clc->idx])
42823bdc5d8SMing Yen Hsieh 			continue;
42923bdc5d8SMing Yen Hsieh 
43023bdc5d8SMing Yen Hsieh 		/* header content sanity */
43123bdc5d8SMing Yen Hsieh 		if (clc->idx == MT7921_CLC_POWER &&
43223bdc5d8SMing Yen Hsieh 		    u8_get_bits(clc->type, MT_EE_HW_TYPE_ENCAP) != hw_encap)
43323bdc5d8SMing Yen Hsieh 			continue;
43423bdc5d8SMing Yen Hsieh 
43523bdc5d8SMing Yen Hsieh 		phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc,
43623bdc5d8SMing Yen Hsieh 						  le32_to_cpu(clc->len),
43723bdc5d8SMing Yen Hsieh 						  GFP_KERNEL);
43823bdc5d8SMing Yen Hsieh 
43923bdc5d8SMing Yen Hsieh 		if (!phy->clc[clc->idx]) {
44023bdc5d8SMing Yen Hsieh 			ret = -ENOMEM;
44123bdc5d8SMing Yen Hsieh 			goto out;
44223bdc5d8SMing Yen Hsieh 		}
44323bdc5d8SMing Yen Hsieh 	}
44423bdc5d8SMing Yen Hsieh 	ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR);
44523bdc5d8SMing Yen Hsieh out:
44623bdc5d8SMing Yen Hsieh 	release_firmware(fw);
44723bdc5d8SMing Yen Hsieh 
44823bdc5d8SMing Yen Hsieh 	return ret;
44923bdc5d8SMing Yen Hsieh }
45023bdc5d8SMing Yen Hsieh 
mt7921_mcu_fw_log_2_host(struct mt792x_dev * dev,u8 ctrl)451975e122dSLorenzo Bianconi int mt7921_mcu_fw_log_2_host(struct mt792x_dev *dev, u8 ctrl)
4521c099ab4SSean Wang {
4531c099ab4SSean Wang 	struct {
4541c099ab4SSean Wang 		u8 ctrl_val;
4551c099ab4SSean Wang 		u8 pad[3];
4561c099ab4SSean Wang 	} data = {
4571c099ab4SSean Wang 		.ctrl_val = ctrl
4581c099ab4SSean Wang 	};
4591c099ab4SSean Wang 
460680a2eadSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(FWLOG_2_HOST),
461680a2eadSLorenzo Bianconi 				 &data, sizeof(data), false);
4621c099ab4SSean Wang }
4631c099ab4SSean Wang 
mt7921_run_firmware(struct mt792x_dev * dev)464975e122dSLorenzo Bianconi int mt7921_run_firmware(struct mt792x_dev *dev)
465d32464e6SLorenzo Bianconi {
466d32464e6SLorenzo Bianconi 	int err;
467d32464e6SLorenzo Bianconi 
468583204aeSLorenzo Bianconi 	err = mt792x_load_firmware(dev);
469d32464e6SLorenzo Bianconi 	if (err)
470d32464e6SLorenzo Bianconi 		return err;
471d32464e6SLorenzo Bianconi 
47216d98b54SSean Wang 	err = mt76_connac_mcu_get_nic_capability(&dev->mphy);
47316d98b54SSean Wang 	if (err)
47416d98b54SSean Wang 		return err;
475d32464e6SLorenzo Bianconi 
47616d98b54SSean Wang 	set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
477583204aeSLorenzo Bianconi 	err = mt7921_load_clc(dev, mt792x_ram_name(dev));
47823bdc5d8SMing Yen Hsieh 	if (err)
47923bdc5d8SMing Yen Hsieh 		return err;
48023bdc5d8SMing Yen Hsieh 
48116d98b54SSean Wang 	return mt7921_mcu_fw_log_2_host(dev, 1);
482d32464e6SLorenzo Bianconi }
4838910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_run_firmware);
484d32464e6SLorenzo Bianconi 
mt7921_mcu_set_tx(struct mt792x_dev * dev,struct ieee80211_vif * vif)485975e122dSLorenzo Bianconi int mt7921_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_vif *vif)
4861c099ab4SSean Wang {
48715ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
4881c099ab4SSean Wang 	struct edca {
48966ca1a7bSSean Wang 		__le16 cw_min;
4901c099ab4SSean Wang 		__le16 cw_max;
4911c099ab4SSean Wang 		__le16 txop;
49266ca1a7bSSean Wang 		__le16 aifs;
49366ca1a7bSSean Wang 		u8 guardtime;
49466ca1a7bSSean Wang 		u8 acm;
49566ca1a7bSSean Wang 	} __packed;
4961c099ab4SSean Wang 	struct mt7921_mcu_tx {
4971c099ab4SSean Wang 		struct edca edca[IEEE80211_NUM_ACS];
49866ca1a7bSSean Wang 		u8 bss_idx;
49966ca1a7bSSean Wang 		u8 qos;
50066ca1a7bSSean Wang 		u8 wmm_idx;
50166ca1a7bSSean Wang 		u8 pad;
5021c099ab4SSean Wang 	} __packed req = {
50366ca1a7bSSean Wang 		.bss_idx = mvif->mt76.idx,
50466ca1a7bSSean Wang 		.qos = vif->bss_conf.qos,
50566ca1a7bSSean Wang 		.wmm_idx = mvif->mt76.wmm_idx,
5061c099ab4SSean Wang 	};
507bb0ae4cfSSean Wang 	struct mu_edca {
508bb0ae4cfSSean Wang 		u8 cw_min;
509bb0ae4cfSSean Wang 		u8 cw_max;
510bb0ae4cfSSean Wang 		u8 aifsn;
511bb0ae4cfSSean Wang 		u8 acm;
512bb0ae4cfSSean Wang 		u8 timer;
513bb0ae4cfSSean Wang 		u8 padding[3];
514bb0ae4cfSSean Wang 	};
515bb0ae4cfSSean Wang 	struct mt7921_mcu_mu_tx {
516bb0ae4cfSSean Wang 		u8 ver;
517bb0ae4cfSSean Wang 		u8 pad0;
518bb0ae4cfSSean Wang 		__le16 len;
519bb0ae4cfSSean Wang 		u8 bss_idx;
520bb0ae4cfSSean Wang 		u8 qos;
521bb0ae4cfSSean Wang 		u8 wmm_idx;
522bb0ae4cfSSean Wang 		u8 pad1;
523bb0ae4cfSSean Wang 		struct mu_edca edca[IEEE80211_NUM_ACS];
524bb0ae4cfSSean Wang 		u8 pad3[32];
525bb0ae4cfSSean Wang 	} __packed req_mu = {
526bb0ae4cfSSean Wang 		.bss_idx = mvif->mt76.idx,
527bb0ae4cfSSean Wang 		.qos = vif->bss_conf.qos,
528bb0ae4cfSSean Wang 		.wmm_idx = mvif->mt76.wmm_idx,
529bb0ae4cfSSean Wang 	};
5304abe5b92SLorenzo Bianconi 	static const int to_aci[] = { 1, 0, 2, 3 };
531bb0ae4cfSSean Wang 	int ac, ret;
5321c099ab4SSean Wang 
5331c099ab4SSean Wang 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
5341c099ab4SSean Wang 		struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
53566ca1a7bSSean Wang 		struct edca *e = &req.edca[to_aci[ac]];
5361c099ab4SSean Wang 
5374abe5b92SLorenzo Bianconi 		e->aifs = cpu_to_le16(q->aifs);
5381c099ab4SSean Wang 		e->txop = cpu_to_le16(q->txop);
5391c099ab4SSean Wang 
5401c099ab4SSean Wang 		if (q->cw_min)
54166ca1a7bSSean Wang 			e->cw_min = cpu_to_le16(q->cw_min);
5421c099ab4SSean Wang 		else
5434abe5b92SLorenzo Bianconi 			e->cw_min = cpu_to_le16(5);
5441c099ab4SSean Wang 
5451c099ab4SSean Wang 		if (q->cw_max)
54666ca1a7bSSean Wang 			e->cw_max = cpu_to_le16(q->cw_max);
5471c099ab4SSean Wang 		else
5481c099ab4SSean Wang 			e->cw_max = cpu_to_le16(10);
5491c099ab4SSean Wang 	}
550bb0ae4cfSSean Wang 
55166ca1a7bSSean Wang 	ret = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_EDCA_PARMS), &req,
55266ca1a7bSSean Wang 				sizeof(req), false);
553bb0ae4cfSSean Wang 	if (ret)
554bb0ae4cfSSean Wang 		return ret;
555bb0ae4cfSSean Wang 
556bb0ae4cfSSean Wang 	if (!vif->bss_conf.he_support)
557bb0ae4cfSSean Wang 		return 0;
558bb0ae4cfSSean Wang 
559bb0ae4cfSSean Wang 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
560bb0ae4cfSSean Wang 		struct ieee80211_he_mu_edca_param_ac_rec *q;
561bb0ae4cfSSean Wang 		struct mu_edca *e;
562bb0ae4cfSSean Wang 
563bb0ae4cfSSean Wang 		if (!mvif->queue_params[ac].mu_edca)
564bb0ae4cfSSean Wang 			break;
565bb0ae4cfSSean Wang 
566bb0ae4cfSSean Wang 		q = &mvif->queue_params[ac].mu_edca_param_rec;
567bb0ae4cfSSean Wang 		e = &(req_mu.edca[to_aci[ac]]);
568bb0ae4cfSSean Wang 
569bb0ae4cfSSean Wang 		e->cw_min = q->ecw_min_max & 0xf;
570bb0ae4cfSSean Wang 		e->cw_max = (q->ecw_min_max & 0xf0) >> 4;
571bb0ae4cfSSean Wang 		e->aifsn = q->aifsn;
572bb0ae4cfSSean Wang 		e->timer = q->mu_edca_timer;
573bb0ae4cfSSean Wang 	}
574bb0ae4cfSSean Wang 
575680a2eadSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_MU_EDCA_PARMS),
576680a2eadSLorenzo Bianconi 				 &req_mu, sizeof(req_mu), false);
5771c099ab4SSean Wang }
5781c099ab4SSean Wang 
mt7921_mcu_set_roc(struct mt792x_phy * phy,struct mt792x_vif * vif,struct ieee80211_channel * chan,int duration,enum mt7921_roc_req type,u8 token_id)57978562b2cSLorenzo Bianconi int mt7921_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
5805b55b6daSQuan Zhou 		       struct ieee80211_channel *chan, int duration,
5815b55b6daSQuan Zhou 		       enum mt7921_roc_req type, u8 token_id)
5825b55b6daSQuan Zhou {
5835b55b6daSQuan Zhou 	int center_ch = ieee80211_frequency_to_channel(chan->center_freq);
584975e122dSLorenzo Bianconi 	struct mt792x_dev *dev = phy->dev;
5855b55b6daSQuan Zhou 	struct {
5865b55b6daSQuan Zhou 		struct {
5875b55b6daSQuan Zhou 			u8 rsv[4];
5885b55b6daSQuan Zhou 		} __packed hdr;
5895b55b6daSQuan Zhou 		struct roc_acquire_tlv {
5905b55b6daSQuan Zhou 			__le16 tag;
5915b55b6daSQuan Zhou 			__le16 len;
5925b55b6daSQuan Zhou 			u8 bss_idx;
5935b55b6daSQuan Zhou 			u8 tokenid;
5945b55b6daSQuan Zhou 			u8 control_channel;
5955b55b6daSQuan Zhou 			u8 sco;
5965b55b6daSQuan Zhou 			u8 band;
5975b55b6daSQuan Zhou 			u8 bw;
5985b55b6daSQuan Zhou 			u8 center_chan;
5995b55b6daSQuan Zhou 			u8 center_chan2;
6005b55b6daSQuan Zhou 			u8 bw_from_ap;
6015b55b6daSQuan Zhou 			u8 center_chan_from_ap;
6025b55b6daSQuan Zhou 			u8 center_chan2_from_ap;
6035b55b6daSQuan Zhou 			u8 reqtype;
6045b55b6daSQuan Zhou 			__le32 maxinterval;
6055b55b6daSQuan Zhou 			u8 dbdcband;
6065b55b6daSQuan Zhou 			u8 rsv[3];
6075b55b6daSQuan Zhou 		} __packed roc;
6085b55b6daSQuan Zhou 	} __packed req = {
6095b55b6daSQuan Zhou 		.roc = {
6105b55b6daSQuan Zhou 			.tag = cpu_to_le16(UNI_ROC_ACQUIRE),
6115b55b6daSQuan Zhou 			.len = cpu_to_le16(sizeof(struct roc_acquire_tlv)),
6125b55b6daSQuan Zhou 			.tokenid = token_id,
6135b55b6daSQuan Zhou 			.reqtype = type,
6145b55b6daSQuan Zhou 			.maxinterval = cpu_to_le32(duration),
6155b55b6daSQuan Zhou 			.bss_idx = vif->mt76.idx,
6165b55b6daSQuan Zhou 			.control_channel = chan->hw_value,
6175b55b6daSQuan Zhou 			.bw = CMD_CBW_20MHZ,
6185b55b6daSQuan Zhou 			.bw_from_ap = CMD_CBW_20MHZ,
6195b55b6daSQuan Zhou 			.center_chan = center_ch,
6205b55b6daSQuan Zhou 			.center_chan_from_ap = center_ch,
6215b55b6daSQuan Zhou 			.dbdcband = 0xff, /* auto */
6225b55b6daSQuan Zhou 		},
6235b55b6daSQuan Zhou 	};
6245b55b6daSQuan Zhou 
6255b55b6daSQuan Zhou 	if (chan->hw_value < center_ch)
6265b55b6daSQuan Zhou 		req.roc.sco = 1; /* SCA */
6275b55b6daSQuan Zhou 	else if (chan->hw_value > center_ch)
6285b55b6daSQuan Zhou 		req.roc.sco = 3; /* SCB */
6295b55b6daSQuan Zhou 
6305b55b6daSQuan Zhou 	switch (chan->band) {
6315b55b6daSQuan Zhou 	case NL80211_BAND_6GHZ:
6325b55b6daSQuan Zhou 		req.roc.band = 3;
6335b55b6daSQuan Zhou 		break;
6345b55b6daSQuan Zhou 	case NL80211_BAND_5GHZ:
6355b55b6daSQuan Zhou 		req.roc.band = 2;
6365b55b6daSQuan Zhou 		break;
6375b55b6daSQuan Zhou 	default:
6385b55b6daSQuan Zhou 		req.roc.band = 1;
6395b55b6daSQuan Zhou 		break;
6405b55b6daSQuan Zhou 	}
6415b55b6daSQuan Zhou 
6425b55b6daSQuan Zhou 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),
6435b55b6daSQuan Zhou 				 &req, sizeof(req), false);
6445b55b6daSQuan Zhou }
6455b55b6daSQuan Zhou 
mt7921_mcu_abort_roc(struct mt792x_phy * phy,struct mt792x_vif * vif,u8 token_id)64678562b2cSLorenzo Bianconi int mt7921_mcu_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif,
6475b55b6daSQuan Zhou 			 u8 token_id)
6485b55b6daSQuan Zhou {
649975e122dSLorenzo Bianconi 	struct mt792x_dev *dev = phy->dev;
6505b55b6daSQuan Zhou 	struct {
6515b55b6daSQuan Zhou 		struct {
6525b55b6daSQuan Zhou 			u8 rsv[4];
6535b55b6daSQuan Zhou 		} __packed hdr;
6545b55b6daSQuan Zhou 		struct roc_abort_tlv {
6555b55b6daSQuan Zhou 			__le16 tag;
6565b55b6daSQuan Zhou 			__le16 len;
6575b55b6daSQuan Zhou 			u8 bss_idx;
6585b55b6daSQuan Zhou 			u8 tokenid;
6595b55b6daSQuan Zhou 			u8 dbdcband;
6605b55b6daSQuan Zhou 			u8 rsv[5];
6615b55b6daSQuan Zhou 		} __packed abort;
6625b55b6daSQuan Zhou 	} __packed req = {
6635b55b6daSQuan Zhou 		.abort = {
6645b55b6daSQuan Zhou 			.tag = cpu_to_le16(UNI_ROC_ABORT),
6655b55b6daSQuan Zhou 			.len = cpu_to_le16(sizeof(struct roc_abort_tlv)),
6665b55b6daSQuan Zhou 			.tokenid = token_id,
6675b55b6daSQuan Zhou 			.bss_idx = vif->mt76.idx,
6685b55b6daSQuan Zhou 			.dbdcband = 0xff, /* auto*/
6695b55b6daSQuan Zhou 		},
6705b55b6daSQuan Zhou 	};
6715b55b6daSQuan Zhou 
6725b55b6daSQuan Zhou 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(ROC),
6735b55b6daSQuan Zhou 				 &req, sizeof(req), false);
6745b55b6daSQuan Zhou }
6755b55b6daSQuan Zhou 
mt7921_mcu_set_chan_info(struct mt792x_phy * phy,int cmd)67678562b2cSLorenzo Bianconi int mt7921_mcu_set_chan_info(struct mt792x_phy *phy, int cmd)
6771c099ab4SSean Wang {
678975e122dSLorenzo Bianconi 	struct mt792x_dev *dev = phy->dev;
6791c099ab4SSean Wang 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
6801c099ab4SSean Wang 	int freq1 = chandef->center_freq1;
6811c099ab4SSean Wang 	struct {
6821c099ab4SSean Wang 		u8 control_ch;
6831c099ab4SSean Wang 		u8 center_ch;
6841c099ab4SSean Wang 		u8 bw;
6851c099ab4SSean Wang 		u8 tx_streams_num;
6861c099ab4SSean Wang 		u8 rx_streams;	/* mask or num */
6871c099ab4SSean Wang 		u8 switch_reason;
6881c099ab4SSean Wang 		u8 band_idx;
6891c099ab4SSean Wang 		u8 center_ch2;	/* for 80+80 only */
6901c099ab4SSean Wang 		__le16 cac_case;
6911c099ab4SSean Wang 		u8 channel_band;
6921c099ab4SSean Wang 		u8 rsv0;
6931c099ab4SSean Wang 		__le32 outband_freq;
6941c099ab4SSean Wang 		u8 txpower_drop;
6951c099ab4SSean Wang 		u8 ap_bw;
6961c099ab4SSean Wang 		u8 ap_center_ch;
6971c099ab4SSean Wang 		u8 rsv1[57];
6981c099ab4SSean Wang 	} __packed req = {
6991c099ab4SSean Wang 		.control_ch = chandef->chan->hw_value,
7001c099ab4SSean Wang 		.center_ch = ieee80211_frequency_to_channel(freq1),
70144c73d17SLorenzo Bianconi 		.bw = mt76_connac_chan_bw(chandef),
7021c099ab4SSean Wang 		.tx_streams_num = hweight8(phy->mt76->antenna_mask),
7031c099ab4SSean Wang 		.rx_streams = phy->mt76->antenna_mask,
7041c099ab4SSean Wang 		.band_idx = phy != &dev->phy,
7051c099ab4SSean Wang 	};
7061c099ab4SSean Wang 
70750ac15a5SLorenzo Bianconi 	if (chandef->chan->band == NL80211_BAND_6GHZ)
70850ac15a5SLorenzo Bianconi 		req.channel_band = 2;
70950ac15a5SLorenzo Bianconi 	else
71050ac15a5SLorenzo Bianconi 		req.channel_band = chandef->chan->band;
71150ac15a5SLorenzo Bianconi 
71224e69f6bSDeren Wu 	if (cmd == MCU_EXT_CMD(SET_RX_PATH) ||
71324e69f6bSDeren Wu 	    dev->mt76.hw->conf.flags & IEEE80211_CONF_MONITOR)
71400a883e6SFelix Fietkau 		req.switch_reason = CH_SWITCH_NORMAL;
71500a883e6SFelix Fietkau 	else if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
7161c099ab4SSean Wang 		req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
71700a883e6SFelix Fietkau 	else if (!cfg80211_reg_can_beacon(dev->mt76.hw->wiphy, chandef,
71800a883e6SFelix Fietkau 					  NL80211_IFTYPE_AP))
7191c099ab4SSean Wang 		req.switch_reason = CH_SWITCH_DFS;
7201c099ab4SSean Wang 	else
7211c099ab4SSean Wang 		req.switch_reason = CH_SWITCH_NORMAL;
7221c099ab4SSean Wang 
723e6d2070dSLorenzo Bianconi 	if (cmd == MCU_EXT_CMD(CHANNEL_SWITCH))
7241c099ab4SSean Wang 		req.rx_streams = hweight8(req.rx_streams);
7251c099ab4SSean Wang 
7261c099ab4SSean Wang 	if (chandef->width == NL80211_CHAN_WIDTH_80P80) {
7271c099ab4SSean Wang 		int freq2 = chandef->center_freq2;
7281c099ab4SSean Wang 
7291c099ab4SSean Wang 		req.center_ch2 = ieee80211_frequency_to_channel(freq2);
7301c099ab4SSean Wang 	}
7311c099ab4SSean Wang 
7321c099ab4SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
7331c099ab4SSean Wang }
7341c099ab4SSean Wang 
mt7921_mcu_set_eeprom(struct mt792x_dev * dev)735975e122dSLorenzo Bianconi int mt7921_mcu_set_eeprom(struct mt792x_dev *dev)
7361c099ab4SSean Wang {
7371c099ab4SSean Wang 	struct req_hdr {
7381c099ab4SSean Wang 		u8 buffer_mode;
7391c099ab4SSean Wang 		u8 format;
7401c099ab4SSean Wang 		__le16 len;
7411c099ab4SSean Wang 	} __packed req = {
7421c099ab4SSean Wang 		.buffer_mode = EE_MODE_EFUSE,
7431c099ab4SSean Wang 		.format = EE_FORMAT_WHOLE,
7441c099ab4SSean Wang 	};
7451c099ab4SSean Wang 
746e6d2070dSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE),
7471c099ab4SSean Wang 				 &req, sizeof(req), true);
7481c099ab4SSean Wang }
7498910a4e5SSean Wang EXPORT_SYMBOL_GPL(mt7921_mcu_set_eeprom);
7501c099ab4SSean Wang 
mt7921_mcu_uni_bss_ps(struct mt792x_dev * dev,struct ieee80211_vif * vif)751975e122dSLorenzo Bianconi int mt7921_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_vif *vif)
75256d965daSSean Wang {
75315ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
75456d965daSSean Wang 	struct {
75556d965daSSean Wang 		struct {
75656d965daSSean Wang 			u8 bss_idx;
75756d965daSSean Wang 			u8 pad[3];
75856d965daSSean Wang 		} __packed hdr;
75956d965daSSean Wang 		struct ps_tlv {
76056d965daSSean Wang 			__le16 tag;
76156d965daSSean Wang 			__le16 len;
76256d965daSSean Wang 			u8 ps_state; /* 0: device awake
76356d965daSSean Wang 				      * 1: static power save
76456d965daSSean Wang 				      * 2: dynamic power saving
76556d965daSSean Wang 				      * 3: enter TWT power saving
76656d965daSSean Wang 				      * 4: leave TWT power saving
76756d965daSSean Wang 				      */
76856d965daSSean Wang 			u8 pad[3];
76956d965daSSean Wang 		} __packed ps;
77056d965daSSean Wang 	} __packed ps_req = {
77156d965daSSean Wang 		.hdr = {
77256d965daSSean Wang 			.bss_idx = mvif->mt76.idx,
77356d965daSSean Wang 		},
77456d965daSSean Wang 		.ps = {
77556d965daSSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_PS),
77656d965daSSean Wang 			.len = cpu_to_le16(sizeof(struct ps_tlv)),
777a3b8008dSJohannes Berg 			.ps_state = vif->cfg.ps ? 2 : 0,
77856d965daSSean Wang 		},
77956d965daSSean Wang 	};
78056d965daSSean Wang 
78156d965daSSean Wang 	if (vif->type != NL80211_IFTYPE_STATION)
78256d965daSSean Wang 		return -EOPNOTSUPP;
78356d965daSSean Wang 
78454722402SLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
78556d965daSSean Wang 				 &ps_req, sizeof(ps_req), true);
78656d965daSSean Wang }
7874086ee28SSean Wang 
788890809caSLorenzo Bianconi static int
mt7921_mcu_uni_bss_bcnft(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)789975e122dSLorenzo Bianconi mt7921_mcu_uni_bss_bcnft(struct mt792x_dev *dev, struct ieee80211_vif *vif,
7904086ee28SSean Wang 			 bool enable)
7914086ee28SSean Wang {
79215ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
7934086ee28SSean Wang 	struct {
7944086ee28SSean Wang 		struct {
7954086ee28SSean Wang 			u8 bss_idx;
7964086ee28SSean Wang 			u8 pad[3];
7974086ee28SSean Wang 		} __packed hdr;
7984086ee28SSean Wang 		struct bcnft_tlv {
7994086ee28SSean Wang 			__le16 tag;
8004086ee28SSean Wang 			__le16 len;
8014086ee28SSean Wang 			__le16 bcn_interval;
8024086ee28SSean Wang 			u8 dtim_period;
8034086ee28SSean Wang 			u8 pad;
8044086ee28SSean Wang 		} __packed bcnft;
8054086ee28SSean Wang 	} __packed bcnft_req = {
8064086ee28SSean Wang 		.hdr = {
8074086ee28SSean Wang 			.bss_idx = mvif->mt76.idx,
8084086ee28SSean Wang 		},
8094086ee28SSean Wang 		.bcnft = {
8104086ee28SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_BCNFT),
8114086ee28SSean Wang 			.len = cpu_to_le16(sizeof(struct bcnft_tlv)),
8124086ee28SSean Wang 			.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
8134086ee28SSean Wang 			.dtim_period = vif->bss_conf.dtim_period,
8144086ee28SSean Wang 		},
8154086ee28SSean Wang 	};
8164086ee28SSean Wang 
8174086ee28SSean Wang 	if (vif->type != NL80211_IFTYPE_STATION)
8184086ee28SSean Wang 		return 0;
8194086ee28SSean Wang 
82054722402SLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
8214086ee28SSean Wang 				 &bcnft_req, sizeof(bcnft_req), true);
8224086ee28SSean Wang }
8234086ee28SSean Wang 
8249d958b60SDeren Wu int
mt7921_mcu_set_bss_pm(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)825975e122dSLorenzo Bianconi mt7921_mcu_set_bss_pm(struct mt792x_dev *dev, struct ieee80211_vif *vif,
8264086ee28SSean Wang 		      bool enable)
8274086ee28SSean Wang {
82815ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
8294086ee28SSean Wang 	struct {
8304086ee28SSean Wang 		u8 bss_idx;
8314086ee28SSean Wang 		u8 dtim_period;
8324086ee28SSean Wang 		__le16 aid;
8334086ee28SSean Wang 		__le16 bcn_interval;
8344086ee28SSean Wang 		__le16 atim_window;
8354086ee28SSean Wang 		u8 uapsd;
8364086ee28SSean Wang 		u8 bmc_delivered_ac;
8374086ee28SSean Wang 		u8 bmc_triggered_ac;
8384086ee28SSean Wang 		u8 pad;
8394086ee28SSean Wang 	} req = {
8404086ee28SSean Wang 		.bss_idx = mvif->mt76.idx,
841f276e20bSJohannes Berg 		.aid = cpu_to_le16(vif->cfg.aid),
8424086ee28SSean Wang 		.dtim_period = vif->bss_conf.dtim_period,
8434086ee28SSean Wang 		.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
8444086ee28SSean Wang 	};
8454086ee28SSean Wang 	struct {
8464086ee28SSean Wang 		u8 bss_idx;
8474086ee28SSean Wang 		u8 pad[3];
8484086ee28SSean Wang 	} req_hdr = {
8494086ee28SSean Wang 		.bss_idx = mvif->mt76.idx,
8504086ee28SSean Wang 	};
8514086ee28SSean Wang 	int err;
8524086ee28SSean Wang 
853680a2eadSLorenzo Bianconi 	err = mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_ABORT),
854680a2eadSLorenzo Bianconi 				&req_hdr, sizeof(req_hdr), false);
8554086ee28SSean Wang 	if (err < 0 || !enable)
8564086ee28SSean Wang 		return err;
8574086ee28SSean Wang 
858680a2eadSLorenzo Bianconi 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_BSS_CONNECTED),
859680a2eadSLorenzo Bianconi 				 &req, sizeof(req), false);
8604086ee28SSean Wang }
8611d8efc74SSean Wang 
mt7921_mcu_sta_update(struct mt792x_dev * dev,struct ieee80211_sta * sta,struct ieee80211_vif * vif,bool enable,enum mt76_sta_info_state state)862975e122dSLorenzo Bianconi int mt7921_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_sta *sta,
863f5056657SSean Wang 			  struct ieee80211_vif *vif, bool enable,
864f5056657SSean Wang 			  enum mt76_sta_info_state state)
86536fcc8cfSLorenzo Bianconi {
86615ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
86736fcc8cfSLorenzo Bianconi 	int rssi = -ewma_rssi_read(&mvif->rssi);
86836fcc8cfSLorenzo Bianconi 	struct mt76_sta_cmd_info info = {
86936fcc8cfSLorenzo Bianconi 		.sta = sta,
87036fcc8cfSLorenzo Bianconi 		.vif = vif,
87136fcc8cfSLorenzo Bianconi 		.enable = enable,
87254722402SLorenzo Bianconi 		.cmd = MCU_UNI_CMD(STA_REC_UPDATE),
873f5056657SSean Wang 		.state = state,
87482453b1cSLorenzo Bianconi 		.offload_fw = true,
87536fcc8cfSLorenzo Bianconi 		.rcpi = to_rcpi(rssi),
87636fcc8cfSLorenzo Bianconi 	};
877b7bfad2cSLorenzo Bianconi 	struct mt792x_sta *msta;
87836fcc8cfSLorenzo Bianconi 
879b7bfad2cSLorenzo Bianconi 	msta = sta ? (struct mt792x_sta *)sta->drv_priv : NULL;
88036fcc8cfSLorenzo Bianconi 	info.wcid = msta ? &msta->wcid : &mvif->sta.wcid;
881f5056657SSean Wang 	info.newly = msta ? state != MT76_STA_INFO_STATE_ASSOC : true;
88236fcc8cfSLorenzo Bianconi 
883f5056657SSean Wang 	return mt76_connac_mcu_sta_cmd(&dev->mphy, &info);
88436fcc8cfSLorenzo Bianconi }
88536fcc8cfSLorenzo Bianconi 
mt7921_mcu_set_beacon_filter(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)886975e122dSLorenzo Bianconi int mt7921_mcu_set_beacon_filter(struct mt792x_dev *dev,
887890809caSLorenzo Bianconi 				 struct ieee80211_vif *vif,
888890809caSLorenzo Bianconi 				 bool enable)
8891d8efc74SSean Wang {
890c222f77fSNeil Chen #define MT7921_FIF_BIT_CLR		BIT(1)
891c222f77fSNeil Chen #define MT7921_FIF_BIT_SET		BIT(0)
892890809caSLorenzo Bianconi 	int err;
8931d8efc74SSean Wang 
894890809caSLorenzo Bianconi 	if (enable) {
895890809caSLorenzo Bianconi 		err = mt7921_mcu_uni_bss_bcnft(dev, vif, true);
896890809caSLorenzo Bianconi 		if (err)
897890809caSLorenzo Bianconi 			return err;
898159f6dd6SSean Wang 
899c222f77fSNeil Chen 		err = mt7921_mcu_set_rxfilter(dev, 0,
900c222f77fSNeil Chen 					      MT7921_FIF_BIT_SET,
901c222f77fSNeil Chen 					      MT_WF_RFCR_DROP_OTHER_BEACON);
902c222f77fSNeil Chen 		if (err)
903c222f77fSNeil Chen 			return err;
904890809caSLorenzo Bianconi 
905890809caSLorenzo Bianconi 		return 0;
906890809caSLorenzo Bianconi 	}
907890809caSLorenzo Bianconi 
908890809caSLorenzo Bianconi 	err = mt7921_mcu_set_bss_pm(dev, vif, false);
909890809caSLorenzo Bianconi 	if (err)
910890809caSLorenzo Bianconi 		return err;
911890809caSLorenzo Bianconi 
912c222f77fSNeil Chen 	err = mt7921_mcu_set_rxfilter(dev, 0,
913c222f77fSNeil Chen 				      MT7921_FIF_BIT_CLR,
914c222f77fSNeil Chen 				      MT_WF_RFCR_DROP_OTHER_BEACON);
915c222f77fSNeil Chen 	if (err)
916c222f77fSNeil Chen 		return err;
917890809caSLorenzo Bianconi 
918890809caSLorenzo Bianconi 	return 0;
9191d8efc74SSean Wang }
9209c9d8321SSean Wang 
mt7921_get_txpwr_info(struct mt792x_dev * dev,struct mt7921_txpwr * txpwr)921975e122dSLorenzo Bianconi int mt7921_get_txpwr_info(struct mt792x_dev *dev, struct mt7921_txpwr *txpwr)
922ea29acc9SSean Wang {
923ea29acc9SSean Wang 	struct mt7921_txpwr_event *event;
924ea29acc9SSean Wang 	struct mt7921_txpwr_req req = {
925ea29acc9SSean Wang 		.dbdc_idx = 0,
926ea29acc9SSean Wang 	};
927ea29acc9SSean Wang 	struct sk_buff *skb;
928ea29acc9SSean Wang 	int ret;
929ea29acc9SSean Wang 
930680a2eadSLorenzo Bianconi 	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CE_CMD(GET_TXPWR),
931ea29acc9SSean Wang 					&req, sizeof(req), true, &skb);
932ea29acc9SSean Wang 	if (ret)
933ea29acc9SSean Wang 		return ret;
934ea29acc9SSean Wang 
935ea29acc9SSean Wang 	event = (struct mt7921_txpwr_event *)skb->data;
936ea29acc9SSean Wang 	WARN_ON(skb->len != le16_to_cpu(event->len));
937ea29acc9SSean Wang 	memcpy(txpwr, &event->txpwr, sizeof(event->txpwr));
938ea29acc9SSean Wang 
939ea29acc9SSean Wang 	dev_kfree_skb(skb);
940ea29acc9SSean Wang 
941ea29acc9SSean Wang 	return 0;
942ea29acc9SSean Wang }
943cbaa0a40SSean Wang 
mt7921_mcu_set_sniffer(struct mt792x_dev * dev,struct ieee80211_vif * vif,bool enable)944975e122dSLorenzo Bianconi int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
945cbaa0a40SSean Wang 			   bool enable)
946cbaa0a40SSean Wang {
947cbaa0a40SSean Wang 	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
948cbaa0a40SSean Wang 	struct {
949cbaa0a40SSean Wang 		struct {
950cbaa0a40SSean Wang 			u8 band_idx;
951cbaa0a40SSean Wang 			u8 pad[3];
952cbaa0a40SSean Wang 		} __packed hdr;
953cbaa0a40SSean Wang 		struct sniffer_enable_tlv {
954cbaa0a40SSean Wang 			__le16 tag;
955cbaa0a40SSean Wang 			__le16 len;
956cbaa0a40SSean Wang 			u8 enable;
957cbaa0a40SSean Wang 			u8 pad[3];
958cbaa0a40SSean Wang 		} __packed enable;
959cbaa0a40SSean Wang 	} req = {
960cbaa0a40SSean Wang 		.hdr = {
961cbaa0a40SSean Wang 			.band_idx = mvif->band_idx,
962cbaa0a40SSean Wang 		},
963cbaa0a40SSean Wang 		.enable = {
964cbaa0a40SSean Wang 			.tag = cpu_to_le16(0),
965cbaa0a40SSean Wang 			.len = cpu_to_le16(sizeof(struct sniffer_enable_tlv)),
966cbaa0a40SSean Wang 			.enable = enable,
967cbaa0a40SSean Wang 		},
968cbaa0a40SSean Wang 	};
969cbaa0a40SSean Wang 
970cbaa0a40SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req),
971cbaa0a40SSean Wang 				 true);
972cbaa0a40SSean Wang }
973116c6960SSean Wang 
mt7921_mcu_config_sniffer(struct mt792x_vif * vif,struct ieee80211_chanctx_conf * ctx)97415ca8970SLorenzo Bianconi int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
975914189afSDeren Wu 			      struct ieee80211_chanctx_conf *ctx)
976914189afSDeren Wu {
977914189afSDeren Wu 	struct cfg80211_chan_def *chandef = &ctx->def;
978914189afSDeren Wu 	int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
979914189afSDeren Wu 	const u8 ch_band[] = {
980914189afSDeren Wu 		[NL80211_BAND_2GHZ] = 1,
981914189afSDeren Wu 		[NL80211_BAND_5GHZ] = 2,
982914189afSDeren Wu 		[NL80211_BAND_6GHZ] = 3,
983914189afSDeren Wu 	};
984914189afSDeren Wu 	const u8 ch_width[] = {
985914189afSDeren Wu 		[NL80211_CHAN_WIDTH_20_NOHT] = 0,
986914189afSDeren Wu 		[NL80211_CHAN_WIDTH_20] = 0,
987914189afSDeren Wu 		[NL80211_CHAN_WIDTH_40] = 0,
988914189afSDeren Wu 		[NL80211_CHAN_WIDTH_80] = 1,
989914189afSDeren Wu 		[NL80211_CHAN_WIDTH_160] = 2,
990914189afSDeren Wu 		[NL80211_CHAN_WIDTH_80P80] = 3,
991914189afSDeren Wu 		[NL80211_CHAN_WIDTH_5] = 4,
992914189afSDeren Wu 		[NL80211_CHAN_WIDTH_10] = 5,
993914189afSDeren Wu 		[NL80211_CHAN_WIDTH_320] = 6,
994914189afSDeren Wu 	};
995914189afSDeren Wu 	struct {
996914189afSDeren Wu 		struct {
997914189afSDeren Wu 			u8 band_idx;
998914189afSDeren Wu 			u8 pad[3];
999914189afSDeren Wu 		} __packed hdr;
1000914189afSDeren Wu 		struct config_tlv {
1001914189afSDeren Wu 			__le16 tag;
1002914189afSDeren Wu 			__le16 len;
1003914189afSDeren Wu 			u16 aid;
1004914189afSDeren Wu 			u8 ch_band;
1005914189afSDeren Wu 			u8 bw;
1006914189afSDeren Wu 			u8 control_ch;
1007914189afSDeren Wu 			u8 sco;
1008914189afSDeren Wu 			u8 center_ch;
1009914189afSDeren Wu 			u8 center_ch2;
1010914189afSDeren Wu 			u8 drop_err;
1011914189afSDeren Wu 			u8 pad[3];
1012914189afSDeren Wu 		} __packed tlv;
1013914189afSDeren Wu 	} __packed req = {
1014914189afSDeren Wu 		.hdr = {
1015914189afSDeren Wu 			.band_idx = vif->mt76.band_idx,
1016914189afSDeren Wu 		},
1017914189afSDeren Wu 		.tlv = {
1018914189afSDeren Wu 			.tag = cpu_to_le16(1),
1019914189afSDeren Wu 			.len = cpu_to_le16(sizeof(req.tlv)),
1020914189afSDeren Wu 			.control_ch = chandef->chan->hw_value,
1021914189afSDeren Wu 			.center_ch = ieee80211_frequency_to_channel(freq1),
1022914189afSDeren Wu 			.drop_err = 1,
1023914189afSDeren Wu 		},
1024914189afSDeren Wu 	};
1025914189afSDeren Wu 	if (chandef->chan->band < ARRAY_SIZE(ch_band))
1026914189afSDeren Wu 		req.tlv.ch_band = ch_band[chandef->chan->band];
1027914189afSDeren Wu 	if (chandef->width < ARRAY_SIZE(ch_width))
1028914189afSDeren Wu 		req.tlv.bw = ch_width[chandef->width];
1029914189afSDeren Wu 
1030914189afSDeren Wu 	if (freq2)
1031914189afSDeren Wu 		req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2);
1032914189afSDeren Wu 
1033914189afSDeren Wu 	if (req.tlv.control_ch < req.tlv.center_ch)
1034914189afSDeren Wu 		req.tlv.sco = 1; /* SCA */
1035914189afSDeren Wu 	else if (req.tlv.control_ch > req.tlv.center_ch)
1036914189afSDeren Wu 		req.tlv.sco = 3; /* SCB */
1037914189afSDeren Wu 
1038914189afSDeren Wu 	return mt76_mcu_send_msg(vif->phy->mt76->dev, MCU_UNI_CMD(SNIFFER),
1039914189afSDeren Wu 				 &req, sizeof(req), true);
1040914189afSDeren Wu }
1041914189afSDeren Wu 
1042116c6960SSean Wang int
mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev * dev,struct ieee80211_hw * hw,struct ieee80211_vif * vif,bool enable)1043975e122dSLorenzo Bianconi mt7921_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
1044116c6960SSean Wang 				  struct ieee80211_hw *hw,
1045116c6960SSean Wang 				  struct ieee80211_vif *vif,
1046116c6960SSean Wang 				  bool enable)
1047116c6960SSean Wang {
104815ca8970SLorenzo Bianconi 	struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
1049116c6960SSean Wang 	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
1050116c6960SSean Wang 	struct ieee80211_mutable_offsets offs;
1051116c6960SSean Wang 	struct {
1052116c6960SSean Wang 		struct req_hdr {
1053116c6960SSean Wang 			u8 bss_idx;
1054116c6960SSean Wang 			u8 pad[3];
1055116c6960SSean Wang 		} __packed hdr;
1056116c6960SSean Wang 		struct bcn_content_tlv {
1057116c6960SSean Wang 			__le16 tag;
1058116c6960SSean Wang 			__le16 len;
1059116c6960SSean Wang 			__le16 tim_ie_pos;
1060116c6960SSean Wang 			__le16 csa_ie_pos;
1061116c6960SSean Wang 			__le16 bcc_ie_pos;
1062116c6960SSean Wang 			/* 0: disable beacon offload
1063116c6960SSean Wang 			 * 1: enable beacon offload
1064116c6960SSean Wang 			 * 2: update probe respond offload
1065116c6960SSean Wang 			 */
1066116c6960SSean Wang 			u8 enable;
1067116c6960SSean Wang 			/* 0: legacy format (TXD + payload)
1068116c6960SSean Wang 			 * 1: only cap field IE
1069116c6960SSean Wang 			 */
1070116c6960SSean Wang 			u8 type;
1071116c6960SSean Wang 			__le16 pkt_len;
1072116c6960SSean Wang 			u8 pkt[512];
1073116c6960SSean Wang 		} __packed beacon_tlv;
1074116c6960SSean Wang 	} req = {
1075116c6960SSean Wang 		.hdr = {
1076116c6960SSean Wang 			.bss_idx = mvif->mt76.idx,
1077116c6960SSean Wang 		},
1078116c6960SSean Wang 		.beacon_tlv = {
1079116c6960SSean Wang 			.tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
1080116c6960SSean Wang 			.len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
1081116c6960SSean Wang 			.enable = enable,
1082116c6960SSean Wang 		},
1083116c6960SSean Wang 	};
1084116c6960SSean Wang 	struct sk_buff *skb;
1085116c6960SSean Wang 
1086c149d3a9SDeren Wu 	/* support enable/update process only
1087c149d3a9SDeren Wu 	 * disable flow would be handled in bss stop handler automatically
1088c149d3a9SDeren Wu 	 */
1089116c6960SSean Wang 	if (!enable)
1090c149d3a9SDeren Wu 		return -EOPNOTSUPP;
1091116c6960SSean Wang 
10926e8912a5SShaul Triebitz 	skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs, 0);
1093116c6960SSean Wang 	if (!skb)
1094116c6960SSean Wang 		return -EINVAL;
1095116c6960SSean Wang 
1096116c6960SSean Wang 	if (skb->len > 512 - MT_TXD_SIZE) {
1097116c6960SSean Wang 		dev_err(dev->mt76.dev, "beacon size limit exceed\n");
1098116c6960SSean Wang 		dev_kfree_skb(skb);
1099116c6960SSean Wang 		return -EINVAL;
1100116c6960SSean Wang 	}
1101116c6960SSean Wang 
1102182071cdSLorenzo Bianconi 	mt76_connac2_mac_write_txwi(&dev->mt76, (__le32 *)(req.beacon_tlv.pkt),
11031d5af0acSFelix Fietkau 				    skb, wcid, NULL, 0, 0, BSS_CHANGED_BEACON);
1104116c6960SSean Wang 	memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
1105116c6960SSean Wang 	req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
1106116c6960SSean Wang 	req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
1107116c6960SSean Wang 
1108116c6960SSean Wang 	if (offs.cntdwn_counter_offs[0]) {
1109116c6960SSean Wang 		u16 csa_offs;
1110116c6960SSean Wang 
1111116c6960SSean Wang 		csa_offs = MT_TXD_SIZE + offs.cntdwn_counter_offs[0] - 4;
1112116c6960SSean Wang 		req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
1113116c6960SSean Wang 	}
1114116c6960SSean Wang 	dev_kfree_skb(skb);
1115116c6960SSean Wang 
1116116c6960SSean Wang 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(BSS_INFO_UPDATE),
1117116c6960SSean Wang 				 &req, sizeof(req), true);
1118116c6960SSean Wang }
111923bdc5d8SMing Yen Hsieh 
112023bdc5d8SMing Yen Hsieh static
__mt7921_mcu_set_clc(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap env_cap,struct mt7921_clc * clc,u8 idx)1121975e122dSLorenzo Bianconi int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
112223bdc5d8SMing Yen Hsieh 			 enum environment_cap env_cap,
112323bdc5d8SMing Yen Hsieh 			 struct mt7921_clc *clc,
112423bdc5d8SMing Yen Hsieh 			 u8 idx)
112523bdc5d8SMing Yen Hsieh {
112623bdc5d8SMing Yen Hsieh 	struct sk_buff *skb;
112723bdc5d8SMing Yen Hsieh 	struct {
112823bdc5d8SMing Yen Hsieh 		u8 ver;
112923bdc5d8SMing Yen Hsieh 		u8 pad0;
113023bdc5d8SMing Yen Hsieh 		__le16 len;
113123bdc5d8SMing Yen Hsieh 		u8 idx;
113223bdc5d8SMing Yen Hsieh 		u8 env;
11337176fe65SQuan Zhou 		u8 acpi_conf;
11347176fe65SQuan Zhou 		u8 pad1;
113523bdc5d8SMing Yen Hsieh 		u8 alpha2[2];
113623bdc5d8SMing Yen Hsieh 		u8 type[2];
113723bdc5d8SMing Yen Hsieh 		u8 rsvd[64];
113823bdc5d8SMing Yen Hsieh 	} __packed req = {
1139*15173a16SMing Yen Hsieh 		.ver = 1,
114023bdc5d8SMing Yen Hsieh 		.idx = idx,
114123bdc5d8SMing Yen Hsieh 		.env = env_cap,
114229f5a494SLorenzo Bianconi 		.acpi_conf = mt792x_acpi_get_flags(&dev->phy),
114323bdc5d8SMing Yen Hsieh 	};
114423bdc5d8SMing Yen Hsieh 	int ret, valid_cnt = 0;
1145*15173a16SMing Yen Hsieh 	u16 buf_len = 0;
1146*15173a16SMing Yen Hsieh 	u8 *pos;
114723bdc5d8SMing Yen Hsieh 
114823bdc5d8SMing Yen Hsieh 	if (!clc)
114923bdc5d8SMing Yen Hsieh 		return 0;
115023bdc5d8SMing Yen Hsieh 
1151*15173a16SMing Yen Hsieh 	buf_len = le16_to_cpu(clc->len) - sizeof(*clc);
115223bdc5d8SMing Yen Hsieh 	pos = clc->data;
1153*15173a16SMing Yen Hsieh 	while (buf_len > 16) {
115423bdc5d8SMing Yen Hsieh 		struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos;
115523bdc5d8SMing Yen Hsieh 		u16 len = le16_to_cpu(rule->len);
1156*15173a16SMing Yen Hsieh 		u16 offset = len + sizeof(*rule);
115723bdc5d8SMing Yen Hsieh 
1158*15173a16SMing Yen Hsieh 		pos += offset;
1159*15173a16SMing Yen Hsieh 		buf_len -= offset;
116023bdc5d8SMing Yen Hsieh 		if (rule->alpha2[0] != alpha2[0] ||
116123bdc5d8SMing Yen Hsieh 		    rule->alpha2[1] != alpha2[1])
116223bdc5d8SMing Yen Hsieh 			continue;
116323bdc5d8SMing Yen Hsieh 
116423bdc5d8SMing Yen Hsieh 		memcpy(req.alpha2, rule->alpha2, 2);
116523bdc5d8SMing Yen Hsieh 		memcpy(req.type, rule->type, 2);
116623bdc5d8SMing Yen Hsieh 
116723bdc5d8SMing Yen Hsieh 		req.len = cpu_to_le16(sizeof(req) + len);
116823bdc5d8SMing Yen Hsieh 		skb = __mt76_mcu_msg_alloc(&dev->mt76, &req,
116923bdc5d8SMing Yen Hsieh 					   le16_to_cpu(req.len),
117023bdc5d8SMing Yen Hsieh 					   sizeof(req), GFP_KERNEL);
117123bdc5d8SMing Yen Hsieh 		if (!skb)
117223bdc5d8SMing Yen Hsieh 			return -ENOMEM;
117323bdc5d8SMing Yen Hsieh 		skb_put_data(skb, rule->data, len);
117423bdc5d8SMing Yen Hsieh 
117523bdc5d8SMing Yen Hsieh 		ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
117623bdc5d8SMing Yen Hsieh 					    MCU_CE_CMD(SET_CLC), false);
117723bdc5d8SMing Yen Hsieh 		if (ret < 0)
117823bdc5d8SMing Yen Hsieh 			return ret;
117923bdc5d8SMing Yen Hsieh 		valid_cnt++;
118023bdc5d8SMing Yen Hsieh 	}
118123bdc5d8SMing Yen Hsieh 
118223bdc5d8SMing Yen Hsieh 	if (!valid_cnt)
118323bdc5d8SMing Yen Hsieh 		return -ENOENT;
118423bdc5d8SMing Yen Hsieh 
118523bdc5d8SMing Yen Hsieh 	return 0;
118623bdc5d8SMing Yen Hsieh }
118723bdc5d8SMing Yen Hsieh 
mt7921_mcu_set_clc(struct mt792x_dev * dev,u8 * alpha2,enum environment_cap env_cap)1188975e122dSLorenzo Bianconi int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
118923bdc5d8SMing Yen Hsieh 		       enum environment_cap env_cap)
119023bdc5d8SMing Yen Hsieh {
119178562b2cSLorenzo Bianconi 	struct mt792x_phy *phy = (struct mt792x_phy *)&dev->phy;
119223bdc5d8SMing Yen Hsieh 	int i, ret;
119323bdc5d8SMing Yen Hsieh 
119423bdc5d8SMing Yen Hsieh 	/* submit all clc config */
119523bdc5d8SMing Yen Hsieh 	for (i = 0; i < ARRAY_SIZE(phy->clc); i++) {
119623bdc5d8SMing Yen Hsieh 		ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap,
119723bdc5d8SMing Yen Hsieh 					   phy->clc[i], i);
119823bdc5d8SMing Yen Hsieh 
119923bdc5d8SMing Yen Hsieh 		/* If no country found, set "00" as default */
120023bdc5d8SMing Yen Hsieh 		if (ret == -ENOENT)
120123bdc5d8SMing Yen Hsieh 			ret = __mt7921_mcu_set_clc(dev, "00",
120223bdc5d8SMing Yen Hsieh 						   ENVIRON_INDOOR,
120323bdc5d8SMing Yen Hsieh 						   phy->clc[i], i);
120423bdc5d8SMing Yen Hsieh 		if (ret < 0)
120523bdc5d8SMing Yen Hsieh 			return ret;
120623bdc5d8SMing Yen Hsieh 	}
120723bdc5d8SMing Yen Hsieh 	return 0;
120823bdc5d8SMing Yen Hsieh }
1209c222f77fSNeil Chen 
mt7921_mcu_get_temperature(struct mt792x_phy * phy)121078562b2cSLorenzo Bianconi int mt7921_mcu_get_temperature(struct mt792x_phy *phy)
12116ae39b7cSBen Greear {
1212975e122dSLorenzo Bianconi 	struct mt792x_dev *dev = phy->dev;
12136ae39b7cSBen Greear 	struct {
12146ae39b7cSBen Greear 		u8 ctrl_id;
12156ae39b7cSBen Greear 		u8 action;
12166ae39b7cSBen Greear 		u8 band_idx;
12176ae39b7cSBen Greear 		u8 rsv[5];
12186ae39b7cSBen Greear 	} req = {
12196ae39b7cSBen Greear 		.ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
12206ae39b7cSBen Greear 		.band_idx = phy->mt76->band_idx,
12216ae39b7cSBen Greear 	};
12226ae39b7cSBen Greear 
12236ae39b7cSBen Greear 	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
12246ae39b7cSBen Greear 				 sizeof(req), true);
12256ae39b7cSBen Greear }
12266ae39b7cSBen Greear 
mt7921_mcu_set_rxfilter(struct mt792x_dev * dev,u32 fif,u8 bit_op,u32 bit_map)1227975e122dSLorenzo Bianconi int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
1228c222f77fSNeil Chen 			    u8 bit_op, u32 bit_map)
1229c222f77fSNeil Chen {
1230c222f77fSNeil Chen 	struct {
1231c222f77fSNeil Chen 		u8 rsv[4];
1232c222f77fSNeil Chen 		u8 mode;
1233c222f77fSNeil Chen 		u8 rsv2[3];
1234c222f77fSNeil Chen 		__le32 fif;
1235c222f77fSNeil Chen 		__le32 bit_map; /* bit_* for bitmap update */
1236c222f77fSNeil Chen 		u8 bit_op;
1237c222f77fSNeil Chen 		u8 pad[51];
1238c222f77fSNeil Chen 	} __packed data = {
1239c222f77fSNeil Chen 		.mode = fif ? 1 : 2,
1240c222f77fSNeil Chen 		.fif = cpu_to_le32(fif),
1241c222f77fSNeil Chen 		.bit_map = cpu_to_le32(bit_map),
1242c222f77fSNeil Chen 		.bit_op = bit_op,
1243c222f77fSNeil Chen 	};
1244c222f77fSNeil Chen 
1245c222f77fSNeil Chen 	return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_RX_FILTER),
1246c222f77fSNeil Chen 				 &data, sizeof(data), false);
1247c222f77fSNeil Chen }
1248