198686cd2SShayne Chen // SPDX-License-Identifier: ISC
298686cd2SShayne Chen /*
398686cd2SShayne Chen  * Copyright (C) 2022 MediaTek Inc.
498686cd2SShayne Chen  */
598686cd2SShayne Chen 
698686cd2SShayne Chen #include <linux/etherdevice.h>
798686cd2SShayne Chen #include <linux/timekeeping.h>
8878161d5SRyder Lee #include "coredump.h"
998686cd2SShayne Chen #include "mt7996.h"
1098686cd2SShayne Chen #include "../dma.h"
1198686cd2SShayne Chen #include "mac.h"
1298686cd2SShayne Chen #include "mcu.h"
1398686cd2SShayne Chen 
14ea5d99d0SRyder Lee #define to_rssi(field, rcpi)	((FIELD_GET(field, rcpi) - 220) / 2)
1598686cd2SShayne Chen 
1698686cd2SShayne Chen #define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
1798686cd2SShayne Chen #define HE_PREP(f, m, v)	le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
1898686cd2SShayne Chen 						 IEEE80211_RADIOTAP_HE_##f)
1998686cd2SShayne Chen 
2098686cd2SShayne Chen static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
2198686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
2298686cd2SShayne Chen 	.radar_pattern = {
2398686cd2SShayne Chen 		[5] =  { 1, 0,  6, 32, 28, 0,  990, 5010, 17, 1, 1 },
2498686cd2SShayne Chen 		[6] =  { 1, 0,  9, 32, 28, 0,  615, 5010, 27, 1, 1 },
2598686cd2SShayne Chen 		[7] =  { 1, 0, 15, 32, 28, 0,  240,  445, 27, 1, 1 },
2698686cd2SShayne Chen 		[8] =  { 1, 0, 12, 32, 28, 0,  240,  510, 42, 1, 1 },
2798686cd2SShayne Chen 		[9] =  { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
2898686cd2SShayne Chen 		[10] = { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
2998686cd2SShayne Chen 		[11] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 18, 32, 28, { },  54 },
3098686cd2SShayne Chen 		[12] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 27, 32, 24, { },  54 },
3198686cd2SShayne Chen 	},
3298686cd2SShayne Chen };
3398686cd2SShayne Chen 
3498686cd2SShayne Chen static const struct mt7996_dfs_radar_spec fcc_radar_specs = {
3598686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
3698686cd2SShayne Chen 	.radar_pattern = {
3798686cd2SShayne Chen 		[0] = { 1, 0,  8,  32, 28, 0, 508, 3076, 13, 1,  1 },
3898686cd2SShayne Chen 		[1] = { 1, 0, 12,  32, 28, 0, 140,  240, 17, 1,  1 },
3998686cd2SShayne Chen 		[2] = { 1, 0,  8,  32, 28, 0, 190,  510, 22, 1,  1 },
4098686cd2SShayne Chen 		[3] = { 1, 0,  6,  32, 28, 0, 190,  510, 32, 1,  1 },
4198686cd2SShayne Chen 		[4] = { 1, 0,  9, 255, 28, 0, 323,  343, 13, 1, 32 },
4298686cd2SShayne Chen 	},
4398686cd2SShayne Chen };
4498686cd2SShayne Chen 
4598686cd2SShayne Chen static const struct mt7996_dfs_radar_spec jp_radar_specs = {
4698686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
4798686cd2SShayne Chen 	.radar_pattern = {
4898686cd2SShayne Chen 		[0] =  { 1, 0,  8,  32, 28, 0,  508, 3076,  13, 1,  1 },
4998686cd2SShayne Chen 		[1] =  { 1, 0, 12,  32, 28, 0,  140,  240,  17, 1,  1 },
5098686cd2SShayne Chen 		[2] =  { 1, 0,  8,  32, 28, 0,  190,  510,  22, 1,  1 },
5198686cd2SShayne Chen 		[3] =  { 1, 0,  6,  32, 28, 0,  190,  510,  32, 1,  1 },
5298686cd2SShayne Chen 		[4] =  { 1, 0,  9, 255, 28, 0,  323,  343,  13, 1, 32 },
5398686cd2SShayne Chen 		[13] = { 1, 0,  7,  32, 28, 0, 3836, 3856,  14, 1,  1 },
5498686cd2SShayne Chen 		[14] = { 1, 0,  6,  32, 28, 0,  615, 5010, 110, 1,  1 },
5598686cd2SShayne Chen 		[15] = { 1, 1,  0,   0,  0, 0,   15, 5010, 110, 0,  0, 12, 32, 28 },
5698686cd2SShayne Chen 	},
5798686cd2SShayne Chen };
5898686cd2SShayne Chen 
5998686cd2SShayne Chen static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
6098686cd2SShayne Chen 					    u16 idx, bool unicast)
6198686cd2SShayne Chen {
6298686cd2SShayne Chen 	struct mt7996_sta *sta;
6398686cd2SShayne Chen 	struct mt76_wcid *wcid;
6498686cd2SShayne Chen 
6598686cd2SShayne Chen 	if (idx >= ARRAY_SIZE(dev->mt76.wcid))
6698686cd2SShayne Chen 		return NULL;
6798686cd2SShayne Chen 
6898686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[idx]);
6998686cd2SShayne Chen 	if (unicast || !wcid)
7098686cd2SShayne Chen 		return wcid;
7198686cd2SShayne Chen 
7298686cd2SShayne Chen 	if (!wcid->sta)
7398686cd2SShayne Chen 		return NULL;
7498686cd2SShayne Chen 
7598686cd2SShayne Chen 	sta = container_of(wcid, struct mt7996_sta, wcid);
7698686cd2SShayne Chen 	if (!sta->vif)
7798686cd2SShayne Chen 		return NULL;
7898686cd2SShayne Chen 
7998686cd2SShayne Chen 	return &sta->vif->sta.wcid;
8098686cd2SShayne Chen }
8198686cd2SShayne Chen 
8298686cd2SShayne Chen bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
8398686cd2SShayne Chen {
8498686cd2SShayne Chen 	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
8598686cd2SShayne Chen 		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
8698686cd2SShayne Chen 
8798686cd2SShayne Chen 	return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
8898686cd2SShayne Chen 			 0, 5000);
8998686cd2SShayne Chen }
9098686cd2SShayne Chen 
9198686cd2SShayne Chen u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
9298686cd2SShayne Chen {
9398686cd2SShayne Chen 	mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
9498686cd2SShayne Chen 		FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
9598686cd2SShayne Chen 
9698686cd2SShayne Chen 	return MT_WTBL_LMAC_OFFS(wcid, dw);
9798686cd2SShayne Chen }
9898686cd2SShayne Chen 
9998686cd2SShayne Chen static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
10098686cd2SShayne Chen {
10198686cd2SShayne Chen 	static const u8 ac_to_tid[] = {
10298686cd2SShayne Chen 		[IEEE80211_AC_BE] = 0,
10398686cd2SShayne Chen 		[IEEE80211_AC_BK] = 1,
10498686cd2SShayne Chen 		[IEEE80211_AC_VI] = 4,
10598686cd2SShayne Chen 		[IEEE80211_AC_VO] = 6
10698686cd2SShayne Chen 	};
10798686cd2SShayne Chen 	struct ieee80211_sta *sta;
10898686cd2SShayne Chen 	struct mt7996_sta *msta;
10998686cd2SShayne Chen 	struct rate_info *rate;
11098686cd2SShayne Chen 	u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
11198686cd2SShayne Chen 	LIST_HEAD(sta_poll_list);
11298686cd2SShayne Chen 	int i;
11398686cd2SShayne Chen 
11498686cd2SShayne Chen 	spin_lock_bh(&dev->sta_poll_lock);
11598686cd2SShayne Chen 	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
11698686cd2SShayne Chen 	spin_unlock_bh(&dev->sta_poll_lock);
11798686cd2SShayne Chen 
11898686cd2SShayne Chen 	rcu_read_lock();
11998686cd2SShayne Chen 
12098686cd2SShayne Chen 	while (true) {
12198686cd2SShayne Chen 		bool clear = false;
12298686cd2SShayne Chen 		u32 addr, val;
12398686cd2SShayne Chen 		u16 idx;
124ea5d99d0SRyder Lee 		s8 rssi[4];
12598686cd2SShayne Chen 		u8 bw;
12698686cd2SShayne Chen 
12798686cd2SShayne Chen 		spin_lock_bh(&dev->sta_poll_lock);
12898686cd2SShayne Chen 		if (list_empty(&sta_poll_list)) {
12998686cd2SShayne Chen 			spin_unlock_bh(&dev->sta_poll_lock);
13098686cd2SShayne Chen 			break;
13198686cd2SShayne Chen 		}
13298686cd2SShayne Chen 		msta = list_first_entry(&sta_poll_list,
13398686cd2SShayne Chen 					struct mt7996_sta, poll_list);
13498686cd2SShayne Chen 		list_del_init(&msta->poll_list);
13598686cd2SShayne Chen 		spin_unlock_bh(&dev->sta_poll_lock);
13698686cd2SShayne Chen 
13798686cd2SShayne Chen 		idx = msta->wcid.idx;
138ea5d99d0SRyder Lee 
139ea5d99d0SRyder Lee 		/* refresh peer's airtime reporting */
14098686cd2SShayne Chen 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
14198686cd2SShayne Chen 
14298686cd2SShayne Chen 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
14398686cd2SShayne Chen 			u32 tx_last = msta->airtime_ac[i];
14498686cd2SShayne Chen 			u32 rx_last = msta->airtime_ac[i + 4];
14598686cd2SShayne Chen 
14698686cd2SShayne Chen 			msta->airtime_ac[i] = mt76_rr(dev, addr);
14798686cd2SShayne Chen 			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
14898686cd2SShayne Chen 
14998686cd2SShayne Chen 			tx_time[i] = msta->airtime_ac[i] - tx_last;
15098686cd2SShayne Chen 			rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
15198686cd2SShayne Chen 
15298686cd2SShayne Chen 			if ((tx_last | rx_last) & BIT(30))
15398686cd2SShayne Chen 				clear = true;
15498686cd2SShayne Chen 
15598686cd2SShayne Chen 			addr += 8;
15698686cd2SShayne Chen 		}
15798686cd2SShayne Chen 
15898686cd2SShayne Chen 		if (clear) {
15998686cd2SShayne Chen 			mt7996_mac_wtbl_update(dev, idx,
16098686cd2SShayne Chen 					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
16198686cd2SShayne Chen 			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
16298686cd2SShayne Chen 		}
16398686cd2SShayne Chen 
16498686cd2SShayne Chen 		if (!msta->wcid.sta)
16598686cd2SShayne Chen 			continue;
16698686cd2SShayne Chen 
16798686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta,
16898686cd2SShayne Chen 				   drv_priv);
16998686cd2SShayne Chen 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
17098686cd2SShayne Chen 			u8 q = mt76_connac_lmac_mapping(i);
17198686cd2SShayne Chen 			u32 tx_cur = tx_time[q];
17298686cd2SShayne Chen 			u32 rx_cur = rx_time[q];
17398686cd2SShayne Chen 			u8 tid = ac_to_tid[i];
17498686cd2SShayne Chen 
17598686cd2SShayne Chen 			if (!tx_cur && !rx_cur)
17698686cd2SShayne Chen 				continue;
17798686cd2SShayne Chen 
17898686cd2SShayne Chen 			ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
17998686cd2SShayne Chen 		}
18098686cd2SShayne Chen 
18198686cd2SShayne Chen 		/* We don't support reading GI info from txs packets.
18298686cd2SShayne Chen 		 * For accurate tx status reporting and AQL improvement,
18398686cd2SShayne Chen 		 * we need to make sure that flags match so polling GI
18498686cd2SShayne Chen 		 * from per-sta counters directly.
18598686cd2SShayne Chen 		 */
18698686cd2SShayne Chen 		rate = &msta->wcid.rate;
18798686cd2SShayne Chen 
18898686cd2SShayne Chen 		switch (rate->bw) {
18980f5a31dSShayne Chen 		case RATE_INFO_BW_320:
19080f5a31dSShayne Chen 			bw = IEEE80211_STA_RX_BW_320;
19180f5a31dSShayne Chen 			break;
19298686cd2SShayne Chen 		case RATE_INFO_BW_160:
19398686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_160;
19498686cd2SShayne Chen 			break;
19598686cd2SShayne Chen 		case RATE_INFO_BW_80:
19698686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_80;
19798686cd2SShayne Chen 			break;
19898686cd2SShayne Chen 		case RATE_INFO_BW_40:
19998686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_40;
20098686cd2SShayne Chen 			break;
20198686cd2SShayne Chen 		default:
20298686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_20;
20398686cd2SShayne Chen 			break;
20498686cd2SShayne Chen 		}
20598686cd2SShayne Chen 
20698686cd2SShayne Chen 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
20798686cd2SShayne Chen 		val = mt76_rr(dev, addr);
20880f5a31dSShayne Chen 		if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
20980f5a31dSShayne Chen 			addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
21080f5a31dSShayne Chen 			val = mt76_rr(dev, addr);
21180f5a31dSShayne Chen 			rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
21280f5a31dSShayne Chen 		} else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
21398686cd2SShayne Chen 			u8 offs = 24 + 2 * bw;
21498686cd2SShayne Chen 
21598686cd2SShayne Chen 			rate->he_gi = (val & (0x3 << offs)) >> offs;
21698686cd2SShayne Chen 		} else if (rate->flags &
21798686cd2SShayne Chen 			   (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
21898686cd2SShayne Chen 			if (val & BIT(12 + bw))
21998686cd2SShayne Chen 				rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
22098686cd2SShayne Chen 			else
22198686cd2SShayne Chen 				rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
22298686cd2SShayne Chen 		}
223ea5d99d0SRyder Lee 
224ea5d99d0SRyder Lee 		/* get signal strength of resp frames (CTS/BA/ACK) */
225ea5d99d0SRyder Lee 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
226ea5d99d0SRyder Lee 		val = mt76_rr(dev, addr);
227ea5d99d0SRyder Lee 
228ea5d99d0SRyder Lee 		rssi[0] = to_rssi(GENMASK(7, 0), val);
229ea5d99d0SRyder Lee 		rssi[1] = to_rssi(GENMASK(15, 8), val);
230ea5d99d0SRyder Lee 		rssi[2] = to_rssi(GENMASK(23, 16), val);
231ea5d99d0SRyder Lee 		rssi[3] = to_rssi(GENMASK(31, 14), val);
232ea5d99d0SRyder Lee 
233ea5d99d0SRyder Lee 		msta->ack_signal =
234ea5d99d0SRyder Lee 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
235ea5d99d0SRyder Lee 
236ea5d99d0SRyder Lee 		ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
23798686cd2SShayne Chen 	}
23898686cd2SShayne Chen 
23998686cd2SShayne Chen 	rcu_read_unlock();
24098686cd2SShayne Chen }
24198686cd2SShayne Chen 
242d75e739bSRyder Lee void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
243d75e739bSRyder Lee 			      struct ieee80211_vif *vif, bool enable)
244d75e739bSRyder Lee {
245d75e739bSRyder Lee 	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
246d75e739bSRyder Lee 	u32 addr;
247d75e739bSRyder Lee 
248d75e739bSRyder Lee 	addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
249d75e739bSRyder Lee 	if (enable)
250d75e739bSRyder Lee 		mt76_set(dev, addr, BIT(5));
251d75e739bSRyder Lee 	else
252d75e739bSRyder Lee 		mt76_clear(dev, addr, BIT(5));
253d75e739bSRyder Lee }
254d75e739bSRyder Lee 
25515ee62e7SRyder Lee void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
25615ee62e7SRyder Lee 				     u8 tbl_idx, u16 rate_idx)
25715ee62e7SRyder Lee {
25815ee62e7SRyder Lee 	u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;
25915ee62e7SRyder Lee 
26015ee62e7SRyder Lee 	mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);
26115ee62e7SRyder Lee 	/* use wtbl spe idx */
26215ee62e7SRyder Lee 	mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);
26315ee62e7SRyder Lee 	mt76_wr(dev, MT_WTBL_ITCR, ctrl);
26415ee62e7SRyder Lee }
26515ee62e7SRyder Lee 
26698686cd2SShayne Chen static void
26798686cd2SShayne Chen mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
26898686cd2SShayne Chen 				 struct ieee80211_radiotap_he *he,
26998686cd2SShayne Chen 				 __le32 *rxv)
27098686cd2SShayne Chen {
27163a37246SRyder Lee 	u32 ru, offs = 0;
27298686cd2SShayne Chen 
27363a37246SRyder Lee 	ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC);
27498686cd2SShayne Chen 
27598686cd2SShayne Chen 	status->bw = RATE_INFO_BW_HE_RU;
27698686cd2SShayne Chen 
27798686cd2SShayne Chen 	switch (ru) {
27898686cd2SShayne Chen 	case 0 ... 36:
27998686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
28098686cd2SShayne Chen 		offs = ru;
28198686cd2SShayne Chen 		break;
28298686cd2SShayne Chen 	case 37 ... 52:
28398686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
28498686cd2SShayne Chen 		offs = ru - 37;
28598686cd2SShayne Chen 		break;
28698686cd2SShayne Chen 	case 53 ... 60:
28798686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
28898686cd2SShayne Chen 		offs = ru - 53;
28998686cd2SShayne Chen 		break;
29098686cd2SShayne Chen 	case 61 ... 64:
29198686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
29298686cd2SShayne Chen 		offs = ru - 61;
29398686cd2SShayne Chen 		break;
29498686cd2SShayne Chen 	case 65 ... 66:
29598686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
29698686cd2SShayne Chen 		offs = ru - 65;
29798686cd2SShayne Chen 		break;
29898686cd2SShayne Chen 	case 67:
29998686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
30098686cd2SShayne Chen 		break;
30198686cd2SShayne Chen 	case 68:
30298686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
30398686cd2SShayne Chen 		break;
30498686cd2SShayne Chen 	}
30598686cd2SShayne Chen 
30698686cd2SShayne Chen 	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
30798686cd2SShayne Chen 	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
30898686cd2SShayne Chen 		     le16_encode_bits(offs,
30998686cd2SShayne Chen 				      IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
31098686cd2SShayne Chen }
31198686cd2SShayne Chen 
31298686cd2SShayne Chen static void
31398686cd2SShayne Chen mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
31498686cd2SShayne Chen {
31598686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
31698686cd2SShayne Chen 	static const struct ieee80211_radiotap_he_mu mu_known = {
31798686cd2SShayne Chen 		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
31898686cd2SShayne Chen 			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
31998686cd2SShayne Chen 			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
32098686cd2SShayne Chen 			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
32198686cd2SShayne Chen 		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
32298686cd2SShayne Chen 	};
32398686cd2SShayne Chen 	struct ieee80211_radiotap_he_mu *he_mu = NULL;
32498686cd2SShayne Chen 
32598686cd2SShayne Chen 	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
32698686cd2SShayne Chen 
32798686cd2SShayne Chen 	he_mu = skb_push(skb, sizeof(mu_known));
32898686cd2SShayne Chen 	memcpy(he_mu, &mu_known, sizeof(mu_known));
32998686cd2SShayne Chen 
33098686cd2SShayne Chen #define MU_PREP(f, v)	le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
33198686cd2SShayne Chen 
33298686cd2SShayne Chen 	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
33398686cd2SShayne Chen 	if (status->he_dcm)
33498686cd2SShayne Chen 		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
33598686cd2SShayne Chen 
33698686cd2SShayne Chen 	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
33798686cd2SShayne Chen 			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
33863a37246SRyder Lee 				 le32_get_bits(rxv[4], MT_CRXV_HE_NUM_USER));
33998686cd2SShayne Chen 
34063a37246SRyder Lee 	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
34198686cd2SShayne Chen 
34298686cd2SShayne Chen 	if (status->bw >= RATE_INFO_BW_40) {
34398686cd2SShayne Chen 		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
34463a37246SRyder Lee 		he_mu->ru_ch2[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU1) & 0xff;
34598686cd2SShayne Chen 	}
34698686cd2SShayne Chen 
34798686cd2SShayne Chen 	if (status->bw >= RATE_INFO_BW_80) {
34863a37246SRyder Lee 		u32 ru_h, ru_l;
34963a37246SRyder Lee 
35063a37246SRyder Lee 		he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
35163a37246SRyder Lee 
35263a37246SRyder Lee 		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
35363a37246SRyder Lee 		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
35463a37246SRyder Lee 		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
35598686cd2SShayne Chen 	}
35698686cd2SShayne Chen }
35798686cd2SShayne Chen 
35898686cd2SShayne Chen static void
35998686cd2SShayne Chen mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
36098686cd2SShayne Chen {
36198686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
36298686cd2SShayne Chen 	static const struct ieee80211_radiotap_he known = {
36398686cd2SShayne Chen 		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
36498686cd2SShayne Chen 			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
36598686cd2SShayne Chen 			 HE_BITS(DATA1_STBC_KNOWN) |
36698686cd2SShayne Chen 			 HE_BITS(DATA1_CODING_KNOWN) |
36798686cd2SShayne Chen 			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
36898686cd2SShayne Chen 			 HE_BITS(DATA1_DOPPLER_KNOWN) |
36998686cd2SShayne Chen 			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
37098686cd2SShayne Chen 			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
37198686cd2SShayne Chen 		.data2 = HE_BITS(DATA2_GI_KNOWN) |
37298686cd2SShayne Chen 			 HE_BITS(DATA2_TXBF_KNOWN) |
37398686cd2SShayne Chen 			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
37498686cd2SShayne Chen 			 HE_BITS(DATA2_TXOP_KNOWN),
37598686cd2SShayne Chen 	};
37698686cd2SShayne Chen 	struct ieee80211_radiotap_he *he = NULL;
37763a37246SRyder Lee 	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
37898686cd2SShayne Chen 
37998686cd2SShayne Chen 	status->flag |= RX_FLAG_RADIOTAP_HE;
38098686cd2SShayne Chen 
38198686cd2SShayne Chen 	he = skb_push(skb, sizeof(known));
38298686cd2SShayne Chen 	memcpy(he, &known, sizeof(known));
38398686cd2SShayne Chen 
38463a37246SRyder Lee 	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
38563a37246SRyder Lee 		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
38663a37246SRyder Lee 	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
38763a37246SRyder Lee 	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
38898686cd2SShayne Chen 		    le16_encode_bits(ltf_size,
38998686cd2SShayne Chen 				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
39098686cd2SShayne Chen 	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
39198686cd2SShayne Chen 		he->data5 |= HE_BITS(DATA5_TXBF);
39263a37246SRyder Lee 	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
39363a37246SRyder Lee 		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
39498686cd2SShayne Chen 
39598686cd2SShayne Chen 	switch (mode) {
39698686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
39798686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
39898686cd2SShayne Chen 			     HE_BITS(DATA1_UL_DL_KNOWN) |
39998686cd2SShayne Chen 			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
40098686cd2SShayne Chen 			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
40198686cd2SShayne Chen 
40263a37246SRyder Lee 		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) |
40363a37246SRyder Lee 			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
40498686cd2SShayne Chen 		break;
40598686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
40698686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
40798686cd2SShayne Chen 			     HE_BITS(DATA1_UL_DL_KNOWN) |
40898686cd2SShayne Chen 			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
40998686cd2SShayne Chen 
41063a37246SRyder Lee 		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
41198686cd2SShayne Chen 		break;
41298686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
41398686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
41498686cd2SShayne Chen 			     HE_BITS(DATA1_UL_DL_KNOWN);
41598686cd2SShayne Chen 
41663a37246SRyder Lee 		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
41763a37246SRyder Lee 		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
41898686cd2SShayne Chen 
41998686cd2SShayne Chen 		mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
42098686cd2SShayne Chen 		mt7996_mac_decode_he_mu_radiotap(skb, rxv);
42198686cd2SShayne Chen 		break;
42298686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
42398686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
42498686cd2SShayne Chen 			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
42598686cd2SShayne Chen 			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
42698686cd2SShayne Chen 			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
42798686cd2SShayne Chen 
42863a37246SRyder Lee 		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[13]) |
42963a37246SRyder Lee 			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
43063a37246SRyder Lee 			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
43163a37246SRyder Lee 			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
43298686cd2SShayne Chen 
43398686cd2SShayne Chen 		mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
43498686cd2SShayne Chen 		break;
43598686cd2SShayne Chen 	default:
43698686cd2SShayne Chen 		break;
43798686cd2SShayne Chen 	}
43898686cd2SShayne Chen }
43998686cd2SShayne Chen 
44098686cd2SShayne Chen /* The HW does not translate the mac header to 802.3 for mesh point */
44198686cd2SShayne Chen static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
44298686cd2SShayne Chen {
44398686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
44498686cd2SShayne Chen 	struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
44598686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid;
44698686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
44798686cd2SShayne Chen 	struct ieee80211_sta *sta;
44898686cd2SShayne Chen 	struct ieee80211_vif *vif;
44998686cd2SShayne Chen 	struct ieee80211_hdr hdr;
45098686cd2SShayne Chen 	u16 frame_control;
45198686cd2SShayne Chen 
45298686cd2SShayne Chen 	if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
45398686cd2SShayne Chen 	    MT_RXD3_NORMAL_U2M)
45498686cd2SShayne Chen 		return -EINVAL;
45598686cd2SShayne Chen 
45698686cd2SShayne Chen 	if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
45798686cd2SShayne Chen 		return -EINVAL;
45898686cd2SShayne Chen 
45998686cd2SShayne Chen 	if (!msta || !msta->vif)
46098686cd2SShayne Chen 		return -EINVAL;
46198686cd2SShayne Chen 
46298686cd2SShayne Chen 	sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
46398686cd2SShayne Chen 	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
46498686cd2SShayne Chen 
46598686cd2SShayne Chen 	/* store the info from RXD and ethhdr to avoid being overridden */
46698686cd2SShayne Chen 	frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);
46798686cd2SShayne Chen 	hdr.frame_control = cpu_to_le16(frame_control);
46898686cd2SShayne Chen 	hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL));
46998686cd2SShayne Chen 	hdr.duration_id = 0;
47098686cd2SShayne Chen 
47198686cd2SShayne Chen 	ether_addr_copy(hdr.addr1, vif->addr);
47298686cd2SShayne Chen 	ether_addr_copy(hdr.addr2, sta->addr);
47398686cd2SShayne Chen 	switch (frame_control & (IEEE80211_FCTL_TODS |
47498686cd2SShayne Chen 				 IEEE80211_FCTL_FROMDS)) {
47598686cd2SShayne Chen 	case 0:
47698686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
47798686cd2SShayne Chen 		break;
47898686cd2SShayne Chen 	case IEEE80211_FCTL_FROMDS:
47998686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_source);
48098686cd2SShayne Chen 		break;
48198686cd2SShayne Chen 	case IEEE80211_FCTL_TODS:
48298686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
48398686cd2SShayne Chen 		break;
48498686cd2SShayne Chen 	case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
48598686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
48698686cd2SShayne Chen 		ether_addr_copy(hdr.addr4, eth_hdr->h_source);
48798686cd2SShayne Chen 		break;
48898686cd2SShayne Chen 	default:
489aed8d9b5SLorenzo Bianconi 		return -EINVAL;
49098686cd2SShayne Chen 	}
49198686cd2SShayne Chen 
49298686cd2SShayne Chen 	skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
49398686cd2SShayne Chen 	if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
49498686cd2SShayne Chen 	    eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
49598686cd2SShayne Chen 		ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
49698686cd2SShayne Chen 	else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
49798686cd2SShayne Chen 		ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
49898686cd2SShayne Chen 	else
49998686cd2SShayne Chen 		skb_pull(skb, 2);
50098686cd2SShayne Chen 
50198686cd2SShayne Chen 	if (ieee80211_has_order(hdr.frame_control))
50298686cd2SShayne Chen 		memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11],
50398686cd2SShayne Chen 		       IEEE80211_HT_CTL_LEN);
50498686cd2SShayne Chen 	if (ieee80211_is_data_qos(hdr.frame_control)) {
50598686cd2SShayne Chen 		__le16 qos_ctrl;
50698686cd2SShayne Chen 
50798686cd2SShayne Chen 		qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL));
50898686cd2SShayne Chen 		memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
50998686cd2SShayne Chen 		       IEEE80211_QOS_CTL_LEN);
51098686cd2SShayne Chen 	}
51198686cd2SShayne Chen 
51298686cd2SShayne Chen 	if (ieee80211_has_a4(hdr.frame_control))
51398686cd2SShayne Chen 		memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
51498686cd2SShayne Chen 	else
51598686cd2SShayne Chen 		memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
51698686cd2SShayne Chen 
51798686cd2SShayne Chen 	return 0;
51898686cd2SShayne Chen }
51998686cd2SShayne Chen 
52098686cd2SShayne Chen static int
52198686cd2SShayne Chen mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
52298686cd2SShayne Chen 			struct mt76_rx_status *status,
52398686cd2SShayne Chen 			struct ieee80211_supported_band *sband,
52498686cd2SShayne Chen 			__le32 *rxv, u8 *mode)
52598686cd2SShayne Chen {
52698686cd2SShayne Chen 	u32 v0, v2;
52798686cd2SShayne Chen 	u8 stbc, gi, bw, dcm, nss;
52898686cd2SShayne Chen 	int i, idx;
52998686cd2SShayne Chen 	bool cck = false;
53098686cd2SShayne Chen 
53198686cd2SShayne Chen 	v0 = le32_to_cpu(rxv[0]);
53298686cd2SShayne Chen 	v2 = le32_to_cpu(rxv[2]);
53398686cd2SShayne Chen 
53498686cd2SShayne Chen 	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
53598686cd2SShayne Chen 	i = idx;
53698686cd2SShayne Chen 	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
53798686cd2SShayne Chen 
53898686cd2SShayne Chen 	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
53998686cd2SShayne Chen 	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
54098686cd2SShayne Chen 	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
54198686cd2SShayne Chen 	dcm = FIELD_GET(MT_PRXV_DCM, v2);
54298686cd2SShayne Chen 	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
54398686cd2SShayne Chen 
54498686cd2SShayne Chen 	switch (*mode) {
54598686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
54698686cd2SShayne Chen 		cck = true;
54798686cd2SShayne Chen 		fallthrough;
54898686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
54998686cd2SShayne Chen 		i = mt76_get_rate(&dev->mt76, sband, i, cck);
55098686cd2SShayne Chen 		break;
55198686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
55298686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
55398686cd2SShayne Chen 		status->encoding = RX_ENC_HT;
55498686cd2SShayne Chen 		if (gi)
55598686cd2SShayne Chen 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
55698686cd2SShayne Chen 		if (i > 31)
55798686cd2SShayne Chen 			return -EINVAL;
55898686cd2SShayne Chen 		break;
55998686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
56098686cd2SShayne Chen 		status->nss = nss;
56198686cd2SShayne Chen 		status->encoding = RX_ENC_VHT;
56298686cd2SShayne Chen 		if (gi)
56398686cd2SShayne Chen 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
56498686cd2SShayne Chen 		if (i > 11)
56598686cd2SShayne Chen 			return -EINVAL;
56698686cd2SShayne Chen 		break;
56798686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
56898686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
56998686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
57098686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
57198686cd2SShayne Chen 		status->nss = nss;
57298686cd2SShayne Chen 		status->encoding = RX_ENC_HE;
57398686cd2SShayne Chen 		i &= GENMASK(3, 0);
57498686cd2SShayne Chen 
57598686cd2SShayne Chen 		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
57698686cd2SShayne Chen 			status->he_gi = gi;
57798686cd2SShayne Chen 
57898686cd2SShayne Chen 		status->he_dcm = dcm;
57998686cd2SShayne Chen 		break;
58080f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
58180f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
58280f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
58380f5a31dSShayne Chen 		status->nss = nss;
584021af945SShayne Chen 		status->encoding = RX_ENC_EHT;
585021af945SShayne Chen 		i &= GENMASK(3, 0);
586021af945SShayne Chen 
587021af945SShayne Chen 		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
588021af945SShayne Chen 			status->eht.gi = gi;
58980f5a31dSShayne Chen 		break;
59098686cd2SShayne Chen 	default:
59198686cd2SShayne Chen 		return -EINVAL;
59298686cd2SShayne Chen 	}
59398686cd2SShayne Chen 	status->rate_idx = i;
59498686cd2SShayne Chen 
59598686cd2SShayne Chen 	switch (bw) {
59698686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_20:
59798686cd2SShayne Chen 		break;
59898686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
59998686cd2SShayne Chen 		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
60098686cd2SShayne Chen 		    (idx & MT_PRXV_TX_ER_SU_106T)) {
60198686cd2SShayne Chen 			status->bw = RATE_INFO_BW_HE_RU;
60298686cd2SShayne Chen 			status->he_ru =
60398686cd2SShayne Chen 				NL80211_RATE_INFO_HE_RU_ALLOC_106;
60498686cd2SShayne Chen 		} else {
60598686cd2SShayne Chen 			status->bw = RATE_INFO_BW_40;
60698686cd2SShayne Chen 		}
60798686cd2SShayne Chen 		break;
60898686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
60998686cd2SShayne Chen 		status->bw = RATE_INFO_BW_80;
61098686cd2SShayne Chen 		break;
61198686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
61298686cd2SShayne Chen 		status->bw = RATE_INFO_BW_160;
61398686cd2SShayne Chen 		break;
61480f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
61580f5a31dSShayne Chen 		status->bw = RATE_INFO_BW_320;
61680f5a31dSShayne Chen 		break;
61798686cd2SShayne Chen 	default:
61898686cd2SShayne Chen 		return -EINVAL;
61998686cd2SShayne Chen 	}
62098686cd2SShayne Chen 
62198686cd2SShayne Chen 	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
62298686cd2SShayne Chen 	if (*mode < MT_PHY_TYPE_HE_SU && gi)
62398686cd2SShayne Chen 		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
62498686cd2SShayne Chen 
62598686cd2SShayne Chen 	return 0;
62698686cd2SShayne Chen }
62798686cd2SShayne Chen 
62898686cd2SShayne Chen static int
62998686cd2SShayne Chen mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
63098686cd2SShayne Chen {
63198686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
63298686cd2SShayne Chen 	struct mt76_phy *mphy = &dev->mt76.phy;
63398686cd2SShayne Chen 	struct mt7996_phy *phy = &dev->phy;
63498686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
63598686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
63698686cd2SShayne Chen 	__le32 *rxv = NULL;
63798686cd2SShayne Chen 	u32 rxd0 = le32_to_cpu(rxd[0]);
63898686cd2SShayne Chen 	u32 rxd1 = le32_to_cpu(rxd[1]);
63998686cd2SShayne Chen 	u32 rxd2 = le32_to_cpu(rxd[2]);
64098686cd2SShayne Chen 	u32 rxd3 = le32_to_cpu(rxd[3]);
64198686cd2SShayne Chen 	u32 rxd4 = le32_to_cpu(rxd[4]);
64298686cd2SShayne Chen 	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
64398686cd2SShayne Chen 	u32 csum_status = *(u32 *)skb->cb;
64427db47abSRyder Lee 	u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP;
64527db47abSRyder Lee 	bool is_mesh = (rxd0 & mesh_mask) == mesh_mask;
64698686cd2SShayne Chen 	bool unicast, insert_ccmp_hdr = false;
64798686cd2SShayne Chen 	u8 remove_pad, amsdu_info, band_idx;
64898686cd2SShayne Chen 	u8 mode = 0, qos_ctl = 0;
64998686cd2SShayne Chen 	bool hdr_trans;
65098686cd2SShayne Chen 	u16 hdr_gap;
65198686cd2SShayne Chen 	u16 seq_ctrl = 0;
65298686cd2SShayne Chen 	__le16 fc = 0;
65398686cd2SShayne Chen 	int idx;
65498686cd2SShayne Chen 
65598686cd2SShayne Chen 	memset(status, 0, sizeof(*status));
65698686cd2SShayne Chen 
65798686cd2SShayne Chen 	band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
65898686cd2SShayne Chen 	mphy = dev->mt76.phys[band_idx];
65998686cd2SShayne Chen 	phy = mphy->priv;
66098686cd2SShayne Chen 	status->phy_idx = mphy->band_idx;
66198686cd2SShayne Chen 
66298686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
66398686cd2SShayne Chen 		return -EINVAL;
66498686cd2SShayne Chen 
66598686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
66698686cd2SShayne Chen 		return -EINVAL;
66798686cd2SShayne Chen 
66898686cd2SShayne Chen 	hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
66998686cd2SShayne Chen 	if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
67098686cd2SShayne Chen 		return -EINVAL;
67198686cd2SShayne Chen 
67298686cd2SShayne Chen 	/* ICV error or CCMP/BIP/WPI MIC error */
67398686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
67498686cd2SShayne Chen 		status->flag |= RX_FLAG_ONLY_MONITOR;
67598686cd2SShayne Chen 
67698686cd2SShayne Chen 	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
67798686cd2SShayne Chen 	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
67898686cd2SShayne Chen 	status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
67998686cd2SShayne Chen 
68098686cd2SShayne Chen 	if (status->wcid) {
68198686cd2SShayne Chen 		struct mt7996_sta *msta;
68298686cd2SShayne Chen 
68398686cd2SShayne Chen 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
68498686cd2SShayne Chen 		spin_lock_bh(&dev->sta_poll_lock);
68598686cd2SShayne Chen 		if (list_empty(&msta->poll_list))
68698686cd2SShayne Chen 			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
68798686cd2SShayne Chen 		spin_unlock_bh(&dev->sta_poll_lock);
68898686cd2SShayne Chen 	}
68998686cd2SShayne Chen 
69098686cd2SShayne Chen 	status->freq = mphy->chandef.chan->center_freq;
69198686cd2SShayne Chen 	status->band = mphy->chandef.chan->band;
69298686cd2SShayne Chen 	if (status->band == NL80211_BAND_5GHZ)
69398686cd2SShayne Chen 		sband = &mphy->sband_5g.sband;
69498686cd2SShayne Chen 	else if (status->band == NL80211_BAND_6GHZ)
69598686cd2SShayne Chen 		sband = &mphy->sband_6g.sband;
69698686cd2SShayne Chen 	else
69798686cd2SShayne Chen 		sband = &mphy->sband_2g.sband;
69898686cd2SShayne Chen 
69998686cd2SShayne Chen 	if (!sband->channels)
70098686cd2SShayne Chen 		return -EINVAL;
70198686cd2SShayne Chen 
70298686cd2SShayne Chen 	if ((rxd0 & csum_mask) == csum_mask &&
70398686cd2SShayne Chen 	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
70498686cd2SShayne Chen 		skb->ip_summed = CHECKSUM_UNNECESSARY;
70598686cd2SShayne Chen 
70698686cd2SShayne Chen 	if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
70798686cd2SShayne Chen 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
70898686cd2SShayne Chen 
70998686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
71098686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_ERROR;
71198686cd2SShayne Chen 
71298686cd2SShayne Chen 	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
71398686cd2SShayne Chen 	    !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
71498686cd2SShayne Chen 		status->flag |= RX_FLAG_DECRYPTED;
71598686cd2SShayne Chen 		status->flag |= RX_FLAG_IV_STRIPPED;
71698686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
71798686cd2SShayne Chen 	}
71898686cd2SShayne Chen 
71998686cd2SShayne Chen 	remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
72098686cd2SShayne Chen 
72198686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
72298686cd2SShayne Chen 		return -EINVAL;
72398686cd2SShayne Chen 
72498686cd2SShayne Chen 	rxd += 8;
72598686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
72698686cd2SShayne Chen 		u32 v0 = le32_to_cpu(rxd[0]);
72798686cd2SShayne Chen 		u32 v2 = le32_to_cpu(rxd[2]);
72898686cd2SShayne Chen 
72998686cd2SShayne Chen 		fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));
73098686cd2SShayne Chen 		qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);
73198686cd2SShayne Chen 		seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);
73298686cd2SShayne Chen 
73398686cd2SShayne Chen 		rxd += 4;
73498686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
73598686cd2SShayne Chen 			return -EINVAL;
73698686cd2SShayne Chen 	}
73798686cd2SShayne Chen 
73898686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
73998686cd2SShayne Chen 		u8 *data = (u8 *)rxd;
74098686cd2SShayne Chen 
74198686cd2SShayne Chen 		if (status->flag & RX_FLAG_DECRYPTED) {
74298686cd2SShayne Chen 			switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
74398686cd2SShayne Chen 			case MT_CIPHER_AES_CCMP:
74498686cd2SShayne Chen 			case MT_CIPHER_CCMP_CCX:
74598686cd2SShayne Chen 			case MT_CIPHER_CCMP_256:
74698686cd2SShayne Chen 				insert_ccmp_hdr =
74798686cd2SShayne Chen 					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
74898686cd2SShayne Chen 				fallthrough;
74998686cd2SShayne Chen 			case MT_CIPHER_TKIP:
75098686cd2SShayne Chen 			case MT_CIPHER_TKIP_NO_MIC:
75198686cd2SShayne Chen 			case MT_CIPHER_GCMP:
75298686cd2SShayne Chen 			case MT_CIPHER_GCMP_256:
75398686cd2SShayne Chen 				status->iv[0] = data[5];
75498686cd2SShayne Chen 				status->iv[1] = data[4];
75598686cd2SShayne Chen 				status->iv[2] = data[3];
75698686cd2SShayne Chen 				status->iv[3] = data[2];
75798686cd2SShayne Chen 				status->iv[4] = data[1];
75898686cd2SShayne Chen 				status->iv[5] = data[0];
75998686cd2SShayne Chen 				break;
76098686cd2SShayne Chen 			default:
76198686cd2SShayne Chen 				break;
76298686cd2SShayne Chen 			}
76398686cd2SShayne Chen 		}
76498686cd2SShayne Chen 		rxd += 4;
76598686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
76698686cd2SShayne Chen 			return -EINVAL;
76798686cd2SShayne Chen 	}
76898686cd2SShayne Chen 
76998686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
77098686cd2SShayne Chen 		status->timestamp = le32_to_cpu(rxd[0]);
77198686cd2SShayne Chen 		status->flag |= RX_FLAG_MACTIME_START;
77298686cd2SShayne Chen 
77398686cd2SShayne Chen 		if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
77498686cd2SShayne Chen 			status->flag |= RX_FLAG_AMPDU_DETAILS;
77598686cd2SShayne Chen 
77698686cd2SShayne Chen 			/* all subframes of an A-MPDU have the same timestamp */
77798686cd2SShayne Chen 			if (phy->rx_ampdu_ts != status->timestamp) {
77898686cd2SShayne Chen 				if (!++phy->ampdu_ref)
77998686cd2SShayne Chen 					phy->ampdu_ref++;
78098686cd2SShayne Chen 			}
78198686cd2SShayne Chen 			phy->rx_ampdu_ts = status->timestamp;
78298686cd2SShayne Chen 
78398686cd2SShayne Chen 			status->ampdu_ref = phy->ampdu_ref;
78498686cd2SShayne Chen 		}
78598686cd2SShayne Chen 
78698686cd2SShayne Chen 		rxd += 4;
78798686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
78898686cd2SShayne Chen 			return -EINVAL;
78998686cd2SShayne Chen 	}
79098686cd2SShayne Chen 
79198686cd2SShayne Chen 	/* RXD Group 3 - P-RXV */
79298686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
79398686cd2SShayne Chen 		u32 v3;
79498686cd2SShayne Chen 		int ret;
79598686cd2SShayne Chen 
79698686cd2SShayne Chen 		rxv = rxd;
79798686cd2SShayne Chen 		rxd += 4;
79898686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
79998686cd2SShayne Chen 			return -EINVAL;
80098686cd2SShayne Chen 
80198686cd2SShayne Chen 		v3 = le32_to_cpu(rxv[3]);
80298686cd2SShayne Chen 
80398686cd2SShayne Chen 		status->chains = mphy->antenna_mask;
80498686cd2SShayne Chen 		status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);
80598686cd2SShayne Chen 		status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);
80698686cd2SShayne Chen 		status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);
80798686cd2SShayne Chen 		status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);
80898686cd2SShayne Chen 
80998686cd2SShayne Chen 		/* RXD Group 5 - C-RXV */
81098686cd2SShayne Chen 		if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
81198686cd2SShayne Chen 			rxd += 24;
81298686cd2SShayne Chen 			if ((u8 *)rxd - skb->data >= skb->len)
81398686cd2SShayne Chen 				return -EINVAL;
81498686cd2SShayne Chen 		}
81598686cd2SShayne Chen 
81698686cd2SShayne Chen 		ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode);
81798686cd2SShayne Chen 		if (ret < 0)
81898686cd2SShayne Chen 			return ret;
81998686cd2SShayne Chen 	}
82098686cd2SShayne Chen 
82198686cd2SShayne Chen 	amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
82298686cd2SShayne Chen 	status->amsdu = !!amsdu_info;
82398686cd2SShayne Chen 	if (status->amsdu) {
82498686cd2SShayne Chen 		status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
82598686cd2SShayne Chen 		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
82698686cd2SShayne Chen 	}
82798686cd2SShayne Chen 
82898686cd2SShayne Chen 	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
82998686cd2SShayne Chen 	if (hdr_trans && ieee80211_has_morefrags(fc)) {
83098686cd2SShayne Chen 		if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
83198686cd2SShayne Chen 			return -EINVAL;
83298686cd2SShayne Chen 		hdr_trans = false;
83398686cd2SShayne Chen 	} else {
83498686cd2SShayne Chen 		int pad_start = 0;
83598686cd2SShayne Chen 
83698686cd2SShayne Chen 		skb_pull(skb, hdr_gap);
83727db47abSRyder Lee 		if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
83898686cd2SShayne Chen 			pad_start = ieee80211_get_hdrlen_from_skb(skb);
83927db47abSRyder Lee 		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR) &&
84027db47abSRyder Lee 			   get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) {
84198686cd2SShayne Chen 			/* When header translation failure is indicated,
84298686cd2SShayne Chen 			 * the hardware will insert an extra 2-byte field
84398686cd2SShayne Chen 			 * containing the data length after the protocol
84498686cd2SShayne Chen 			 * type field.
84598686cd2SShayne Chen 			 */
84627db47abSRyder Lee 			pad_start = 16;
84798686cd2SShayne Chen 		}
84898686cd2SShayne Chen 
84998686cd2SShayne Chen 		if (pad_start) {
85098686cd2SShayne Chen 			memmove(skb->data + 2, skb->data, pad_start);
85198686cd2SShayne Chen 			skb_pull(skb, 2);
85298686cd2SShayne Chen 		}
85398686cd2SShayne Chen 	}
85498686cd2SShayne Chen 
85598686cd2SShayne Chen 	if (!hdr_trans) {
85698686cd2SShayne Chen 		struct ieee80211_hdr *hdr;
85798686cd2SShayne Chen 
85898686cd2SShayne Chen 		if (insert_ccmp_hdr) {
85998686cd2SShayne Chen 			u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
86098686cd2SShayne Chen 
86198686cd2SShayne Chen 			mt76_insert_ccmp_hdr(skb, key_id);
86298686cd2SShayne Chen 		}
86398686cd2SShayne Chen 
86498686cd2SShayne Chen 		hdr = mt76_skb_get_hdr(skb);
86598686cd2SShayne Chen 		fc = hdr->frame_control;
86698686cd2SShayne Chen 		if (ieee80211_is_data_qos(fc)) {
86727db47abSRyder Lee 			u8 *qos = ieee80211_get_qos_ctl(hdr);
86827db47abSRyder Lee 
86998686cd2SShayne Chen 			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
87027db47abSRyder Lee 			qos_ctl = *qos;
87127db47abSRyder Lee 
87227db47abSRyder Lee 			/* Mesh DA/SA/Length will be stripped after hardware
87327db47abSRyder Lee 			 * de-amsdu, so here needs to clear amsdu present bit
87427db47abSRyder Lee 			 * to mark it as a normal mesh frame.
87527db47abSRyder Lee 			 */
87627db47abSRyder Lee 			if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
87727db47abSRyder Lee 				*qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
87898686cd2SShayne Chen 		}
87998686cd2SShayne Chen 	} else {
88098686cd2SShayne Chen 		status->flag |= RX_FLAG_8023;
88198686cd2SShayne Chen 	}
88298686cd2SShayne Chen 
88398686cd2SShayne Chen 	if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
88498686cd2SShayne Chen 		mt7996_mac_decode_he_radiotap(skb, rxv, mode);
88598686cd2SShayne Chen 
88698686cd2SShayne Chen 	if (!status->wcid || !ieee80211_is_data_qos(fc))
88798686cd2SShayne Chen 		return 0;
88898686cd2SShayne Chen 
88998686cd2SShayne Chen 	status->aggr = unicast &&
89098686cd2SShayne Chen 		       !ieee80211_is_qos_nullfunc(fc);
89198686cd2SShayne Chen 	status->qos_ctl = qos_ctl;
89298686cd2SShayne Chen 	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
89398686cd2SShayne Chen 
89498686cd2SShayne Chen 	return 0;
89598686cd2SShayne Chen }
89698686cd2SShayne Chen 
89798686cd2SShayne Chen static void
89898686cd2SShayne Chen mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
89998686cd2SShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid)
90098686cd2SShayne Chen {
90198686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
90298686cd2SShayne Chen 	u8 fc_type, fc_stype;
90398686cd2SShayne Chen 	u16 ethertype;
90498686cd2SShayne Chen 	bool wmm = false;
90598686cd2SShayne Chen 	u32 val;
90698686cd2SShayne Chen 
90798686cd2SShayne Chen 	if (wcid->sta) {
90898686cd2SShayne Chen 		struct ieee80211_sta *sta;
90998686cd2SShayne Chen 
91098686cd2SShayne Chen 		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
91198686cd2SShayne Chen 		wmm = sta->wme;
91298686cd2SShayne Chen 	}
91398686cd2SShayne Chen 
91498686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
91598686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
91698686cd2SShayne Chen 
91798686cd2SShayne Chen 	ethertype = get_unaligned_be16(&skb->data[12]);
91898686cd2SShayne Chen 	if (ethertype >= ETH_P_802_3_MIN)
91998686cd2SShayne Chen 		val |= MT_TXD1_ETH_802_3;
92098686cd2SShayne Chen 
92198686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
92298686cd2SShayne Chen 
92398686cd2SShayne Chen 	fc_type = IEEE80211_FTYPE_DATA >> 2;
92498686cd2SShayne Chen 	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
92598686cd2SShayne Chen 
92698686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
92798686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
92898686cd2SShayne Chen 
92998686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
93098686cd2SShayne Chen }
93198686cd2SShayne Chen 
93298686cd2SShayne Chen static void
93398686cd2SShayne Chen mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
93498686cd2SShayne Chen 			    struct sk_buff *skb, struct ieee80211_key_conf *key)
93598686cd2SShayne Chen {
93698686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
93798686cd2SShayne Chen 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
93898686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
93998686cd2SShayne Chen 	bool multicast = is_multicast_ether_addr(hdr->addr1);
94098686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
94198686cd2SShayne Chen 	__le16 fc = hdr->frame_control;
94298686cd2SShayne Chen 	u8 fc_type, fc_stype;
94398686cd2SShayne Chen 	u32 val;
94498686cd2SShayne Chen 
94598686cd2SShayne Chen 	if (ieee80211_is_action(fc) &&
94698686cd2SShayne Chen 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
94798686cd2SShayne Chen 	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
94898686cd2SShayne Chen 		tid = MT_TX_ADDBA;
94998686cd2SShayne Chen 	else if (ieee80211_is_mgmt(hdr->frame_control))
95098686cd2SShayne Chen 		tid = MT_TX_NORMAL;
95198686cd2SShayne Chen 
95298686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
95398686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_HDR_INFO,
95498686cd2SShayne Chen 			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
95598686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
95698686cd2SShayne Chen 
95798686cd2SShayne Chen 	if (!ieee80211_is_data(fc) || multicast ||
95898686cd2SShayne Chen 	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
95998686cd2SShayne Chen 		val |= MT_TXD1_FIXED_RATE;
96098686cd2SShayne Chen 
96198686cd2SShayne Chen 	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
96298686cd2SShayne Chen 	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
96398686cd2SShayne Chen 		val |= MT_TXD1_BIP;
96498686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
96598686cd2SShayne Chen 	}
96698686cd2SShayne Chen 
96798686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
96898686cd2SShayne Chen 
96998686cd2SShayne Chen 	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
97098686cd2SShayne Chen 	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
97198686cd2SShayne Chen 
97298686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
97398686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
97498686cd2SShayne Chen 
97598686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
97698686cd2SShayne Chen 
97798686cd2SShayne Chen 	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
97898686cd2SShayne Chen 	if (ieee80211_is_beacon(fc)) {
97998686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
98098686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
98198686cd2SShayne Chen 	}
98298686cd2SShayne Chen 
98398686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
98498686cd2SShayne Chen 		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
98598686cd2SShayne Chen 
98698686cd2SShayne Chen 		if (ieee80211_is_back_req(hdr->frame_control)) {
98798686cd2SShayne Chen 			struct ieee80211_bar *bar;
98898686cd2SShayne Chen 
98998686cd2SShayne Chen 			bar = (struct ieee80211_bar *)skb->data;
99098686cd2SShayne Chen 			seqno = le16_to_cpu(bar->start_seq_num);
99198686cd2SShayne Chen 		}
99298686cd2SShayne Chen 
99398686cd2SShayne Chen 		val = MT_TXD3_SN_VALID |
99498686cd2SShayne Chen 		      FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
99598686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(val);
99698686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
99798686cd2SShayne Chen 	}
99898686cd2SShayne Chen }
99998686cd2SShayne Chen 
100098686cd2SShayne Chen void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
1001d0b6f86fSShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid,
1002d0b6f86fSShayne Chen 			   struct ieee80211_key_conf *key, int pid,
1003d0b6f86fSShayne Chen 			   enum mt76_txq_id qid, u32 changed)
100498686cd2SShayne Chen {
100598686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
100698686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
100798686cd2SShayne Chen 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
100898686cd2SShayne Chen 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
100998686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
1010*ead44902SLorenzo Bianconi 	struct mt7996_vif *mvif;
101198686cd2SShayne Chen 	u16 tx_count = 15;
101298686cd2SShayne Chen 	u32 val;
101398686cd2SShayne Chen 	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
101498686cd2SShayne Chen 				    BSS_CHANGED_BEACON_ENABLED));
101598686cd2SShayne Chen 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
101698686cd2SShayne Chen 					 BSS_CHANGED_FILS_DISCOVERY));
101798686cd2SShayne Chen 
1018*ead44902SLorenzo Bianconi 	mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
1019*ead44902SLorenzo Bianconi 	if (mvif) {
102098686cd2SShayne Chen 		omac_idx = mvif->mt76.omac_idx;
102198686cd2SShayne Chen 		wmm_idx = mvif->mt76.wmm_idx;
102298686cd2SShayne Chen 		band_idx = mvif->mt76.band_idx;
102398686cd2SShayne Chen 	}
102498686cd2SShayne Chen 
102598686cd2SShayne Chen 	if (inband_disc) {
102698686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
102798686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
102898686cd2SShayne Chen 	} else if (beacon) {
102998686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
103098686cd2SShayne Chen 		q_idx = MT_LMAC_BCN0;
1031d0b6f86fSShayne Chen 	} else if (qid >= MT_TXQ_PSD) {
103298686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
103398686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
103498686cd2SShayne Chen 	} else {
103598686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
103698686cd2SShayne Chen 		q_idx = wmm_idx * MT7996_MAX_WMM_SETS +
103798686cd2SShayne Chen 			mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
103898686cd2SShayne Chen 	}
103998686cd2SShayne Chen 
104098686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
104198686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
104298686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
104398686cd2SShayne Chen 	txwi[0] = cpu_to_le32(val);
104498686cd2SShayne Chen 
104598686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
104698686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
104798686cd2SShayne Chen 
104898686cd2SShayne Chen 	if (band_idx)
104998686cd2SShayne Chen 		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
105098686cd2SShayne Chen 
105198686cd2SShayne Chen 	txwi[1] = cpu_to_le32(val);
105298686cd2SShayne Chen 	txwi[2] = 0;
105398686cd2SShayne Chen 
105498686cd2SShayne Chen 	val = MT_TXD3_SW_POWER_MGMT |
105598686cd2SShayne Chen 	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
105698686cd2SShayne Chen 	if (key)
105798686cd2SShayne Chen 		val |= MT_TXD3_PROTECT_FRAME;
105898686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
105998686cd2SShayne Chen 		val |= MT_TXD3_NO_ACK;
106098686cd2SShayne Chen 	if (wcid->amsdu)
106198686cd2SShayne Chen 		val |= MT_TXD3_HW_AMSDU;
106298686cd2SShayne Chen 
106398686cd2SShayne Chen 	txwi[3] = cpu_to_le32(val);
106498686cd2SShayne Chen 	txwi[4] = 0;
106598686cd2SShayne Chen 
106698686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD5_PID, pid);
106798686cd2SShayne Chen 	if (pid >= MT_PACKET_ID_FIRST)
106898686cd2SShayne Chen 		val |= MT_TXD5_TX_STATUS_HOST;
106998686cd2SShayne Chen 	txwi[5] = cpu_to_le32(val);
107098686cd2SShayne Chen 
107198686cd2SShayne Chen 	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
107298686cd2SShayne Chen 	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
107398686cd2SShayne Chen 	txwi[6] = cpu_to_le32(val);
107498686cd2SShayne Chen 	txwi[7] = 0;
107598686cd2SShayne Chen 
107698686cd2SShayne Chen 	if (is_8023)
107798686cd2SShayne Chen 		mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);
107898686cd2SShayne Chen 	else
107998686cd2SShayne Chen 		mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
108098686cd2SShayne Chen 
108198686cd2SShayne Chen 	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
1082ab0eec4bSRyder Lee 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
1083ab0eec4bSRyder Lee 		bool mcast = ieee80211_is_data(hdr->frame_control) &&
1084ab0eec4bSRyder Lee 			     is_multicast_ether_addr(hdr->addr1);
1085*ead44902SLorenzo Bianconi 		u8 idx = MT7996_BASIC_RATES_TBL;
108698686cd2SShayne Chen 
1087*ead44902SLorenzo Bianconi 		if (mvif) {
1088ab0eec4bSRyder Lee 			if (mcast && mvif->mcast_rates_idx)
1089ab0eec4bSRyder Lee 				idx = mvif->mcast_rates_idx;
1090c2171b06SRyder Lee 			else if (beacon && mvif->beacon_rates_idx)
1091c2171b06SRyder Lee 				idx = mvif->beacon_rates_idx;
1092*ead44902SLorenzo Bianconi 			else
1093*ead44902SLorenzo Bianconi 				idx = mvif->basic_rates_idx;
1094*ead44902SLorenzo Bianconi 		}
1095ab0eec4bSRyder Lee 
1096cdc26ee8SRyder Lee 		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
109798686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
109898686cd2SShayne Chen 	}
109998686cd2SShayne Chen }
110098686cd2SShayne Chen 
110198686cd2SShayne Chen int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
110298686cd2SShayne Chen 			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
110398686cd2SShayne Chen 			  struct ieee80211_sta *sta,
110498686cd2SShayne Chen 			  struct mt76_tx_info *tx_info)
110598686cd2SShayne Chen {
110698686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
110798686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
110898686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
110998686cd2SShayne Chen 	struct ieee80211_key_conf *key = info->control.hw_key;
111098686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
11113c38dfc1SLorenzo Bianconi 	struct mt76_connac_txp_common *txp;
111298686cd2SShayne Chen 	struct mt76_txwi_cache *t;
111398686cd2SShayne Chen 	int id, i, pid, nbuf = tx_info->nbuf - 1;
111498686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
111598686cd2SShayne Chen 	u8 *txwi = (u8 *)txwi_ptr;
111698686cd2SShayne Chen 
111798686cd2SShayne Chen 	if (unlikely(tx_info->skb->len <= ETH_HLEN))
111898686cd2SShayne Chen 		return -EINVAL;
111998686cd2SShayne Chen 
112098686cd2SShayne Chen 	if (!wcid)
112198686cd2SShayne Chen 		wcid = &dev->mt76.global_wcid;
112298686cd2SShayne Chen 
112398686cd2SShayne Chen 	if (sta) {
112498686cd2SShayne Chen 		struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
112598686cd2SShayne Chen 
112698686cd2SShayne Chen 		if (time_after(jiffies, msta->jiffies + HZ / 4)) {
112798686cd2SShayne Chen 			info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
112898686cd2SShayne Chen 			msta->jiffies = jiffies;
112998686cd2SShayne Chen 		}
113098686cd2SShayne Chen 	}
113198686cd2SShayne Chen 
113298686cd2SShayne Chen 	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
113398686cd2SShayne Chen 	t->skb = tx_info->skb;
113498686cd2SShayne Chen 
113598686cd2SShayne Chen 	id = mt76_token_consume(mdev, &t);
113698686cd2SShayne Chen 	if (id < 0)
113798686cd2SShayne Chen 		return id;
113898686cd2SShayne Chen 
113998686cd2SShayne Chen 	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
1140d0b6f86fSShayne Chen 	mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
1141d0b6f86fSShayne Chen 			      pid, qid, 0);
114298686cd2SShayne Chen 
11433c38dfc1SLorenzo Bianconi 	txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
114498686cd2SShayne Chen 	for (i = 0; i < nbuf; i++) {
11453c38dfc1SLorenzo Bianconi 		txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
11463c38dfc1SLorenzo Bianconi 		txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
114798686cd2SShayne Chen 	}
11483c38dfc1SLorenzo Bianconi 	txp->fw.nbuf = nbuf;
114998686cd2SShayne Chen 
11503b522cadSRyder Lee 	txp->fw.flags =
11513b522cadSRyder Lee 		cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD);
115298686cd2SShayne Chen 
115398686cd2SShayne Chen 	if (!key)
11543c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
115598686cd2SShayne Chen 
115698686cd2SShayne Chen 	if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
11573c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
115898686cd2SShayne Chen 
115998686cd2SShayne Chen 	if (vif) {
116098686cd2SShayne Chen 		struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
116198686cd2SShayne Chen 
11623c38dfc1SLorenzo Bianconi 		txp->fw.bss_idx = mvif->mt76.idx;
116398686cd2SShayne Chen 	}
116498686cd2SShayne Chen 
11653c38dfc1SLorenzo Bianconi 	txp->fw.token = cpu_to_le16(id);
116698686cd2SShayne Chen 	if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
11673c38dfc1SLorenzo Bianconi 		txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
116898686cd2SShayne Chen 	else
11693c38dfc1SLorenzo Bianconi 		txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
117098686cd2SShayne Chen 	tx_info->skb = DMA_DUMMY_DATA;
117198686cd2SShayne Chen 
117298686cd2SShayne Chen 	/* pass partial skb header to fw */
117398686cd2SShayne Chen 	tx_info->buf[1].len = MT_CT_PARSE_LEN;
117498686cd2SShayne Chen 	tx_info->buf[1].skip_unmap = true;
117598686cd2SShayne Chen 	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
117698686cd2SShayne Chen 
117798686cd2SShayne Chen 	return 0;
117898686cd2SShayne Chen }
117998686cd2SShayne Chen 
118098686cd2SShayne Chen static void
118198686cd2SShayne Chen mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
118298686cd2SShayne Chen {
118398686cd2SShayne Chen 	struct mt7996_sta *msta;
118498686cd2SShayne Chen 	u16 fc, tid;
118598686cd2SShayne Chen 	u32 val;
118698686cd2SShayne Chen 
118798686cd2SShayne Chen 	if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
118898686cd2SShayne Chen 		return;
118998686cd2SShayne Chen 
119098686cd2SShayne Chen 	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
119198686cd2SShayne Chen 	if (tid >= 6) /* skip VO queue */
119298686cd2SShayne Chen 		return;
119398686cd2SShayne Chen 
119498686cd2SShayne Chen 	val = le32_to_cpu(txwi[2]);
119598686cd2SShayne Chen 	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
119698686cd2SShayne Chen 	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
119798686cd2SShayne Chen 	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
119898686cd2SShayne Chen 		return;
119998686cd2SShayne Chen 
120098686cd2SShayne Chen 	msta = (struct mt7996_sta *)sta->drv_priv;
120198686cd2SShayne Chen 	if (!test_and_set_bit(tid, &msta->ampdu_state))
120298686cd2SShayne Chen 		ieee80211_start_tx_ba_session(sta, tid, 0);
120398686cd2SShayne Chen }
120498686cd2SShayne Chen 
120598686cd2SShayne Chen static void
120698686cd2SShayne Chen mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
120798686cd2SShayne Chen 		 struct ieee80211_sta *sta, struct list_head *free_list)
120898686cd2SShayne Chen {
120998686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
121098686cd2SShayne Chen 	struct mt76_wcid *wcid;
121198686cd2SShayne Chen 	__le32 *txwi;
121298686cd2SShayne Chen 	u16 wcid_idx;
121398686cd2SShayne Chen 
121430495864SLorenzo Bianconi 	mt76_connac_txp_skb_unmap(mdev, t);
121598686cd2SShayne Chen 	if (!t->skb)
121698686cd2SShayne Chen 		goto out;
121798686cd2SShayne Chen 
121898686cd2SShayne Chen 	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
121998686cd2SShayne Chen 	if (sta) {
122098686cd2SShayne Chen 		wcid = (struct mt76_wcid *)sta->drv_priv;
122198686cd2SShayne Chen 		wcid_idx = wcid->idx;
122298686cd2SShayne Chen 
122398686cd2SShayne Chen 		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
122498686cd2SShayne Chen 			mt7996_tx_check_aggr(sta, txwi);
122598686cd2SShayne Chen 	} else {
122698686cd2SShayne Chen 		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
122798686cd2SShayne Chen 	}
122898686cd2SShayne Chen 
122998686cd2SShayne Chen 	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
123098686cd2SShayne Chen 
123198686cd2SShayne Chen out:
123298686cd2SShayne Chen 	t->skb = NULL;
123398686cd2SShayne Chen 	mt76_put_txwi(mdev, t);
123498686cd2SShayne Chen }
123598686cd2SShayne Chen 
123698686cd2SShayne Chen static void
123798686cd2SShayne Chen mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
123898686cd2SShayne Chen {
123998686cd2SShayne Chen 	__le32 *tx_free = (__le32 *)data, *cur_info;
124098686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
124198686cd2SShayne Chen 	struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
124298686cd2SShayne Chen 	struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
124398686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
124498686cd2SShayne Chen 	struct ieee80211_sta *sta = NULL;
124598686cd2SShayne Chen 	LIST_HEAD(free_list);
124698686cd2SShayne Chen 	struct sk_buff *skb, *tmp;
124798686cd2SShayne Chen 	void *end = data + len;
124898686cd2SShayne Chen 	bool wake = false;
124998686cd2SShayne Chen 	u16 total, count = 0;
125098686cd2SShayne Chen 
125198686cd2SShayne Chen 	/* clean DMA queues and unmap buffers first */
125298686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
125398686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
125498686cd2SShayne Chen 	if (phy2) {
125598686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false);
125698686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false);
125798686cd2SShayne Chen 	}
125898686cd2SShayne Chen 	if (phy3) {
125998686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false);
126098686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);
126198686cd2SShayne Chen 	}
126298686cd2SShayne Chen 
126398686cd2SShayne Chen 	if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))
126498686cd2SShayne Chen 		return;
126598686cd2SShayne Chen 
126698686cd2SShayne Chen 	total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);
126798686cd2SShayne Chen 	for (cur_info = &tx_free[2]; count < total; cur_info++) {
126898686cd2SShayne Chen 		u32 msdu, info;
126998686cd2SShayne Chen 		u8 i;
127098686cd2SShayne Chen 
127198686cd2SShayne Chen 		if (WARN_ON_ONCE((void *)cur_info >= end))
127298686cd2SShayne Chen 			return;
127398686cd2SShayne Chen 		/* 1'b1: new wcid pair.
127498686cd2SShayne Chen 		 * 1'b0: msdu_id with the same 'wcid pair' as above.
127598686cd2SShayne Chen 		 */
127698686cd2SShayne Chen 		info = le32_to_cpu(*cur_info);
127798686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_PAIR) {
127898686cd2SShayne Chen 			struct mt7996_sta *msta;
127998686cd2SShayne Chen 			struct mt76_wcid *wcid;
128098686cd2SShayne Chen 			u16 idx;
128198686cd2SShayne Chen 
128298686cd2SShayne Chen 			idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
128398686cd2SShayne Chen 			wcid = rcu_dereference(dev->mt76.wcid[idx]);
128498686cd2SShayne Chen 			sta = wcid_to_sta(wcid);
128598686cd2SShayne Chen 			if (!sta)
128698686cd2SShayne Chen 				continue;
128798686cd2SShayne Chen 
128898686cd2SShayne Chen 			msta = container_of(wcid, struct mt7996_sta, wcid);
128998686cd2SShayne Chen 			spin_lock_bh(&dev->sta_poll_lock);
129098686cd2SShayne Chen 			if (list_empty(&msta->poll_list))
129198686cd2SShayne Chen 				list_add_tail(&msta->poll_list, &dev->sta_poll_list);
129298686cd2SShayne Chen 			spin_unlock_bh(&dev->sta_poll_lock);
129398686cd2SShayne Chen 			continue;
129498686cd2SShayne Chen 		}
129598686cd2SShayne Chen 
129698686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_HEADER)
129798686cd2SShayne Chen 			continue;
129898686cd2SShayne Chen 
129998686cd2SShayne Chen 		for (i = 0; i < 2; i++) {
130098686cd2SShayne Chen 			msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;
130198686cd2SShayne Chen 			if (msdu == MT_TXFREE_INFO_MSDU_ID)
130298686cd2SShayne Chen 				continue;
130398686cd2SShayne Chen 
130498686cd2SShayne Chen 			count++;
130598686cd2SShayne Chen 			txwi = mt76_token_release(mdev, msdu, &wake);
130698686cd2SShayne Chen 			if (!txwi)
130798686cd2SShayne Chen 				continue;
130898686cd2SShayne Chen 
130998686cd2SShayne Chen 			mt7996_txwi_free(dev, txwi, sta, &free_list);
131098686cd2SShayne Chen 		}
131198686cd2SShayne Chen 	}
131298686cd2SShayne Chen 
131398686cd2SShayne Chen 	mt7996_mac_sta_poll(dev);
131498686cd2SShayne Chen 
131598686cd2SShayne Chen 	if (wake)
131698686cd2SShayne Chen 		mt76_set_tx_blocked(&dev->mt76, false);
131798686cd2SShayne Chen 
131898686cd2SShayne Chen 	mt76_worker_schedule(&dev->mt76.tx_worker);
131998686cd2SShayne Chen 
132098686cd2SShayne Chen 	list_for_each_entry_safe(skb, tmp, &free_list, list) {
132198686cd2SShayne Chen 		skb_list_del_init(skb);
132298686cd2SShayne Chen 		napi_consume_skb(skb, 1);
132398686cd2SShayne Chen 	}
132498686cd2SShayne Chen }
132598686cd2SShayne Chen 
132698686cd2SShayne Chen static bool
132798686cd2SShayne Chen mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid,
132898686cd2SShayne Chen 		       __le32 *txs_data, struct mt76_sta_stats *stats)
132998686cd2SShayne Chen {
133098686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
133198686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
133298686cd2SShayne Chen 	struct mt76_phy *mphy;
133398686cd2SShayne Chen 	struct ieee80211_tx_info *info;
133498686cd2SShayne Chen 	struct sk_buff_head list;
133598686cd2SShayne Chen 	struct rate_info rate = {};
133698686cd2SShayne Chen 	struct sk_buff *skb;
133798686cd2SShayne Chen 	bool cck = false;
133898686cd2SShayne Chen 	u32 txrate, txs, mode, stbc;
133998686cd2SShayne Chen 
134098686cd2SShayne Chen 	mt76_tx_status_lock(mdev, &list);
134198686cd2SShayne Chen 	skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
134298686cd2SShayne Chen 	if (!skb)
134398686cd2SShayne Chen 		goto out_no_skb;
134498686cd2SShayne Chen 
134598686cd2SShayne Chen 	txs = le32_to_cpu(txs_data[0]);
134698686cd2SShayne Chen 
134798686cd2SShayne Chen 	info = IEEE80211_SKB_CB(skb);
134898686cd2SShayne Chen 	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
134998686cd2SShayne Chen 		info->flags |= IEEE80211_TX_STAT_ACK;
135098686cd2SShayne Chen 
135198686cd2SShayne Chen 	info->status.ampdu_len = 1;
135298686cd2SShayne Chen 	info->status.ampdu_ack_len = !!(info->flags &
135398686cd2SShayne Chen 					IEEE80211_TX_STAT_ACK);
135498686cd2SShayne Chen 
135598686cd2SShayne Chen 	info->status.rates[0].idx = -1;
135698686cd2SShayne Chen 
135798686cd2SShayne Chen 	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
135898686cd2SShayne Chen 
135998686cd2SShayne Chen 	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
136098686cd2SShayne Chen 	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
136198686cd2SShayne Chen 	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
136298686cd2SShayne Chen 
136398686cd2SShayne Chen 	if (stbc && rate.nss > 1)
136498686cd2SShayne Chen 		rate.nss >>= 1;
136598686cd2SShayne Chen 
136698686cd2SShayne Chen 	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
136798686cd2SShayne Chen 		stats->tx_nss[rate.nss - 1]++;
136898686cd2SShayne Chen 	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
136998686cd2SShayne Chen 		stats->tx_mcs[rate.mcs]++;
137098686cd2SShayne Chen 
137198686cd2SShayne Chen 	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
137298686cd2SShayne Chen 	switch (mode) {
137398686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
137498686cd2SShayne Chen 		cck = true;
137598686cd2SShayne Chen 		fallthrough;
137698686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
137798686cd2SShayne Chen 		mphy = mt76_dev_phy(mdev, wcid->phy_idx);
137898686cd2SShayne Chen 
137998686cd2SShayne Chen 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
138098686cd2SShayne Chen 			sband = &mphy->sband_5g.sband;
138198686cd2SShayne Chen 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
138298686cd2SShayne Chen 			sband = &mphy->sband_6g.sband;
138398686cd2SShayne Chen 		else
138498686cd2SShayne Chen 			sband = &mphy->sband_2g.sband;
138598686cd2SShayne Chen 
138698686cd2SShayne Chen 		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
138798686cd2SShayne Chen 		rate.legacy = sband->bitrates[rate.mcs].bitrate;
138898686cd2SShayne Chen 		break;
138998686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
139098686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
139198686cd2SShayne Chen 		if (rate.mcs > 31)
139298686cd2SShayne Chen 			goto out;
139398686cd2SShayne Chen 
139498686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_MCS;
139598686cd2SShayne Chen 		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
139698686cd2SShayne Chen 			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
139798686cd2SShayne Chen 		break;
139898686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
139998686cd2SShayne Chen 		if (rate.mcs > 9)
140098686cd2SShayne Chen 			goto out;
140198686cd2SShayne Chen 
140298686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
140398686cd2SShayne Chen 		break;
140498686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
140598686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
140698686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
140798686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
140898686cd2SShayne Chen 		if (rate.mcs > 11)
140998686cd2SShayne Chen 			goto out;
141098686cd2SShayne Chen 
141198686cd2SShayne Chen 		rate.he_gi = wcid->rate.he_gi;
141298686cd2SShayne Chen 		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
141398686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_HE_MCS;
141498686cd2SShayne Chen 		break;
141580f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
141680f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
141780f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
141880f5a31dSShayne Chen 		if (rate.mcs > 13)
141980f5a31dSShayne Chen 			goto out;
142080f5a31dSShayne Chen 
142180f5a31dSShayne Chen 		rate.eht_gi = wcid->rate.eht_gi;
142280f5a31dSShayne Chen 		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
142380f5a31dSShayne Chen 		break;
142498686cd2SShayne Chen 	default:
142598686cd2SShayne Chen 		goto out;
142698686cd2SShayne Chen 	}
142798686cd2SShayne Chen 
142898686cd2SShayne Chen 	stats->tx_mode[mode]++;
142998686cd2SShayne Chen 
143098686cd2SShayne Chen 	switch (FIELD_GET(MT_TXS0_BW, txs)) {
143180f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
143280f5a31dSShayne Chen 		rate.bw = RATE_INFO_BW_320;
143380f5a31dSShayne Chen 		stats->tx_bw[4]++;
143480f5a31dSShayne Chen 		break;
143598686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
143698686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_160;
143798686cd2SShayne Chen 		stats->tx_bw[3]++;
143898686cd2SShayne Chen 		break;
143998686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
144098686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_80;
144198686cd2SShayne Chen 		stats->tx_bw[2]++;
144298686cd2SShayne Chen 		break;
144398686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
144498686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_40;
144598686cd2SShayne Chen 		stats->tx_bw[1]++;
144698686cd2SShayne Chen 		break;
144798686cd2SShayne Chen 	default:
144898686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_20;
144998686cd2SShayne Chen 		stats->tx_bw[0]++;
145098686cd2SShayne Chen 		break;
145198686cd2SShayne Chen 	}
145298686cd2SShayne Chen 	wcid->rate = rate;
145398686cd2SShayne Chen 
145498686cd2SShayne Chen out:
145598686cd2SShayne Chen 	mt76_tx_status_skb_done(mdev, skb, &list);
145698686cd2SShayne Chen 
145798686cd2SShayne Chen out_no_skb:
145898686cd2SShayne Chen 	mt76_tx_status_unlock(mdev, &list);
145998686cd2SShayne Chen 
146098686cd2SShayne Chen 	return !!skb;
146198686cd2SShayne Chen }
146298686cd2SShayne Chen 
146398686cd2SShayne Chen static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
146498686cd2SShayne Chen {
146598686cd2SShayne Chen 	struct mt7996_sta *msta = NULL;
146698686cd2SShayne Chen 	struct mt76_wcid *wcid;
146798686cd2SShayne Chen 	__le32 *txs_data = data;
146898686cd2SShayne Chen 	u16 wcidx;
146998686cd2SShayne Chen 	u8 pid;
147098686cd2SShayne Chen 
147198686cd2SShayne Chen 	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
147298686cd2SShayne Chen 		return;
147398686cd2SShayne Chen 
147498686cd2SShayne Chen 	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
147598686cd2SShayne Chen 	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
147698686cd2SShayne Chen 
147798686cd2SShayne Chen 	if (pid < MT_PACKET_ID_FIRST)
147898686cd2SShayne Chen 		return;
147998686cd2SShayne Chen 
148043482540SShayne Chen 	if (wcidx >= mt7996_wtbl_size(dev))
148198686cd2SShayne Chen 		return;
148298686cd2SShayne Chen 
148398686cd2SShayne Chen 	rcu_read_lock();
148498686cd2SShayne Chen 
148598686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
148698686cd2SShayne Chen 	if (!wcid)
148798686cd2SShayne Chen 		goto out;
148898686cd2SShayne Chen 
148998686cd2SShayne Chen 	msta = container_of(wcid, struct mt7996_sta, wcid);
149098686cd2SShayne Chen 
149198686cd2SShayne Chen 	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats);
149298686cd2SShayne Chen 
149398686cd2SShayne Chen 	if (!wcid->sta)
149498686cd2SShayne Chen 		goto out;
149598686cd2SShayne Chen 
149698686cd2SShayne Chen 	spin_lock_bh(&dev->sta_poll_lock);
149798686cd2SShayne Chen 	if (list_empty(&msta->poll_list))
149898686cd2SShayne Chen 		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
149998686cd2SShayne Chen 	spin_unlock_bh(&dev->sta_poll_lock);
150098686cd2SShayne Chen 
150198686cd2SShayne Chen out:
150298686cd2SShayne Chen 	rcu_read_unlock();
150398686cd2SShayne Chen }
150498686cd2SShayne Chen 
150598686cd2SShayne Chen bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
150698686cd2SShayne Chen {
150798686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
150898686cd2SShayne Chen 	__le32 *rxd = (__le32 *)data;
150998686cd2SShayne Chen 	__le32 *end = (__le32 *)&rxd[len / 4];
151098686cd2SShayne Chen 	enum rx_pkt_type type;
151198686cd2SShayne Chen 
151298686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
151398686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
151498686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
151598686cd2SShayne Chen 
151698686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
151798686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
151898686cd2SShayne Chen 			return true;
151998686cd2SShayne Chen 	}
152098686cd2SShayne Chen 
152198686cd2SShayne Chen 	switch (type) {
152298686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
152398686cd2SShayne Chen 		mt7996_mac_tx_free(dev, data, len);
152498686cd2SShayne Chen 		return false;
152598686cd2SShayne Chen 	case PKT_TYPE_TXS:
152698686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
152798686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
152898686cd2SShayne Chen 		return false;
152998686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
153098686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, data, len);
153198686cd2SShayne Chen 		return false;
153298686cd2SShayne Chen 	default:
153398686cd2SShayne Chen 		return true;
153498686cd2SShayne Chen 	}
153598686cd2SShayne Chen }
153698686cd2SShayne Chen 
153798686cd2SShayne Chen void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
153898686cd2SShayne Chen 			 struct sk_buff *skb, u32 *info)
153998686cd2SShayne Chen {
154098686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
154198686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
154298686cd2SShayne Chen 	__le32 *end = (__le32 *)&skb->data[skb->len];
154398686cd2SShayne Chen 	enum rx_pkt_type type;
154498686cd2SShayne Chen 
154598686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
154698686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
154798686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
154898686cd2SShayne Chen 
154998686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
155098686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
155198686cd2SShayne Chen 			type = PKT_TYPE_NORMAL;
155298686cd2SShayne Chen 	}
155398686cd2SShayne Chen 
155498686cd2SShayne Chen 	switch (type) {
155598686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
155698686cd2SShayne Chen 		mt7996_mac_tx_free(dev, skb->data, skb->len);
155798686cd2SShayne Chen 		napi_consume_skb(skb, 1);
155898686cd2SShayne Chen 		break;
155998686cd2SShayne Chen 	case PKT_TYPE_RX_EVENT:
156098686cd2SShayne Chen 		mt7996_mcu_rx_event(dev, skb);
156198686cd2SShayne Chen 		break;
156298686cd2SShayne Chen 	case PKT_TYPE_TXS:
156398686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
156498686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
156598686cd2SShayne Chen 		dev_kfree_skb(skb);
156698686cd2SShayne Chen 		break;
156798686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
156898686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
156998686cd2SShayne Chen 		dev_kfree_skb(skb);
157098686cd2SShayne Chen 		break;
157198686cd2SShayne Chen 	case PKT_TYPE_NORMAL:
157298686cd2SShayne Chen 		if (!mt7996_mac_fill_rx(dev, skb)) {
157398686cd2SShayne Chen 			mt76_rx(&dev->mt76, q, skb);
157498686cd2SShayne Chen 			return;
157598686cd2SShayne Chen 		}
157698686cd2SShayne Chen 		fallthrough;
157798686cd2SShayne Chen 	default:
157898686cd2SShayne Chen 		dev_kfree_skb(skb);
157998686cd2SShayne Chen 		break;
158098686cd2SShayne Chen 	}
158198686cd2SShayne Chen }
158298686cd2SShayne Chen 
158398686cd2SShayne Chen void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
158498686cd2SShayne Chen {
158598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
158698686cd2SShayne Chen 	u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx);
158798686cd2SShayne Chen 
158898686cd2SShayne Chen 	mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN);
158998686cd2SShayne Chen 	mt76_set(dev, reg, BIT(11) | BIT(9));
159098686cd2SShayne Chen }
159198686cd2SShayne Chen 
159298686cd2SShayne Chen void mt7996_mac_reset_counters(struct mt7996_phy *phy)
159398686cd2SShayne Chen {
159498686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
159598686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
159698686cd2SShayne Chen 	int i;
159798686cd2SShayne Chen 
159898686cd2SShayne Chen 	for (i = 0; i < 16; i++)
159998686cd2SShayne Chen 		mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
160098686cd2SShayne Chen 
160198686cd2SShayne Chen 	phy->mt76->survey_time = ktime_get_boottime();
160298686cd2SShayne Chen 
160398686cd2SShayne Chen 	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
160498686cd2SShayne Chen 
160598686cd2SShayne Chen 	/* reset airtime counters */
160698686cd2SShayne Chen 	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx),
160798686cd2SShayne Chen 		 MT_WF_RMAC_MIB_RXTIME_CLR);
160898686cd2SShayne Chen 
160998686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, true);
161098686cd2SShayne Chen }
161198686cd2SShayne Chen 
161298686cd2SShayne Chen void mt7996_mac_set_timing(struct mt7996_phy *phy)
161398686cd2SShayne Chen {
161498686cd2SShayne Chen 	s16 coverage_class = phy->coverage_class;
161598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
161698686cd2SShayne Chen 	struct mt7996_phy *phy2 = mt7996_phy2(dev);
161798686cd2SShayne Chen 	struct mt7996_phy *phy3 = mt7996_phy3(dev);
161898686cd2SShayne Chen 	u32 val, reg_offset;
161998686cd2SShayne Chen 	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
162098686cd2SShayne Chen 		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
162198686cd2SShayne Chen 	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
162298686cd2SShayne Chen 		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
162398686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
162498686cd2SShayne Chen 	int offset;
162598686cd2SShayne Chen 	bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
162698686cd2SShayne Chen 
162798686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
162898686cd2SShayne Chen 		return;
162998686cd2SShayne Chen 
163098686cd2SShayne Chen 	if (phy2)
163198686cd2SShayne Chen 		coverage_class = max_t(s16, dev->phy.coverage_class,
163298686cd2SShayne Chen 				       phy2->coverage_class);
163398686cd2SShayne Chen 
163498686cd2SShayne Chen 	if (phy3)
163598686cd2SShayne Chen 		coverage_class = max_t(s16, coverage_class,
163698686cd2SShayne Chen 				       phy3->coverage_class);
163798686cd2SShayne Chen 
163898686cd2SShayne Chen 	mt76_set(dev, MT_ARB_SCR(band_idx),
163998686cd2SShayne Chen 		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
164098686cd2SShayne Chen 	udelay(1);
164198686cd2SShayne Chen 
164298686cd2SShayne Chen 	offset = 3 * coverage_class;
164398686cd2SShayne Chen 	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
164498686cd2SShayne Chen 		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
164598686cd2SShayne Chen 
164698686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
164798686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
164898686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_ICR0(band_idx),
164998686cd2SShayne Chen 		FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) |
165098686cd2SShayne Chen 		FIELD_PREP(MT_IFS_RIFS, 2) |
165198686cd2SShayne Chen 		FIELD_PREP(MT_IFS_SIFS, 10) |
165298686cd2SShayne Chen 		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
165398686cd2SShayne Chen 
165498686cd2SShayne Chen 	if (!a_band)
165598686cd2SShayne Chen 		mt76_wr(dev, MT_TMAC_ICR1(band_idx),
165698686cd2SShayne Chen 			FIELD_PREP(MT_IFS_EIFS_CCK, 314));
165798686cd2SShayne Chen 
165898686cd2SShayne Chen 	if (phy->slottime < 20 || a_band)
165998686cd2SShayne Chen 		val = MT7996_CFEND_RATE_DEFAULT;
166098686cd2SShayne Chen 	else
166198686cd2SShayne Chen 		val = MT7996_CFEND_RATE_11B;
166298686cd2SShayne Chen 
1663793445cfSShayne Chen 	mt76_rmw_field(dev, MT_RATE_HRCR0(band_idx), MT_RATE_HRCR0_CFEND_RATE, val);
166498686cd2SShayne Chen 	mt76_clear(dev, MT_ARB_SCR(band_idx),
166598686cd2SShayne Chen 		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
166698686cd2SShayne Chen }
166798686cd2SShayne Chen 
166898686cd2SShayne Chen void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
166998686cd2SShayne Chen {
167098686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band),
167198686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY |
167298686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR);
167398686cd2SShayne Chen 
167498686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band),
167598686cd2SShayne Chen 		 FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5));
167698686cd2SShayne Chen }
167798686cd2SShayne Chen 
167898686cd2SShayne Chen static u8
167998686cd2SShayne Chen mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
168098686cd2SShayne Chen {
168198686cd2SShayne Chen 	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
168298686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
168398686cd2SShayne Chen 	u32 val, sum = 0, n = 0;
168498686cd2SShayne Chen 	int ant, i;
168598686cd2SShayne Chen 
168698686cd2SShayne Chen 	for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) {
168798686cd2SShayne Chen 		u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant);
168898686cd2SShayne Chen 
168998686cd2SShayne Chen 		for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
169098686cd2SShayne Chen 			val = mt76_rr(dev, reg);
169198686cd2SShayne Chen 			sum += val * nf_power[i];
169298686cd2SShayne Chen 			n += val;
169398686cd2SShayne Chen 		}
169498686cd2SShayne Chen 	}
169598686cd2SShayne Chen 
169698686cd2SShayne Chen 	return n ? sum / n : 0;
169798686cd2SShayne Chen }
169898686cd2SShayne Chen 
169998686cd2SShayne Chen void mt7996_update_channel(struct mt76_phy *mphy)
170098686cd2SShayne Chen {
170198686cd2SShayne Chen 	struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
170298686cd2SShayne Chen 	struct mt76_channel_state *state = mphy->chan_state;
170398686cd2SShayne Chen 	int nf;
170498686cd2SShayne Chen 
170598686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, false);
170698686cd2SShayne Chen 
170798686cd2SShayne Chen 	nf = mt7996_phy_get_nf(phy, mphy->band_idx);
170898686cd2SShayne Chen 	if (!phy->noise)
170998686cd2SShayne Chen 		phy->noise = nf << 4;
171098686cd2SShayne Chen 	else if (nf)
171198686cd2SShayne Chen 		phy->noise += nf - (phy->noise >> 4);
171298686cd2SShayne Chen 
171398686cd2SShayne Chen 	state->noise = -(phy->noise >> 4);
171498686cd2SShayne Chen }
171598686cd2SShayne Chen 
171698686cd2SShayne Chen static bool
171798686cd2SShayne Chen mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
171898686cd2SShayne Chen {
171998686cd2SShayne Chen 	bool ret;
172098686cd2SShayne Chen 
172198686cd2SShayne Chen 	ret = wait_event_timeout(dev->reset_wait,
172227015b6fSBo Jiao 				 (READ_ONCE(dev->recovery.state) & state),
172398686cd2SShayne Chen 				 MT7996_RESET_TIMEOUT);
172498686cd2SShayne Chen 
172598686cd2SShayne Chen 	WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
172698686cd2SShayne Chen 	return ret;
172798686cd2SShayne Chen }
172898686cd2SShayne Chen 
172998686cd2SShayne Chen static void
173098686cd2SShayne Chen mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
173198686cd2SShayne Chen {
173298686cd2SShayne Chen 	struct ieee80211_hw *hw = priv;
173398686cd2SShayne Chen 
173498686cd2SShayne Chen 	switch (vif->type) {
173598686cd2SShayne Chen 	case NL80211_IFTYPE_MESH_POINT:
173698686cd2SShayne Chen 	case NL80211_IFTYPE_ADHOC:
173798686cd2SShayne Chen 	case NL80211_IFTYPE_AP:
173898686cd2SShayne Chen 		mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
173998686cd2SShayne Chen 		break;
174098686cd2SShayne Chen 	default:
174198686cd2SShayne Chen 		break;
174298686cd2SShayne Chen 	}
174398686cd2SShayne Chen }
174498686cd2SShayne Chen 
174598686cd2SShayne Chen static void
174698686cd2SShayne Chen mt7996_update_beacons(struct mt7996_dev *dev)
174798686cd2SShayne Chen {
174898686cd2SShayne Chen 	struct mt76_phy *phy2, *phy3;
174998686cd2SShayne Chen 
175098686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(dev->mt76.hw,
175198686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
175298686cd2SShayne Chen 					    mt7996_update_vif_beacon, dev->mt76.hw);
175398686cd2SShayne Chen 
175498686cd2SShayne Chen 	phy2 = dev->mt76.phys[MT_BAND1];
175598686cd2SShayne Chen 	if (!phy2)
175698686cd2SShayne Chen 		return;
175798686cd2SShayne Chen 
175898686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy2->hw,
175998686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
176098686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy2->hw);
176198686cd2SShayne Chen 
176298686cd2SShayne Chen 	phy3 = dev->mt76.phys[MT_BAND2];
176398686cd2SShayne Chen 	if (!phy3)
176498686cd2SShayne Chen 		return;
176598686cd2SShayne Chen 
176698686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy3->hw,
176798686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
176898686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy3->hw);
176998686cd2SShayne Chen }
177098686cd2SShayne Chen 
177198686cd2SShayne Chen void mt7996_tx_token_put(struct mt7996_dev *dev)
177298686cd2SShayne Chen {
177398686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
177498686cd2SShayne Chen 	int id;
177598686cd2SShayne Chen 
177698686cd2SShayne Chen 	spin_lock_bh(&dev->mt76.token_lock);
177798686cd2SShayne Chen 	idr_for_each_entry(&dev->mt76.token, txwi, id) {
177898686cd2SShayne Chen 		mt7996_txwi_free(dev, txwi, NULL, NULL);
177998686cd2SShayne Chen 		dev->mt76.token_count--;
178098686cd2SShayne Chen 	}
178198686cd2SShayne Chen 	spin_unlock_bh(&dev->mt76.token_lock);
178298686cd2SShayne Chen 	idr_destroy(&dev->mt76.token);
178398686cd2SShayne Chen }
178498686cd2SShayne Chen 
178527015b6fSBo Jiao static int
178627015b6fSBo Jiao mt7996_mac_restart(struct mt7996_dev *dev)
178727015b6fSBo Jiao {
178827015b6fSBo Jiao 	struct mt7996_phy *phy2, *phy3;
178927015b6fSBo Jiao 	struct mt76_dev *mdev = &dev->mt76;
179027015b6fSBo Jiao 	int i, ret;
179127015b6fSBo Jiao 
179227015b6fSBo Jiao 	phy2 = mt7996_phy2(dev);
179327015b6fSBo Jiao 	phy3 = mt7996_phy3(dev);
179427015b6fSBo Jiao 
179527015b6fSBo Jiao 	if (dev->hif2) {
179627015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
179727015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
179827015b6fSBo Jiao 	}
179927015b6fSBo Jiao 
180027015b6fSBo Jiao 	if (dev_is_pci(mdev->dev)) {
180127015b6fSBo Jiao 		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
180227015b6fSBo Jiao 		if (dev->hif2)
180327015b6fSBo Jiao 			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
180427015b6fSBo Jiao 	}
180527015b6fSBo Jiao 
180627015b6fSBo Jiao 	set_bit(MT76_RESET, &dev->mphy.state);
180727015b6fSBo Jiao 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
180827015b6fSBo Jiao 	wake_up(&dev->mt76.mcu.wait);
180927015b6fSBo Jiao 	if (phy2) {
181027015b6fSBo Jiao 		set_bit(MT76_RESET, &phy2->mt76->state);
181127015b6fSBo Jiao 		set_bit(MT76_MCU_RESET, &phy2->mt76->state);
181227015b6fSBo Jiao 	}
181327015b6fSBo Jiao 	if (phy3) {
181427015b6fSBo Jiao 		set_bit(MT76_RESET, &phy3->mt76->state);
181527015b6fSBo Jiao 		set_bit(MT76_MCU_RESET, &phy3->mt76->state);
181627015b6fSBo Jiao 	}
181727015b6fSBo Jiao 
181827015b6fSBo Jiao 	/* lock/unlock all queues to ensure that no tx is pending */
181927015b6fSBo Jiao 	mt76_txq_schedule_all(&dev->mphy);
182027015b6fSBo Jiao 	if (phy2)
182127015b6fSBo Jiao 		mt76_txq_schedule_all(phy2->mt76);
182227015b6fSBo Jiao 	if (phy3)
182327015b6fSBo Jiao 		mt76_txq_schedule_all(phy3->mt76);
182427015b6fSBo Jiao 
182527015b6fSBo Jiao 	/* disable all tx/rx napi */
182627015b6fSBo Jiao 	mt76_worker_disable(&dev->mt76.tx_worker);
182727015b6fSBo Jiao 	mt76_for_each_q_rx(mdev, i) {
182827015b6fSBo Jiao 		if (mdev->q_rx[i].ndesc)
182927015b6fSBo Jiao 			napi_disable(&dev->mt76.napi[i]);
183027015b6fSBo Jiao 	}
183127015b6fSBo Jiao 	napi_disable(&dev->mt76.tx_napi);
183227015b6fSBo Jiao 
183327015b6fSBo Jiao 	/* token reinit */
183427015b6fSBo Jiao 	mt7996_tx_token_put(dev);
183527015b6fSBo Jiao 	idr_init(&dev->mt76.token);
183627015b6fSBo Jiao 
183727015b6fSBo Jiao 	mt7996_dma_reset(dev, true);
183827015b6fSBo Jiao 
183927015b6fSBo Jiao 	local_bh_disable();
184027015b6fSBo Jiao 	mt76_for_each_q_rx(mdev, i) {
184127015b6fSBo Jiao 		if (mdev->q_rx[i].ndesc) {
184227015b6fSBo Jiao 			napi_enable(&dev->mt76.napi[i]);
184327015b6fSBo Jiao 			napi_schedule(&dev->mt76.napi[i]);
184427015b6fSBo Jiao 		}
184527015b6fSBo Jiao 	}
184627015b6fSBo Jiao 	local_bh_enable();
184727015b6fSBo Jiao 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
184827015b6fSBo Jiao 	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
184927015b6fSBo Jiao 
185027015b6fSBo Jiao 	mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
185127015b6fSBo Jiao 	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
185227015b6fSBo Jiao 	if (dev->hif2) {
185327015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
185427015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
185527015b6fSBo Jiao 	}
185627015b6fSBo Jiao 	if (dev_is_pci(mdev->dev)) {
185727015b6fSBo Jiao 		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
185827015b6fSBo Jiao 		if (dev->hif2)
185927015b6fSBo Jiao 			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
186027015b6fSBo Jiao 	}
186127015b6fSBo Jiao 
186227015b6fSBo Jiao 	/* load firmware */
186327015b6fSBo Jiao 	ret = mt7996_mcu_init_firmware(dev);
186427015b6fSBo Jiao 	if (ret)
186527015b6fSBo Jiao 		goto out;
186627015b6fSBo Jiao 
186727015b6fSBo Jiao 	/* set the necessary init items */
186827015b6fSBo Jiao 	ret = mt7996_mcu_set_eeprom(dev);
186927015b6fSBo Jiao 	if (ret)
187027015b6fSBo Jiao 		goto out;
187127015b6fSBo Jiao 
187227015b6fSBo Jiao 	mt7996_mac_init(dev);
187327015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
187427015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
187527015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
187627015b6fSBo Jiao 	ret = mt7996_txbf_init(dev);
187727015b6fSBo Jiao 
187827015b6fSBo Jiao 	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
187927015b6fSBo Jiao 		ret = mt7996_run(dev->mphy.hw);
188027015b6fSBo Jiao 		if (ret)
188127015b6fSBo Jiao 			goto out;
188227015b6fSBo Jiao 	}
188327015b6fSBo Jiao 
188427015b6fSBo Jiao 	if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
188527015b6fSBo Jiao 		ret = mt7996_run(phy2->mt76->hw);
188627015b6fSBo Jiao 		if (ret)
188727015b6fSBo Jiao 			goto out;
188827015b6fSBo Jiao 	}
188927015b6fSBo Jiao 
189027015b6fSBo Jiao 	if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
189127015b6fSBo Jiao 		ret = mt7996_run(phy3->mt76->hw);
189227015b6fSBo Jiao 		if (ret)
189327015b6fSBo Jiao 			goto out;
189427015b6fSBo Jiao 	}
189527015b6fSBo Jiao 
189627015b6fSBo Jiao out:
189727015b6fSBo Jiao 	/* reset done */
189827015b6fSBo Jiao 	clear_bit(MT76_RESET, &dev->mphy.state);
189927015b6fSBo Jiao 	if (phy2)
190027015b6fSBo Jiao 		clear_bit(MT76_RESET, &phy2->mt76->state);
190127015b6fSBo Jiao 	if (phy3)
190227015b6fSBo Jiao 		clear_bit(MT76_RESET, &phy3->mt76->state);
190327015b6fSBo Jiao 
190427015b6fSBo Jiao 	local_bh_disable();
190527015b6fSBo Jiao 	napi_enable(&dev->mt76.tx_napi);
190627015b6fSBo Jiao 	napi_schedule(&dev->mt76.tx_napi);
190727015b6fSBo Jiao 	local_bh_enable();
190827015b6fSBo Jiao 
190927015b6fSBo Jiao 	mt76_worker_enable(&dev->mt76.tx_worker);
191027015b6fSBo Jiao 	return ret;
191127015b6fSBo Jiao }
191227015b6fSBo Jiao 
191327015b6fSBo Jiao static void
191427015b6fSBo Jiao mt7996_mac_full_reset(struct mt7996_dev *dev)
191527015b6fSBo Jiao {
191627015b6fSBo Jiao 	struct mt7996_phy *phy2, *phy3;
191727015b6fSBo Jiao 	int i;
191827015b6fSBo Jiao 
191927015b6fSBo Jiao 	phy2 = mt7996_phy2(dev);
192027015b6fSBo Jiao 	phy3 = mt7996_phy3(dev);
192127015b6fSBo Jiao 	dev->recovery.hw_full_reset = true;
192227015b6fSBo Jiao 
192327015b6fSBo Jiao 	wake_up(&dev->mt76.mcu.wait);
192427015b6fSBo Jiao 	ieee80211_stop_queues(mt76_hw(dev));
192527015b6fSBo Jiao 	if (phy2)
192627015b6fSBo Jiao 		ieee80211_stop_queues(phy2->mt76->hw);
192727015b6fSBo Jiao 	if (phy3)
192827015b6fSBo Jiao 		ieee80211_stop_queues(phy3->mt76->hw);
192927015b6fSBo Jiao 
193027015b6fSBo Jiao 	cancel_delayed_work_sync(&dev->mphy.mac_work);
193127015b6fSBo Jiao 	if (phy2)
193227015b6fSBo Jiao 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
193327015b6fSBo Jiao 	if (phy3)
193427015b6fSBo Jiao 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
193527015b6fSBo Jiao 
193627015b6fSBo Jiao 	mutex_lock(&dev->mt76.mutex);
193727015b6fSBo Jiao 	for (i = 0; i < 10; i++) {
193827015b6fSBo Jiao 		if (!mt7996_mac_restart(dev))
193927015b6fSBo Jiao 			break;
194027015b6fSBo Jiao 	}
194127015b6fSBo Jiao 	mutex_unlock(&dev->mt76.mutex);
194227015b6fSBo Jiao 
194327015b6fSBo Jiao 	if (i == 10)
194427015b6fSBo Jiao 		dev_err(dev->mt76.dev, "chip full reset failed\n");
194527015b6fSBo Jiao 
194627015b6fSBo Jiao 	ieee80211_restart_hw(mt76_hw(dev));
194727015b6fSBo Jiao 	if (phy2)
194827015b6fSBo Jiao 		ieee80211_restart_hw(phy2->mt76->hw);
194927015b6fSBo Jiao 	if (phy3)
195027015b6fSBo Jiao 		ieee80211_restart_hw(phy3->mt76->hw);
195127015b6fSBo Jiao 
195227015b6fSBo Jiao 	ieee80211_wake_queues(mt76_hw(dev));
195327015b6fSBo Jiao 	if (phy2)
195427015b6fSBo Jiao 		ieee80211_wake_queues(phy2->mt76->hw);
195527015b6fSBo Jiao 	if (phy3)
195627015b6fSBo Jiao 		ieee80211_wake_queues(phy3->mt76->hw);
195727015b6fSBo Jiao 
195827015b6fSBo Jiao 	dev->recovery.hw_full_reset = false;
195927015b6fSBo Jiao 	ieee80211_queue_delayed_work(mt76_hw(dev),
196027015b6fSBo Jiao 				     &dev->mphy.mac_work,
196127015b6fSBo Jiao 				     MT7996_WATCHDOG_TIME);
196227015b6fSBo Jiao 	if (phy2)
196327015b6fSBo Jiao 		ieee80211_queue_delayed_work(phy2->mt76->hw,
196427015b6fSBo Jiao 					     &phy2->mt76->mac_work,
196527015b6fSBo Jiao 					     MT7996_WATCHDOG_TIME);
196627015b6fSBo Jiao 	if (phy3)
196727015b6fSBo Jiao 		ieee80211_queue_delayed_work(phy3->mt76->hw,
196827015b6fSBo Jiao 					     &phy3->mt76->mac_work,
196927015b6fSBo Jiao 					     MT7996_WATCHDOG_TIME);
197027015b6fSBo Jiao }
197127015b6fSBo Jiao 
197298686cd2SShayne Chen void mt7996_mac_reset_work(struct work_struct *work)
197398686cd2SShayne Chen {
197498686cd2SShayne Chen 	struct mt7996_phy *phy2, *phy3;
197598686cd2SShayne Chen 	struct mt7996_dev *dev;
197698686cd2SShayne Chen 	int i;
197798686cd2SShayne Chen 
197898686cd2SShayne Chen 	dev = container_of(work, struct mt7996_dev, reset_work);
197998686cd2SShayne Chen 	phy2 = mt7996_phy2(dev);
198098686cd2SShayne Chen 	phy3 = mt7996_phy3(dev);
198198686cd2SShayne Chen 
198227015b6fSBo Jiao 	/* chip full reset */
198327015b6fSBo Jiao 	if (dev->recovery.restart) {
198427015b6fSBo Jiao 		/* disable WA/WM WDT */
198527015b6fSBo Jiao 		mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
198627015b6fSBo Jiao 			   MT_MCU_CMD_WDT_MASK);
198727015b6fSBo Jiao 
198827015b6fSBo Jiao 		if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
198927015b6fSBo Jiao 			dev->recovery.wa_reset_count++;
199027015b6fSBo Jiao 		else
199127015b6fSBo Jiao 			dev->recovery.wm_reset_count++;
199227015b6fSBo Jiao 
199327015b6fSBo Jiao 		mt7996_mac_full_reset(dev);
199427015b6fSBo Jiao 
199527015b6fSBo Jiao 		/* enable mcu irq */
199627015b6fSBo Jiao 		mt7996_irq_enable(dev, MT_INT_MCU_CMD);
199727015b6fSBo Jiao 		mt7996_irq_disable(dev, 0);
199827015b6fSBo Jiao 
199927015b6fSBo Jiao 		/* enable WA/WM WDT */
200027015b6fSBo Jiao 		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
200127015b6fSBo Jiao 
200227015b6fSBo Jiao 		dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
200327015b6fSBo Jiao 		dev->recovery.restart = false;
200427015b6fSBo Jiao 		return;
200527015b6fSBo Jiao 	}
200627015b6fSBo Jiao 
200727015b6fSBo Jiao 	if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
200898686cd2SShayne Chen 		return;
200998686cd2SShayne Chen 
201027015b6fSBo Jiao 	dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
201127015b6fSBo Jiao 		 wiphy_name(dev->mt76.hw->wiphy));
201298686cd2SShayne Chen 	ieee80211_stop_queues(mt76_hw(dev));
201398686cd2SShayne Chen 	if (phy2)
201498686cd2SShayne Chen 		ieee80211_stop_queues(phy2->mt76->hw);
201598686cd2SShayne Chen 	if (phy3)
201698686cd2SShayne Chen 		ieee80211_stop_queues(phy3->mt76->hw);
201798686cd2SShayne Chen 
201898686cd2SShayne Chen 	set_bit(MT76_RESET, &dev->mphy.state);
201998686cd2SShayne Chen 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
202098686cd2SShayne Chen 	wake_up(&dev->mt76.mcu.wait);
202198686cd2SShayne Chen 	cancel_delayed_work_sync(&dev->mphy.mac_work);
202298686cd2SShayne Chen 	if (phy2) {
202398686cd2SShayne Chen 		set_bit(MT76_RESET, &phy2->mt76->state);
202498686cd2SShayne Chen 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
202598686cd2SShayne Chen 	}
202698686cd2SShayne Chen 	if (phy3) {
202798686cd2SShayne Chen 		set_bit(MT76_RESET, &phy3->mt76->state);
202898686cd2SShayne Chen 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
202998686cd2SShayne Chen 	}
203098686cd2SShayne Chen 	mt76_worker_disable(&dev->mt76.tx_worker);
203198686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i)
203298686cd2SShayne Chen 		napi_disable(&dev->mt76.napi[i]);
203398686cd2SShayne Chen 	napi_disable(&dev->mt76.tx_napi);
203498686cd2SShayne Chen 
203598686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
203698686cd2SShayne Chen 
203798686cd2SShayne Chen 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
203898686cd2SShayne Chen 
203998686cd2SShayne Chen 	if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
204027015b6fSBo Jiao 		mt7996_dma_reset(dev, false);
204198686cd2SShayne Chen 
204298686cd2SShayne Chen 		mt7996_tx_token_put(dev);
204398686cd2SShayne Chen 		idr_init(&dev->mt76.token);
204498686cd2SShayne Chen 
204598686cd2SShayne Chen 		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
204698686cd2SShayne Chen 		mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
204798686cd2SShayne Chen 	}
204898686cd2SShayne Chen 
204998686cd2SShayne Chen 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
205098686cd2SShayne Chen 	clear_bit(MT76_RESET, &dev->mphy.state);
205198686cd2SShayne Chen 	if (phy2)
205298686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy2->mt76->state);
205398686cd2SShayne Chen 	if (phy3)
205498686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy3->mt76->state);
205598686cd2SShayne Chen 
205698686cd2SShayne Chen 	local_bh_disable();
205798686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i) {
205898686cd2SShayne Chen 		napi_enable(&dev->mt76.napi[i]);
205998686cd2SShayne Chen 		napi_schedule(&dev->mt76.napi[i]);
206098686cd2SShayne Chen 	}
206198686cd2SShayne Chen 	local_bh_enable();
206298686cd2SShayne Chen 
2063ec193b41SLorenzo Bianconi 	tasklet_schedule(&dev->mt76.irq_tasklet);
206498686cd2SShayne Chen 
206598686cd2SShayne Chen 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
206698686cd2SShayne Chen 	mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
206798686cd2SShayne Chen 
206898686cd2SShayne Chen 	mt76_worker_enable(&dev->mt76.tx_worker);
206998686cd2SShayne Chen 
207098686cd2SShayne Chen 	local_bh_disable();
207198686cd2SShayne Chen 	napi_enable(&dev->mt76.tx_napi);
207298686cd2SShayne Chen 	napi_schedule(&dev->mt76.tx_napi);
207398686cd2SShayne Chen 	local_bh_enable();
207498686cd2SShayne Chen 
207598686cd2SShayne Chen 	ieee80211_wake_queues(mt76_hw(dev));
207698686cd2SShayne Chen 	if (phy2)
207798686cd2SShayne Chen 		ieee80211_wake_queues(phy2->mt76->hw);
207898686cd2SShayne Chen 	if (phy3)
207998686cd2SShayne Chen 		ieee80211_wake_queues(phy3->mt76->hw);
208098686cd2SShayne Chen 
208198686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
208298686cd2SShayne Chen 
208398686cd2SShayne Chen 	mt7996_update_beacons(dev);
208498686cd2SShayne Chen 
208598686cd2SShayne Chen 	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
208698686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
208798686cd2SShayne Chen 	if (phy2)
208898686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy2->mt76->hw,
208998686cd2SShayne Chen 					     &phy2->mt76->mac_work,
209098686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
209198686cd2SShayne Chen 	if (phy3)
209298686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy3->mt76->hw,
209398686cd2SShayne Chen 					     &phy3->mt76->mac_work,
209498686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
209527015b6fSBo Jiao 	dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
209627015b6fSBo Jiao 		 wiphy_name(dev->mt76.hw->wiphy));
209727015b6fSBo Jiao }
209827015b6fSBo Jiao 
2099878161d5SRyder Lee /* firmware coredump */
2100878161d5SRyder Lee void mt7996_mac_dump_work(struct work_struct *work)
2101878161d5SRyder Lee {
2102878161d5SRyder Lee 	const struct mt7996_mem_region *mem_region;
2103878161d5SRyder Lee 	struct mt7996_crash_data *crash_data;
2104878161d5SRyder Lee 	struct mt7996_dev *dev;
2105878161d5SRyder Lee 	struct mt7996_mem_hdr *hdr;
2106878161d5SRyder Lee 	size_t buf_len;
2107878161d5SRyder Lee 	int i;
2108878161d5SRyder Lee 	u32 num;
2109878161d5SRyder Lee 	u8 *buf;
2110878161d5SRyder Lee 
2111878161d5SRyder Lee 	dev = container_of(work, struct mt7996_dev, dump_work);
2112878161d5SRyder Lee 
2113878161d5SRyder Lee 	mutex_lock(&dev->dump_mutex);
2114878161d5SRyder Lee 
2115878161d5SRyder Lee 	crash_data = mt7996_coredump_new(dev);
2116878161d5SRyder Lee 	if (!crash_data) {
2117878161d5SRyder Lee 		mutex_unlock(&dev->dump_mutex);
2118878161d5SRyder Lee 		goto skip_coredump;
2119878161d5SRyder Lee 	}
2120878161d5SRyder Lee 
2121878161d5SRyder Lee 	mem_region = mt7996_coredump_get_mem_layout(dev, &num);
2122878161d5SRyder Lee 	if (!mem_region || !crash_data->memdump_buf_len) {
2123878161d5SRyder Lee 		mutex_unlock(&dev->dump_mutex);
2124878161d5SRyder Lee 		goto skip_memdump;
2125878161d5SRyder Lee 	}
2126878161d5SRyder Lee 
2127878161d5SRyder Lee 	buf = crash_data->memdump_buf;
2128878161d5SRyder Lee 	buf_len = crash_data->memdump_buf_len;
2129878161d5SRyder Lee 
2130878161d5SRyder Lee 	/* dumping memory content... */
2131878161d5SRyder Lee 	memset(buf, 0, buf_len);
2132878161d5SRyder Lee 	for (i = 0; i < num; i++) {
2133878161d5SRyder Lee 		if (mem_region->len > buf_len) {
2134878161d5SRyder Lee 			dev_warn(dev->mt76.dev, "%s len %zu is too large\n",
2135878161d5SRyder Lee 				 mem_region->name, mem_region->len);
2136878161d5SRyder Lee 			break;
2137878161d5SRyder Lee 		}
2138878161d5SRyder Lee 
2139878161d5SRyder Lee 		/* reserve space for the header */
2140878161d5SRyder Lee 		hdr = (void *)buf;
2141878161d5SRyder Lee 		buf += sizeof(*hdr);
2142878161d5SRyder Lee 		buf_len -= sizeof(*hdr);
2143878161d5SRyder Lee 
2144878161d5SRyder Lee 		mt7996_memcpy_fromio(dev, buf, mem_region->start,
2145878161d5SRyder Lee 				     mem_region->len);
2146878161d5SRyder Lee 
2147878161d5SRyder Lee 		hdr->start = mem_region->start;
2148878161d5SRyder Lee 		hdr->len = mem_region->len;
2149878161d5SRyder Lee 
2150878161d5SRyder Lee 		if (!mem_region->len)
2151878161d5SRyder Lee 			/* note: the header remains, just with zero length */
2152878161d5SRyder Lee 			break;
2153878161d5SRyder Lee 
2154878161d5SRyder Lee 		buf += mem_region->len;
2155878161d5SRyder Lee 		buf_len -= mem_region->len;
2156878161d5SRyder Lee 
2157878161d5SRyder Lee 		mem_region++;
2158878161d5SRyder Lee 	}
2159878161d5SRyder Lee 
2160878161d5SRyder Lee 	mutex_unlock(&dev->dump_mutex);
2161878161d5SRyder Lee 
2162878161d5SRyder Lee skip_memdump:
2163878161d5SRyder Lee 	mt7996_coredump_submit(dev);
2164878161d5SRyder Lee skip_coredump:
2165878161d5SRyder Lee 	queue_work(dev->mt76.wq, &dev->reset_work);
2166878161d5SRyder Lee }
2167878161d5SRyder Lee 
216827015b6fSBo Jiao void mt7996_reset(struct mt7996_dev *dev)
216927015b6fSBo Jiao {
217027015b6fSBo Jiao 	if (!dev->recovery.hw_init_done)
217127015b6fSBo Jiao 		return;
217227015b6fSBo Jiao 
217327015b6fSBo Jiao 	if (dev->recovery.hw_full_reset)
217427015b6fSBo Jiao 		return;
217527015b6fSBo Jiao 
217627015b6fSBo Jiao 	/* wm/wa exception: do full recovery */
217727015b6fSBo Jiao 	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
217827015b6fSBo Jiao 		dev->recovery.restart = true;
217927015b6fSBo Jiao 		dev_info(dev->mt76.dev,
218027015b6fSBo Jiao 			 "%s indicated firmware crash, attempting recovery\n",
218127015b6fSBo Jiao 			 wiphy_name(dev->mt76.hw->wiphy));
218227015b6fSBo Jiao 
218327015b6fSBo Jiao 		mt7996_irq_disable(dev, MT_INT_MCU_CMD);
2184878161d5SRyder Lee 		queue_work(dev->mt76.wq, &dev->dump_work);
218527015b6fSBo Jiao 		return;
218627015b6fSBo Jiao 	}
218727015b6fSBo Jiao 
218827015b6fSBo Jiao 	queue_work(dev->mt76.wq, &dev->reset_work);
218927015b6fSBo Jiao 	wake_up(&dev->reset_wait);
219098686cd2SShayne Chen }
219198686cd2SShayne Chen 
219298686cd2SShayne Chen void mt7996_mac_update_stats(struct mt7996_phy *phy)
219398686cd2SShayne Chen {
219498686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
219598686cd2SShayne Chen 	struct mib_stats *mib = &phy->mib;
219698686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
219798686cd2SShayne Chen 	u32 cnt;
219898686cd2SShayne Chen 	int i;
219998686cd2SShayne Chen 
220098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx));
220198686cd2SShayne Chen 	mib->fcs_err_cnt += cnt;
220298686cd2SShayne Chen 
220398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx));
220498686cd2SShayne Chen 	mib->rx_fifo_full_cnt += cnt;
220598686cd2SShayne Chen 
220698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx));
220798686cd2SShayne Chen 	mib->rx_mpdu_cnt += cnt;
220898686cd2SShayne Chen 
220998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx));
221098686cd2SShayne Chen 	mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
221198686cd2SShayne Chen 
221298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx));
221398686cd2SShayne Chen 	mib->rx_vector_mismatch_cnt += cnt;
221498686cd2SShayne Chen 
221598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx));
221698686cd2SShayne Chen 	mib->rx_delimiter_fail_cnt += cnt;
221798686cd2SShayne Chen 
221898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx));
221998686cd2SShayne Chen 	mib->rx_len_mismatch_cnt += cnt;
222098686cd2SShayne Chen 
222198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx));
222298686cd2SShayne Chen 	mib->tx_ampdu_cnt += cnt;
222398686cd2SShayne Chen 
222498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx));
222598686cd2SShayne Chen 	mib->tx_stop_q_empty_cnt += cnt;
222698686cd2SShayne Chen 
222798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx));
222898686cd2SShayne Chen 	mib->tx_mpdu_attempts_cnt += cnt;
222998686cd2SShayne Chen 
223098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx));
223198686cd2SShayne Chen 	mib->tx_mpdu_success_cnt += cnt;
223298686cd2SShayne Chen 
223398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx));
223498686cd2SShayne Chen 	mib->rx_ampdu_cnt += cnt;
223598686cd2SShayne Chen 
223698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx));
223798686cd2SShayne Chen 	mib->rx_ampdu_bytes_cnt += cnt;
223898686cd2SShayne Chen 
223998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx));
224098686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_cnt += cnt;
224198686cd2SShayne Chen 
224298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx));
224398686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
224498686cd2SShayne Chen 
224598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx));
224698686cd2SShayne Chen 	mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt);
224798686cd2SShayne Chen 
224898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx));
224998686cd2SShayne Chen 	mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt);
225098686cd2SShayne Chen 
225198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx));
225298686cd2SShayne Chen 	mib->rx_pfdrop_cnt += cnt;
225398686cd2SShayne Chen 
225498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx));
225598686cd2SShayne Chen 	mib->rx_vec_queue_overflow_drop_cnt += cnt;
225698686cd2SShayne Chen 
225798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx));
225898686cd2SShayne Chen 	mib->rx_ba_cnt += cnt;
225998686cd2SShayne Chen 
226098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx));
226198686cd2SShayne Chen 	mib->tx_bf_ebf_ppdu_cnt += cnt;
226298686cd2SShayne Chen 
226398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx));
226498686cd2SShayne Chen 	mib->tx_bf_ibf_ppdu_cnt += cnt;
226598686cd2SShayne Chen 
226698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx));
226798686cd2SShayne Chen 	mib->tx_mu_bf_cnt += cnt;
226898686cd2SShayne Chen 
226998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx));
227098686cd2SShayne Chen 	mib->tx_mu_mpdu_cnt += cnt;
227198686cd2SShayne Chen 
227298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx));
227398686cd2SShayne Chen 	mib->tx_mu_acked_mpdu_cnt += cnt;
227498686cd2SShayne Chen 
227598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx));
227698686cd2SShayne Chen 	mib->tx_su_acked_mpdu_cnt += cnt;
227798686cd2SShayne Chen 
227898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx));
227998686cd2SShayne Chen 	mib->tx_bf_rx_fb_ht_cnt += cnt;
228098686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
228198686cd2SShayne Chen 
228298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx));
228398686cd2SShayne Chen 	mib->tx_bf_rx_fb_vht_cnt += cnt;
228498686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
228598686cd2SShayne Chen 
228698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx));
228798686cd2SShayne Chen 	mib->tx_bf_rx_fb_he_cnt += cnt;
228898686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
228998686cd2SShayne Chen 
229098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx));
229198686cd2SShayne Chen 	mib->tx_bf_rx_fb_eht_cnt += cnt;
229298686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
229398686cd2SShayne Chen 
229498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx));
229598686cd2SShayne Chen 	mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt);
229698686cd2SShayne Chen 	mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt);
229798686cd2SShayne Chen 	mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt);
229898686cd2SShayne Chen 
229998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR7(band_idx));
230098686cd2SShayne Chen 	mib->tx_bf_fb_trig_cnt += cnt;
230198686cd2SShayne Chen 
230298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx));
230398686cd2SShayne Chen 	mib->tx_bf_fb_cpl_cnt += cnt;
230498686cd2SShayne Chen 
230598686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
230698686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
230798686cd2SShayne Chen 		mib->tx_amsdu[i] += cnt;
230898686cd2SShayne Chen 		mib->tx_amsdu_cnt += cnt;
230998686cd2SShayne Chen 	}
231098686cd2SShayne Chen 
231198686cd2SShayne Chen 	/* rts count */
231298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx));
231398686cd2SShayne Chen 	mib->rts_cnt += cnt;
231498686cd2SShayne Chen 
231598686cd2SShayne Chen 	/* rts retry count */
231698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx));
231798686cd2SShayne Chen 	mib->rts_retries_cnt += cnt;
231898686cd2SShayne Chen 
231998686cd2SShayne Chen 	/* ba miss count */
232098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx));
232198686cd2SShayne Chen 	mib->ba_miss_cnt += cnt;
232298686cd2SShayne Chen 
232398686cd2SShayne Chen 	/* ack fail count */
232498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx));
232598686cd2SShayne Chen 	mib->ack_fail_cnt += cnt;
232698686cd2SShayne Chen 
232798686cd2SShayne Chen 	for (i = 0; i < 16; i++) {
232898686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
232998686cd2SShayne Chen 		phy->mt76->aggr_stats[i] += cnt;
233098686cd2SShayne Chen 	}
233198686cd2SShayne Chen }
233298686cd2SShayne Chen 
233398686cd2SShayne Chen void mt7996_mac_sta_rc_work(struct work_struct *work)
233498686cd2SShayne Chen {
233598686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
233698686cd2SShayne Chen 	struct ieee80211_sta *sta;
233798686cd2SShayne Chen 	struct ieee80211_vif *vif;
233898686cd2SShayne Chen 	struct mt7996_sta *msta;
233998686cd2SShayne Chen 	u32 changed;
234098686cd2SShayne Chen 	LIST_HEAD(list);
234198686cd2SShayne Chen 
234298686cd2SShayne Chen 	spin_lock_bh(&dev->sta_poll_lock);
234398686cd2SShayne Chen 	list_splice_init(&dev->sta_rc_list, &list);
234498686cd2SShayne Chen 
234598686cd2SShayne Chen 	while (!list_empty(&list)) {
234698686cd2SShayne Chen 		msta = list_first_entry(&list, struct mt7996_sta, rc_list);
234798686cd2SShayne Chen 		list_del_init(&msta->rc_list);
234898686cd2SShayne Chen 		changed = msta->changed;
234998686cd2SShayne Chen 		msta->changed = 0;
235098686cd2SShayne Chen 		spin_unlock_bh(&dev->sta_poll_lock);
235198686cd2SShayne Chen 
235298686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
235398686cd2SShayne Chen 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
235498686cd2SShayne Chen 
235598686cd2SShayne Chen 		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
235698686cd2SShayne Chen 			       IEEE80211_RC_NSS_CHANGED |
235798686cd2SShayne Chen 			       IEEE80211_RC_BW_CHANGED))
235898686cd2SShayne Chen 			mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
235998686cd2SShayne Chen 
236098686cd2SShayne Chen 		/* TODO: smps change */
236198686cd2SShayne Chen 
236298686cd2SShayne Chen 		spin_lock_bh(&dev->sta_poll_lock);
236398686cd2SShayne Chen 	}
236498686cd2SShayne Chen 
236598686cd2SShayne Chen 	spin_unlock_bh(&dev->sta_poll_lock);
236698686cd2SShayne Chen }
236798686cd2SShayne Chen 
236898686cd2SShayne Chen void mt7996_mac_work(struct work_struct *work)
236998686cd2SShayne Chen {
237098686cd2SShayne Chen 	struct mt7996_phy *phy;
237198686cd2SShayne Chen 	struct mt76_phy *mphy;
237298686cd2SShayne Chen 
237398686cd2SShayne Chen 	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
237498686cd2SShayne Chen 					       mac_work.work);
237598686cd2SShayne Chen 	phy = mphy->priv;
237698686cd2SShayne Chen 
237798686cd2SShayne Chen 	mutex_lock(&mphy->dev->mutex);
237898686cd2SShayne Chen 
237998686cd2SShayne Chen 	mt76_update_survey(mphy);
238098686cd2SShayne Chen 	if (++mphy->mac_work_count == 5) {
238198686cd2SShayne Chen 		mphy->mac_work_count = 0;
238298686cd2SShayne Chen 
238398686cd2SShayne Chen 		mt7996_mac_update_stats(phy);
238498686cd2SShayne Chen 	}
238598686cd2SShayne Chen 
238698686cd2SShayne Chen 	mutex_unlock(&mphy->dev->mutex);
238798686cd2SShayne Chen 
238898686cd2SShayne Chen 	mt76_tx_status_check(mphy->dev, false);
238998686cd2SShayne Chen 
239098686cd2SShayne Chen 	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
239198686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
239298686cd2SShayne Chen }
239398686cd2SShayne Chen 
239498686cd2SShayne Chen static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
239598686cd2SShayne Chen {
239698686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
239798686cd2SShayne Chen 
239898686cd2SShayne Chen 	if (phy->rdd_state & BIT(0))
239998686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0,
240098686cd2SShayne Chen 				   MT_RX_SEL0, 0);
240198686cd2SShayne Chen 	if (phy->rdd_state & BIT(1))
240298686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1,
240398686cd2SShayne Chen 				   MT_RX_SEL0, 0);
240498686cd2SShayne Chen }
240598686cd2SShayne Chen 
240698686cd2SShayne Chen static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
240798686cd2SShayne Chen {
240898686cd2SShayne Chen 	int err, region;
240998686cd2SShayne Chen 
241098686cd2SShayne Chen 	switch (dev->mt76.region) {
241198686cd2SShayne Chen 	case NL80211_DFS_ETSI:
241298686cd2SShayne Chen 		region = 0;
241398686cd2SShayne Chen 		break;
241498686cd2SShayne Chen 	case NL80211_DFS_JP:
241598686cd2SShayne Chen 		region = 2;
241698686cd2SShayne Chen 		break;
241798686cd2SShayne Chen 	case NL80211_DFS_FCC:
241898686cd2SShayne Chen 	default:
241998686cd2SShayne Chen 		region = 1;
242098686cd2SShayne Chen 		break;
242198686cd2SShayne Chen 	}
242298686cd2SShayne Chen 
242398686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain,
242498686cd2SShayne Chen 				 MT_RX_SEL0, region);
242598686cd2SShayne Chen 	if (err < 0)
242698686cd2SShayne Chen 		return err;
242798686cd2SShayne Chen 
242898686cd2SShayne Chen 	return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
242998686cd2SShayne Chen 				 MT_RX_SEL0, 1);
243098686cd2SShayne Chen }
243198686cd2SShayne Chen 
243298686cd2SShayne Chen static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
243398686cd2SShayne Chen {
243498686cd2SShayne Chen 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
243598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
243698686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
243798686cd2SShayne Chen 	int err;
243898686cd2SShayne Chen 
243998686cd2SShayne Chen 	/* start CAC */
244098686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx,
244198686cd2SShayne Chen 				 MT_RX_SEL0, 0);
244298686cd2SShayne Chen 	if (err < 0)
244398686cd2SShayne Chen 		return err;
244498686cd2SShayne Chen 
244598686cd2SShayne Chen 	err = mt7996_dfs_start_rdd(dev, band_idx);
244698686cd2SShayne Chen 	if (err < 0)
244798686cd2SShayne Chen 		return err;
244898686cd2SShayne Chen 
244998686cd2SShayne Chen 	phy->rdd_state |= BIT(band_idx);
245098686cd2SShayne Chen 
245198686cd2SShayne Chen 	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
245298686cd2SShayne Chen 	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
245398686cd2SShayne Chen 		err = mt7996_dfs_start_rdd(dev, 1);
245498686cd2SShayne Chen 		if (err < 0)
245598686cd2SShayne Chen 			return err;
245698686cd2SShayne Chen 
245798686cd2SShayne Chen 		phy->rdd_state |= BIT(1);
245898686cd2SShayne Chen 	}
245998686cd2SShayne Chen 
246098686cd2SShayne Chen 	return 0;
246198686cd2SShayne Chen }
246298686cd2SShayne Chen 
246398686cd2SShayne Chen static int
246498686cd2SShayne Chen mt7996_dfs_init_radar_specs(struct mt7996_phy *phy)
246598686cd2SShayne Chen {
246698686cd2SShayne Chen 	const struct mt7996_dfs_radar_spec *radar_specs;
246798686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
246898686cd2SShayne Chen 	int err, i;
246998686cd2SShayne Chen 
247098686cd2SShayne Chen 	switch (dev->mt76.region) {
247198686cd2SShayne Chen 	case NL80211_DFS_FCC:
247298686cd2SShayne Chen 		radar_specs = &fcc_radar_specs;
247398686cd2SShayne Chen 		err = mt7996_mcu_set_fcc5_lpn(dev, 8);
247498686cd2SShayne Chen 		if (err < 0)
247598686cd2SShayne Chen 			return err;
247698686cd2SShayne Chen 		break;
247798686cd2SShayne Chen 	case NL80211_DFS_ETSI:
247898686cd2SShayne Chen 		radar_specs = &etsi_radar_specs;
247998686cd2SShayne Chen 		break;
248098686cd2SShayne Chen 	case NL80211_DFS_JP:
248198686cd2SShayne Chen 		radar_specs = &jp_radar_specs;
248298686cd2SShayne Chen 		break;
248398686cd2SShayne Chen 	default:
248498686cd2SShayne Chen 		return -EINVAL;
248598686cd2SShayne Chen 	}
248698686cd2SShayne Chen 
248798686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
248898686cd2SShayne Chen 		err = mt7996_mcu_set_radar_th(dev, i,
248998686cd2SShayne Chen 					      &radar_specs->radar_pattern[i]);
249098686cd2SShayne Chen 		if (err < 0)
249198686cd2SShayne Chen 			return err;
249298686cd2SShayne Chen 	}
249398686cd2SShayne Chen 
249498686cd2SShayne Chen 	return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
249598686cd2SShayne Chen }
249698686cd2SShayne Chen 
249798686cd2SShayne Chen int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
249898686cd2SShayne Chen {
249998686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
250098686cd2SShayne Chen 	enum mt76_dfs_state dfs_state, prev_state;
250198686cd2SShayne Chen 	int err;
250298686cd2SShayne Chen 
250398686cd2SShayne Chen 	prev_state = phy->mt76->dfs_state;
250498686cd2SShayne Chen 	dfs_state = mt76_phy_dfs_state(phy->mt76);
250598686cd2SShayne Chen 
250698686cd2SShayne Chen 	if (prev_state == dfs_state)
250798686cd2SShayne Chen 		return 0;
250898686cd2SShayne Chen 
250998686cd2SShayne Chen 	if (prev_state == MT_DFS_STATE_UNKNOWN)
251098686cd2SShayne Chen 		mt7996_dfs_stop_radar_detector(phy);
251198686cd2SShayne Chen 
251298686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_DISABLED)
251398686cd2SShayne Chen 		goto stop;
251498686cd2SShayne Chen 
251598686cd2SShayne Chen 	if (prev_state <= MT_DFS_STATE_DISABLED) {
251698686cd2SShayne Chen 		err = mt7996_dfs_init_radar_specs(phy);
251798686cd2SShayne Chen 		if (err < 0)
251898686cd2SShayne Chen 			return err;
251998686cd2SShayne Chen 
252098686cd2SShayne Chen 		err = mt7996_dfs_start_radar_detector(phy);
252198686cd2SShayne Chen 		if (err < 0)
252298686cd2SShayne Chen 			return err;
252398686cd2SShayne Chen 
252498686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_CAC;
252598686cd2SShayne Chen 	}
252698686cd2SShayne Chen 
252798686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_CAC)
252898686cd2SShayne Chen 		return 0;
252998686cd2SShayne Chen 
253098686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END,
253198686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
253298686cd2SShayne Chen 	if (err < 0) {
253398686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
253498686cd2SShayne Chen 		return err;
253598686cd2SShayne Chen 	}
253698686cd2SShayne Chen 
253798686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
253898686cd2SShayne Chen 	return 0;
253998686cd2SShayne Chen 
254098686cd2SShayne Chen stop:
254198686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START,
254298686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
254398686cd2SShayne Chen 	if (err < 0)
254498686cd2SShayne Chen 		return err;
254598686cd2SShayne Chen 
254698686cd2SShayne Chen 	mt7996_dfs_stop_radar_detector(phy);
254798686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
254898686cd2SShayne Chen 
254998686cd2SShayne Chen 	return 0;
255098686cd2SShayne Chen }
255198686cd2SShayne Chen 
255298686cd2SShayne Chen static int
255398686cd2SShayne Chen mt7996_mac_twt_duration_align(int duration)
255498686cd2SShayne Chen {
255598686cd2SShayne Chen 	return duration << 8;
255698686cd2SShayne Chen }
255798686cd2SShayne Chen 
255898686cd2SShayne Chen static u64
255998686cd2SShayne Chen mt7996_mac_twt_sched_list_add(struct mt7996_dev *dev,
256098686cd2SShayne Chen 			      struct mt7996_twt_flow *flow)
256198686cd2SShayne Chen {
256298686cd2SShayne Chen 	struct mt7996_twt_flow *iter, *iter_next;
256398686cd2SShayne Chen 	u32 duration = flow->duration << 8;
256498686cd2SShayne Chen 	u64 start_tsf;
256598686cd2SShayne Chen 
256698686cd2SShayne Chen 	iter = list_first_entry_or_null(&dev->twt_list,
256798686cd2SShayne Chen 					struct mt7996_twt_flow, list);
256898686cd2SShayne Chen 	if (!iter || !iter->sched || iter->start_tsf > duration) {
256998686cd2SShayne Chen 		/* add flow as first entry in the list */
257098686cd2SShayne Chen 		list_add(&flow->list, &dev->twt_list);
257198686cd2SShayne Chen 		return 0;
257298686cd2SShayne Chen 	}
257398686cd2SShayne Chen 
257498686cd2SShayne Chen 	list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
257598686cd2SShayne Chen 		start_tsf = iter->start_tsf +
257698686cd2SShayne Chen 			    mt7996_mac_twt_duration_align(iter->duration);
257798686cd2SShayne Chen 		if (list_is_last(&iter->list, &dev->twt_list))
257898686cd2SShayne Chen 			break;
257998686cd2SShayne Chen 
258098686cd2SShayne Chen 		if (!iter_next->sched ||
258198686cd2SShayne Chen 		    iter_next->start_tsf > start_tsf + duration) {
258298686cd2SShayne Chen 			list_add(&flow->list, &iter->list);
258398686cd2SShayne Chen 			goto out;
258498686cd2SShayne Chen 		}
258598686cd2SShayne Chen 	}
258698686cd2SShayne Chen 
258798686cd2SShayne Chen 	/* add flow as last entry in the list */
258898686cd2SShayne Chen 	list_add_tail(&flow->list, &dev->twt_list);
258998686cd2SShayne Chen out:
259098686cd2SShayne Chen 	return start_tsf;
259198686cd2SShayne Chen }
259298686cd2SShayne Chen 
259398686cd2SShayne Chen static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
259498686cd2SShayne Chen {
259598686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt;
259698686cd2SShayne Chen 	u64 interval, duration;
259798686cd2SShayne Chen 	u16 mantissa;
259898686cd2SShayne Chen 	u8 exp;
259998686cd2SShayne Chen 
260098686cd2SShayne Chen 	/* only individual agreement supported */
260198686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
260298686cd2SShayne Chen 		return -EOPNOTSUPP;
260398686cd2SShayne Chen 
260498686cd2SShayne Chen 	/* only 256us unit supported */
260598686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
260698686cd2SShayne Chen 		return -EOPNOTSUPP;
260798686cd2SShayne Chen 
260898686cd2SShayne Chen 	twt_agrt = (struct ieee80211_twt_params *)twt->params;
260998686cd2SShayne Chen 
261098686cd2SShayne Chen 	/* explicit agreement not supported */
261198686cd2SShayne Chen 	if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
261298686cd2SShayne Chen 		return -EOPNOTSUPP;
261398686cd2SShayne Chen 
261498686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
261598686cd2SShayne Chen 			le16_to_cpu(twt_agrt->req_type));
261698686cd2SShayne Chen 	mantissa = le16_to_cpu(twt_agrt->mantissa);
261798686cd2SShayne Chen 	duration = twt_agrt->min_twt_dur << 8;
261898686cd2SShayne Chen 
261998686cd2SShayne Chen 	interval = (u64)mantissa << exp;
262098686cd2SShayne Chen 	if (interval < duration)
262198686cd2SShayne Chen 		return -EOPNOTSUPP;
262298686cd2SShayne Chen 
262398686cd2SShayne Chen 	return 0;
262498686cd2SShayne Chen }
262598686cd2SShayne Chen 
262698686cd2SShayne Chen void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
262798686cd2SShayne Chen 			      struct ieee80211_sta *sta,
262898686cd2SShayne Chen 			      struct ieee80211_twt_setup *twt)
262998686cd2SShayne Chen {
263098686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
263198686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
263298686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
263398686cd2SShayne Chen 	u16 req_type = le16_to_cpu(twt_agrt->req_type);
263498686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd sta_setup_cmd;
263598686cd2SShayne Chen 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
263698686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
263798686cd2SShayne Chen 	int flowid, table_id;
263898686cd2SShayne Chen 	u8 exp;
263998686cd2SShayne Chen 
264098686cd2SShayne Chen 	if (mt7996_mac_check_twt_req(twt))
264198686cd2SShayne Chen 		goto out;
264298686cd2SShayne Chen 
264398686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
264498686cd2SShayne Chen 
264598686cd2SShayne Chen 	if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
264698686cd2SShayne Chen 		goto unlock;
264798686cd2SShayne Chen 
264898686cd2SShayne Chen 	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
264998686cd2SShayne Chen 		goto unlock;
265098686cd2SShayne Chen 
265198686cd2SShayne Chen 	flowid = ffs(~msta->twt.flowid_mask) - 1;
265298686cd2SShayne Chen 	le16p_replace_bits(&twt_agrt->req_type, flowid,
265398686cd2SShayne Chen 			   IEEE80211_TWT_REQTYPE_FLOWID);
265498686cd2SShayne Chen 
265598686cd2SShayne Chen 	table_id = ffs(~dev->twt.table_mask) - 1;
265698686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
265798686cd2SShayne Chen 	sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
265898686cd2SShayne Chen 
265998686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
266098686cd2SShayne Chen 	memset(flow, 0, sizeof(*flow));
266198686cd2SShayne Chen 	INIT_LIST_HEAD(&flow->list);
266298686cd2SShayne Chen 	flow->wcid = msta->wcid.idx;
266398686cd2SShayne Chen 	flow->table_id = table_id;
266498686cd2SShayne Chen 	flow->id = flowid;
266598686cd2SShayne Chen 	flow->duration = twt_agrt->min_twt_dur;
266698686cd2SShayne Chen 	flow->mantissa = twt_agrt->mantissa;
266798686cd2SShayne Chen 	flow->exp = exp;
266898686cd2SShayne Chen 	flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
266998686cd2SShayne Chen 	flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
267098686cd2SShayne Chen 	flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
267198686cd2SShayne Chen 
267298686cd2SShayne Chen 	if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
267398686cd2SShayne Chen 	    sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
267498686cd2SShayne Chen 		u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
267598686cd2SShayne Chen 		u64 flow_tsf, curr_tsf;
267698686cd2SShayne Chen 		u32 rem;
267798686cd2SShayne Chen 
267898686cd2SShayne Chen 		flow->sched = true;
267998686cd2SShayne Chen 		flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
268098686cd2SShayne Chen 		curr_tsf = __mt7996_get_tsf(hw, msta->vif);
268198686cd2SShayne Chen 		div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
268298686cd2SShayne Chen 		flow_tsf = curr_tsf + interval - rem;
268398686cd2SShayne Chen 		twt_agrt->twt = cpu_to_le64(flow_tsf);
268498686cd2SShayne Chen 	} else {
268598686cd2SShayne Chen 		list_add_tail(&flow->list, &dev->twt_list);
268698686cd2SShayne Chen 	}
268798686cd2SShayne Chen 	flow->tsf = le64_to_cpu(twt_agrt->twt);
268898686cd2SShayne Chen 
268998686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
269098686cd2SShayne Chen 		goto unlock;
269198686cd2SShayne Chen 
269298686cd2SShayne Chen 	setup_cmd = TWT_SETUP_CMD_ACCEPT;
269398686cd2SShayne Chen 	dev->twt.table_mask |= BIT(table_id);
269498686cd2SShayne Chen 	msta->twt.flowid_mask |= BIT(flowid);
269598686cd2SShayne Chen 	dev->twt.n_agrt++;
269698686cd2SShayne Chen 
269798686cd2SShayne Chen unlock:
269898686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
269998686cd2SShayne Chen out:
270098686cd2SShayne Chen 	le16p_replace_bits(&twt_agrt->req_type, setup_cmd,
270198686cd2SShayne Chen 			   IEEE80211_TWT_REQTYPE_SETUP_CMD);
270298686cd2SShayne Chen 	twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) |
270398686cd2SShayne Chen 		       (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED);
270498686cd2SShayne Chen }
270598686cd2SShayne Chen 
270698686cd2SShayne Chen void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
270798686cd2SShayne Chen 				  struct mt7996_sta *msta,
270898686cd2SShayne Chen 				  u8 flowid)
270998686cd2SShayne Chen {
271098686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
271198686cd2SShayne Chen 
271298686cd2SShayne Chen 	lockdep_assert_held(&dev->mt76.mutex);
271398686cd2SShayne Chen 
271498686cd2SShayne Chen 	if (flowid >= ARRAY_SIZE(msta->twt.flow))
271598686cd2SShayne Chen 		return;
271698686cd2SShayne Chen 
271798686cd2SShayne Chen 	if (!(msta->twt.flowid_mask & BIT(flowid)))
271898686cd2SShayne Chen 		return;
271998686cd2SShayne Chen 
272098686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
272198686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
272298686cd2SShayne Chen 				       MCU_TWT_AGRT_DELETE))
272398686cd2SShayne Chen 		return;
272498686cd2SShayne Chen 
272598686cd2SShayne Chen 	list_del_init(&flow->list);
272698686cd2SShayne Chen 	msta->twt.flowid_mask &= ~BIT(flowid);
272798686cd2SShayne Chen 	dev->twt.table_mask &= ~BIT(flow->table_id);
272898686cd2SShayne Chen 	dev->twt.n_agrt--;
272998686cd2SShayne Chen }
2730