162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/etherdevice.h>
562306a36Sopenharmony_ci#include <linux/timekeeping.h>
662306a36Sopenharmony_ci#include "coredump.h"
762306a36Sopenharmony_ci#include "mt7915.h"
862306a36Sopenharmony_ci#include "../dma.h"
962306a36Sopenharmony_ci#include "mac.h"
1062306a36Sopenharmony_ci#include "mcu.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define to_rssi(field, rcpi)	((FIELD_GET(field, rcpi) - 220) / 2)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic const struct mt7915_dfs_radar_spec etsi_radar_specs = {
1562306a36Sopenharmony_ci	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
1662306a36Sopenharmony_ci	.radar_pattern = {
1762306a36Sopenharmony_ci		[5] =  { 1, 0,  6, 32, 28, 0,  990, 5010, 17, 1, 1 },
1862306a36Sopenharmony_ci		[6] =  { 1, 0,  9, 32, 28, 0,  615, 5010, 27, 1, 1 },
1962306a36Sopenharmony_ci		[7] =  { 1, 0, 15, 32, 28, 0,  240,  445, 27, 1, 1 },
2062306a36Sopenharmony_ci		[8] =  { 1, 0, 12, 32, 28, 0,  240,  510, 42, 1, 1 },
2162306a36Sopenharmony_ci		[9] =  { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
2262306a36Sopenharmony_ci		[10] = { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
2362306a36Sopenharmony_ci		[11] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 18, 32, 28, { },  54 },
2462306a36Sopenharmony_ci		[12] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 27, 32, 24, { },  54 },
2562306a36Sopenharmony_ci	},
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic const struct mt7915_dfs_radar_spec fcc_radar_specs = {
2962306a36Sopenharmony_ci	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
3062306a36Sopenharmony_ci	.radar_pattern = {
3162306a36Sopenharmony_ci		[0] = { 1, 0,  8,  32, 28, 0, 508, 3076, 13, 1,  1 },
3262306a36Sopenharmony_ci		[1] = { 1, 0, 12,  32, 28, 0, 140,  240, 17, 1,  1 },
3362306a36Sopenharmony_ci		[2] = { 1, 0,  8,  32, 28, 0, 190,  510, 22, 1,  1 },
3462306a36Sopenharmony_ci		[3] = { 1, 0,  6,  32, 28, 0, 190,  510, 32, 1,  1 },
3562306a36Sopenharmony_ci		[4] = { 1, 0,  9, 255, 28, 0, 323,  343, 13, 1, 32 },
3662306a36Sopenharmony_ci	},
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const struct mt7915_dfs_radar_spec jp_radar_specs = {
4062306a36Sopenharmony_ci	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
4162306a36Sopenharmony_ci	.radar_pattern = {
4262306a36Sopenharmony_ci		[0] =  { 1, 0,  8,  32, 28, 0,  508, 3076,  13, 1,  1 },
4362306a36Sopenharmony_ci		[1] =  { 1, 0, 12,  32, 28, 0,  140,  240,  17, 1,  1 },
4462306a36Sopenharmony_ci		[2] =  { 1, 0,  8,  32, 28, 0,  190,  510,  22, 1,  1 },
4562306a36Sopenharmony_ci		[3] =  { 1, 0,  6,  32, 28, 0,  190,  510,  32, 1,  1 },
4662306a36Sopenharmony_ci		[4] =  { 1, 0,  9, 255, 28, 0,  323,  343,  13, 1, 32 },
4762306a36Sopenharmony_ci		[13] = { 1, 0,  7,  32, 28, 0, 3836, 3856,  14, 1,  1 },
4862306a36Sopenharmony_ci		[14] = { 1, 0,  6,  32, 28, 0,  615, 5010, 110, 1,  1 },
4962306a36Sopenharmony_ci		[15] = { 1, 1,  0,   0,  0, 0,   15, 5010, 110, 0,  0, 12, 32, 28 },
5062306a36Sopenharmony_ci	},
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic struct mt76_wcid *mt7915_rx_get_wcid(struct mt7915_dev *dev,
5462306a36Sopenharmony_ci					    u16 idx, bool unicast)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct mt7915_sta *sta;
5762306a36Sopenharmony_ci	struct mt76_wcid *wcid;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (idx >= ARRAY_SIZE(dev->mt76.wcid))
6062306a36Sopenharmony_ci		return NULL;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[idx]);
6362306a36Sopenharmony_ci	if (unicast || !wcid)
6462306a36Sopenharmony_ci		return wcid;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (!wcid->sta)
6762306a36Sopenharmony_ci		return NULL;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	sta = container_of(wcid, struct mt7915_sta, wcid);
7062306a36Sopenharmony_ci	if (!sta->vif)
7162306a36Sopenharmony_ci		return NULL;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return &sta->vif->sta.wcid;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cibool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
7962306a36Sopenharmony_ci		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
8262306a36Sopenharmony_ci			 0, 5000);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciu32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
8862306a36Sopenharmony_ci		FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return MT_WTBL_LMAC_OFFS(wcid, dw);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void mt7915_mac_sta_poll(struct mt7915_dev *dev)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	static const u8 ac_to_tid[] = {
9662306a36Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
9762306a36Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
9862306a36Sopenharmony_ci		[IEEE80211_AC_VI] = 4,
9962306a36Sopenharmony_ci		[IEEE80211_AC_VO] = 6
10062306a36Sopenharmony_ci	};
10162306a36Sopenharmony_ci	struct ieee80211_sta *sta;
10262306a36Sopenharmony_ci	struct mt7915_sta *msta;
10362306a36Sopenharmony_ci	struct rate_info *rate;
10462306a36Sopenharmony_ci	u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
10562306a36Sopenharmony_ci	LIST_HEAD(sta_poll_list);
10662306a36Sopenharmony_ci	int i;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.sta_poll_lock);
10962306a36Sopenharmony_ci	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
11062306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.sta_poll_lock);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	rcu_read_lock();
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	while (true) {
11562306a36Sopenharmony_ci		bool clear = false;
11662306a36Sopenharmony_ci		u32 addr, val;
11762306a36Sopenharmony_ci		u16 idx;
11862306a36Sopenharmony_ci		s8 rssi[4];
11962306a36Sopenharmony_ci		u8 bw;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
12262306a36Sopenharmony_ci		if (list_empty(&sta_poll_list)) {
12362306a36Sopenharmony_ci			spin_unlock_bh(&dev->mt76.sta_poll_lock);
12462306a36Sopenharmony_ci			break;
12562306a36Sopenharmony_ci		}
12662306a36Sopenharmony_ci		msta = list_first_entry(&sta_poll_list,
12762306a36Sopenharmony_ci					struct mt7915_sta, wcid.poll_list);
12862306a36Sopenharmony_ci		list_del_init(&msta->wcid.poll_list);
12962306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		idx = msta->wcid.idx;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		/* refresh peer's airtime reporting */
13462306a36Sopenharmony_ci		addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 20);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
13762306a36Sopenharmony_ci			u32 tx_last = msta->airtime_ac[i];
13862306a36Sopenharmony_ci			u32 rx_last = msta->airtime_ac[i + 4];
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci			msta->airtime_ac[i] = mt76_rr(dev, addr);
14162306a36Sopenharmony_ci			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci			tx_time[i] = msta->airtime_ac[i] - tx_last;
14462306a36Sopenharmony_ci			rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci			if ((tx_last | rx_last) & BIT(30))
14762306a36Sopenharmony_ci				clear = true;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci			addr += 8;
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci		if (clear) {
15362306a36Sopenharmony_ci			mt7915_mac_wtbl_update(dev, idx,
15462306a36Sopenharmony_ci					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
15562306a36Sopenharmony_ci			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		if (!msta->wcid.sta)
15962306a36Sopenharmony_ci			continue;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		sta = container_of((void *)msta, struct ieee80211_sta,
16262306a36Sopenharmony_ci				   drv_priv);
16362306a36Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
16462306a36Sopenharmony_ci			u8 queue = mt76_connac_lmac_mapping(i);
16562306a36Sopenharmony_ci			u32 tx_cur = tx_time[queue];
16662306a36Sopenharmony_ci			u32 rx_cur = rx_time[queue];
16762306a36Sopenharmony_ci			u8 tid = ac_to_tid[i];
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci			if (!tx_cur && !rx_cur)
17062306a36Sopenharmony_ci				continue;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			ieee80211_sta_register_airtime(sta, tid, tx_cur,
17362306a36Sopenharmony_ci						       rx_cur);
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		/*
17762306a36Sopenharmony_ci		 * We don't support reading GI info from txs packets.
17862306a36Sopenharmony_ci		 * For accurate tx status reporting and AQL improvement,
17962306a36Sopenharmony_ci		 * we need to make sure that flags match so polling GI
18062306a36Sopenharmony_ci		 * from per-sta counters directly.
18162306a36Sopenharmony_ci		 */
18262306a36Sopenharmony_ci		rate = &msta->wcid.rate;
18362306a36Sopenharmony_ci		addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 7);
18462306a36Sopenharmony_ci		val = mt76_rr(dev, addr);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		switch (rate->bw) {
18762306a36Sopenharmony_ci		case RATE_INFO_BW_160:
18862306a36Sopenharmony_ci			bw = IEEE80211_STA_RX_BW_160;
18962306a36Sopenharmony_ci			break;
19062306a36Sopenharmony_ci		case RATE_INFO_BW_80:
19162306a36Sopenharmony_ci			bw = IEEE80211_STA_RX_BW_80;
19262306a36Sopenharmony_ci			break;
19362306a36Sopenharmony_ci		case RATE_INFO_BW_40:
19462306a36Sopenharmony_ci			bw = IEEE80211_STA_RX_BW_40;
19562306a36Sopenharmony_ci			break;
19662306a36Sopenharmony_ci		default:
19762306a36Sopenharmony_ci			bw = IEEE80211_STA_RX_BW_20;
19862306a36Sopenharmony_ci			break;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
20262306a36Sopenharmony_ci			u8 offs = 24 + 2 * bw;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci			rate->he_gi = (val & (0x3 << offs)) >> offs;
20562306a36Sopenharmony_ci		} else if (rate->flags &
20662306a36Sopenharmony_ci			   (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
20762306a36Sopenharmony_ci			if (val & BIT(12 + bw))
20862306a36Sopenharmony_ci				rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
20962306a36Sopenharmony_ci			else
21062306a36Sopenharmony_ci				rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
21162306a36Sopenharmony_ci		}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		/* get signal strength of resp frames (CTS/BA/ACK) */
21462306a36Sopenharmony_ci		addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 30);
21562306a36Sopenharmony_ci		val = mt76_rr(dev, addr);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		rssi[0] = to_rssi(GENMASK(7, 0), val);
21862306a36Sopenharmony_ci		rssi[1] = to_rssi(GENMASK(15, 8), val);
21962306a36Sopenharmony_ci		rssi[2] = to_rssi(GENMASK(23, 16), val);
22062306a36Sopenharmony_ci		rssi[3] = to_rssi(GENMASK(31, 14), val);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		msta->ack_signal =
22362306a36Sopenharmony_ci			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	rcu_read_unlock();
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_civoid mt7915_mac_enable_rtscts(struct mt7915_dev *dev,
23262306a36Sopenharmony_ci			      struct ieee80211_vif *vif, bool enable)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
23562306a36Sopenharmony_ci	u32 addr;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
23862306a36Sopenharmony_ci	if (enable)
23962306a36Sopenharmony_ci		mt76_set(dev, addr, BIT(5));
24062306a36Sopenharmony_ci	else
24162306a36Sopenharmony_ci		mt76_clear(dev, addr, BIT(5));
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic void
24562306a36Sopenharmony_cimt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q,
24662306a36Sopenharmony_ci		     struct mt7915_sta *msta, struct sk_buff *skb,
24762306a36Sopenharmony_ci		     u32 info)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct ieee80211_vif *vif;
25062306a36Sopenharmony_ci	struct wireless_dev *wdev;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (!msta || !msta->vif)
25362306a36Sopenharmony_ci		return;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (!mt76_queue_is_wed_rx(q))
25662306a36Sopenharmony_ci		return;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if (!(info & MT_DMA_INFO_PPE_VLD))
25962306a36Sopenharmony_ci		return;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	vif = container_of((void *)msta->vif, struct ieee80211_vif,
26262306a36Sopenharmony_ci			   drv_priv);
26362306a36Sopenharmony_ci	wdev = ieee80211_vif_to_wdev(vif);
26462306a36Sopenharmony_ci	skb->dev = wdev->netdev;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb,
26762306a36Sopenharmony_ci				 FIELD_GET(MT_DMA_PPE_CPU_REASON, info),
26862306a36Sopenharmony_ci				 FIELD_GET(MT_DMA_PPE_ENTRY, info));
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int
27262306a36Sopenharmony_cimt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
27362306a36Sopenharmony_ci		   enum mt76_rxq_id q, u32 *info)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
27662306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
27762306a36Sopenharmony_ci	struct mt7915_phy *phy = &dev->phy;
27862306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
27962306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
28062306a36Sopenharmony_ci	__le32 *rxv = NULL;
28162306a36Sopenharmony_ci	u32 rxd0 = le32_to_cpu(rxd[0]);
28262306a36Sopenharmony_ci	u32 rxd1 = le32_to_cpu(rxd[1]);
28362306a36Sopenharmony_ci	u32 rxd2 = le32_to_cpu(rxd[2]);
28462306a36Sopenharmony_ci	u32 rxd3 = le32_to_cpu(rxd[3]);
28562306a36Sopenharmony_ci	u32 rxd4 = le32_to_cpu(rxd[4]);
28662306a36Sopenharmony_ci	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
28762306a36Sopenharmony_ci	bool unicast, insert_ccmp_hdr = false;
28862306a36Sopenharmony_ci	u8 remove_pad, amsdu_info;
28962306a36Sopenharmony_ci	u8 mode = 0, qos_ctl = 0;
29062306a36Sopenharmony_ci	struct mt7915_sta *msta = NULL;
29162306a36Sopenharmony_ci	u32 csum_status = *(u32 *)skb->cb;
29262306a36Sopenharmony_ci	bool hdr_trans;
29362306a36Sopenharmony_ci	u16 hdr_gap;
29462306a36Sopenharmony_ci	u16 seq_ctrl = 0;
29562306a36Sopenharmony_ci	__le16 fc = 0;
29662306a36Sopenharmony_ci	int idx;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	memset(status, 0, sizeof(*status));
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->mt76->band_idx) {
30162306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
30262306a36Sopenharmony_ci		if (!mphy)
30362306a36Sopenharmony_ci			return -EINVAL;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		phy = mphy->priv;
30662306a36Sopenharmony_ci		status->phy_idx = 1;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
31062306a36Sopenharmony_ci		return -EINVAL;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
31362306a36Sopenharmony_ci		return -EINVAL;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
31662306a36Sopenharmony_ci	if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
31762306a36Sopenharmony_ci		return -EINVAL;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* ICV error or CCMP/BIP/WPI MIC error */
32062306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
32162306a36Sopenharmony_ci		status->flag |= RX_FLAG_ONLY_MONITOR;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
32462306a36Sopenharmony_ci	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
32562306a36Sopenharmony_ci	status->wcid = mt7915_rx_get_wcid(dev, idx, unicast);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (status->wcid) {
32862306a36Sopenharmony_ci		msta = container_of(status->wcid, struct mt7915_sta, wcid);
32962306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
33062306a36Sopenharmony_ci		if (list_empty(&msta->wcid.poll_list))
33162306a36Sopenharmony_ci			list_add_tail(&msta->wcid.poll_list,
33262306a36Sopenharmony_ci				      &dev->mt76.sta_poll_list);
33362306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	status->freq = mphy->chandef.chan->center_freq;
33762306a36Sopenharmony_ci	status->band = mphy->chandef.chan->band;
33862306a36Sopenharmony_ci	if (status->band == NL80211_BAND_5GHZ)
33962306a36Sopenharmony_ci		sband = &mphy->sband_5g.sband;
34062306a36Sopenharmony_ci	else if (status->band == NL80211_BAND_6GHZ)
34162306a36Sopenharmony_ci		sband = &mphy->sband_6g.sband;
34262306a36Sopenharmony_ci	else
34362306a36Sopenharmony_ci		sband = &mphy->sband_2g.sband;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (!sband->channels)
34662306a36Sopenharmony_ci		return -EINVAL;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if ((rxd0 & csum_mask) == csum_mask &&
34962306a36Sopenharmony_ci	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
35062306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_FCS_ERR)
35362306a36Sopenharmony_ci		status->flag |= RX_FLAG_FAILED_FCS_CRC;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
35662306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_ERROR;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1) != 0 &&
35962306a36Sopenharmony_ci	    !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
36062306a36Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
36162306a36Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
36262306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
36862306a36Sopenharmony_ci		return -EINVAL;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	rxd += 6;
37162306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
37262306a36Sopenharmony_ci		u32 v0 = le32_to_cpu(rxd[0]);
37362306a36Sopenharmony_ci		u32 v2 = le32_to_cpu(rxd[2]);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		fc = cpu_to_le16(FIELD_GET(MT_RXD6_FRAME_CONTROL, v0));
37662306a36Sopenharmony_ci		qos_ctl = FIELD_GET(MT_RXD8_QOS_CTL, v2);
37762306a36Sopenharmony_ci		seq_ctrl = FIELD_GET(MT_RXD8_SEQ_CTRL, v2);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		rxd += 4;
38062306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
38162306a36Sopenharmony_ci			return -EINVAL;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
38562306a36Sopenharmony_ci		u8 *data = (u8 *)rxd;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		if (status->flag & RX_FLAG_DECRYPTED) {
38862306a36Sopenharmony_ci			switch (FIELD_GET(MT_RXD1_NORMAL_SEC_MODE, rxd1)) {
38962306a36Sopenharmony_ci			case MT_CIPHER_AES_CCMP:
39062306a36Sopenharmony_ci			case MT_CIPHER_CCMP_CCX:
39162306a36Sopenharmony_ci			case MT_CIPHER_CCMP_256:
39262306a36Sopenharmony_ci				insert_ccmp_hdr =
39362306a36Sopenharmony_ci					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
39462306a36Sopenharmony_ci				fallthrough;
39562306a36Sopenharmony_ci			case MT_CIPHER_TKIP:
39662306a36Sopenharmony_ci			case MT_CIPHER_TKIP_NO_MIC:
39762306a36Sopenharmony_ci			case MT_CIPHER_GCMP:
39862306a36Sopenharmony_ci			case MT_CIPHER_GCMP_256:
39962306a36Sopenharmony_ci				status->iv[0] = data[5];
40062306a36Sopenharmony_ci				status->iv[1] = data[4];
40162306a36Sopenharmony_ci				status->iv[2] = data[3];
40262306a36Sopenharmony_ci				status->iv[3] = data[2];
40362306a36Sopenharmony_ci				status->iv[4] = data[1];
40462306a36Sopenharmony_ci				status->iv[5] = data[0];
40562306a36Sopenharmony_ci				break;
40662306a36Sopenharmony_ci			default:
40762306a36Sopenharmony_ci				break;
40862306a36Sopenharmony_ci			}
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci		rxd += 4;
41162306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
41262306a36Sopenharmony_ci			return -EINVAL;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
41662306a36Sopenharmony_ci		status->timestamp = le32_to_cpu(rxd[0]);
41762306a36Sopenharmony_ci		status->flag |= RX_FLAG_MACTIME_START;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
42062306a36Sopenharmony_ci			status->flag |= RX_FLAG_AMPDU_DETAILS;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci			/* all subframes of an A-MPDU have the same timestamp */
42362306a36Sopenharmony_ci			if (phy->rx_ampdu_ts != status->timestamp) {
42462306a36Sopenharmony_ci				if (!++phy->ampdu_ref)
42562306a36Sopenharmony_ci					phy->ampdu_ref++;
42662306a36Sopenharmony_ci			}
42762306a36Sopenharmony_ci			phy->rx_ampdu_ts = status->timestamp;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci			status->ampdu_ref = phy->ampdu_ref;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		rxd += 2;
43362306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
43462306a36Sopenharmony_ci			return -EINVAL;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	/* RXD Group 3 - P-RXV */
43862306a36Sopenharmony_ci	if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
43962306a36Sopenharmony_ci		u32 v0, v1;
44062306a36Sopenharmony_ci		int ret;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		rxv = rxd;
44362306a36Sopenharmony_ci		rxd += 2;
44462306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
44562306a36Sopenharmony_ci			return -EINVAL;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci		v0 = le32_to_cpu(rxv[0]);
44862306a36Sopenharmony_ci		v1 = le32_to_cpu(rxv[1]);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		if (v0 & MT_PRXV_HT_AD_CODE)
45162306a36Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_LDPC;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		status->chains = mphy->antenna_mask;
45462306a36Sopenharmony_ci		status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1);
45562306a36Sopenharmony_ci		status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1);
45662306a36Sopenharmony_ci		status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1);
45762306a36Sopenharmony_ci		status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		/* RXD Group 5 - C-RXV */
46062306a36Sopenharmony_ci		if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
46162306a36Sopenharmony_ci			rxd += 18;
46262306a36Sopenharmony_ci			if ((u8 *)rxd - skb->data >= skb->len)
46362306a36Sopenharmony_ci				return -EINVAL;
46462306a36Sopenharmony_ci		}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci		if (!is_mt7915(&dev->mt76) || (rxd1 & MT_RXD1_NORMAL_GROUP_5)) {
46762306a36Sopenharmony_ci			ret = mt76_connac2_mac_fill_rx_rate(&dev->mt76, status,
46862306a36Sopenharmony_ci							    sband, rxv, &mode);
46962306a36Sopenharmony_ci			if (ret < 0)
47062306a36Sopenharmony_ci				return ret;
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
47562306a36Sopenharmony_ci	status->amsdu = !!amsdu_info;
47662306a36Sopenharmony_ci	if (status->amsdu) {
47762306a36Sopenharmony_ci		status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
47862306a36Sopenharmony_ci		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
48262306a36Sopenharmony_ci	if (hdr_trans && ieee80211_has_morefrags(fc)) {
48362306a36Sopenharmony_ci		struct ieee80211_vif *vif;
48462306a36Sopenharmony_ci		int err;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		if (!msta || !msta->vif)
48762306a36Sopenharmony_ci			return -EINVAL;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		vif = container_of((void *)msta->vif, struct ieee80211_vif,
49062306a36Sopenharmony_ci				   drv_priv);
49162306a36Sopenharmony_ci		err = mt76_connac2_reverse_frag0_hdr_trans(vif, skb, hdr_gap);
49262306a36Sopenharmony_ci		if (err)
49362306a36Sopenharmony_ci			return err;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		hdr_trans = false;
49662306a36Sopenharmony_ci	} else {
49762306a36Sopenharmony_ci		int pad_start = 0;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		skb_pull(skb, hdr_gap);
50062306a36Sopenharmony_ci		if (!hdr_trans && status->amsdu) {
50162306a36Sopenharmony_ci			pad_start = ieee80211_get_hdrlen_from_skb(skb);
50262306a36Sopenharmony_ci		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
50362306a36Sopenharmony_ci			/*
50462306a36Sopenharmony_ci			 * When header translation failure is indicated,
50562306a36Sopenharmony_ci			 * the hardware will insert an extra 2-byte field
50662306a36Sopenharmony_ci			 * containing the data length after the protocol
50762306a36Sopenharmony_ci			 * type field. This happens either when the LLC-SNAP
50862306a36Sopenharmony_ci			 * pattern did not match, or if a VLAN header was
50962306a36Sopenharmony_ci			 * detected.
51062306a36Sopenharmony_ci			 */
51162306a36Sopenharmony_ci			pad_start = 12;
51262306a36Sopenharmony_ci			if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
51362306a36Sopenharmony_ci				pad_start += 4;
51462306a36Sopenharmony_ci			else
51562306a36Sopenharmony_ci				pad_start = 0;
51662306a36Sopenharmony_ci		}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		if (pad_start) {
51962306a36Sopenharmony_ci			memmove(skb->data + 2, skb->data, pad_start);
52062306a36Sopenharmony_ci			skb_pull(skb, 2);
52162306a36Sopenharmony_ci		}
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (!hdr_trans) {
52562306a36Sopenharmony_ci		struct ieee80211_hdr *hdr;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		if (insert_ccmp_hdr) {
52862306a36Sopenharmony_ci			u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci			mt76_insert_ccmp_hdr(skb, key_id);
53162306a36Sopenharmony_ci		}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		hdr = mt76_skb_get_hdr(skb);
53462306a36Sopenharmony_ci		fc = hdr->frame_control;
53562306a36Sopenharmony_ci		if (ieee80211_is_data_qos(fc)) {
53662306a36Sopenharmony_ci			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
53762306a36Sopenharmony_ci			qos_ctl = *ieee80211_get_qos_ctl(hdr);
53862306a36Sopenharmony_ci		}
53962306a36Sopenharmony_ci	} else {
54062306a36Sopenharmony_ci		status->flag |= RX_FLAG_8023;
54162306a36Sopenharmony_ci		mt7915_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb,
54262306a36Sopenharmony_ci				     *info);
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
54662306a36Sopenharmony_ci		mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv, mode);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (!status->wcid || !ieee80211_is_data_qos(fc))
54962306a36Sopenharmony_ci		return 0;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	status->aggr = unicast &&
55262306a36Sopenharmony_ci		       !ieee80211_is_qos_nullfunc(fc);
55362306a36Sopenharmony_ci	status->qos_ctl = qos_ctl;
55462306a36Sopenharmony_ci	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	return 0;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void
56062306a36Sopenharmony_cimt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
56362306a36Sopenharmony_ci	struct mt7915_phy *phy = &dev->phy;
56462306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
56562306a36Sopenharmony_ci	__le32 *rxv_hdr = rxd + 2;
56662306a36Sopenharmony_ci	__le32 *rxv = rxd + 4;
56762306a36Sopenharmony_ci	u32 rcpi, ib_rssi, wb_rssi, v20, v21;
56862306a36Sopenharmony_ci	u8 band_idx;
56962306a36Sopenharmony_ci	s32 foe;
57062306a36Sopenharmony_ci	u8 snr;
57162306a36Sopenharmony_ci	int i;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	band_idx = le32_get_bits(rxv_hdr[1], MT_RXV_HDR_BAND_IDX);
57462306a36Sopenharmony_ci	if (band_idx && !phy->mt76->band_idx) {
57562306a36Sopenharmony_ci		phy = mt7915_ext_phy(dev);
57662306a36Sopenharmony_ci		if (!phy)
57762306a36Sopenharmony_ci			goto out;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	rcpi = le32_to_cpu(rxv[6]);
58162306a36Sopenharmony_ci	ib_rssi = le32_to_cpu(rxv[7]);
58262306a36Sopenharmony_ci	wb_rssi = le32_to_cpu(rxv[8]) >> 5;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	for (i = 0; i < 4; i++, rcpi >>= 8, ib_rssi >>= 8, wb_rssi >>= 9) {
58562306a36Sopenharmony_ci		if (i == 3)
58662306a36Sopenharmony_ci			wb_rssi = le32_to_cpu(rxv[9]);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		phy->test.last_rcpi[i] = rcpi & 0xff;
58962306a36Sopenharmony_ci		phy->test.last_ib_rssi[i] = ib_rssi & 0xff;
59062306a36Sopenharmony_ci		phy->test.last_wb_rssi[i] = wb_rssi & 0xff;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	v20 = le32_to_cpu(rxv[20]);
59462306a36Sopenharmony_ci	v21 = le32_to_cpu(rxv[21]);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	foe = FIELD_GET(MT_CRXV_FOE_LO, v20) |
59762306a36Sopenharmony_ci	      (FIELD_GET(MT_CRXV_FOE_HI, v21) << MT_CRXV_FOE_SHIFT);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	snr = FIELD_GET(MT_CRXV_SNR, v20) - 16;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	phy->test.last_freq_offset = foe;
60262306a36Sopenharmony_ci	phy->test.last_snr = snr;
60362306a36Sopenharmony_ciout:
60462306a36Sopenharmony_ci#endif
60562306a36Sopenharmony_ci	dev_kfree_skb(skb);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic void
60962306a36Sopenharmony_cimt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
61062306a36Sopenharmony_ci			 struct sk_buff *skb)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
61362306a36Sopenharmony_ci	struct mt76_testmode_data *td = &phy->mt76->test;
61462306a36Sopenharmony_ci	const struct ieee80211_rate *r;
61562306a36Sopenharmony_ci	u8 bw, mode, nss = td->tx_rate_nss;
61662306a36Sopenharmony_ci	u8 rate_idx = td->tx_rate_idx;
61762306a36Sopenharmony_ci	u16 rateval = 0;
61862306a36Sopenharmony_ci	u32 val;
61962306a36Sopenharmony_ci	bool cck = false;
62062306a36Sopenharmony_ci	int band;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (skb != phy->mt76->test.tx_skb)
62362306a36Sopenharmony_ci		return;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	switch (td->tx_rate_mode) {
62662306a36Sopenharmony_ci	case MT76_TM_TX_MODE_HT:
62762306a36Sopenharmony_ci		nss = 1 + (rate_idx >> 3);
62862306a36Sopenharmony_ci		mode = MT_PHY_TYPE_HT;
62962306a36Sopenharmony_ci		break;
63062306a36Sopenharmony_ci	case MT76_TM_TX_MODE_VHT:
63162306a36Sopenharmony_ci		mode = MT_PHY_TYPE_VHT;
63262306a36Sopenharmony_ci		break;
63362306a36Sopenharmony_ci	case MT76_TM_TX_MODE_HE_SU:
63462306a36Sopenharmony_ci		mode = MT_PHY_TYPE_HE_SU;
63562306a36Sopenharmony_ci		break;
63662306a36Sopenharmony_ci	case MT76_TM_TX_MODE_HE_EXT_SU:
63762306a36Sopenharmony_ci		mode = MT_PHY_TYPE_HE_EXT_SU;
63862306a36Sopenharmony_ci		break;
63962306a36Sopenharmony_ci	case MT76_TM_TX_MODE_HE_TB:
64062306a36Sopenharmony_ci		mode = MT_PHY_TYPE_HE_TB;
64162306a36Sopenharmony_ci		break;
64262306a36Sopenharmony_ci	case MT76_TM_TX_MODE_HE_MU:
64362306a36Sopenharmony_ci		mode = MT_PHY_TYPE_HE_MU;
64462306a36Sopenharmony_ci		break;
64562306a36Sopenharmony_ci	case MT76_TM_TX_MODE_CCK:
64662306a36Sopenharmony_ci		cck = true;
64762306a36Sopenharmony_ci		fallthrough;
64862306a36Sopenharmony_ci	case MT76_TM_TX_MODE_OFDM:
64962306a36Sopenharmony_ci		band = phy->mt76->chandef.chan->band;
65062306a36Sopenharmony_ci		if (band == NL80211_BAND_2GHZ && !cck)
65162306a36Sopenharmony_ci			rate_idx += 4;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		r = &phy->mt76->hw->wiphy->bands[band]->bitrates[rate_idx];
65462306a36Sopenharmony_ci		val = cck ? r->hw_value_short : r->hw_value;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci		mode = val >> 8;
65762306a36Sopenharmony_ci		rate_idx = val & 0xff;
65862306a36Sopenharmony_ci		break;
65962306a36Sopenharmony_ci	default:
66062306a36Sopenharmony_ci		mode = MT_PHY_TYPE_OFDM;
66162306a36Sopenharmony_ci		break;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	switch (phy->mt76->chandef.width) {
66562306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_40:
66662306a36Sopenharmony_ci		bw = 1;
66762306a36Sopenharmony_ci		break;
66862306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_80:
66962306a36Sopenharmony_ci		bw = 2;
67062306a36Sopenharmony_ci		break;
67162306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_80P80:
67262306a36Sopenharmony_ci	case NL80211_CHAN_WIDTH_160:
67362306a36Sopenharmony_ci		bw = 3;
67462306a36Sopenharmony_ci		break;
67562306a36Sopenharmony_ci	default:
67662306a36Sopenharmony_ci		bw = 0;
67762306a36Sopenharmony_ci		break;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (td->tx_rate_stbc && nss == 1) {
68162306a36Sopenharmony_ci		nss++;
68262306a36Sopenharmony_ci		rateval |= MT_TX_RATE_STBC;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	rateval |= FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
68662306a36Sopenharmony_ci		   FIELD_PREP(MT_TX_RATE_MODE, mode) |
68762306a36Sopenharmony_ci		   FIELD_PREP(MT_TX_RATE_NSS, nss - 1);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	le32p_replace_bits(&txwi[3], 1, MT_TXD3_REM_TX_COUNT);
69262306a36Sopenharmony_ci	if (td->tx_rate_mode < MT76_TM_TX_MODE_HT)
69362306a36Sopenharmony_ci		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	val = MT_TXD6_FIXED_BW |
69662306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD6_BW, bw) |
69762306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD6_TX_RATE, rateval) |
69862306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD6_SGI, td->tx_rate_sgi);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	/* for HE_SU/HE_EXT_SU PPDU
70162306a36Sopenharmony_ci	 * - 1x, 2x, 4x LTF + 0.8us GI
70262306a36Sopenharmony_ci	 * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
70362306a36Sopenharmony_ci	 * for HE_MU PPDU
70462306a36Sopenharmony_ci	 * - 2x, 4x LTF + 0.8us GI
70562306a36Sopenharmony_ci	 * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
70662306a36Sopenharmony_ci	 * for HE_TB PPDU
70762306a36Sopenharmony_ci	 * - 1x, 2x LTF + 1.6us GI
70862306a36Sopenharmony_ci	 * - 4x LTF + 3.2us GI
70962306a36Sopenharmony_ci	 */
71062306a36Sopenharmony_ci	if (mode >= MT_PHY_TYPE_HE_SU)
71162306a36Sopenharmony_ci		val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU))
71462306a36Sopenharmony_ci		val |= MT_TXD6_LDPC;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	txwi[3] &= ~cpu_to_le32(MT_TXD3_SN_VALID);
71762306a36Sopenharmony_ci	txwi[6] |= cpu_to_le32(val);
71862306a36Sopenharmony_ci	txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX,
71962306a36Sopenharmony_ci					  phy->test.spe_idx));
72062306a36Sopenharmony_ci#endif
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_civoid mt7915_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
72462306a36Sopenharmony_ci			   struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
72562306a36Sopenharmony_ci			   struct ieee80211_key_conf *key,
72662306a36Sopenharmony_ci			   enum mt76_txq_id qid, u32 changed)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
72962306a36Sopenharmony_ci	u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
73062306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->phy;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (phy_idx && dev->phys[MT_BAND1])
73362306a36Sopenharmony_ci		mphy = dev->phys[MT_BAND1];
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	mt76_connac2_mac_write_txwi(dev, txwi, skb, wcid, key, pid, qid, changed);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	if (mt76_testmode_enabled(mphy))
73862306a36Sopenharmony_ci		mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ciint mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
74262306a36Sopenharmony_ci			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
74362306a36Sopenharmony_ci			  struct ieee80211_sta *sta,
74462306a36Sopenharmony_ci			  struct mt76_tx_info *tx_info)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
74762306a36Sopenharmony_ci	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
74862306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
74962306a36Sopenharmony_ci	struct ieee80211_key_conf *key = info->control.hw_key;
75062306a36Sopenharmony_ci	struct ieee80211_vif *vif = info->control.vif;
75162306a36Sopenharmony_ci	struct mt76_connac_fw_txp *txp;
75262306a36Sopenharmony_ci	struct mt76_txwi_cache *t;
75362306a36Sopenharmony_ci	int id, i, nbuf = tx_info->nbuf - 1;
75462306a36Sopenharmony_ci	u8 *txwi = (u8 *)txwi_ptr;
75562306a36Sopenharmony_ci	int pid;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (unlikely(tx_info->skb->len <= ETH_HLEN))
75862306a36Sopenharmony_ci		return -EINVAL;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (!wcid)
76162306a36Sopenharmony_ci		wcid = &dev->mt76.global_wcid;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (sta) {
76462306a36Sopenharmony_ci		struct mt7915_sta *msta;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		msta = (struct mt7915_sta *)sta->drv_priv;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci		if (time_after(jiffies, msta->jiffies + HZ / 4)) {
76962306a36Sopenharmony_ci			info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
77062306a36Sopenharmony_ci			msta->jiffies = jiffies;
77162306a36Sopenharmony_ci		}
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
77562306a36Sopenharmony_ci	t->skb = tx_info->skb;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	id = mt76_token_consume(mdev, &t);
77862306a36Sopenharmony_ci	if (id < 0)
77962306a36Sopenharmony_ci		return id;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
78262306a36Sopenharmony_ci	mt7915_mac_write_txwi(mdev, txwi_ptr, tx_info->skb, wcid, pid, key,
78362306a36Sopenharmony_ci			      qid, 0);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	txp = (struct mt76_connac_fw_txp *)(txwi + MT_TXD_SIZE);
78662306a36Sopenharmony_ci	for (i = 0; i < nbuf; i++) {
78762306a36Sopenharmony_ci		txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
78862306a36Sopenharmony_ci		txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci	txp->nbuf = nbuf;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (!key)
79562306a36Sopenharmony_ci		txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
79862306a36Sopenharmony_ci	    ieee80211_is_mgmt(hdr->frame_control))
79962306a36Sopenharmony_ci		txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (vif) {
80262306a36Sopenharmony_ci		struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		txp->bss_idx = mvif->mt76.idx;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	txp->token = cpu_to_le16(id);
80862306a36Sopenharmony_ci	if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
80962306a36Sopenharmony_ci		txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
81062306a36Sopenharmony_ci	else
81162306a36Sopenharmony_ci		txp->rept_wds_wcid = cpu_to_le16(0x3ff);
81262306a36Sopenharmony_ci	tx_info->skb = NULL;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* pass partial skb header to fw */
81562306a36Sopenharmony_ci	tx_info->buf[1].len = MT_CT_PARSE_LEN;
81662306a36Sopenharmony_ci	tx_info->buf[1].skip_unmap = true;
81762306a36Sopenharmony_ci	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return 0;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ciu32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE;
82562306a36Sopenharmony_ci	__le32 *txwi = ptr;
82662306a36Sopenharmony_ci	u32 val;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp));
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) |
83162306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT);
83262306a36Sopenharmony_ci	txwi[0] = cpu_to_le32(val);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	val = MT_TXD1_LONG_FORMAT |
83562306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3);
83662306a36Sopenharmony_ci	txwi[1] = cpu_to_le32(val);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	txp->token = cpu_to_le16(token_id);
83962306a36Sopenharmony_ci	txp->nbuf = 1;
84062306a36Sopenharmony_ci	txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp));
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	return MT_TXD_SIZE + sizeof(*txp);
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void
84662306a36Sopenharmony_cimt7915_mac_tx_free_prepare(struct mt7915_dev *dev)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
84962306a36Sopenharmony_ci	struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1];
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	/* clean DMA queues and unmap buffers first */
85262306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
85362306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
85462306a36Sopenharmony_ci	if (mphy_ext) {
85562306a36Sopenharmony_ci		mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false);
85662306a36Sopenharmony_ci		mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false);
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic void
86162306a36Sopenharmony_cimt7915_mac_tx_free_done(struct mt7915_dev *dev,
86262306a36Sopenharmony_ci			struct list_head *free_list, bool wake)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct sk_buff *skb, *tmp;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	mt7915_mac_sta_poll(dev);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (wake)
86962306a36Sopenharmony_ci		mt76_set_tx_blocked(&dev->mt76, false);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	mt76_worker_schedule(&dev->mt76.tx_worker);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	list_for_each_entry_safe(skb, tmp, free_list, list) {
87462306a36Sopenharmony_ci		skb_list_del_init(skb);
87562306a36Sopenharmony_ci		napi_consume_skb(skb, 1);
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic void
88062306a36Sopenharmony_cimt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	struct mt76_connac_tx_free *free = data;
88362306a36Sopenharmony_ci	__le32 *tx_info = (__le32 *)(data + sizeof(*free));
88462306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
88562306a36Sopenharmony_ci	struct mt76_txwi_cache *txwi;
88662306a36Sopenharmony_ci	struct ieee80211_sta *sta = NULL;
88762306a36Sopenharmony_ci	struct mt76_wcid *wcid = NULL;
88862306a36Sopenharmony_ci	LIST_HEAD(free_list);
88962306a36Sopenharmony_ci	void *end = data + len;
89062306a36Sopenharmony_ci	bool v3, wake = false;
89162306a36Sopenharmony_ci	u16 total, count = 0;
89262306a36Sopenharmony_ci	u32 txd = le32_to_cpu(free->txd);
89362306a36Sopenharmony_ci	__le32 *cur_info;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	mt7915_mac_tx_free_prepare(dev);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT);
89862306a36Sopenharmony_ci	v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	for (cur_info = tx_info; count < total; cur_info++) {
90162306a36Sopenharmony_ci		u32 msdu, info;
90262306a36Sopenharmony_ci		u8 i;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci		if (WARN_ON_ONCE((void *)cur_info >= end))
90562306a36Sopenharmony_ci			return;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci		/*
90862306a36Sopenharmony_ci		 * 1'b1: new wcid pair.
90962306a36Sopenharmony_ci		 * 1'b0: msdu_id with the same 'wcid pair' as above.
91062306a36Sopenharmony_ci		 */
91162306a36Sopenharmony_ci		info = le32_to_cpu(*cur_info);
91262306a36Sopenharmony_ci		if (info & MT_TX_FREE_PAIR) {
91362306a36Sopenharmony_ci			struct mt7915_sta *msta;
91462306a36Sopenharmony_ci			u16 idx;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci			idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
91762306a36Sopenharmony_ci			wcid = rcu_dereference(dev->mt76.wcid[idx]);
91862306a36Sopenharmony_ci			sta = wcid_to_sta(wcid);
91962306a36Sopenharmony_ci			if (!sta)
92062306a36Sopenharmony_ci				continue;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci			msta = container_of(wcid, struct mt7915_sta, wcid);
92362306a36Sopenharmony_ci			spin_lock_bh(&mdev->sta_poll_lock);
92462306a36Sopenharmony_ci			if (list_empty(&msta->wcid.poll_list))
92562306a36Sopenharmony_ci				list_add_tail(&msta->wcid.poll_list,
92662306a36Sopenharmony_ci					      &mdev->sta_poll_list);
92762306a36Sopenharmony_ci			spin_unlock_bh(&mdev->sta_poll_lock);
92862306a36Sopenharmony_ci			continue;
92962306a36Sopenharmony_ci		}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) {
93262306a36Sopenharmony_ci			u32 tx_retries = 0, tx_failed = 0;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci			if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) {
93562306a36Sopenharmony_ci				tx_retries =
93662306a36Sopenharmony_ci					FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1;
93762306a36Sopenharmony_ci				tx_failed = tx_retries +
93862306a36Sopenharmony_ci					!!FIELD_GET(MT_TX_FREE_STAT_V3, info);
93962306a36Sopenharmony_ci			} else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) {
94062306a36Sopenharmony_ci				tx_retries =
94162306a36Sopenharmony_ci					FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
94262306a36Sopenharmony_ci				tx_failed = tx_retries +
94362306a36Sopenharmony_ci					!!FIELD_GET(MT_TX_FREE_STAT, info);
94462306a36Sopenharmony_ci			}
94562306a36Sopenharmony_ci			wcid->stats.tx_retries += tx_retries;
94662306a36Sopenharmony_ci			wcid->stats.tx_failed += tx_failed;
94762306a36Sopenharmony_ci		}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3))
95062306a36Sopenharmony_ci			continue;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci		for (i = 0; i < 1 + v3; i++) {
95362306a36Sopenharmony_ci			if (v3) {
95462306a36Sopenharmony_ci				msdu = (info >> (15 * i)) & MT_TX_FREE_MSDU_ID_V3;
95562306a36Sopenharmony_ci				if (msdu == MT_TX_FREE_MSDU_ID_V3)
95662306a36Sopenharmony_ci					continue;
95762306a36Sopenharmony_ci			} else {
95862306a36Sopenharmony_ci				msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
95962306a36Sopenharmony_ci			}
96062306a36Sopenharmony_ci			count++;
96162306a36Sopenharmony_ci			txwi = mt76_token_release(mdev, msdu, &wake);
96262306a36Sopenharmony_ci			if (!txwi)
96362306a36Sopenharmony_ci				continue;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci			mt76_connac2_txwi_free(mdev, txwi, sta, &free_list);
96662306a36Sopenharmony_ci		}
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	mt7915_mac_tx_free_done(dev, &free_list, wake);
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic void
97362306a36Sopenharmony_cimt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct mt76_connac_tx_free *free = data;
97662306a36Sopenharmony_ci	__le16 *info = (__le16 *)(data + sizeof(*free));
97762306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
97862306a36Sopenharmony_ci	void *end = data + len;
97962306a36Sopenharmony_ci	LIST_HEAD(free_list);
98062306a36Sopenharmony_ci	bool wake = false;
98162306a36Sopenharmony_ci	u8 i, count;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	mt7915_mac_tx_free_prepare(dev);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	count = FIELD_GET(MT_TX_FREE_MSDU_CNT_V0, le16_to_cpu(free->ctrl));
98662306a36Sopenharmony_ci	if (WARN_ON_ONCE((void *)&info[count] > end))
98762306a36Sopenharmony_ci		return;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
99062306a36Sopenharmony_ci		struct mt76_txwi_cache *txwi;
99162306a36Sopenharmony_ci		u16 msdu = le16_to_cpu(info[i]);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci		txwi = mt76_token_release(mdev, msdu, &wake);
99462306a36Sopenharmony_ci		if (!txwi)
99562306a36Sopenharmony_ci			continue;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		mt76_connac2_txwi_free(mdev, txwi, NULL, &free_list);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	mt7915_mac_tx_free_done(dev, &free_list, wake);
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct mt7915_sta *msta = NULL;
100662306a36Sopenharmony_ci	struct mt76_wcid *wcid;
100762306a36Sopenharmony_ci	__le32 *txs_data = data;
100862306a36Sopenharmony_ci	u16 wcidx;
100962306a36Sopenharmony_ci	u8 pid;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
101262306a36Sopenharmony_ci	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	if (pid < MT_PACKET_ID_WED)
101562306a36Sopenharmony_ci		return;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (wcidx >= mt7915_wtbl_size(dev))
101862306a36Sopenharmony_ci		return;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	rcu_read_lock();
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
102362306a36Sopenharmony_ci	if (!wcid)
102462306a36Sopenharmony_ci		goto out;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	msta = container_of(wcid, struct mt7915_sta, wcid);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (pid == MT_PACKET_ID_WED)
102962306a36Sopenharmony_ci		mt76_connac2_mac_fill_txs(&dev->mt76, wcid, txs_data);
103062306a36Sopenharmony_ci	else
103162306a36Sopenharmony_ci		mt76_connac2_mac_add_txs_skb(&dev->mt76, wcid, pid, txs_data);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (!wcid->sta)
103462306a36Sopenharmony_ci		goto out;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.sta_poll_lock);
103762306a36Sopenharmony_ci	if (list_empty(&msta->wcid.poll_list))
103862306a36Sopenharmony_ci		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
103962306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.sta_poll_lock);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ciout:
104262306a36Sopenharmony_ci	rcu_read_unlock();
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cibool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
104862306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)data;
104962306a36Sopenharmony_ci	__le32 *end = (__le32 *)&rxd[len / 4];
105062306a36Sopenharmony_ci	enum rx_pkt_type type;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	switch (type) {
105562306a36Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY:
105662306a36Sopenharmony_ci		mt7915_mac_tx_free(dev, data, len);
105762306a36Sopenharmony_ci		return false;
105862306a36Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY_V0:
105962306a36Sopenharmony_ci		mt7915_mac_tx_free_v0(dev, data, len);
106062306a36Sopenharmony_ci		return false;
106162306a36Sopenharmony_ci	case PKT_TYPE_TXS:
106262306a36Sopenharmony_ci		for (rxd += 2; rxd + 8 <= end; rxd += 8)
106362306a36Sopenharmony_ci			mt7915_mac_add_txs(dev, rxd);
106462306a36Sopenharmony_ci		return false;
106562306a36Sopenharmony_ci	case PKT_TYPE_RX_FW_MONITOR:
106662306a36Sopenharmony_ci		mt7915_debugfs_rx_fw_monitor(dev, data, len);
106762306a36Sopenharmony_ci		return false;
106862306a36Sopenharmony_ci	default:
106962306a36Sopenharmony_ci		return true;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_civoid mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
107462306a36Sopenharmony_ci			 struct sk_buff *skb, u32 *info)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
107762306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
107862306a36Sopenharmony_ci	__le32 *end = (__le32 *)&skb->data[skb->len];
107962306a36Sopenharmony_ci	enum rx_pkt_type type;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	switch (type) {
108462306a36Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY:
108562306a36Sopenharmony_ci		mt7915_mac_tx_free(dev, skb->data, skb->len);
108662306a36Sopenharmony_ci		napi_consume_skb(skb, 1);
108762306a36Sopenharmony_ci		break;
108862306a36Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY_V0:
108962306a36Sopenharmony_ci		mt7915_mac_tx_free_v0(dev, skb->data, skb->len);
109062306a36Sopenharmony_ci		napi_consume_skb(skb, 1);
109162306a36Sopenharmony_ci		break;
109262306a36Sopenharmony_ci	case PKT_TYPE_RX_EVENT:
109362306a36Sopenharmony_ci		mt7915_mcu_rx_event(dev, skb);
109462306a36Sopenharmony_ci		break;
109562306a36Sopenharmony_ci	case PKT_TYPE_TXRXV:
109662306a36Sopenharmony_ci		mt7915_mac_fill_rx_vector(dev, skb);
109762306a36Sopenharmony_ci		break;
109862306a36Sopenharmony_ci	case PKT_TYPE_TXS:
109962306a36Sopenharmony_ci		for (rxd += 2; rxd + 8 <= end; rxd += 8)
110062306a36Sopenharmony_ci			mt7915_mac_add_txs(dev, rxd);
110162306a36Sopenharmony_ci		dev_kfree_skb(skb);
110262306a36Sopenharmony_ci		break;
110362306a36Sopenharmony_ci	case PKT_TYPE_RX_FW_MONITOR:
110462306a36Sopenharmony_ci		mt7915_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
110562306a36Sopenharmony_ci		dev_kfree_skb(skb);
110662306a36Sopenharmony_ci		break;
110762306a36Sopenharmony_ci	case PKT_TYPE_NORMAL:
110862306a36Sopenharmony_ci		if (!mt7915_mac_fill_rx(dev, skb, q, info)) {
110962306a36Sopenharmony_ci			mt76_rx(&dev->mt76, q, skb);
111062306a36Sopenharmony_ci			return;
111162306a36Sopenharmony_ci		}
111262306a36Sopenharmony_ci		fallthrough;
111362306a36Sopenharmony_ci	default:
111462306a36Sopenharmony_ci		dev_kfree_skb(skb);
111562306a36Sopenharmony_ci		break;
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_civoid mt7915_mac_cca_stats_reset(struct mt7915_phy *phy)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
112262306a36Sopenharmony_ci	u32 reg = MT_WF_PHY_RX_CTRL1(phy->mt76->band_idx);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	mt76_clear(dev, reg, MT_WF_PHY_RX_CTRL1_STSCNT_EN);
112562306a36Sopenharmony_ci	mt76_set(dev, reg, BIT(11) | BIT(9));
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_civoid mt7915_mac_reset_counters(struct mt7915_phy *phy)
112962306a36Sopenharmony_ci{
113062306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
113162306a36Sopenharmony_ci	int i;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
113462306a36Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(phy->mt76->band_idx, i));
113562306a36Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT2(phy->mt76->band_idx, i));
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	phy->mt76->survey_time = ktime_get_boottime();
113962306a36Sopenharmony_ci	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* reset airtime counters */
114262306a36Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(phy->mt76->band_idx),
114362306a36Sopenharmony_ci		 MT_WF_RMAC_MIB_RXTIME_CLR);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	mt7915_mcu_get_chan_mib_info(phy, true);
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_civoid mt7915_mac_set_timing(struct mt7915_phy *phy)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	s16 coverage_class = phy->coverage_class;
115162306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
115262306a36Sopenharmony_ci	struct mt7915_phy *ext_phy = mt7915_ext_phy(dev);
115362306a36Sopenharmony_ci	u32 val, reg_offset;
115462306a36Sopenharmony_ci	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
115562306a36Sopenharmony_ci		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
115662306a36Sopenharmony_ci	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
115762306a36Sopenharmony_ci		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
115862306a36Sopenharmony_ci	u8 band = phy->mt76->band_idx;
115962306a36Sopenharmony_ci	int eifs_ofdm = 360, sifs = 10, offset;
116062306a36Sopenharmony_ci	bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
116362306a36Sopenharmony_ci		return;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	if (ext_phy)
116662306a36Sopenharmony_ci		coverage_class = max_t(s16, dev->phy.coverage_class,
116762306a36Sopenharmony_ci				       ext_phy->coverage_class);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	mt76_set(dev, MT_ARB_SCR(band),
117062306a36Sopenharmony_ci		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
117162306a36Sopenharmony_ci	udelay(1);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	offset = 3 * coverage_class;
117462306a36Sopenharmony_ci	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
117562306a36Sopenharmony_ci		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76)) {
117862306a36Sopenharmony_ci		if (!a_band) {
117962306a36Sopenharmony_ci			mt76_wr(dev, MT_TMAC_ICR1(band),
118062306a36Sopenharmony_ci				FIELD_PREP(MT_IFS_EIFS_CCK, 314));
118162306a36Sopenharmony_ci			eifs_ofdm = 78;
118262306a36Sopenharmony_ci		} else {
118362306a36Sopenharmony_ci			eifs_ofdm = 84;
118462306a36Sopenharmony_ci		}
118562306a36Sopenharmony_ci	} else if (a_band) {
118662306a36Sopenharmony_ci		sifs = 16;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	mt76_wr(dev, MT_TMAC_CDTR(band), cck + reg_offset);
119062306a36Sopenharmony_ci	mt76_wr(dev, MT_TMAC_ODTR(band), ofdm + reg_offset);
119162306a36Sopenharmony_ci	mt76_wr(dev, MT_TMAC_ICR0(band),
119262306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_EIFS_OFDM, eifs_ofdm) |
119362306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_RIFS, 2) |
119462306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_SIFS, sifs) |
119562306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	if (phy->slottime < 20 || a_band)
119862306a36Sopenharmony_ci		val = MT7915_CFEND_RATE_DEFAULT;
119962306a36Sopenharmony_ci	else
120062306a36Sopenharmony_ci		val = MT7915_CFEND_RATE_11B;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_AGG_ACR0(band), MT_AGG_ACR_CFEND_RATE, val);
120362306a36Sopenharmony_ci	mt76_clear(dev, MT_ARB_SCR(band),
120462306a36Sopenharmony_ci		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
120562306a36Sopenharmony_ci}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_civoid mt7915_mac_enable_nf(struct mt7915_dev *dev, bool band)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	u32 reg;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RXTD12(band) :
121262306a36Sopenharmony_ci				      MT_WF_PHY_RXTD12_MT7916(band);
121362306a36Sopenharmony_ci	mt76_set(dev, reg,
121462306a36Sopenharmony_ci		 MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY |
121562306a36Sopenharmony_ci		 MT_WF_PHY_RXTD12_IRPI_SW_CLR);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	reg = is_mt7915(&dev->mt76) ? MT_WF_PHY_RX_CTRL1(band) :
121862306a36Sopenharmony_ci				      MT_WF_PHY_RX_CTRL1_MT7916(band);
121962306a36Sopenharmony_ci	mt76_set(dev, reg, FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5));
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic u8
122362306a36Sopenharmony_cimt7915_phy_get_nf(struct mt7915_phy *phy, int idx)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
122662306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
122762306a36Sopenharmony_ci	u32 val, sum = 0, n = 0;
122862306a36Sopenharmony_ci	int nss, i;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	for (nss = 0; nss < hweight8(phy->mt76->chainmask); nss++) {
123162306a36Sopenharmony_ci		u32 reg = is_mt7915(&dev->mt76) ?
123262306a36Sopenharmony_ci			MT_WF_IRPI_NSS(0, nss + (idx << dev->dbdc_support)) :
123362306a36Sopenharmony_ci			MT_WF_IRPI_NSS_MT7916(idx, nss);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
123662306a36Sopenharmony_ci			val = mt76_rr(dev, reg);
123762306a36Sopenharmony_ci			sum += val * nf_power[i];
123862306a36Sopenharmony_ci			n += val;
123962306a36Sopenharmony_ci		}
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	if (!n)
124362306a36Sopenharmony_ci		return 0;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	return sum / n;
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_civoid mt7915_update_channel(struct mt76_phy *mphy)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv;
125162306a36Sopenharmony_ci	struct mt76_channel_state *state = mphy->chan_state;
125262306a36Sopenharmony_ci	int nf;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	mt7915_mcu_get_chan_mib_info(phy, false);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	nf = mt7915_phy_get_nf(phy, phy->mt76->band_idx);
125762306a36Sopenharmony_ci	if (!phy->noise)
125862306a36Sopenharmony_ci		phy->noise = nf << 4;
125962306a36Sopenharmony_ci	else if (nf)
126062306a36Sopenharmony_ci		phy->noise += nf - (phy->noise >> 4);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	state->noise = -(phy->noise >> 4);
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic bool
126662306a36Sopenharmony_cimt7915_wait_reset_state(struct mt7915_dev *dev, u32 state)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	bool ret;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	ret = wait_event_timeout(dev->reset_wait,
127162306a36Sopenharmony_ci				 (READ_ONCE(dev->recovery.state) & state),
127262306a36Sopenharmony_ci				 MT7915_RESET_TIMEOUT);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
127562306a36Sopenharmony_ci	return ret;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic void
127962306a36Sopenharmony_cimt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct ieee80211_hw *hw = priv;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	switch (vif->type) {
128462306a36Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
128562306a36Sopenharmony_ci	case NL80211_IFTYPE_ADHOC:
128662306a36Sopenharmony_ci	case NL80211_IFTYPE_AP:
128762306a36Sopenharmony_ci		mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon,
128862306a36Sopenharmony_ci				      BSS_CHANGED_BEACON_ENABLED);
128962306a36Sopenharmony_ci		break;
129062306a36Sopenharmony_ci	default:
129162306a36Sopenharmony_ci		break;
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic void
129662306a36Sopenharmony_cimt7915_update_beacons(struct mt7915_dev *dev)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1];
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces(dev->mt76.hw,
130162306a36Sopenharmony_ci		IEEE80211_IFACE_ITER_RESUME_ALL,
130262306a36Sopenharmony_ci		mt7915_update_vif_beacon, dev->mt76.hw);
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	if (!mphy_ext)
130562306a36Sopenharmony_ci		return;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	ieee80211_iterate_active_interfaces(mphy_ext->hw,
130862306a36Sopenharmony_ci		IEEE80211_IFACE_ITER_RESUME_ALL,
130962306a36Sopenharmony_ci		mt7915_update_vif_beacon, mphy_ext->hw);
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic int
131362306a36Sopenharmony_cimt7915_mac_restart(struct mt7915_dev *dev)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct mt7915_phy *phy2;
131662306a36Sopenharmony_ci	struct mt76_phy *ext_phy;
131762306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
131862306a36Sopenharmony_ci	int i, ret;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	ext_phy = dev->mt76.phys[MT_BAND1];
132162306a36Sopenharmony_ci	phy2 = ext_phy ? ext_phy->priv : NULL;
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	if (dev->hif2) {
132462306a36Sopenharmony_ci		mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
132562306a36Sopenharmony_ci		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (dev_is_pci(mdev->dev)) {
132962306a36Sopenharmony_ci		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
133062306a36Sopenharmony_ci		if (dev->hif2) {
133162306a36Sopenharmony_ci			if (is_mt7915(mdev))
133262306a36Sopenharmony_ci				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
133362306a36Sopenharmony_ci			else
133462306a36Sopenharmony_ci				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0x0);
133562306a36Sopenharmony_ci		}
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	set_bit(MT76_RESET, &dev->mphy.state);
133962306a36Sopenharmony_ci	set_bit(MT76_MCU_RESET, &dev->mphy.state);
134062306a36Sopenharmony_ci	wake_up(&dev->mt76.mcu.wait);
134162306a36Sopenharmony_ci	if (ext_phy) {
134262306a36Sopenharmony_ci		set_bit(MT76_RESET, &ext_phy->state);
134362306a36Sopenharmony_ci		set_bit(MT76_MCU_RESET, &ext_phy->state);
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* lock/unlock all queues to ensure that no tx is pending */
134762306a36Sopenharmony_ci	mt76_txq_schedule_all(&dev->mphy);
134862306a36Sopenharmony_ci	if (ext_phy)
134962306a36Sopenharmony_ci		mt76_txq_schedule_all(ext_phy);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/* disable all tx/rx napi */
135262306a36Sopenharmony_ci	mt76_worker_disable(&dev->mt76.tx_worker);
135362306a36Sopenharmony_ci	mt76_for_each_q_rx(mdev, i) {
135462306a36Sopenharmony_ci		if (mdev->q_rx[i].ndesc)
135562306a36Sopenharmony_ci			napi_disable(&dev->mt76.napi[i]);
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci	napi_disable(&dev->mt76.tx_napi);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	/* token reinit */
136062306a36Sopenharmony_ci	mt76_connac2_tx_token_put(&dev->mt76);
136162306a36Sopenharmony_ci	idr_init(&dev->mt76.token);
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	mt7915_dma_reset(dev, true);
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	local_bh_disable();
136662306a36Sopenharmony_ci	mt76_for_each_q_rx(mdev, i) {
136762306a36Sopenharmony_ci		if (mdev->q_rx[i].ndesc) {
136862306a36Sopenharmony_ci			napi_enable(&dev->mt76.napi[i]);
136962306a36Sopenharmony_ci			napi_schedule(&dev->mt76.napi[i]);
137062306a36Sopenharmony_ci		}
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci	local_bh_enable();
137362306a36Sopenharmony_ci	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
137462306a36Sopenharmony_ci	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
137762306a36Sopenharmony_ci	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (dev->hif2) {
138062306a36Sopenharmony_ci		mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
138162306a36Sopenharmony_ci		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci	if (dev_is_pci(mdev->dev)) {
138462306a36Sopenharmony_ci		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
138562306a36Sopenharmony_ci		if (dev->hif2) {
138662306a36Sopenharmony_ci			if (is_mt7915(mdev))
138762306a36Sopenharmony_ci				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
138862306a36Sopenharmony_ci			else
138962306a36Sopenharmony_ci				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff);
139062306a36Sopenharmony_ci		}
139162306a36Sopenharmony_ci	}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* load firmware */
139462306a36Sopenharmony_ci	ret = mt7915_mcu_init_firmware(dev);
139562306a36Sopenharmony_ci	if (ret)
139662306a36Sopenharmony_ci		goto out;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	/* set the necessary init items */
139962306a36Sopenharmony_ci	ret = mt7915_mcu_set_eeprom(dev);
140062306a36Sopenharmony_ci	if (ret)
140162306a36Sopenharmony_ci		goto out;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	mt7915_mac_init(dev);
140462306a36Sopenharmony_ci	mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
140562306a36Sopenharmony_ci	mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
140662306a36Sopenharmony_ci	ret = mt7915_txbf_init(dev);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
140962306a36Sopenharmony_ci		ret = mt7915_run(dev->mphy.hw);
141062306a36Sopenharmony_ci		if (ret)
141162306a36Sopenharmony_ci			goto out;
141262306a36Sopenharmony_ci	}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) {
141562306a36Sopenharmony_ci		ret = mt7915_run(ext_phy->hw);
141662306a36Sopenharmony_ci		if (ret)
141762306a36Sopenharmony_ci			goto out;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ciout:
142162306a36Sopenharmony_ci	/* reset done */
142262306a36Sopenharmony_ci	clear_bit(MT76_RESET, &dev->mphy.state);
142362306a36Sopenharmony_ci	if (phy2)
142462306a36Sopenharmony_ci		clear_bit(MT76_RESET, &phy2->mt76->state);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	local_bh_disable();
142762306a36Sopenharmony_ci	napi_enable(&dev->mt76.tx_napi);
142862306a36Sopenharmony_ci	napi_schedule(&dev->mt76.tx_napi);
142962306a36Sopenharmony_ci	local_bh_enable();
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	mt76_worker_enable(&dev->mt76.tx_worker);
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	return ret;
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic void
143762306a36Sopenharmony_cimt7915_mac_full_reset(struct mt7915_dev *dev)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct mt76_phy *ext_phy;
144062306a36Sopenharmony_ci	int i;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	ext_phy = dev->mt76.phys[MT_BAND1];
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	dev->recovery.hw_full_reset = true;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	wake_up(&dev->mt76.mcu.wait);
144762306a36Sopenharmony_ci	ieee80211_stop_queues(mt76_hw(dev));
144862306a36Sopenharmony_ci	if (ext_phy)
144962306a36Sopenharmony_ci		ieee80211_stop_queues(ext_phy->hw);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	cancel_delayed_work_sync(&dev->mphy.mac_work);
145262306a36Sopenharmony_ci	if (ext_phy)
145362306a36Sopenharmony_ci		cancel_delayed_work_sync(&ext_phy->mac_work);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
145662306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
145762306a36Sopenharmony_ci		if (!mt7915_mac_restart(dev))
145862306a36Sopenharmony_ci			break;
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	if (i == 10)
146362306a36Sopenharmony_ci		dev_err(dev->mt76.dev, "chip full reset failed\n");
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	ieee80211_restart_hw(mt76_hw(dev));
146662306a36Sopenharmony_ci	if (ext_phy)
146762306a36Sopenharmony_ci		ieee80211_restart_hw(ext_phy->hw);
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	ieee80211_wake_queues(mt76_hw(dev));
147062306a36Sopenharmony_ci	if (ext_phy)
147162306a36Sopenharmony_ci		ieee80211_wake_queues(ext_phy->hw);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	dev->recovery.hw_full_reset = false;
147462306a36Sopenharmony_ci	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
147562306a36Sopenharmony_ci				     MT7915_WATCHDOG_TIME);
147662306a36Sopenharmony_ci	if (ext_phy)
147762306a36Sopenharmony_ci		ieee80211_queue_delayed_work(ext_phy->hw,
147862306a36Sopenharmony_ci					     &ext_phy->mac_work,
147962306a36Sopenharmony_ci					     MT7915_WATCHDOG_TIME);
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci/* system error recovery */
148362306a36Sopenharmony_civoid mt7915_mac_reset_work(struct work_struct *work)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	struct mt7915_phy *phy2;
148662306a36Sopenharmony_ci	struct mt76_phy *ext_phy;
148762306a36Sopenharmony_ci	struct mt7915_dev *dev;
148862306a36Sopenharmony_ci	int i;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	dev = container_of(work, struct mt7915_dev, reset_work);
149162306a36Sopenharmony_ci	ext_phy = dev->mt76.phys[MT_BAND1];
149262306a36Sopenharmony_ci	phy2 = ext_phy ? ext_phy->priv : NULL;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/* chip full reset */
149562306a36Sopenharmony_ci	if (dev->recovery.restart) {
149662306a36Sopenharmony_ci		/* disable WA/WM WDT */
149762306a36Sopenharmony_ci		mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
149862306a36Sopenharmony_ci			   MT_MCU_CMD_WDT_MASK);
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
150162306a36Sopenharmony_ci			dev->recovery.wa_reset_count++;
150262306a36Sopenharmony_ci		else
150362306a36Sopenharmony_ci			dev->recovery.wm_reset_count++;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		mt7915_mac_full_reset(dev);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci		/* enable mcu irq */
150862306a36Sopenharmony_ci		mt7915_irq_enable(dev, MT_INT_MCU_CMD);
150962306a36Sopenharmony_ci		mt7915_irq_disable(dev, 0);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci		/* enable WA/WM WDT */
151262306a36Sopenharmony_ci		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
151562306a36Sopenharmony_ci		dev->recovery.restart = false;
151662306a36Sopenharmony_ci		return;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	/* chip partial reset */
152062306a36Sopenharmony_ci	if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
152162306a36Sopenharmony_ci		return;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
152462306a36Sopenharmony_ci		mtk_wed_device_stop(&dev->mt76.mmio.wed);
152562306a36Sopenharmony_ci		if (!is_mt798x(&dev->mt76))
152662306a36Sopenharmony_ci			mt76_wr(dev, MT_INT_WED_MASK_CSR, 0);
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	ieee80211_stop_queues(mt76_hw(dev));
153062306a36Sopenharmony_ci	if (ext_phy)
153162306a36Sopenharmony_ci		ieee80211_stop_queues(ext_phy->hw);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	set_bit(MT76_RESET, &dev->mphy.state);
153462306a36Sopenharmony_ci	set_bit(MT76_MCU_RESET, &dev->mphy.state);
153562306a36Sopenharmony_ci	wake_up(&dev->mt76.mcu.wait);
153662306a36Sopenharmony_ci	cancel_delayed_work_sync(&dev->mphy.mac_work);
153762306a36Sopenharmony_ci	if (phy2) {
153862306a36Sopenharmony_ci		set_bit(MT76_RESET, &phy2->mt76->state);
153962306a36Sopenharmony_ci		cancel_delayed_work_sync(&phy2->mt76->mac_work);
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci	mt76_worker_disable(&dev->mt76.tx_worker);
154262306a36Sopenharmony_ci	mt76_for_each_q_rx(&dev->mt76, i)
154362306a36Sopenharmony_ci		napi_disable(&dev->mt76.napi[i]);
154462306a36Sopenharmony_ci	napi_disable(&dev->mt76.tx_napi);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
155162306a36Sopenharmony_ci		mt7915_dma_reset(dev, false);
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci		mt76_connac2_tx_token_put(&dev->mt76);
155462306a36Sopenharmony_ci		idr_init(&dev->mt76.token);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
155762306a36Sopenharmony_ci		mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
155862306a36Sopenharmony_ci	}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
156162306a36Sopenharmony_ci	mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	/* enable DMA Tx/Rx and interrupt */
156462306a36Sopenharmony_ci	mt7915_dma_start(dev, false, false);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
156762306a36Sopenharmony_ci	clear_bit(MT76_RESET, &dev->mphy.state);
156862306a36Sopenharmony_ci	if (phy2)
156962306a36Sopenharmony_ci		clear_bit(MT76_RESET, &phy2->mt76->state);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	local_bh_disable();
157262306a36Sopenharmony_ci	mt76_for_each_q_rx(&dev->mt76, i) {
157362306a36Sopenharmony_ci		napi_enable(&dev->mt76.napi[i]);
157462306a36Sopenharmony_ci		napi_schedule(&dev->mt76.napi[i]);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci	local_bh_enable();
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	tasklet_schedule(&dev->mt76.irq_tasklet);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	mt76_worker_enable(&dev->mt76.tx_worker);
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	local_bh_disable();
158362306a36Sopenharmony_ci	napi_enable(&dev->mt76.tx_napi);
158462306a36Sopenharmony_ci	napi_schedule(&dev->mt76.tx_napi);
158562306a36Sopenharmony_ci	local_bh_enable();
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	ieee80211_wake_queues(mt76_hw(dev));
158862306a36Sopenharmony_ci	if (ext_phy)
158962306a36Sopenharmony_ci		ieee80211_wake_queues(ext_phy->hw);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	mt7915_update_beacons(dev);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
159662306a36Sopenharmony_ci				     MT7915_WATCHDOG_TIME);
159762306a36Sopenharmony_ci	if (phy2)
159862306a36Sopenharmony_ci		ieee80211_queue_delayed_work(ext_phy->hw,
159962306a36Sopenharmony_ci					     &phy2->mt76->mac_work,
160062306a36Sopenharmony_ci					     MT7915_WATCHDOG_TIME);
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci/* firmware coredump */
160462306a36Sopenharmony_civoid mt7915_mac_dump_work(struct work_struct *work)
160562306a36Sopenharmony_ci{
160662306a36Sopenharmony_ci	const struct mt7915_mem_region *mem_region;
160762306a36Sopenharmony_ci	struct mt7915_crash_data *crash_data;
160862306a36Sopenharmony_ci	struct mt7915_dev *dev;
160962306a36Sopenharmony_ci	struct mt7915_mem_hdr *hdr;
161062306a36Sopenharmony_ci	size_t buf_len;
161162306a36Sopenharmony_ci	int i;
161262306a36Sopenharmony_ci	u32 num;
161362306a36Sopenharmony_ci	u8 *buf;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	dev = container_of(work, struct mt7915_dev, dump_work);
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	mutex_lock(&dev->dump_mutex);
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	crash_data = mt7915_coredump_new(dev);
162062306a36Sopenharmony_ci	if (!crash_data) {
162162306a36Sopenharmony_ci		mutex_unlock(&dev->dump_mutex);
162262306a36Sopenharmony_ci		goto skip_coredump;
162362306a36Sopenharmony_ci	}
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	mem_region = mt7915_coredump_get_mem_layout(dev, &num);
162662306a36Sopenharmony_ci	if (!mem_region || !crash_data->memdump_buf_len) {
162762306a36Sopenharmony_ci		mutex_unlock(&dev->dump_mutex);
162862306a36Sopenharmony_ci		goto skip_memdump;
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	buf = crash_data->memdump_buf;
163262306a36Sopenharmony_ci	buf_len = crash_data->memdump_buf_len;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	/* dumping memory content... */
163562306a36Sopenharmony_ci	memset(buf, 0, buf_len);
163662306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
163762306a36Sopenharmony_ci		if (mem_region->len > buf_len) {
163862306a36Sopenharmony_ci			dev_warn(dev->mt76.dev, "%s len %lu is too large\n",
163962306a36Sopenharmony_ci				 mem_region->name,
164062306a36Sopenharmony_ci				 (unsigned long)mem_region->len);
164162306a36Sopenharmony_ci			break;
164262306a36Sopenharmony_ci		}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci		/* reserve space for the header */
164562306a36Sopenharmony_ci		hdr = (void *)buf;
164662306a36Sopenharmony_ci		buf += sizeof(*hdr);
164762306a36Sopenharmony_ci		buf_len -= sizeof(*hdr);
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci		mt7915_memcpy_fromio(dev, buf, mem_region->start,
165062306a36Sopenharmony_ci				     mem_region->len);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		hdr->start = mem_region->start;
165362306a36Sopenharmony_ci		hdr->len = mem_region->len;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		if (!mem_region->len)
165662306a36Sopenharmony_ci			/* note: the header remains, just with zero length */
165762306a36Sopenharmony_ci			break;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		buf += mem_region->len;
166062306a36Sopenharmony_ci		buf_len -= mem_region->len;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci		mem_region++;
166362306a36Sopenharmony_ci	}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	mutex_unlock(&dev->dump_mutex);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ciskip_memdump:
166862306a36Sopenharmony_ci	mt7915_coredump_submit(dev);
166962306a36Sopenharmony_ciskip_coredump:
167062306a36Sopenharmony_ci	queue_work(dev->mt76.wq, &dev->reset_work);
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_civoid mt7915_reset(struct mt7915_dev *dev)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	if (!dev->recovery.hw_init_done)
167662306a36Sopenharmony_ci		return;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	if (dev->recovery.hw_full_reset)
167962306a36Sopenharmony_ci		return;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* wm/wa exception: do full recovery */
168262306a36Sopenharmony_ci	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
168362306a36Sopenharmony_ci		dev->recovery.restart = true;
168462306a36Sopenharmony_ci		dev_info(dev->mt76.dev,
168562306a36Sopenharmony_ci			 "%s indicated firmware crash, attempting recovery\n",
168662306a36Sopenharmony_ci			 wiphy_name(dev->mt76.hw->wiphy));
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci		mt7915_irq_disable(dev, MT_INT_MCU_CMD);
168962306a36Sopenharmony_ci		queue_work(dev->mt76.wq, &dev->dump_work);
169062306a36Sopenharmony_ci		return;
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	queue_work(dev->mt76.wq, &dev->reset_work);
169462306a36Sopenharmony_ci	wake_up(&dev->reset_wait);
169562306a36Sopenharmony_ci}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_civoid mt7915_mac_update_stats(struct mt7915_phy *phy)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	struct mt76_mib_stats *mib = &phy->mib;
170062306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
170162306a36Sopenharmony_ci	int i, aggr0 = 0, aggr1, cnt;
170262306a36Sopenharmony_ci	u8 band = phy->mt76->band_idx;
170362306a36Sopenharmony_ci	u32 val;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR3(band));
170662306a36Sopenharmony_ci	mib->fcs_err_cnt += is_mt7915(&dev->mt76) ?
170762306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) :
170862306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt);
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR4(band));
171162306a36Sopenharmony_ci	mib->rx_fifo_full_cnt += FIELD_GET(MT_MIB_SDR4_RX_FIFO_FULL_MASK, cnt);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR5(band));
171462306a36Sopenharmony_ci	mib->rx_mpdu_cnt += cnt;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR6(band));
171762306a36Sopenharmony_ci	mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR7(band));
172062306a36Sopenharmony_ci	mib->rx_vector_mismatch_cnt +=
172162306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR7_RX_VECTOR_MISMATCH_CNT_MASK, cnt);
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR8(band));
172462306a36Sopenharmony_ci	mib->rx_delimiter_fail_cnt +=
172562306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR8_RX_DELIMITER_FAIL_CNT_MASK, cnt);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR10(band));
172862306a36Sopenharmony_ci	mib->rx_mrdy_cnt += is_mt7915(&dev->mt76) ?
172962306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK, cnt) :
173062306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR10_MRDY_COUNT_MASK_MT7916, cnt);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR11(band));
173362306a36Sopenharmony_ci	mib->rx_len_mismatch_cnt +=
173462306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR11_RX_LEN_MISMATCH_CNT_MASK, cnt);
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR12(band));
173762306a36Sopenharmony_ci	mib->tx_ampdu_cnt += cnt;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR13(band));
174062306a36Sopenharmony_ci	mib->tx_stop_q_empty_cnt +=
174162306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR13_TX_STOP_Q_EMPTY_CNT_MASK, cnt);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR14(band));
174462306a36Sopenharmony_ci	mib->tx_mpdu_attempts_cnt += is_mt7915(&dev->mt76) ?
174562306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK, cnt) :
174662306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR14_TX_MPDU_ATTEMPTS_CNT_MASK_MT7916, cnt);
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR15(band));
174962306a36Sopenharmony_ci	mib->tx_mpdu_success_cnt += is_mt7915(&dev->mt76) ?
175062306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK, cnt) :
175162306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR15_TX_MPDU_SUCCESS_CNT_MASK_MT7916, cnt);
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR16(band));
175462306a36Sopenharmony_ci	mib->primary_cca_busy_time +=
175562306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR16_PRIMARY_CCA_BUSY_TIME_MASK, cnt);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR17(band));
175862306a36Sopenharmony_ci	mib->secondary_cca_busy_time +=
175962306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR17_SECONDARY_CCA_BUSY_TIME_MASK, cnt);
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR18(band));
176262306a36Sopenharmony_ci	mib->primary_energy_detect_time +=
176362306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR18_PRIMARY_ENERGY_DETECT_TIME_MASK, cnt);
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR19(band));
176662306a36Sopenharmony_ci	mib->cck_mdrdy_time += FIELD_GET(MT_MIB_SDR19_CCK_MDRDY_TIME_MASK, cnt);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR20(band));
176962306a36Sopenharmony_ci	mib->ofdm_mdrdy_time +=
177062306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR20_OFDM_VHT_MDRDY_TIME_MASK, cnt);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR21(band));
177362306a36Sopenharmony_ci	mib->green_mdrdy_time +=
177462306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR21_GREEN_MDRDY_TIME_MASK, cnt);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR22(band));
177762306a36Sopenharmony_ci	mib->rx_ampdu_cnt += cnt;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR23(band));
178062306a36Sopenharmony_ci	mib->rx_ampdu_bytes_cnt += cnt;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR24(band));
178362306a36Sopenharmony_ci	mib->rx_ampdu_valid_subframe_cnt += is_mt7915(&dev->mt76) ?
178462306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK, cnt) :
178562306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR24_RX_AMPDU_SF_CNT_MASK_MT7916, cnt);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR25(band));
178862306a36Sopenharmony_ci	mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR27(band));
179162306a36Sopenharmony_ci	mib->tx_rwp_fail_cnt +=
179262306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT_MASK, cnt);
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR28(band));
179562306a36Sopenharmony_ci	mib->tx_rwp_need_cnt +=
179662306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT_MASK, cnt);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR29(band));
179962306a36Sopenharmony_ci	mib->rx_pfdrop_cnt += is_mt7915(&dev->mt76) ?
180062306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK, cnt) :
180162306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR29_RX_PFDROP_CNT_MASK_MT7916, cnt);
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDRVEC(band));
180462306a36Sopenharmony_ci	mib->rx_vec_queue_overflow_drop_cnt += is_mt7915(&dev->mt76) ?
180562306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK, cnt) :
180662306a36Sopenharmony_ci		FIELD_GET(MT_MIB_SDR30_RX_VEC_QUEUE_OVERFLOW_DROP_CNT_MASK_MT7916, cnt);
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDR31(band));
180962306a36Sopenharmony_ci	mib->rx_ba_cnt += cnt;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_SDRMUBF(band));
181262306a36Sopenharmony_ci	mib->tx_bf_cnt += FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_DR8(band));
181562306a36Sopenharmony_ci	mib->tx_mu_mpdu_cnt += cnt;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_DR9(band));
181862306a36Sopenharmony_ci	mib->tx_mu_acked_mpdu_cnt += cnt;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_MIB_DR11(band));
182162306a36Sopenharmony_ci	mib->tx_su_acked_mpdu_cnt += cnt;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	cnt = mt76_rr(dev, MT_ETBF_PAR_RPT0(band));
182462306a36Sopenharmony_ci	mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_PAR_RPT0_FB_BW, cnt);
182562306a36Sopenharmony_ci	mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NC, cnt);
182662306a36Sopenharmony_ci	mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_PAR_RPT0_FB_NR, cnt);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
182962306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
183062306a36Sopenharmony_ci		mib->tx_amsdu[i] += cnt;
183162306a36Sopenharmony_ci		mib->tx_amsdu_cnt += cnt;
183262306a36Sopenharmony_ci	}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	if (is_mt7915(&dev->mt76)) {
183562306a36Sopenharmony_ci		for (i = 0, aggr1 = aggr0 + 8; i < 4; i++) {
183662306a36Sopenharmony_ci			val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 4)));
183762306a36Sopenharmony_ci			mib->ba_miss_cnt +=
183862306a36Sopenharmony_ci				FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val);
183962306a36Sopenharmony_ci			mib->ack_fail_cnt +=
184062306a36Sopenharmony_ci				FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK, val);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci			val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 4)));
184362306a36Sopenharmony_ci			mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val);
184462306a36Sopenharmony_ci			mib->rts_retries_cnt +=
184562306a36Sopenharmony_ci				FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci			val = mt76_rr(dev, MT_TX_AGG_CNT(band, i));
184862306a36Sopenharmony_ci			phy->mt76->aggr_stats[aggr0++] += val & 0xffff;
184962306a36Sopenharmony_ci			phy->mt76->aggr_stats[aggr0++] += val >> 16;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci			val = mt76_rr(dev, MT_TX_AGG_CNT2(band, i));
185262306a36Sopenharmony_ci			phy->mt76->aggr_stats[aggr1++] += val & 0xffff;
185362306a36Sopenharmony_ci			phy->mt76->aggr_stats[aggr1++] += val >> 16;
185462306a36Sopenharmony_ci		}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_SDR32(band));
185762306a36Sopenharmony_ci		mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt);
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_SDR33(band));
186062306a36Sopenharmony_ci		mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR33_TX_PKT_IBF_CNT, cnt);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_ETBF_TX_APP_CNT(band));
186362306a36Sopenharmony_ci		mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_IBF_CNT, cnt);
186462306a36Sopenharmony_ci		mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_ETBF_TX_EBF_CNT, cnt);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_ETBF_TX_NDP_BFRP(band));
186762306a36Sopenharmony_ci		mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_ETBF_TX_FB_CPL, cnt);
186862306a36Sopenharmony_ci		mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_ETBF_TX_FB_TRI, cnt);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_ETBF_RX_FB_CNT(band));
187162306a36Sopenharmony_ci		mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_ETBF_RX_FB_ALL, cnt);
187262306a36Sopenharmony_ci		mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_ETBF_RX_FB_HE, cnt);
187362306a36Sopenharmony_ci		mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_ETBF_RX_FB_VHT, cnt);
187462306a36Sopenharmony_ci		mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_ETBF_RX_FB_HT, cnt);
187562306a36Sopenharmony_ci	} else {
187662306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
187762306a36Sopenharmony_ci			/* rts count */
187862306a36Sopenharmony_ci			val = mt76_rr(dev, MT_MIB_MB_SDR0(band, (i << 2)));
187962306a36Sopenharmony_ci			mib->rts_cnt += FIELD_GET(GENMASK(15, 0), val);
188062306a36Sopenharmony_ci			mib->rts_cnt += FIELD_GET(GENMASK(31, 16), val);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci			/* rts retry count */
188362306a36Sopenharmony_ci			val = mt76_rr(dev, MT_MIB_MB_SDR1(band, (i << 2)));
188462306a36Sopenharmony_ci			mib->rts_retries_cnt += FIELD_GET(GENMASK(15, 0), val);
188562306a36Sopenharmony_ci			mib->rts_retries_cnt += FIELD_GET(GENMASK(31, 16), val);
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci			/* ba miss count */
188862306a36Sopenharmony_ci			val = mt76_rr(dev, MT_MIB_MB_SDR2(band, (i << 2)));
188962306a36Sopenharmony_ci			mib->ba_miss_cnt += FIELD_GET(GENMASK(15, 0), val);
189062306a36Sopenharmony_ci			mib->ba_miss_cnt += FIELD_GET(GENMASK(31, 16), val);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci			/* ack fail count */
189362306a36Sopenharmony_ci			val = mt76_rr(dev, MT_MIB_MB_BFTF(band, (i << 2)));
189462306a36Sopenharmony_ci			mib->ack_fail_cnt += FIELD_GET(GENMASK(15, 0), val);
189562306a36Sopenharmony_ci			mib->ack_fail_cnt += FIELD_GET(GENMASK(31, 16), val);
189662306a36Sopenharmony_ci		}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
189962306a36Sopenharmony_ci			val = mt76_rr(dev, MT_TX_AGG_CNT(band, i));
190062306a36Sopenharmony_ci			phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(15, 0), val);
190162306a36Sopenharmony_ci			phy->mt76->aggr_stats[aggr0++] += FIELD_GET(GENMASK(31, 16), val);
190262306a36Sopenharmony_ci		}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_SDR32(band));
190562306a36Sopenharmony_ci		mib->tx_pkt_ibf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt);
190662306a36Sopenharmony_ci		mib->tx_bf_ibf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_IBF_CNT, cnt);
190762306a36Sopenharmony_ci		mib->tx_pkt_ebf_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt);
190862306a36Sopenharmony_ci		mib->tx_bf_ebf_ppdu_cnt += FIELD_GET(MT_MIB_SDR32_TX_PKT_EBF_CNT, cnt);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_BFCR7(band));
191162306a36Sopenharmony_ci		mib->tx_bf_fb_cpl_cnt += FIELD_GET(MT_MIB_BFCR7_BFEE_TX_FB_CPL, cnt);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_BFCR2(band));
191462306a36Sopenharmony_ci		mib->tx_bf_fb_trig_cnt += FIELD_GET(MT_MIB_BFCR2_BFEE_TX_FB_TRIG, cnt);
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_BFCR0(band));
191762306a36Sopenharmony_ci		mib->tx_bf_rx_fb_vht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt);
191862306a36Sopenharmony_ci		mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_VHT, cnt);
191962306a36Sopenharmony_ci		mib->tx_bf_rx_fb_ht_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt);
192062306a36Sopenharmony_ci		mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR0_RX_FB_HT, cnt);
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci		cnt = mt76_rr(dev, MT_MIB_BFCR1(band));
192362306a36Sopenharmony_ci		mib->tx_bf_rx_fb_he_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt);
192462306a36Sopenharmony_ci		mib->tx_bf_rx_fb_all_cnt += FIELD_GET(MT_MIB_BFCR1_RX_FB_HE, cnt);
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_cistatic void mt7915_mac_severe_check(struct mt7915_phy *phy)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
193162306a36Sopenharmony_ci	u32 trb;
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	if (!phy->omac_mask)
193462306a36Sopenharmony_ci		return;
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	/* In rare cases, TRB pointers might be out of sync leads to RMAC
193762306a36Sopenharmony_ci	 * stopping Rx, so check status periodically to see if TRB hardware
193862306a36Sopenharmony_ci	 * requires minimal recovery.
193962306a36Sopenharmony_ci	 */
194062306a36Sopenharmony_ci	trb = mt76_rr(dev, MT_TRB_RXPSR0(phy->mt76->band_idx));
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	if ((FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, trb) !=
194362306a36Sopenharmony_ci	     FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, trb)) &&
194462306a36Sopenharmony_ci	    (FIELD_GET(MT_TRB_RXPSR0_RX_RMAC_PTR, phy->trb_ts) !=
194562306a36Sopenharmony_ci	     FIELD_GET(MT_TRB_RXPSR0_RX_WTBL_PTR, phy->trb_ts)) &&
194662306a36Sopenharmony_ci	    trb == phy->trb_ts)
194762306a36Sopenharmony_ci		mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L3_RX_ABORT,
194862306a36Sopenharmony_ci				   phy->mt76->band_idx);
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	phy->trb_ts = trb;
195162306a36Sopenharmony_ci}
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_civoid mt7915_mac_sta_rc_work(struct work_struct *work)
195462306a36Sopenharmony_ci{
195562306a36Sopenharmony_ci	struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
195662306a36Sopenharmony_ci	struct ieee80211_sta *sta;
195762306a36Sopenharmony_ci	struct ieee80211_vif *vif;
195862306a36Sopenharmony_ci	struct mt7915_sta *msta;
195962306a36Sopenharmony_ci	u32 changed;
196062306a36Sopenharmony_ci	LIST_HEAD(list);
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.sta_poll_lock);
196362306a36Sopenharmony_ci	list_splice_init(&dev->sta_rc_list, &list);
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	while (!list_empty(&list)) {
196662306a36Sopenharmony_ci		msta = list_first_entry(&list, struct mt7915_sta, rc_list);
196762306a36Sopenharmony_ci		list_del_init(&msta->rc_list);
196862306a36Sopenharmony_ci		changed = msta->changed;
196962306a36Sopenharmony_ci		msta->changed = 0;
197062306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
197362306a36Sopenharmony_ci		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
197662306a36Sopenharmony_ci			       IEEE80211_RC_NSS_CHANGED |
197762306a36Sopenharmony_ci			       IEEE80211_RC_BW_CHANGED))
197862306a36Sopenharmony_ci			mt7915_mcu_add_rate_ctrl(dev, vif, sta, true);
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		if (changed & IEEE80211_RC_SMPS_CHANGED)
198162306a36Sopenharmony_ci			mt7915_mcu_add_smps(dev, vif, sta);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
198462306a36Sopenharmony_ci	}
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.sta_poll_lock);
198762306a36Sopenharmony_ci}
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_civoid mt7915_mac_work(struct work_struct *work)
199062306a36Sopenharmony_ci{
199162306a36Sopenharmony_ci	struct mt7915_phy *phy;
199262306a36Sopenharmony_ci	struct mt76_phy *mphy;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
199562306a36Sopenharmony_ci					       mac_work.work);
199662306a36Sopenharmony_ci	phy = mphy->priv;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	mutex_lock(&mphy->dev->mutex);
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	mt76_update_survey(mphy);
200162306a36Sopenharmony_ci	if (++mphy->mac_work_count == 5) {
200262306a36Sopenharmony_ci		mphy->mac_work_count = 0;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci		mt7915_mac_update_stats(phy);
200562306a36Sopenharmony_ci		mt7915_mac_severe_check(phy);
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		if (phy->dev->muru_debug)
200862306a36Sopenharmony_ci			mt7915_mcu_muru_debug_get(phy);
200962306a36Sopenharmony_ci	}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	mutex_unlock(&mphy->dev->mutex);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci	mt76_tx_status_check(mphy->dev, false);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
201662306a36Sopenharmony_ci				     MT7915_WATCHDOG_TIME);
201762306a36Sopenharmony_ci}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_cistatic void mt7915_dfs_stop_radar_detector(struct mt7915_phy *phy)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	if (phy->rdd_state & BIT(0))
202462306a36Sopenharmony_ci		mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0,
202562306a36Sopenharmony_ci					MT_RX_SEL0, 0);
202662306a36Sopenharmony_ci	if (phy->rdd_state & BIT(1))
202762306a36Sopenharmony_ci		mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1,
202862306a36Sopenharmony_ci					MT_RX_SEL0, 0);
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_cistatic int mt7915_dfs_start_rdd(struct mt7915_dev *dev, int chain)
203262306a36Sopenharmony_ci{
203362306a36Sopenharmony_ci	int err, region;
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci	switch (dev->mt76.region) {
203662306a36Sopenharmony_ci	case NL80211_DFS_ETSI:
203762306a36Sopenharmony_ci		region = 0;
203862306a36Sopenharmony_ci		break;
203962306a36Sopenharmony_ci	case NL80211_DFS_JP:
204062306a36Sopenharmony_ci		region = 2;
204162306a36Sopenharmony_ci		break;
204262306a36Sopenharmony_ci	case NL80211_DFS_FCC:
204362306a36Sopenharmony_ci	default:
204462306a36Sopenharmony_ci		region = 1;
204562306a36Sopenharmony_ci		break;
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain,
204962306a36Sopenharmony_ci				      MT_RX_SEL0, region);
205062306a36Sopenharmony_ci	if (err < 0)
205162306a36Sopenharmony_ci		return err;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	if (is_mt7915(&dev->mt76)) {
205462306a36Sopenharmony_ci		err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT, chain,
205562306a36Sopenharmony_ci					      0, dev->dbdc_support ? 2 : 0);
205662306a36Sopenharmony_ci		if (err < 0)
205762306a36Sopenharmony_ci			return err;
205862306a36Sopenharmony_ci	}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain,
206162306a36Sopenharmony_ci				       MT_RX_SEL0, 1);
206262306a36Sopenharmony_ci}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_cistatic int mt7915_dfs_start_radar_detector(struct mt7915_phy *phy)
206562306a36Sopenharmony_ci{
206662306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
206762306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
206862306a36Sopenharmony_ci	int err;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci	/* start CAC */
207162306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START,
207262306a36Sopenharmony_ci				      phy->mt76->band_idx, MT_RX_SEL0, 0);
207362306a36Sopenharmony_ci	if (err < 0)
207462306a36Sopenharmony_ci		return err;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	err = mt7915_dfs_start_rdd(dev, phy->mt76->band_idx);
207762306a36Sopenharmony_ci	if (err < 0)
207862306a36Sopenharmony_ci		return err;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	phy->rdd_state |= BIT(phy->mt76->band_idx);
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	if (!is_mt7915(&dev->mt76))
208362306a36Sopenharmony_ci		return 0;
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
208662306a36Sopenharmony_ci	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
208762306a36Sopenharmony_ci		err = mt7915_dfs_start_rdd(dev, 1);
208862306a36Sopenharmony_ci		if (err < 0)
208962306a36Sopenharmony_ci			return err;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci		phy->rdd_state |= BIT(1);
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	return 0;
209562306a36Sopenharmony_ci}
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_cistatic int
209862306a36Sopenharmony_cimt7915_dfs_init_radar_specs(struct mt7915_phy *phy)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	const struct mt7915_dfs_radar_spec *radar_specs;
210162306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
210262306a36Sopenharmony_ci	int err, i;
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	switch (dev->mt76.region) {
210562306a36Sopenharmony_ci	case NL80211_DFS_FCC:
210662306a36Sopenharmony_ci		radar_specs = &fcc_radar_specs;
210762306a36Sopenharmony_ci		err = mt7915_mcu_set_fcc5_lpn(dev, 8);
210862306a36Sopenharmony_ci		if (err < 0)
210962306a36Sopenharmony_ci			return err;
211062306a36Sopenharmony_ci		break;
211162306a36Sopenharmony_ci	case NL80211_DFS_ETSI:
211262306a36Sopenharmony_ci		radar_specs = &etsi_radar_specs;
211362306a36Sopenharmony_ci		break;
211462306a36Sopenharmony_ci	case NL80211_DFS_JP:
211562306a36Sopenharmony_ci		radar_specs = &jp_radar_specs;
211662306a36Sopenharmony_ci		break;
211762306a36Sopenharmony_ci	default:
211862306a36Sopenharmony_ci		return -EINVAL;
211962306a36Sopenharmony_ci	}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
212262306a36Sopenharmony_ci		err = mt7915_mcu_set_radar_th(dev, i,
212362306a36Sopenharmony_ci					      &radar_specs->radar_pattern[i]);
212462306a36Sopenharmony_ci		if (err < 0)
212562306a36Sopenharmony_ci			return err;
212662306a36Sopenharmony_ci	}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	return mt7915_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ciint mt7915_dfs_init_radar_detector(struct mt7915_phy *phy)
213262306a36Sopenharmony_ci{
213362306a36Sopenharmony_ci	struct mt7915_dev *dev = phy->dev;
213462306a36Sopenharmony_ci	enum mt76_dfs_state dfs_state, prev_state;
213562306a36Sopenharmony_ci	int err;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	prev_state = phy->mt76->dfs_state;
213862306a36Sopenharmony_ci	dfs_state = mt76_phy_dfs_state(phy->mt76);
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	if (prev_state == dfs_state)
214162306a36Sopenharmony_ci		return 0;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	if (prev_state == MT_DFS_STATE_UNKNOWN)
214462306a36Sopenharmony_ci		mt7915_dfs_stop_radar_detector(phy);
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (dfs_state == MT_DFS_STATE_DISABLED)
214762306a36Sopenharmony_ci		goto stop;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	if (prev_state <= MT_DFS_STATE_DISABLED) {
215062306a36Sopenharmony_ci		err = mt7915_dfs_init_radar_specs(phy);
215162306a36Sopenharmony_ci		if (err < 0)
215262306a36Sopenharmony_ci			return err;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci		err = mt7915_dfs_start_radar_detector(phy);
215562306a36Sopenharmony_ci		if (err < 0)
215662306a36Sopenharmony_ci			return err;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci		phy->mt76->dfs_state = MT_DFS_STATE_CAC;
215962306a36Sopenharmony_ci	}
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	if (dfs_state == MT_DFS_STATE_CAC)
216262306a36Sopenharmony_ci		return 0;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END,
216562306a36Sopenharmony_ci				      phy->mt76->band_idx, MT_RX_SEL0, 0);
216662306a36Sopenharmony_ci	if (err < 0) {
216762306a36Sopenharmony_ci		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
216862306a36Sopenharmony_ci		return err;
216962306a36Sopenharmony_ci	}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
217262306a36Sopenharmony_ci	return 0;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_cistop:
217562306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START,
217662306a36Sopenharmony_ci				      phy->mt76->band_idx, MT_RX_SEL0, 0);
217762306a36Sopenharmony_ci	if (err < 0)
217862306a36Sopenharmony_ci		return err;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	if (is_mt7915(&dev->mt76)) {
218162306a36Sopenharmony_ci		err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_SET_WF_ANT,
218262306a36Sopenharmony_ci					      phy->mt76->band_idx, 0,
218362306a36Sopenharmony_ci					      dev->dbdc_support ? 2 : 0);
218462306a36Sopenharmony_ci		if (err < 0)
218562306a36Sopenharmony_ci			return err;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	mt7915_dfs_stop_radar_detector(phy);
218962306a36Sopenharmony_ci	phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	return 0;
219262306a36Sopenharmony_ci}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_cistatic int
219562306a36Sopenharmony_cimt7915_mac_twt_duration_align(int duration)
219662306a36Sopenharmony_ci{
219762306a36Sopenharmony_ci	return duration << 8;
219862306a36Sopenharmony_ci}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_cistatic u64
220162306a36Sopenharmony_cimt7915_mac_twt_sched_list_add(struct mt7915_dev *dev,
220262306a36Sopenharmony_ci			      struct mt7915_twt_flow *flow)
220362306a36Sopenharmony_ci{
220462306a36Sopenharmony_ci	struct mt7915_twt_flow *iter, *iter_next;
220562306a36Sopenharmony_ci	u32 duration = flow->duration << 8;
220662306a36Sopenharmony_ci	u64 start_tsf;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	iter = list_first_entry_or_null(&dev->twt_list,
220962306a36Sopenharmony_ci					struct mt7915_twt_flow, list);
221062306a36Sopenharmony_ci	if (!iter || !iter->sched || iter->start_tsf > duration) {
221162306a36Sopenharmony_ci		/* add flow as first entry in the list */
221262306a36Sopenharmony_ci		list_add(&flow->list, &dev->twt_list);
221362306a36Sopenharmony_ci		return 0;
221462306a36Sopenharmony_ci	}
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
221762306a36Sopenharmony_ci		start_tsf = iter->start_tsf +
221862306a36Sopenharmony_ci			    mt7915_mac_twt_duration_align(iter->duration);
221962306a36Sopenharmony_ci		if (list_is_last(&iter->list, &dev->twt_list))
222062306a36Sopenharmony_ci			break;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci		if (!iter_next->sched ||
222362306a36Sopenharmony_ci		    iter_next->start_tsf > start_tsf + duration) {
222462306a36Sopenharmony_ci			list_add(&flow->list, &iter->list);
222562306a36Sopenharmony_ci			goto out;
222662306a36Sopenharmony_ci		}
222762306a36Sopenharmony_ci	}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	/* add flow as last entry in the list */
223062306a36Sopenharmony_ci	list_add_tail(&flow->list, &dev->twt_list);
223162306a36Sopenharmony_ciout:
223262306a36Sopenharmony_ci	return start_tsf;
223362306a36Sopenharmony_ci}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_cistatic int mt7915_mac_check_twt_req(struct ieee80211_twt_setup *twt)
223662306a36Sopenharmony_ci{
223762306a36Sopenharmony_ci	struct ieee80211_twt_params *twt_agrt;
223862306a36Sopenharmony_ci	u64 interval, duration;
223962306a36Sopenharmony_ci	u16 mantissa;
224062306a36Sopenharmony_ci	u8 exp;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	/* only individual agreement supported */
224362306a36Sopenharmony_ci	if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
224462306a36Sopenharmony_ci		return -EOPNOTSUPP;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	/* only 256us unit supported */
224762306a36Sopenharmony_ci	if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
224862306a36Sopenharmony_ci		return -EOPNOTSUPP;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	twt_agrt = (struct ieee80211_twt_params *)twt->params;
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	/* explicit agreement not supported */
225362306a36Sopenharmony_ci	if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
225462306a36Sopenharmony_ci		return -EOPNOTSUPP;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
225762306a36Sopenharmony_ci			le16_to_cpu(twt_agrt->req_type));
225862306a36Sopenharmony_ci	mantissa = le16_to_cpu(twt_agrt->mantissa);
225962306a36Sopenharmony_ci	duration = twt_agrt->min_twt_dur << 8;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci	interval = (u64)mantissa << exp;
226262306a36Sopenharmony_ci	if (interval < duration)
226362306a36Sopenharmony_ci		return -EOPNOTSUPP;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	return 0;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_cistatic bool
226962306a36Sopenharmony_cimt7915_mac_twt_param_equal(struct mt7915_sta *msta,
227062306a36Sopenharmony_ci			   struct ieee80211_twt_params *twt_agrt)
227162306a36Sopenharmony_ci{
227262306a36Sopenharmony_ci	u16 type = le16_to_cpu(twt_agrt->req_type);
227362306a36Sopenharmony_ci	u8 exp;
227462306a36Sopenharmony_ci	int i;
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type);
227762306a36Sopenharmony_ci	for (i = 0; i < MT7915_MAX_STA_TWT_AGRT; i++) {
227862306a36Sopenharmony_ci		struct mt7915_twt_flow *f;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci		if (!(msta->twt.flowid_mask & BIT(i)))
228162306a36Sopenharmony_ci			continue;
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci		f = &msta->twt.flow[i];
228462306a36Sopenharmony_ci		if (f->duration == twt_agrt->min_twt_dur &&
228562306a36Sopenharmony_ci		    f->mantissa == twt_agrt->mantissa &&
228662306a36Sopenharmony_ci		    f->exp == exp &&
228762306a36Sopenharmony_ci		    f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) &&
228862306a36Sopenharmony_ci		    f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) &&
228962306a36Sopenharmony_ci		    f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER))
229062306a36Sopenharmony_ci			return true;
229162306a36Sopenharmony_ci	}
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	return false;
229462306a36Sopenharmony_ci}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_civoid mt7915_mac_add_twt_setup(struct ieee80211_hw *hw,
229762306a36Sopenharmony_ci			      struct ieee80211_sta *sta,
229862306a36Sopenharmony_ci			      struct ieee80211_twt_setup *twt)
229962306a36Sopenharmony_ci{
230062306a36Sopenharmony_ci	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
230162306a36Sopenharmony_ci	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
230262306a36Sopenharmony_ci	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
230362306a36Sopenharmony_ci	u16 req_type = le16_to_cpu(twt_agrt->req_type);
230462306a36Sopenharmony_ci	enum ieee80211_twt_setup_cmd sta_setup_cmd;
230562306a36Sopenharmony_ci	struct mt7915_dev *dev = mt7915_hw_dev(hw);
230662306a36Sopenharmony_ci	struct mt7915_twt_flow *flow;
230762306a36Sopenharmony_ci	int flowid, table_id;
230862306a36Sopenharmony_ci	u8 exp;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	if (mt7915_mac_check_twt_req(twt))
231162306a36Sopenharmony_ci		goto out;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	if (dev->twt.n_agrt == MT7915_MAX_TWT_AGRT)
231662306a36Sopenharmony_ci		goto unlock;
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
231962306a36Sopenharmony_ci		goto unlock;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	if (twt_agrt->min_twt_dur < MT7915_MIN_TWT_DUR) {
232262306a36Sopenharmony_ci		setup_cmd = TWT_SETUP_CMD_DICTATE;
232362306a36Sopenharmony_ci		twt_agrt->min_twt_dur = MT7915_MIN_TWT_DUR;
232462306a36Sopenharmony_ci		goto unlock;
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	flowid = ffs(~msta->twt.flowid_mask) - 1;
232862306a36Sopenharmony_ci	twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID);
232962306a36Sopenharmony_ci	twt_agrt->req_type |= le16_encode_bits(flowid,
233062306a36Sopenharmony_ci					       IEEE80211_TWT_REQTYPE_FLOWID);
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	table_id = ffs(~dev->twt.table_mask) - 1;
233362306a36Sopenharmony_ci	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
233462306a36Sopenharmony_ci	sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	if (mt7915_mac_twt_param_equal(msta, twt_agrt))
233762306a36Sopenharmony_ci		goto unlock;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	flow = &msta->twt.flow[flowid];
234062306a36Sopenharmony_ci	memset(flow, 0, sizeof(*flow));
234162306a36Sopenharmony_ci	INIT_LIST_HEAD(&flow->list);
234262306a36Sopenharmony_ci	flow->wcid = msta->wcid.idx;
234362306a36Sopenharmony_ci	flow->table_id = table_id;
234462306a36Sopenharmony_ci	flow->id = flowid;
234562306a36Sopenharmony_ci	flow->duration = twt_agrt->min_twt_dur;
234662306a36Sopenharmony_ci	flow->mantissa = twt_agrt->mantissa;
234762306a36Sopenharmony_ci	flow->exp = exp;
234862306a36Sopenharmony_ci	flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
234962306a36Sopenharmony_ci	flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
235062306a36Sopenharmony_ci	flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
235362306a36Sopenharmony_ci	    sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
235462306a36Sopenharmony_ci		u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
235562306a36Sopenharmony_ci		u64 flow_tsf, curr_tsf;
235662306a36Sopenharmony_ci		u32 rem;
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci		flow->sched = true;
235962306a36Sopenharmony_ci		flow->start_tsf = mt7915_mac_twt_sched_list_add(dev, flow);
236062306a36Sopenharmony_ci		curr_tsf = __mt7915_get_tsf(hw, msta->vif);
236162306a36Sopenharmony_ci		div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
236262306a36Sopenharmony_ci		flow_tsf = curr_tsf + interval - rem;
236362306a36Sopenharmony_ci		twt_agrt->twt = cpu_to_le64(flow_tsf);
236462306a36Sopenharmony_ci	} else {
236562306a36Sopenharmony_ci		list_add_tail(&flow->list, &dev->twt_list);
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci	flow->tsf = le64_to_cpu(twt_agrt->twt);
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
237062306a36Sopenharmony_ci		goto unlock;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	setup_cmd = TWT_SETUP_CMD_ACCEPT;
237362306a36Sopenharmony_ci	dev->twt.table_mask |= BIT(table_id);
237462306a36Sopenharmony_ci	msta->twt.flowid_mask |= BIT(flowid);
237562306a36Sopenharmony_ci	dev->twt.n_agrt++;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ciunlock:
237862306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
237962306a36Sopenharmony_ciout:
238062306a36Sopenharmony_ci	twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD);
238162306a36Sopenharmony_ci	twt_agrt->req_type |=
238262306a36Sopenharmony_ci		le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD);
238362306a36Sopenharmony_ci	twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) |
238462306a36Sopenharmony_ci		       (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED);
238562306a36Sopenharmony_ci}
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_civoid mt7915_mac_twt_teardown_flow(struct mt7915_dev *dev,
238862306a36Sopenharmony_ci				  struct mt7915_sta *msta,
238962306a36Sopenharmony_ci				  u8 flowid)
239062306a36Sopenharmony_ci{
239162306a36Sopenharmony_ci	struct mt7915_twt_flow *flow;
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	lockdep_assert_held(&dev->mt76.mutex);
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	if (flowid >= ARRAY_SIZE(msta->twt.flow))
239662306a36Sopenharmony_ci		return;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (!(msta->twt.flowid_mask & BIT(flowid)))
239962306a36Sopenharmony_ci		return;
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	flow = &msta->twt.flow[flowid];
240262306a36Sopenharmony_ci	if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow,
240362306a36Sopenharmony_ci				       MCU_TWT_AGRT_DELETE))
240462306a36Sopenharmony_ci		return;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	list_del_init(&flow->list);
240762306a36Sopenharmony_ci	msta->twt.flowid_mask &= ~BIT(flowid);
240862306a36Sopenharmony_ci	dev->twt.table_mask &= ~BIT(flow->table_id);
240962306a36Sopenharmony_ci	dev->twt.n_agrt--;
241062306a36Sopenharmony_ci}
2411