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>
898686cd2SShayne Chen #include "mt7996.h"
998686cd2SShayne Chen #include "../dma.h"
1098686cd2SShayne Chen #include "mac.h"
1198686cd2SShayne Chen #include "mcu.h"
1298686cd2SShayne Chen 
13ea5d99d0SRyder Lee #define to_rssi(field, rcpi)	((FIELD_GET(field, rcpi) - 220) / 2)
1498686cd2SShayne Chen 
1598686cd2SShayne Chen #define HE_BITS(f)		cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
1698686cd2SShayne Chen #define HE_PREP(f, m, v)	le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
1798686cd2SShayne Chen 						 IEEE80211_RADIOTAP_HE_##f)
1898686cd2SShayne Chen 
1998686cd2SShayne Chen static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
2098686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
2198686cd2SShayne Chen 	.radar_pattern = {
2298686cd2SShayne Chen 		[5] =  { 1, 0,  6, 32, 28, 0,  990, 5010, 17, 1, 1 },
2398686cd2SShayne Chen 		[6] =  { 1, 0,  9, 32, 28, 0,  615, 5010, 27, 1, 1 },
2498686cd2SShayne Chen 		[7] =  { 1, 0, 15, 32, 28, 0,  240,  445, 27, 1, 1 },
2598686cd2SShayne Chen 		[8] =  { 1, 0, 12, 32, 28, 0,  240,  510, 42, 1, 1 },
2698686cd2SShayne Chen 		[9] =  { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
2798686cd2SShayne Chen 		[10] = { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
2898686cd2SShayne Chen 		[11] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 18, 32, 28, { },  54 },
2998686cd2SShayne Chen 		[12] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 27, 32, 24, { },  54 },
3098686cd2SShayne Chen 	},
3198686cd2SShayne Chen };
3298686cd2SShayne Chen 
3398686cd2SShayne Chen static const struct mt7996_dfs_radar_spec fcc_radar_specs = {
3498686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
3598686cd2SShayne Chen 	.radar_pattern = {
3698686cd2SShayne Chen 		[0] = { 1, 0,  8,  32, 28, 0, 508, 3076, 13, 1,  1 },
3798686cd2SShayne Chen 		[1] = { 1, 0, 12,  32, 28, 0, 140,  240, 17, 1,  1 },
3898686cd2SShayne Chen 		[2] = { 1, 0,  8,  32, 28, 0, 190,  510, 22, 1,  1 },
3998686cd2SShayne Chen 		[3] = { 1, 0,  6,  32, 28, 0, 190,  510, 32, 1,  1 },
4098686cd2SShayne Chen 		[4] = { 1, 0,  9, 255, 28, 0, 323,  343, 13, 1, 32 },
4198686cd2SShayne Chen 	},
4298686cd2SShayne Chen };
4398686cd2SShayne Chen 
4498686cd2SShayne Chen static const struct mt7996_dfs_radar_spec jp_radar_specs = {
4598686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
4698686cd2SShayne Chen 	.radar_pattern = {
4798686cd2SShayne Chen 		[0] =  { 1, 0,  8,  32, 28, 0,  508, 3076,  13, 1,  1 },
4898686cd2SShayne Chen 		[1] =  { 1, 0, 12,  32, 28, 0,  140,  240,  17, 1,  1 },
4998686cd2SShayne Chen 		[2] =  { 1, 0,  8,  32, 28, 0,  190,  510,  22, 1,  1 },
5098686cd2SShayne Chen 		[3] =  { 1, 0,  6,  32, 28, 0,  190,  510,  32, 1,  1 },
5198686cd2SShayne Chen 		[4] =  { 1, 0,  9, 255, 28, 0,  323,  343,  13, 1, 32 },
5298686cd2SShayne Chen 		[13] = { 1, 0,  7,  32, 28, 0, 3836, 3856,  14, 1,  1 },
5398686cd2SShayne Chen 		[14] = { 1, 0,  6,  32, 28, 0,  615, 5010, 110, 1,  1 },
5498686cd2SShayne Chen 		[15] = { 1, 1,  0,   0,  0, 0,   15, 5010, 110, 0,  0, 12, 32, 28 },
5598686cd2SShayne Chen 	},
5698686cd2SShayne Chen };
5798686cd2SShayne Chen 
5898686cd2SShayne Chen static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
5998686cd2SShayne Chen 					    u16 idx, bool unicast)
6098686cd2SShayne Chen {
6198686cd2SShayne Chen 	struct mt7996_sta *sta;
6298686cd2SShayne Chen 	struct mt76_wcid *wcid;
6398686cd2SShayne Chen 
6498686cd2SShayne Chen 	if (idx >= ARRAY_SIZE(dev->mt76.wcid))
6598686cd2SShayne Chen 		return NULL;
6698686cd2SShayne Chen 
6798686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[idx]);
6898686cd2SShayne Chen 	if (unicast || !wcid)
6998686cd2SShayne Chen 		return wcid;
7098686cd2SShayne Chen 
7198686cd2SShayne Chen 	if (!wcid->sta)
7298686cd2SShayne Chen 		return NULL;
7398686cd2SShayne Chen 
7498686cd2SShayne Chen 	sta = container_of(wcid, struct mt7996_sta, wcid);
7598686cd2SShayne Chen 	if (!sta->vif)
7698686cd2SShayne Chen 		return NULL;
7798686cd2SShayne Chen 
7898686cd2SShayne Chen 	return &sta->vif->sta.wcid;
7998686cd2SShayne Chen }
8098686cd2SShayne Chen 
8198686cd2SShayne Chen void mt7996_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
8298686cd2SShayne Chen {
8398686cd2SShayne Chen }
8498686cd2SShayne Chen 
8598686cd2SShayne Chen bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
8698686cd2SShayne Chen {
8798686cd2SShayne Chen 	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
8898686cd2SShayne Chen 		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
8998686cd2SShayne Chen 
9098686cd2SShayne Chen 	return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
9198686cd2SShayne Chen 			 0, 5000);
9298686cd2SShayne Chen }
9398686cd2SShayne Chen 
9498686cd2SShayne Chen u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
9598686cd2SShayne Chen {
9698686cd2SShayne Chen 	mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
9798686cd2SShayne Chen 		FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
9898686cd2SShayne Chen 
9998686cd2SShayne Chen 	return MT_WTBL_LMAC_OFFS(wcid, dw);
10098686cd2SShayne Chen }
10198686cd2SShayne Chen 
10298686cd2SShayne Chen static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
10398686cd2SShayne Chen {
10498686cd2SShayne Chen 	static const u8 ac_to_tid[] = {
10598686cd2SShayne Chen 		[IEEE80211_AC_BE] = 0,
10698686cd2SShayne Chen 		[IEEE80211_AC_BK] = 1,
10798686cd2SShayne Chen 		[IEEE80211_AC_VI] = 4,
10898686cd2SShayne Chen 		[IEEE80211_AC_VO] = 6
10998686cd2SShayne Chen 	};
11098686cd2SShayne Chen 	struct ieee80211_sta *sta;
11198686cd2SShayne Chen 	struct mt7996_sta *msta;
11298686cd2SShayne Chen 	struct rate_info *rate;
11398686cd2SShayne Chen 	u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
11498686cd2SShayne Chen 	LIST_HEAD(sta_poll_list);
11598686cd2SShayne Chen 	int i;
11698686cd2SShayne Chen 
11798686cd2SShayne Chen 	spin_lock_bh(&dev->sta_poll_lock);
11898686cd2SShayne Chen 	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
11998686cd2SShayne Chen 	spin_unlock_bh(&dev->sta_poll_lock);
12098686cd2SShayne Chen 
12198686cd2SShayne Chen 	rcu_read_lock();
12298686cd2SShayne Chen 
12398686cd2SShayne Chen 	while (true) {
12498686cd2SShayne Chen 		bool clear = false;
12598686cd2SShayne Chen 		u32 addr, val;
12698686cd2SShayne Chen 		u16 idx;
127ea5d99d0SRyder Lee 		s8 rssi[4];
12898686cd2SShayne Chen 		u8 bw;
12998686cd2SShayne Chen 
13098686cd2SShayne Chen 		spin_lock_bh(&dev->sta_poll_lock);
13198686cd2SShayne Chen 		if (list_empty(&sta_poll_list)) {
13298686cd2SShayne Chen 			spin_unlock_bh(&dev->sta_poll_lock);
13398686cd2SShayne Chen 			break;
13498686cd2SShayne Chen 		}
13598686cd2SShayne Chen 		msta = list_first_entry(&sta_poll_list,
13698686cd2SShayne Chen 					struct mt7996_sta, poll_list);
13798686cd2SShayne Chen 		list_del_init(&msta->poll_list);
13898686cd2SShayne Chen 		spin_unlock_bh(&dev->sta_poll_lock);
13998686cd2SShayne Chen 
14098686cd2SShayne Chen 		idx = msta->wcid.idx;
141ea5d99d0SRyder Lee 
142ea5d99d0SRyder Lee 		/* refresh peer's airtime reporting */
14398686cd2SShayne Chen 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
14498686cd2SShayne Chen 
14598686cd2SShayne Chen 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
14698686cd2SShayne Chen 			u32 tx_last = msta->airtime_ac[i];
14798686cd2SShayne Chen 			u32 rx_last = msta->airtime_ac[i + 4];
14898686cd2SShayne Chen 
14998686cd2SShayne Chen 			msta->airtime_ac[i] = mt76_rr(dev, addr);
15098686cd2SShayne Chen 			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
15198686cd2SShayne Chen 
15298686cd2SShayne Chen 			tx_time[i] = msta->airtime_ac[i] - tx_last;
15398686cd2SShayne Chen 			rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
15498686cd2SShayne Chen 
15598686cd2SShayne Chen 			if ((tx_last | rx_last) & BIT(30))
15698686cd2SShayne Chen 				clear = true;
15798686cd2SShayne Chen 
15898686cd2SShayne Chen 			addr += 8;
15998686cd2SShayne Chen 		}
16098686cd2SShayne Chen 
16198686cd2SShayne Chen 		if (clear) {
16298686cd2SShayne Chen 			mt7996_mac_wtbl_update(dev, idx,
16398686cd2SShayne Chen 					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
16498686cd2SShayne Chen 			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
16598686cd2SShayne Chen 		}
16698686cd2SShayne Chen 
16798686cd2SShayne Chen 		if (!msta->wcid.sta)
16898686cd2SShayne Chen 			continue;
16998686cd2SShayne Chen 
17098686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta,
17198686cd2SShayne Chen 				   drv_priv);
17298686cd2SShayne Chen 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
17398686cd2SShayne Chen 			u8 q = mt76_connac_lmac_mapping(i);
17498686cd2SShayne Chen 			u32 tx_cur = tx_time[q];
17598686cd2SShayne Chen 			u32 rx_cur = rx_time[q];
17698686cd2SShayne Chen 			u8 tid = ac_to_tid[i];
17798686cd2SShayne Chen 
17898686cd2SShayne Chen 			if (!tx_cur && !rx_cur)
17998686cd2SShayne Chen 				continue;
18098686cd2SShayne Chen 
18198686cd2SShayne Chen 			ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
18298686cd2SShayne Chen 		}
18398686cd2SShayne Chen 
18498686cd2SShayne Chen 		/* We don't support reading GI info from txs packets.
18598686cd2SShayne Chen 		 * For accurate tx status reporting and AQL improvement,
18698686cd2SShayne Chen 		 * we need to make sure that flags match so polling GI
18798686cd2SShayne Chen 		 * from per-sta counters directly.
18898686cd2SShayne Chen 		 */
18998686cd2SShayne Chen 		rate = &msta->wcid.rate;
19098686cd2SShayne Chen 
19198686cd2SShayne Chen 		switch (rate->bw) {
19280f5a31dSShayne Chen 		case RATE_INFO_BW_320:
19380f5a31dSShayne Chen 			bw = IEEE80211_STA_RX_BW_320;
19480f5a31dSShayne Chen 			break;
19598686cd2SShayne Chen 		case RATE_INFO_BW_160:
19698686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_160;
19798686cd2SShayne Chen 			break;
19898686cd2SShayne Chen 		case RATE_INFO_BW_80:
19998686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_80;
20098686cd2SShayne Chen 			break;
20198686cd2SShayne Chen 		case RATE_INFO_BW_40:
20298686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_40;
20398686cd2SShayne Chen 			break;
20498686cd2SShayne Chen 		default:
20598686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_20;
20698686cd2SShayne Chen 			break;
20798686cd2SShayne Chen 		}
20898686cd2SShayne Chen 
20998686cd2SShayne Chen 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
21098686cd2SShayne Chen 		val = mt76_rr(dev, addr);
21180f5a31dSShayne Chen 		if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
21280f5a31dSShayne Chen 			addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
21380f5a31dSShayne Chen 			val = mt76_rr(dev, addr);
21480f5a31dSShayne Chen 			rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
21580f5a31dSShayne Chen 		} else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
21698686cd2SShayne Chen 			u8 offs = 24 + 2 * bw;
21798686cd2SShayne Chen 
21898686cd2SShayne Chen 			rate->he_gi = (val & (0x3 << offs)) >> offs;
21998686cd2SShayne Chen 		} else if (rate->flags &
22098686cd2SShayne Chen 			   (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
22198686cd2SShayne Chen 			if (val & BIT(12 + bw))
22298686cd2SShayne Chen 				rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
22398686cd2SShayne Chen 			else
22498686cd2SShayne Chen 				rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
22598686cd2SShayne Chen 		}
226ea5d99d0SRyder Lee 
227ea5d99d0SRyder Lee 		/* get signal strength of resp frames (CTS/BA/ACK) */
228ea5d99d0SRyder Lee 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
229ea5d99d0SRyder Lee 		val = mt76_rr(dev, addr);
230ea5d99d0SRyder Lee 
231ea5d99d0SRyder Lee 		rssi[0] = to_rssi(GENMASK(7, 0), val);
232ea5d99d0SRyder Lee 		rssi[1] = to_rssi(GENMASK(15, 8), val);
233ea5d99d0SRyder Lee 		rssi[2] = to_rssi(GENMASK(23, 16), val);
234ea5d99d0SRyder Lee 		rssi[3] = to_rssi(GENMASK(31, 14), val);
235ea5d99d0SRyder Lee 
236ea5d99d0SRyder Lee 		msta->ack_signal =
237ea5d99d0SRyder Lee 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
238ea5d99d0SRyder Lee 
239ea5d99d0SRyder Lee 		ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
24098686cd2SShayne Chen 	}
24198686cd2SShayne Chen 
24298686cd2SShayne Chen 	rcu_read_unlock();
24398686cd2SShayne Chen }
24498686cd2SShayne Chen 
245d75e739bSRyder Lee void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
246d75e739bSRyder Lee 			      struct ieee80211_vif *vif, bool enable)
247d75e739bSRyder Lee {
248d75e739bSRyder Lee 	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
249d75e739bSRyder Lee 	u32 addr;
250d75e739bSRyder Lee 
251d75e739bSRyder Lee 	addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
252d75e739bSRyder Lee 	if (enable)
253d75e739bSRyder Lee 		mt76_set(dev, addr, BIT(5));
254d75e739bSRyder Lee 	else
255d75e739bSRyder Lee 		mt76_clear(dev, addr, BIT(5));
256d75e739bSRyder Lee }
257d75e739bSRyder Lee 
25898686cd2SShayne Chen static void
25998686cd2SShayne Chen mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
26098686cd2SShayne Chen 				 struct ieee80211_radiotap_he *he,
26198686cd2SShayne Chen 				 __le32 *rxv)
26298686cd2SShayne Chen {
263*63a37246SRyder Lee 	u32 ru, offs = 0;
26498686cd2SShayne Chen 
265*63a37246SRyder Lee 	ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC);
26698686cd2SShayne Chen 
26798686cd2SShayne Chen 	status->bw = RATE_INFO_BW_HE_RU;
26898686cd2SShayne Chen 
26998686cd2SShayne Chen 	switch (ru) {
27098686cd2SShayne Chen 	case 0 ... 36:
27198686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
27298686cd2SShayne Chen 		offs = ru;
27398686cd2SShayne Chen 		break;
27498686cd2SShayne Chen 	case 37 ... 52:
27598686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
27698686cd2SShayne Chen 		offs = ru - 37;
27798686cd2SShayne Chen 		break;
27898686cd2SShayne Chen 	case 53 ... 60:
27998686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
28098686cd2SShayne Chen 		offs = ru - 53;
28198686cd2SShayne Chen 		break;
28298686cd2SShayne Chen 	case 61 ... 64:
28398686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
28498686cd2SShayne Chen 		offs = ru - 61;
28598686cd2SShayne Chen 		break;
28698686cd2SShayne Chen 	case 65 ... 66:
28798686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
28898686cd2SShayne Chen 		offs = ru - 65;
28998686cd2SShayne Chen 		break;
29098686cd2SShayne Chen 	case 67:
29198686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
29298686cd2SShayne Chen 		break;
29398686cd2SShayne Chen 	case 68:
29498686cd2SShayne Chen 		status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
29598686cd2SShayne Chen 		break;
29698686cd2SShayne Chen 	}
29798686cd2SShayne Chen 
29898686cd2SShayne Chen 	he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
29998686cd2SShayne Chen 	he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
30098686cd2SShayne Chen 		     le16_encode_bits(offs,
30198686cd2SShayne Chen 				      IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
30298686cd2SShayne Chen }
30398686cd2SShayne Chen 
30498686cd2SShayne Chen static void
30598686cd2SShayne Chen mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
30698686cd2SShayne Chen {
30798686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
30898686cd2SShayne Chen 	static const struct ieee80211_radiotap_he_mu mu_known = {
30998686cd2SShayne Chen 		.flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
31098686cd2SShayne Chen 			  HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
31198686cd2SShayne Chen 			  HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
31298686cd2SShayne Chen 			  HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
31398686cd2SShayne Chen 		.flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
31498686cd2SShayne Chen 	};
31598686cd2SShayne Chen 	struct ieee80211_radiotap_he_mu *he_mu = NULL;
31698686cd2SShayne Chen 
31798686cd2SShayne Chen 	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
31898686cd2SShayne Chen 
31998686cd2SShayne Chen 	he_mu = skb_push(skb, sizeof(mu_known));
32098686cd2SShayne Chen 	memcpy(he_mu, &mu_known, sizeof(mu_known));
32198686cd2SShayne Chen 
32298686cd2SShayne Chen #define MU_PREP(f, v)	le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
32398686cd2SShayne Chen 
32498686cd2SShayne Chen 	he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
32598686cd2SShayne Chen 	if (status->he_dcm)
32698686cd2SShayne Chen 		he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
32798686cd2SShayne Chen 
32898686cd2SShayne Chen 	he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
32998686cd2SShayne Chen 			 MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
330*63a37246SRyder Lee 				 le32_get_bits(rxv[4], MT_CRXV_HE_NUM_USER));
33198686cd2SShayne Chen 
332*63a37246SRyder Lee 	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
33398686cd2SShayne Chen 
33498686cd2SShayne Chen 	if (status->bw >= RATE_INFO_BW_40) {
33598686cd2SShayne Chen 		he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
336*63a37246SRyder Lee 		he_mu->ru_ch2[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU1) & 0xff;
33798686cd2SShayne Chen 	}
33898686cd2SShayne Chen 
33998686cd2SShayne Chen 	if (status->bw >= RATE_INFO_BW_80) {
340*63a37246SRyder Lee 		u32 ru_h, ru_l;
341*63a37246SRyder Lee 
342*63a37246SRyder Lee 		he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
343*63a37246SRyder Lee 
344*63a37246SRyder Lee 		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
345*63a37246SRyder Lee 		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
346*63a37246SRyder Lee 		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
34798686cd2SShayne Chen 	}
34898686cd2SShayne Chen }
34998686cd2SShayne Chen 
35098686cd2SShayne Chen static void
35198686cd2SShayne Chen mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
35298686cd2SShayne Chen {
35398686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
35498686cd2SShayne Chen 	static const struct ieee80211_radiotap_he known = {
35598686cd2SShayne Chen 		.data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
35698686cd2SShayne Chen 			 HE_BITS(DATA1_DATA_DCM_KNOWN) |
35798686cd2SShayne Chen 			 HE_BITS(DATA1_STBC_KNOWN) |
35898686cd2SShayne Chen 			 HE_BITS(DATA1_CODING_KNOWN) |
35998686cd2SShayne Chen 			 HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
36098686cd2SShayne Chen 			 HE_BITS(DATA1_DOPPLER_KNOWN) |
36198686cd2SShayne Chen 			 HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
36298686cd2SShayne Chen 			 HE_BITS(DATA1_BSS_COLOR_KNOWN),
36398686cd2SShayne Chen 		.data2 = HE_BITS(DATA2_GI_KNOWN) |
36498686cd2SShayne Chen 			 HE_BITS(DATA2_TXBF_KNOWN) |
36598686cd2SShayne Chen 			 HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
36698686cd2SShayne Chen 			 HE_BITS(DATA2_TXOP_KNOWN),
36798686cd2SShayne Chen 	};
36898686cd2SShayne Chen 	struct ieee80211_radiotap_he *he = NULL;
369*63a37246SRyder Lee 	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
37098686cd2SShayne Chen 
37198686cd2SShayne Chen 	status->flag |= RX_FLAG_RADIOTAP_HE;
37298686cd2SShayne Chen 
37398686cd2SShayne Chen 	he = skb_push(skb, sizeof(known));
37498686cd2SShayne Chen 	memcpy(he, &known, sizeof(known));
37598686cd2SShayne Chen 
376*63a37246SRyder Lee 	he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[9]) |
377*63a37246SRyder Lee 		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
378*63a37246SRyder Lee 	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
379*63a37246SRyder Lee 	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
38098686cd2SShayne Chen 		    le16_encode_bits(ltf_size,
38198686cd2SShayne Chen 				     IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
38298686cd2SShayne Chen 	if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
38398686cd2SShayne Chen 		he->data5 |= HE_BITS(DATA5_TXBF);
384*63a37246SRyder Lee 	he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[9]) |
385*63a37246SRyder Lee 		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
38698686cd2SShayne Chen 
38798686cd2SShayne Chen 	switch (mode) {
38898686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
38998686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
39098686cd2SShayne Chen 			     HE_BITS(DATA1_UL_DL_KNOWN) |
39198686cd2SShayne Chen 			     HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
39298686cd2SShayne Chen 			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
39398686cd2SShayne Chen 
394*63a37246SRyder Lee 		he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[8]) |
395*63a37246SRyder Lee 			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
39698686cd2SShayne Chen 		break;
39798686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
39898686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
39998686cd2SShayne Chen 			     HE_BITS(DATA1_UL_DL_KNOWN) |
40098686cd2SShayne Chen 			     HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
40198686cd2SShayne Chen 
402*63a37246SRyder Lee 		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
40398686cd2SShayne Chen 		break;
40498686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
40598686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
40698686cd2SShayne Chen 			     HE_BITS(DATA1_UL_DL_KNOWN);
40798686cd2SShayne Chen 
408*63a37246SRyder Lee 		he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
409*63a37246SRyder Lee 		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
41098686cd2SShayne Chen 
41198686cd2SShayne Chen 		mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
41298686cd2SShayne Chen 		mt7996_mac_decode_he_mu_radiotap(skb, rxv);
41398686cd2SShayne Chen 		break;
41498686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
41598686cd2SShayne Chen 		he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
41698686cd2SShayne Chen 			     HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
41798686cd2SShayne Chen 			     HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
41898686cd2SShayne Chen 			     HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
41998686cd2SShayne Chen 
420*63a37246SRyder Lee 		he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[13]) |
421*63a37246SRyder Lee 			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
422*63a37246SRyder Lee 			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
423*63a37246SRyder Lee 			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
42498686cd2SShayne Chen 
42598686cd2SShayne Chen 		mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
42698686cd2SShayne Chen 		break;
42798686cd2SShayne Chen 	default:
42898686cd2SShayne Chen 		break;
42998686cd2SShayne Chen 	}
43098686cd2SShayne Chen }
43198686cd2SShayne Chen 
43298686cd2SShayne Chen /* The HW does not translate the mac header to 802.3 for mesh point */
43398686cd2SShayne Chen static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
43498686cd2SShayne Chen {
43598686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
43698686cd2SShayne Chen 	struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
43798686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid;
43898686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
43998686cd2SShayne Chen 	struct ieee80211_sta *sta;
44098686cd2SShayne Chen 	struct ieee80211_vif *vif;
44198686cd2SShayne Chen 	struct ieee80211_hdr hdr;
44298686cd2SShayne Chen 	u16 frame_control;
44398686cd2SShayne Chen 
44498686cd2SShayne Chen 	if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
44598686cd2SShayne Chen 	    MT_RXD3_NORMAL_U2M)
44698686cd2SShayne Chen 		return -EINVAL;
44798686cd2SShayne Chen 
44898686cd2SShayne Chen 	if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
44998686cd2SShayne Chen 		return -EINVAL;
45098686cd2SShayne Chen 
45198686cd2SShayne Chen 	if (!msta || !msta->vif)
45298686cd2SShayne Chen 		return -EINVAL;
45398686cd2SShayne Chen 
45498686cd2SShayne Chen 	sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
45598686cd2SShayne Chen 	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
45698686cd2SShayne Chen 
45798686cd2SShayne Chen 	/* store the info from RXD and ethhdr to avoid being overridden */
45898686cd2SShayne Chen 	frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);
45998686cd2SShayne Chen 	hdr.frame_control = cpu_to_le16(frame_control);
46098686cd2SShayne Chen 	hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL));
46198686cd2SShayne Chen 	hdr.duration_id = 0;
46298686cd2SShayne Chen 
46398686cd2SShayne Chen 	ether_addr_copy(hdr.addr1, vif->addr);
46498686cd2SShayne Chen 	ether_addr_copy(hdr.addr2, sta->addr);
46598686cd2SShayne Chen 	switch (frame_control & (IEEE80211_FCTL_TODS |
46698686cd2SShayne Chen 				 IEEE80211_FCTL_FROMDS)) {
46798686cd2SShayne Chen 	case 0:
46898686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
46998686cd2SShayne Chen 		break;
47098686cd2SShayne Chen 	case IEEE80211_FCTL_FROMDS:
47198686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_source);
47298686cd2SShayne Chen 		break;
47398686cd2SShayne Chen 	case IEEE80211_FCTL_TODS:
47498686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
47598686cd2SShayne Chen 		break;
47698686cd2SShayne Chen 	case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
47798686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
47898686cd2SShayne Chen 		ether_addr_copy(hdr.addr4, eth_hdr->h_source);
47998686cd2SShayne Chen 		break;
48098686cd2SShayne Chen 	default:
481aed8d9b5SLorenzo Bianconi 		return -EINVAL;
48298686cd2SShayne Chen 	}
48398686cd2SShayne Chen 
48498686cd2SShayne Chen 	skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
48598686cd2SShayne Chen 	if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
48698686cd2SShayne Chen 	    eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
48798686cd2SShayne Chen 		ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
48898686cd2SShayne Chen 	else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
48998686cd2SShayne Chen 		ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
49098686cd2SShayne Chen 	else
49198686cd2SShayne Chen 		skb_pull(skb, 2);
49298686cd2SShayne Chen 
49398686cd2SShayne Chen 	if (ieee80211_has_order(hdr.frame_control))
49498686cd2SShayne Chen 		memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11],
49598686cd2SShayne Chen 		       IEEE80211_HT_CTL_LEN);
49698686cd2SShayne Chen 	if (ieee80211_is_data_qos(hdr.frame_control)) {
49798686cd2SShayne Chen 		__le16 qos_ctrl;
49898686cd2SShayne Chen 
49998686cd2SShayne Chen 		qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL));
50098686cd2SShayne Chen 		memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
50198686cd2SShayne Chen 		       IEEE80211_QOS_CTL_LEN);
50298686cd2SShayne Chen 	}
50398686cd2SShayne Chen 
50498686cd2SShayne Chen 	if (ieee80211_has_a4(hdr.frame_control))
50598686cd2SShayne Chen 		memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
50698686cd2SShayne Chen 	else
50798686cd2SShayne Chen 		memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
50898686cd2SShayne Chen 
50998686cd2SShayne Chen 	return 0;
51098686cd2SShayne Chen }
51198686cd2SShayne Chen 
51298686cd2SShayne Chen static int
51398686cd2SShayne Chen mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
51498686cd2SShayne Chen 			struct mt76_rx_status *status,
51598686cd2SShayne Chen 			struct ieee80211_supported_band *sband,
51698686cd2SShayne Chen 			__le32 *rxv, u8 *mode)
51798686cd2SShayne Chen {
51898686cd2SShayne Chen 	u32 v0, v2;
51998686cd2SShayne Chen 	u8 stbc, gi, bw, dcm, nss;
52098686cd2SShayne Chen 	int i, idx;
52198686cd2SShayne Chen 	bool cck = false;
52298686cd2SShayne Chen 
52398686cd2SShayne Chen 	v0 = le32_to_cpu(rxv[0]);
52498686cd2SShayne Chen 	v2 = le32_to_cpu(rxv[2]);
52598686cd2SShayne Chen 
52698686cd2SShayne Chen 	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
52798686cd2SShayne Chen 	i = idx;
52898686cd2SShayne Chen 	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
52998686cd2SShayne Chen 
53098686cd2SShayne Chen 	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
53198686cd2SShayne Chen 	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
53298686cd2SShayne Chen 	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
53398686cd2SShayne Chen 	dcm = FIELD_GET(MT_PRXV_DCM, v2);
53498686cd2SShayne Chen 	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
53598686cd2SShayne Chen 
53698686cd2SShayne Chen 	switch (*mode) {
53798686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
53898686cd2SShayne Chen 		cck = true;
53998686cd2SShayne Chen 		fallthrough;
54098686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
54198686cd2SShayne Chen 		i = mt76_get_rate(&dev->mt76, sband, i, cck);
54298686cd2SShayne Chen 		break;
54398686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
54498686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
54598686cd2SShayne Chen 		status->encoding = RX_ENC_HT;
54698686cd2SShayne Chen 		if (gi)
54798686cd2SShayne Chen 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
54898686cd2SShayne Chen 		if (i > 31)
54998686cd2SShayne Chen 			return -EINVAL;
55098686cd2SShayne Chen 		break;
55198686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
55298686cd2SShayne Chen 		status->nss = nss;
55398686cd2SShayne Chen 		status->encoding = RX_ENC_VHT;
55498686cd2SShayne Chen 		if (gi)
55598686cd2SShayne Chen 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
55698686cd2SShayne Chen 		if (i > 11)
55798686cd2SShayne Chen 			return -EINVAL;
55898686cd2SShayne Chen 		break;
55998686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
56098686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
56198686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
56298686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
56398686cd2SShayne Chen 		status->nss = nss;
56498686cd2SShayne Chen 		status->encoding = RX_ENC_HE;
56598686cd2SShayne Chen 		i &= GENMASK(3, 0);
56698686cd2SShayne Chen 
56798686cd2SShayne Chen 		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
56898686cd2SShayne Chen 			status->he_gi = gi;
56998686cd2SShayne Chen 
57098686cd2SShayne Chen 		status->he_dcm = dcm;
57198686cd2SShayne Chen 		break;
57280f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
57380f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
57480f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
57580f5a31dSShayne Chen 		/* TODO: currently report rx rate with HE rate */
57680f5a31dSShayne Chen 		status->nss = nss;
57780f5a31dSShayne Chen 		status->encoding = RX_ENC_HE;
57880f5a31dSShayne Chen 		bw = min_t(int, bw, IEEE80211_STA_RX_BW_160);
57980f5a31dSShayne Chen 		i = min_t(int, i & 0xf, 11);
58080f5a31dSShayne Chen 		break;
58198686cd2SShayne Chen 	default:
58298686cd2SShayne Chen 		return -EINVAL;
58398686cd2SShayne Chen 	}
58498686cd2SShayne Chen 	status->rate_idx = i;
58598686cd2SShayne Chen 
58698686cd2SShayne Chen 	switch (bw) {
58798686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_20:
58898686cd2SShayne Chen 		break;
58998686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
59098686cd2SShayne Chen 		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
59198686cd2SShayne Chen 		    (idx & MT_PRXV_TX_ER_SU_106T)) {
59298686cd2SShayne Chen 			status->bw = RATE_INFO_BW_HE_RU;
59398686cd2SShayne Chen 			status->he_ru =
59498686cd2SShayne Chen 				NL80211_RATE_INFO_HE_RU_ALLOC_106;
59598686cd2SShayne Chen 		} else {
59698686cd2SShayne Chen 			status->bw = RATE_INFO_BW_40;
59798686cd2SShayne Chen 		}
59898686cd2SShayne Chen 		break;
59998686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
60098686cd2SShayne Chen 		status->bw = RATE_INFO_BW_80;
60198686cd2SShayne Chen 		break;
60298686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
60398686cd2SShayne Chen 		status->bw = RATE_INFO_BW_160;
60498686cd2SShayne Chen 		break;
60580f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
60680f5a31dSShayne Chen 		status->bw = RATE_INFO_BW_320;
60780f5a31dSShayne Chen 		break;
60898686cd2SShayne Chen 	default:
60998686cd2SShayne Chen 		return -EINVAL;
61098686cd2SShayne Chen 	}
61198686cd2SShayne Chen 
61298686cd2SShayne Chen 	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
61398686cd2SShayne Chen 	if (*mode < MT_PHY_TYPE_HE_SU && gi)
61498686cd2SShayne Chen 		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
61598686cd2SShayne Chen 
61698686cd2SShayne Chen 	return 0;
61798686cd2SShayne Chen }
61898686cd2SShayne Chen 
61998686cd2SShayne Chen static int
62098686cd2SShayne Chen mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
62198686cd2SShayne Chen {
62298686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
62398686cd2SShayne Chen 	struct mt76_phy *mphy = &dev->mt76.phy;
62498686cd2SShayne Chen 	struct mt7996_phy *phy = &dev->phy;
62598686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
62698686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
62798686cd2SShayne Chen 	__le32 *rxv = NULL;
62898686cd2SShayne Chen 	u32 rxd0 = le32_to_cpu(rxd[0]);
62998686cd2SShayne Chen 	u32 rxd1 = le32_to_cpu(rxd[1]);
63098686cd2SShayne Chen 	u32 rxd2 = le32_to_cpu(rxd[2]);
63198686cd2SShayne Chen 	u32 rxd3 = le32_to_cpu(rxd[3]);
63298686cd2SShayne Chen 	u32 rxd4 = le32_to_cpu(rxd[4]);
63398686cd2SShayne Chen 	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
63498686cd2SShayne Chen 	u32 csum_status = *(u32 *)skb->cb;
63598686cd2SShayne Chen 	bool unicast, insert_ccmp_hdr = false;
63698686cd2SShayne Chen 	u8 remove_pad, amsdu_info, band_idx;
63798686cd2SShayne Chen 	u8 mode = 0, qos_ctl = 0;
63898686cd2SShayne Chen 	bool hdr_trans;
63998686cd2SShayne Chen 	u16 hdr_gap;
64098686cd2SShayne Chen 	u16 seq_ctrl = 0;
64198686cd2SShayne Chen 	__le16 fc = 0;
64298686cd2SShayne Chen 	int idx;
64398686cd2SShayne Chen 
64498686cd2SShayne Chen 	memset(status, 0, sizeof(*status));
64598686cd2SShayne Chen 
64698686cd2SShayne Chen 	band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
64798686cd2SShayne Chen 	mphy = dev->mt76.phys[band_idx];
64898686cd2SShayne Chen 	phy = mphy->priv;
64998686cd2SShayne Chen 	status->phy_idx = mphy->band_idx;
65098686cd2SShayne Chen 
65198686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
65298686cd2SShayne Chen 		return -EINVAL;
65398686cd2SShayne Chen 
65498686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
65598686cd2SShayne Chen 		return -EINVAL;
65698686cd2SShayne Chen 
65798686cd2SShayne Chen 	hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
65898686cd2SShayne Chen 	if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
65998686cd2SShayne Chen 		return -EINVAL;
66098686cd2SShayne Chen 
66198686cd2SShayne Chen 	/* ICV error or CCMP/BIP/WPI MIC error */
66298686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
66398686cd2SShayne Chen 		status->flag |= RX_FLAG_ONLY_MONITOR;
66498686cd2SShayne Chen 
66598686cd2SShayne Chen 	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
66698686cd2SShayne Chen 	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
66798686cd2SShayne Chen 	status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
66898686cd2SShayne Chen 
66998686cd2SShayne Chen 	if (status->wcid) {
67098686cd2SShayne Chen 		struct mt7996_sta *msta;
67198686cd2SShayne Chen 
67298686cd2SShayne Chen 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
67398686cd2SShayne Chen 		spin_lock_bh(&dev->sta_poll_lock);
67498686cd2SShayne Chen 		if (list_empty(&msta->poll_list))
67598686cd2SShayne Chen 			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
67698686cd2SShayne Chen 		spin_unlock_bh(&dev->sta_poll_lock);
67798686cd2SShayne Chen 	}
67898686cd2SShayne Chen 
67998686cd2SShayne Chen 	status->freq = mphy->chandef.chan->center_freq;
68098686cd2SShayne Chen 	status->band = mphy->chandef.chan->band;
68198686cd2SShayne Chen 	if (status->band == NL80211_BAND_5GHZ)
68298686cd2SShayne Chen 		sband = &mphy->sband_5g.sband;
68398686cd2SShayne Chen 	else if (status->band == NL80211_BAND_6GHZ)
68498686cd2SShayne Chen 		sband = &mphy->sband_6g.sband;
68598686cd2SShayne Chen 	else
68698686cd2SShayne Chen 		sband = &mphy->sband_2g.sband;
68798686cd2SShayne Chen 
68898686cd2SShayne Chen 	if (!sband->channels)
68998686cd2SShayne Chen 		return -EINVAL;
69098686cd2SShayne Chen 
69198686cd2SShayne Chen 	if ((rxd0 & csum_mask) == csum_mask &&
69298686cd2SShayne Chen 	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
69398686cd2SShayne Chen 		skb->ip_summed = CHECKSUM_UNNECESSARY;
69498686cd2SShayne Chen 
69598686cd2SShayne Chen 	if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
69698686cd2SShayne Chen 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
69798686cd2SShayne Chen 
69898686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
69998686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_ERROR;
70098686cd2SShayne Chen 
70198686cd2SShayne Chen 	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
70298686cd2SShayne Chen 	    !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
70398686cd2SShayne Chen 		status->flag |= RX_FLAG_DECRYPTED;
70498686cd2SShayne Chen 		status->flag |= RX_FLAG_IV_STRIPPED;
70598686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
70698686cd2SShayne Chen 	}
70798686cd2SShayne Chen 
70898686cd2SShayne Chen 	remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
70998686cd2SShayne Chen 
71098686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
71198686cd2SShayne Chen 		return -EINVAL;
71298686cd2SShayne Chen 
71398686cd2SShayne Chen 	rxd += 8;
71498686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
71598686cd2SShayne Chen 		u32 v0 = le32_to_cpu(rxd[0]);
71698686cd2SShayne Chen 		u32 v2 = le32_to_cpu(rxd[2]);
71798686cd2SShayne Chen 
71898686cd2SShayne Chen 		fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));
71998686cd2SShayne Chen 		qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);
72098686cd2SShayne Chen 		seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);
72198686cd2SShayne Chen 
72298686cd2SShayne Chen 		rxd += 4;
72398686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
72498686cd2SShayne Chen 			return -EINVAL;
72598686cd2SShayne Chen 	}
72698686cd2SShayne Chen 
72798686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
72898686cd2SShayne Chen 		u8 *data = (u8 *)rxd;
72998686cd2SShayne Chen 
73098686cd2SShayne Chen 		if (status->flag & RX_FLAG_DECRYPTED) {
73198686cd2SShayne Chen 			switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
73298686cd2SShayne Chen 			case MT_CIPHER_AES_CCMP:
73398686cd2SShayne Chen 			case MT_CIPHER_CCMP_CCX:
73498686cd2SShayne Chen 			case MT_CIPHER_CCMP_256:
73598686cd2SShayne Chen 				insert_ccmp_hdr =
73698686cd2SShayne Chen 					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
73798686cd2SShayne Chen 				fallthrough;
73898686cd2SShayne Chen 			case MT_CIPHER_TKIP:
73998686cd2SShayne Chen 			case MT_CIPHER_TKIP_NO_MIC:
74098686cd2SShayne Chen 			case MT_CIPHER_GCMP:
74198686cd2SShayne Chen 			case MT_CIPHER_GCMP_256:
74298686cd2SShayne Chen 				status->iv[0] = data[5];
74398686cd2SShayne Chen 				status->iv[1] = data[4];
74498686cd2SShayne Chen 				status->iv[2] = data[3];
74598686cd2SShayne Chen 				status->iv[3] = data[2];
74698686cd2SShayne Chen 				status->iv[4] = data[1];
74798686cd2SShayne Chen 				status->iv[5] = data[0];
74898686cd2SShayne Chen 				break;
74998686cd2SShayne Chen 			default:
75098686cd2SShayne Chen 				break;
75198686cd2SShayne Chen 			}
75298686cd2SShayne Chen 		}
75398686cd2SShayne Chen 		rxd += 4;
75498686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
75598686cd2SShayne Chen 			return -EINVAL;
75698686cd2SShayne Chen 	}
75798686cd2SShayne Chen 
75898686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
75998686cd2SShayne Chen 		status->timestamp = le32_to_cpu(rxd[0]);
76098686cd2SShayne Chen 		status->flag |= RX_FLAG_MACTIME_START;
76198686cd2SShayne Chen 
76298686cd2SShayne Chen 		if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
76398686cd2SShayne Chen 			status->flag |= RX_FLAG_AMPDU_DETAILS;
76498686cd2SShayne Chen 
76598686cd2SShayne Chen 			/* all subframes of an A-MPDU have the same timestamp */
76698686cd2SShayne Chen 			if (phy->rx_ampdu_ts != status->timestamp) {
76798686cd2SShayne Chen 				if (!++phy->ampdu_ref)
76898686cd2SShayne Chen 					phy->ampdu_ref++;
76998686cd2SShayne Chen 			}
77098686cd2SShayne Chen 			phy->rx_ampdu_ts = status->timestamp;
77198686cd2SShayne Chen 
77298686cd2SShayne Chen 			status->ampdu_ref = phy->ampdu_ref;
77398686cd2SShayne Chen 		}
77498686cd2SShayne Chen 
77598686cd2SShayne Chen 		rxd += 4;
77698686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
77798686cd2SShayne Chen 			return -EINVAL;
77898686cd2SShayne Chen 	}
77998686cd2SShayne Chen 
78098686cd2SShayne Chen 	/* RXD Group 3 - P-RXV */
78198686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
78298686cd2SShayne Chen 		u32 v3;
78398686cd2SShayne Chen 		int ret;
78498686cd2SShayne Chen 
78598686cd2SShayne Chen 		rxv = rxd;
78698686cd2SShayne Chen 		rxd += 4;
78798686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
78898686cd2SShayne Chen 			return -EINVAL;
78998686cd2SShayne Chen 
79098686cd2SShayne Chen 		v3 = le32_to_cpu(rxv[3]);
79198686cd2SShayne Chen 
79298686cd2SShayne Chen 		status->chains = mphy->antenna_mask;
79398686cd2SShayne Chen 		status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);
79498686cd2SShayne Chen 		status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);
79598686cd2SShayne Chen 		status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);
79698686cd2SShayne Chen 		status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);
79798686cd2SShayne Chen 
79898686cd2SShayne Chen 		/* RXD Group 5 - C-RXV */
79998686cd2SShayne Chen 		if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
80098686cd2SShayne Chen 			rxd += 24;
80198686cd2SShayne Chen 			if ((u8 *)rxd - skb->data >= skb->len)
80298686cd2SShayne Chen 				return -EINVAL;
80398686cd2SShayne Chen 		}
80498686cd2SShayne Chen 
80598686cd2SShayne Chen 		ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode);
80698686cd2SShayne Chen 		if (ret < 0)
80798686cd2SShayne Chen 			return ret;
80898686cd2SShayne Chen 	}
80998686cd2SShayne Chen 
81098686cd2SShayne Chen 	amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
81198686cd2SShayne Chen 	status->amsdu = !!amsdu_info;
81298686cd2SShayne Chen 	if (status->amsdu) {
81398686cd2SShayne Chen 		status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
81498686cd2SShayne Chen 		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
81598686cd2SShayne Chen 	}
81698686cd2SShayne Chen 
81798686cd2SShayne Chen 	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
81898686cd2SShayne Chen 	if (hdr_trans && ieee80211_has_morefrags(fc)) {
81998686cd2SShayne Chen 		if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
82098686cd2SShayne Chen 			return -EINVAL;
82198686cd2SShayne Chen 		hdr_trans = false;
82298686cd2SShayne Chen 	} else {
82398686cd2SShayne Chen 		int pad_start = 0;
82498686cd2SShayne Chen 
82598686cd2SShayne Chen 		skb_pull(skb, hdr_gap);
82698686cd2SShayne Chen 		if (!hdr_trans && status->amsdu) {
82798686cd2SShayne Chen 			pad_start = ieee80211_get_hdrlen_from_skb(skb);
82898686cd2SShayne Chen 		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
82998686cd2SShayne Chen 			/* When header translation failure is indicated,
83098686cd2SShayne Chen 			 * the hardware will insert an extra 2-byte field
83198686cd2SShayne Chen 			 * containing the data length after the protocol
83298686cd2SShayne Chen 			 * type field.
83398686cd2SShayne Chen 			 */
83498686cd2SShayne Chen 			pad_start = 12;
83598686cd2SShayne Chen 			if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
83698686cd2SShayne Chen 				pad_start += 4;
83798686cd2SShayne Chen 			else
83898686cd2SShayne Chen 				pad_start = 0;
83998686cd2SShayne Chen 		}
84098686cd2SShayne Chen 
84198686cd2SShayne Chen 		if (pad_start) {
84298686cd2SShayne Chen 			memmove(skb->data + 2, skb->data, pad_start);
84398686cd2SShayne Chen 			skb_pull(skb, 2);
84498686cd2SShayne Chen 		}
84598686cd2SShayne Chen 	}
84698686cd2SShayne Chen 
84798686cd2SShayne Chen 	if (!hdr_trans) {
84898686cd2SShayne Chen 		struct ieee80211_hdr *hdr;
84998686cd2SShayne Chen 
85098686cd2SShayne Chen 		if (insert_ccmp_hdr) {
85198686cd2SShayne Chen 			u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
85298686cd2SShayne Chen 
85398686cd2SShayne Chen 			mt76_insert_ccmp_hdr(skb, key_id);
85498686cd2SShayne Chen 		}
85598686cd2SShayne Chen 
85698686cd2SShayne Chen 		hdr = mt76_skb_get_hdr(skb);
85798686cd2SShayne Chen 		fc = hdr->frame_control;
85898686cd2SShayne Chen 		if (ieee80211_is_data_qos(fc)) {
85998686cd2SShayne Chen 			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
86098686cd2SShayne Chen 			qos_ctl = *ieee80211_get_qos_ctl(hdr);
86198686cd2SShayne Chen 		}
86298686cd2SShayne Chen 	} else {
86398686cd2SShayne Chen 		status->flag |= RX_FLAG_8023;
86498686cd2SShayne Chen 	}
86598686cd2SShayne Chen 
86698686cd2SShayne Chen 	if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
86798686cd2SShayne Chen 		mt7996_mac_decode_he_radiotap(skb, rxv, mode);
86898686cd2SShayne Chen 
86998686cd2SShayne Chen 	if (!status->wcid || !ieee80211_is_data_qos(fc))
87098686cd2SShayne Chen 		return 0;
87198686cd2SShayne Chen 
87298686cd2SShayne Chen 	status->aggr = unicast &&
87398686cd2SShayne Chen 		       !ieee80211_is_qos_nullfunc(fc);
87498686cd2SShayne Chen 	status->qos_ctl = qos_ctl;
87598686cd2SShayne Chen 	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
87698686cd2SShayne Chen 
87798686cd2SShayne Chen 	return 0;
87898686cd2SShayne Chen }
87998686cd2SShayne Chen 
88098686cd2SShayne Chen static void
88198686cd2SShayne Chen mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
88298686cd2SShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid)
88398686cd2SShayne Chen {
88498686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
88598686cd2SShayne Chen 	u8 fc_type, fc_stype;
88698686cd2SShayne Chen 	u16 ethertype;
88798686cd2SShayne Chen 	bool wmm = false;
88898686cd2SShayne Chen 	u32 val;
88998686cd2SShayne Chen 
89098686cd2SShayne Chen 	if (wcid->sta) {
89198686cd2SShayne Chen 		struct ieee80211_sta *sta;
89298686cd2SShayne Chen 
89398686cd2SShayne Chen 		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
89498686cd2SShayne Chen 		wmm = sta->wme;
89598686cd2SShayne Chen 	}
89698686cd2SShayne Chen 
89798686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
89898686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
89998686cd2SShayne Chen 
90098686cd2SShayne Chen 	ethertype = get_unaligned_be16(&skb->data[12]);
90198686cd2SShayne Chen 	if (ethertype >= ETH_P_802_3_MIN)
90298686cd2SShayne Chen 		val |= MT_TXD1_ETH_802_3;
90398686cd2SShayne Chen 
90498686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
90598686cd2SShayne Chen 
90698686cd2SShayne Chen 	fc_type = IEEE80211_FTYPE_DATA >> 2;
90798686cd2SShayne Chen 	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
90898686cd2SShayne Chen 
90998686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
91098686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
91198686cd2SShayne Chen 
91298686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
91398686cd2SShayne Chen }
91498686cd2SShayne Chen 
91598686cd2SShayne Chen static void
91698686cd2SShayne Chen mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
91798686cd2SShayne Chen 			    struct sk_buff *skb, struct ieee80211_key_conf *key)
91898686cd2SShayne Chen {
91998686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
92098686cd2SShayne Chen 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
92198686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
92298686cd2SShayne Chen 	bool multicast = is_multicast_ether_addr(hdr->addr1);
92398686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
92498686cd2SShayne Chen 	__le16 fc = hdr->frame_control;
92598686cd2SShayne Chen 	u8 fc_type, fc_stype;
92698686cd2SShayne Chen 	u32 val;
92798686cd2SShayne Chen 
92898686cd2SShayne Chen 	if (ieee80211_is_action(fc) &&
92998686cd2SShayne Chen 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
93098686cd2SShayne Chen 	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
93198686cd2SShayne Chen 		tid = MT_TX_ADDBA;
93298686cd2SShayne Chen 	else if (ieee80211_is_mgmt(hdr->frame_control))
93398686cd2SShayne Chen 		tid = MT_TX_NORMAL;
93498686cd2SShayne Chen 
93598686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
93698686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_HDR_INFO,
93798686cd2SShayne Chen 			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
93898686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
93998686cd2SShayne Chen 
94098686cd2SShayne Chen 	if (!ieee80211_is_data(fc) || multicast ||
94198686cd2SShayne Chen 	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
94298686cd2SShayne Chen 		val |= MT_TXD1_FIXED_RATE;
94398686cd2SShayne Chen 
94498686cd2SShayne Chen 	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
94598686cd2SShayne Chen 	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
94698686cd2SShayne Chen 		val |= MT_TXD1_BIP;
94798686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
94898686cd2SShayne Chen 	}
94998686cd2SShayne Chen 
95098686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
95198686cd2SShayne Chen 
95298686cd2SShayne Chen 	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
95398686cd2SShayne Chen 	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
95498686cd2SShayne Chen 
95598686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
95698686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
95798686cd2SShayne Chen 
95898686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
95998686cd2SShayne Chen 
96098686cd2SShayne Chen 	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
96198686cd2SShayne Chen 	if (ieee80211_is_beacon(fc)) {
96298686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
96398686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
96498686cd2SShayne Chen 	}
96598686cd2SShayne Chen 
96698686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
96798686cd2SShayne Chen 		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
96898686cd2SShayne Chen 
96998686cd2SShayne Chen 		if (ieee80211_is_back_req(hdr->frame_control)) {
97098686cd2SShayne Chen 			struct ieee80211_bar *bar;
97198686cd2SShayne Chen 
97298686cd2SShayne Chen 			bar = (struct ieee80211_bar *)skb->data;
97398686cd2SShayne Chen 			seqno = le16_to_cpu(bar->start_seq_num);
97498686cd2SShayne Chen 		}
97598686cd2SShayne Chen 
97698686cd2SShayne Chen 		val = MT_TXD3_SN_VALID |
97798686cd2SShayne Chen 		      FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
97898686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(val);
97998686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
98098686cd2SShayne Chen 	}
98198686cd2SShayne Chen }
98298686cd2SShayne Chen 
98398686cd2SShayne Chen void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
98498686cd2SShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
98598686cd2SShayne Chen 			   struct ieee80211_key_conf *key, u32 changed)
98698686cd2SShayne Chen {
98798686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
98898686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
98998686cd2SShayne Chen 	struct mt76_phy *mphy = &dev->mphy;
99098686cd2SShayne Chen 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
99198686cd2SShayne Chen 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
99298686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
99398686cd2SShayne Chen 	u16 tx_count = 15;
99498686cd2SShayne Chen 	u32 val;
99598686cd2SShayne Chen 	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
99698686cd2SShayne Chen 				    BSS_CHANGED_BEACON_ENABLED));
99798686cd2SShayne Chen 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
99898686cd2SShayne Chen 					 BSS_CHANGED_FILS_DISCOVERY));
99998686cd2SShayne Chen 
100098686cd2SShayne Chen 	if (vif) {
100198686cd2SShayne Chen 		struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
100298686cd2SShayne Chen 
100398686cd2SShayne Chen 		omac_idx = mvif->mt76.omac_idx;
100498686cd2SShayne Chen 		wmm_idx = mvif->mt76.wmm_idx;
100598686cd2SShayne Chen 		band_idx = mvif->mt76.band_idx;
100698686cd2SShayne Chen 	}
100798686cd2SShayne Chen 
100898686cd2SShayne Chen 	mphy = mt76_dev_phy(&dev->mt76, band_idx);
100998686cd2SShayne Chen 
101098686cd2SShayne Chen 	if (inband_disc) {
101198686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
101298686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
101398686cd2SShayne Chen 	} else if (beacon) {
101498686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
101598686cd2SShayne Chen 		q_idx = MT_LMAC_BCN0;
101698686cd2SShayne Chen 	} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
101798686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
101898686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
101998686cd2SShayne Chen 	} else {
102098686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
102198686cd2SShayne Chen 		q_idx = wmm_idx * MT7996_MAX_WMM_SETS +
102298686cd2SShayne Chen 			mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
102398686cd2SShayne Chen 	}
102498686cd2SShayne Chen 
102598686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
102698686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
102798686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
102898686cd2SShayne Chen 	txwi[0] = cpu_to_le32(val);
102998686cd2SShayne Chen 
103098686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
103198686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
103298686cd2SShayne Chen 
103398686cd2SShayne Chen 	if (band_idx)
103498686cd2SShayne Chen 		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
103598686cd2SShayne Chen 
103698686cd2SShayne Chen 	txwi[1] = cpu_to_le32(val);
103798686cd2SShayne Chen 	txwi[2] = 0;
103898686cd2SShayne Chen 
103998686cd2SShayne Chen 	val = MT_TXD3_SW_POWER_MGMT |
104098686cd2SShayne Chen 	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
104198686cd2SShayne Chen 	if (key)
104298686cd2SShayne Chen 		val |= MT_TXD3_PROTECT_FRAME;
104398686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
104498686cd2SShayne Chen 		val |= MT_TXD3_NO_ACK;
104598686cd2SShayne Chen 	if (wcid->amsdu)
104698686cd2SShayne Chen 		val |= MT_TXD3_HW_AMSDU;
104798686cd2SShayne Chen 
104898686cd2SShayne Chen 	txwi[3] = cpu_to_le32(val);
104998686cd2SShayne Chen 	txwi[4] = 0;
105098686cd2SShayne Chen 
105198686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD5_PID, pid);
105298686cd2SShayne Chen 	if (pid >= MT_PACKET_ID_FIRST)
105398686cd2SShayne Chen 		val |= MT_TXD5_TX_STATUS_HOST;
105498686cd2SShayne Chen 	txwi[5] = cpu_to_le32(val);
105598686cd2SShayne Chen 
105698686cd2SShayne Chen 	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
105798686cd2SShayne Chen 	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
105898686cd2SShayne Chen 	txwi[6] = cpu_to_le32(val);
105998686cd2SShayne Chen 	txwi[7] = 0;
106098686cd2SShayne Chen 
106198686cd2SShayne Chen 	if (is_8023)
106298686cd2SShayne Chen 		mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);
106398686cd2SShayne Chen 	else
106498686cd2SShayne Chen 		mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
106598686cd2SShayne Chen 
106698686cd2SShayne Chen 	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
106798686cd2SShayne Chen 		/* Fixed rata is available just for 802.11 txd */
106898686cd2SShayne Chen 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
106998686cd2SShayne Chen 		bool multicast = is_multicast_ether_addr(hdr->addr1);
10700b8e2d69SLorenzo Bianconi 		u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
10710b8e2d69SLorenzo Bianconi 							multicast);
107298686cd2SShayne Chen 
107398686cd2SShayne Chen 		/* fix to bw 20 */
107498686cd2SShayne Chen 		val = MT_TXD6_FIXED_BW |
107598686cd2SShayne Chen 		      FIELD_PREP(MT_TXD6_BW, 0) |
107698686cd2SShayne Chen 		      FIELD_PREP(MT_TXD6_TX_RATE, rate);
107798686cd2SShayne Chen 
107898686cd2SShayne Chen 		txwi[6] |= cpu_to_le32(val);
107998686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
108098686cd2SShayne Chen 	}
108198686cd2SShayne Chen }
108298686cd2SShayne Chen 
108398686cd2SShayne Chen int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
108498686cd2SShayne Chen 			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
108598686cd2SShayne Chen 			  struct ieee80211_sta *sta,
108698686cd2SShayne Chen 			  struct mt76_tx_info *tx_info)
108798686cd2SShayne Chen {
108898686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
108998686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
109098686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
109198686cd2SShayne Chen 	struct ieee80211_key_conf *key = info->control.hw_key;
109298686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
10933c38dfc1SLorenzo Bianconi 	struct mt76_connac_txp_common *txp;
109498686cd2SShayne Chen 	struct mt76_txwi_cache *t;
109598686cd2SShayne Chen 	int id, i, pid, nbuf = tx_info->nbuf - 1;
109698686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
109798686cd2SShayne Chen 	u8 *txwi = (u8 *)txwi_ptr;
109898686cd2SShayne Chen 
109998686cd2SShayne Chen 	if (unlikely(tx_info->skb->len <= ETH_HLEN))
110098686cd2SShayne Chen 		return -EINVAL;
110198686cd2SShayne Chen 
110298686cd2SShayne Chen 	if (!wcid)
110398686cd2SShayne Chen 		wcid = &dev->mt76.global_wcid;
110498686cd2SShayne Chen 
110598686cd2SShayne Chen 	if (sta) {
110698686cd2SShayne Chen 		struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
110798686cd2SShayne Chen 
110898686cd2SShayne Chen 		if (time_after(jiffies, msta->jiffies + HZ / 4)) {
110998686cd2SShayne Chen 			info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
111098686cd2SShayne Chen 			msta->jiffies = jiffies;
111198686cd2SShayne Chen 		}
111298686cd2SShayne Chen 	}
111398686cd2SShayne Chen 
111498686cd2SShayne Chen 	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
111598686cd2SShayne Chen 	t->skb = tx_info->skb;
111698686cd2SShayne Chen 
111798686cd2SShayne Chen 	id = mt76_token_consume(mdev, &t);
111898686cd2SShayne Chen 	if (id < 0)
111998686cd2SShayne Chen 		return id;
112098686cd2SShayne Chen 
112198686cd2SShayne Chen 	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
112298686cd2SShayne Chen 	memset(txwi_ptr, 0, MT_TXD_SIZE);
112398686cd2SShayne Chen 	/* Transmit non qos data by 802.11 header and need to fill txd by host*/
112498686cd2SShayne Chen 	if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
112598686cd2SShayne Chen 		mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
112698686cd2SShayne Chen 				      key, 0);
112798686cd2SShayne Chen 
11283c38dfc1SLorenzo Bianconi 	txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
112998686cd2SShayne Chen 	for (i = 0; i < nbuf; i++) {
11303c38dfc1SLorenzo Bianconi 		txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
11313c38dfc1SLorenzo Bianconi 		txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
113298686cd2SShayne Chen 	}
11333c38dfc1SLorenzo Bianconi 	txp->fw.nbuf = nbuf;
113498686cd2SShayne Chen 
11353c38dfc1SLorenzo Bianconi 	txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
113698686cd2SShayne Chen 
113798686cd2SShayne Chen 	if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
11383c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
113998686cd2SShayne Chen 
114098686cd2SShayne Chen 	if (!key)
11413c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
114298686cd2SShayne Chen 
114398686cd2SShayne Chen 	if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
11443c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
114598686cd2SShayne Chen 
114698686cd2SShayne Chen 	if (vif) {
114798686cd2SShayne Chen 		struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
114898686cd2SShayne Chen 
11493c38dfc1SLorenzo Bianconi 		txp->fw.bss_idx = mvif->mt76.idx;
115098686cd2SShayne Chen 	}
115198686cd2SShayne Chen 
11523c38dfc1SLorenzo Bianconi 	txp->fw.token = cpu_to_le16(id);
115398686cd2SShayne Chen 	if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
11543c38dfc1SLorenzo Bianconi 		txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
115598686cd2SShayne Chen 	else
11563c38dfc1SLorenzo Bianconi 		txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
115798686cd2SShayne Chen 	tx_info->skb = DMA_DUMMY_DATA;
115898686cd2SShayne Chen 
115998686cd2SShayne Chen 	/* pass partial skb header to fw */
116098686cd2SShayne Chen 	tx_info->buf[1].len = MT_CT_PARSE_LEN;
116198686cd2SShayne Chen 	tx_info->buf[1].skip_unmap = true;
116298686cd2SShayne Chen 	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
116398686cd2SShayne Chen 
116498686cd2SShayne Chen 	return 0;
116598686cd2SShayne Chen }
116698686cd2SShayne Chen 
116798686cd2SShayne Chen static void
116898686cd2SShayne Chen mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
116998686cd2SShayne Chen {
117098686cd2SShayne Chen 	struct mt7996_sta *msta;
117198686cd2SShayne Chen 	u16 fc, tid;
117298686cd2SShayne Chen 	u32 val;
117398686cd2SShayne Chen 
117498686cd2SShayne Chen 	if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
117598686cd2SShayne Chen 		return;
117698686cd2SShayne Chen 
117798686cd2SShayne Chen 	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
117898686cd2SShayne Chen 	if (tid >= 6) /* skip VO queue */
117998686cd2SShayne Chen 		return;
118098686cd2SShayne Chen 
118198686cd2SShayne Chen 	val = le32_to_cpu(txwi[2]);
118298686cd2SShayne Chen 	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
118398686cd2SShayne Chen 	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
118498686cd2SShayne Chen 	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
118598686cd2SShayne Chen 		return;
118698686cd2SShayne Chen 
118798686cd2SShayne Chen 	msta = (struct mt7996_sta *)sta->drv_priv;
118898686cd2SShayne Chen 	if (!test_and_set_bit(tid, &msta->ampdu_state))
118998686cd2SShayne Chen 		ieee80211_start_tx_ba_session(sta, tid, 0);
119098686cd2SShayne Chen }
119198686cd2SShayne Chen 
119298686cd2SShayne Chen static void
119398686cd2SShayne Chen mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
119498686cd2SShayne Chen 		 struct ieee80211_sta *sta, struct list_head *free_list)
119598686cd2SShayne Chen {
119698686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
119798686cd2SShayne Chen 	struct mt76_wcid *wcid;
119898686cd2SShayne Chen 	__le32 *txwi;
119998686cd2SShayne Chen 	u16 wcid_idx;
120098686cd2SShayne Chen 
120130495864SLorenzo Bianconi 	mt76_connac_txp_skb_unmap(mdev, t);
120298686cd2SShayne Chen 	if (!t->skb)
120398686cd2SShayne Chen 		goto out;
120498686cd2SShayne Chen 
120598686cd2SShayne Chen 	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
120698686cd2SShayne Chen 	if (sta) {
120798686cd2SShayne Chen 		wcid = (struct mt76_wcid *)sta->drv_priv;
120898686cd2SShayne Chen 		wcid_idx = wcid->idx;
120998686cd2SShayne Chen 
121098686cd2SShayne Chen 		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
121198686cd2SShayne Chen 			mt7996_tx_check_aggr(sta, txwi);
121298686cd2SShayne Chen 	} else {
121398686cd2SShayne Chen 		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
121498686cd2SShayne Chen 	}
121598686cd2SShayne Chen 
121698686cd2SShayne Chen 	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
121798686cd2SShayne Chen 
121898686cd2SShayne Chen out:
121998686cd2SShayne Chen 	t->skb = NULL;
122098686cd2SShayne Chen 	mt76_put_txwi(mdev, t);
122198686cd2SShayne Chen }
122298686cd2SShayne Chen 
122398686cd2SShayne Chen static void
122498686cd2SShayne Chen mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
122598686cd2SShayne Chen {
122698686cd2SShayne Chen 	__le32 *tx_free = (__le32 *)data, *cur_info;
122798686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
122898686cd2SShayne Chen 	struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
122998686cd2SShayne Chen 	struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
123098686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
123198686cd2SShayne Chen 	struct ieee80211_sta *sta = NULL;
123298686cd2SShayne Chen 	LIST_HEAD(free_list);
123398686cd2SShayne Chen 	struct sk_buff *skb, *tmp;
123498686cd2SShayne Chen 	void *end = data + len;
123598686cd2SShayne Chen 	bool wake = false;
123698686cd2SShayne Chen 	u16 total, count = 0;
123798686cd2SShayne Chen 
123898686cd2SShayne Chen 	/* clean DMA queues and unmap buffers first */
123998686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
124098686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
124198686cd2SShayne Chen 	if (phy2) {
124298686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false);
124398686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false);
124498686cd2SShayne Chen 	}
124598686cd2SShayne Chen 	if (phy3) {
124698686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false);
124798686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);
124898686cd2SShayne Chen 	}
124998686cd2SShayne Chen 
125098686cd2SShayne Chen 	if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))
125198686cd2SShayne Chen 		return;
125298686cd2SShayne Chen 
125398686cd2SShayne Chen 	total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);
125498686cd2SShayne Chen 	for (cur_info = &tx_free[2]; count < total; cur_info++) {
125598686cd2SShayne Chen 		u32 msdu, info;
125698686cd2SShayne Chen 		u8 i;
125798686cd2SShayne Chen 
125898686cd2SShayne Chen 		if (WARN_ON_ONCE((void *)cur_info >= end))
125998686cd2SShayne Chen 			return;
126098686cd2SShayne Chen 		/* 1'b1: new wcid pair.
126198686cd2SShayne Chen 		 * 1'b0: msdu_id with the same 'wcid pair' as above.
126298686cd2SShayne Chen 		 */
126398686cd2SShayne Chen 		info = le32_to_cpu(*cur_info);
126498686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_PAIR) {
126598686cd2SShayne Chen 			struct mt7996_sta *msta;
126698686cd2SShayne Chen 			struct mt76_wcid *wcid;
126798686cd2SShayne Chen 			u16 idx;
126898686cd2SShayne Chen 
126998686cd2SShayne Chen 			idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
127098686cd2SShayne Chen 			wcid = rcu_dereference(dev->mt76.wcid[idx]);
127198686cd2SShayne Chen 			sta = wcid_to_sta(wcid);
127298686cd2SShayne Chen 			if (!sta)
127398686cd2SShayne Chen 				continue;
127498686cd2SShayne Chen 
127598686cd2SShayne Chen 			msta = container_of(wcid, struct mt7996_sta, wcid);
127698686cd2SShayne Chen 			spin_lock_bh(&dev->sta_poll_lock);
127798686cd2SShayne Chen 			if (list_empty(&msta->poll_list))
127898686cd2SShayne Chen 				list_add_tail(&msta->poll_list, &dev->sta_poll_list);
127998686cd2SShayne Chen 			spin_unlock_bh(&dev->sta_poll_lock);
128098686cd2SShayne Chen 			continue;
128198686cd2SShayne Chen 		}
128298686cd2SShayne Chen 
128398686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_HEADER)
128498686cd2SShayne Chen 			continue;
128598686cd2SShayne Chen 
128698686cd2SShayne Chen 		for (i = 0; i < 2; i++) {
128798686cd2SShayne Chen 			msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;
128898686cd2SShayne Chen 			if (msdu == MT_TXFREE_INFO_MSDU_ID)
128998686cd2SShayne Chen 				continue;
129098686cd2SShayne Chen 
129198686cd2SShayne Chen 			count++;
129298686cd2SShayne Chen 			txwi = mt76_token_release(mdev, msdu, &wake);
129398686cd2SShayne Chen 			if (!txwi)
129498686cd2SShayne Chen 				continue;
129598686cd2SShayne Chen 
129698686cd2SShayne Chen 			mt7996_txwi_free(dev, txwi, sta, &free_list);
129798686cd2SShayne Chen 		}
129898686cd2SShayne Chen 	}
129998686cd2SShayne Chen 
130098686cd2SShayne Chen 	mt7996_mac_sta_poll(dev);
130198686cd2SShayne Chen 
130298686cd2SShayne Chen 	if (wake)
130398686cd2SShayne Chen 		mt76_set_tx_blocked(&dev->mt76, false);
130498686cd2SShayne Chen 
130598686cd2SShayne Chen 	mt76_worker_schedule(&dev->mt76.tx_worker);
130698686cd2SShayne Chen 
130798686cd2SShayne Chen 	list_for_each_entry_safe(skb, tmp, &free_list, list) {
130898686cd2SShayne Chen 		skb_list_del_init(skb);
130998686cd2SShayne Chen 		napi_consume_skb(skb, 1);
131098686cd2SShayne Chen 	}
131198686cd2SShayne Chen }
131298686cd2SShayne Chen 
131398686cd2SShayne Chen static bool
131498686cd2SShayne Chen mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid,
131598686cd2SShayne Chen 		       __le32 *txs_data, struct mt76_sta_stats *stats)
131698686cd2SShayne Chen {
131798686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
131898686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
131998686cd2SShayne Chen 	struct mt76_phy *mphy;
132098686cd2SShayne Chen 	struct ieee80211_tx_info *info;
132198686cd2SShayne Chen 	struct sk_buff_head list;
132298686cd2SShayne Chen 	struct rate_info rate = {};
132398686cd2SShayne Chen 	struct sk_buff *skb;
132498686cd2SShayne Chen 	bool cck = false;
132598686cd2SShayne Chen 	u32 txrate, txs, mode, stbc;
132698686cd2SShayne Chen 
132798686cd2SShayne Chen 	mt76_tx_status_lock(mdev, &list);
132898686cd2SShayne Chen 	skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
132998686cd2SShayne Chen 	if (!skb)
133098686cd2SShayne Chen 		goto out_no_skb;
133198686cd2SShayne Chen 
133298686cd2SShayne Chen 	txs = le32_to_cpu(txs_data[0]);
133398686cd2SShayne Chen 
133498686cd2SShayne Chen 	info = IEEE80211_SKB_CB(skb);
133598686cd2SShayne Chen 	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
133698686cd2SShayne Chen 		info->flags |= IEEE80211_TX_STAT_ACK;
133798686cd2SShayne Chen 
133898686cd2SShayne Chen 	info->status.ampdu_len = 1;
133998686cd2SShayne Chen 	info->status.ampdu_ack_len = !!(info->flags &
134098686cd2SShayne Chen 					IEEE80211_TX_STAT_ACK);
134198686cd2SShayne Chen 
134298686cd2SShayne Chen 	info->status.rates[0].idx = -1;
134398686cd2SShayne Chen 
134498686cd2SShayne Chen 	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
134598686cd2SShayne Chen 
134698686cd2SShayne Chen 	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
134798686cd2SShayne Chen 	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
134898686cd2SShayne Chen 	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
134998686cd2SShayne Chen 
135098686cd2SShayne Chen 	if (stbc && rate.nss > 1)
135198686cd2SShayne Chen 		rate.nss >>= 1;
135298686cd2SShayne Chen 
135398686cd2SShayne Chen 	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
135498686cd2SShayne Chen 		stats->tx_nss[rate.nss - 1]++;
135598686cd2SShayne Chen 	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
135698686cd2SShayne Chen 		stats->tx_mcs[rate.mcs]++;
135798686cd2SShayne Chen 
135898686cd2SShayne Chen 	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
135998686cd2SShayne Chen 	switch (mode) {
136098686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
136198686cd2SShayne Chen 		cck = true;
136298686cd2SShayne Chen 		fallthrough;
136398686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
136498686cd2SShayne Chen 		mphy = mt76_dev_phy(mdev, wcid->phy_idx);
136598686cd2SShayne Chen 
136698686cd2SShayne Chen 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
136798686cd2SShayne Chen 			sband = &mphy->sband_5g.sband;
136898686cd2SShayne Chen 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
136998686cd2SShayne Chen 			sband = &mphy->sband_6g.sband;
137098686cd2SShayne Chen 		else
137198686cd2SShayne Chen 			sband = &mphy->sband_2g.sband;
137298686cd2SShayne Chen 
137398686cd2SShayne Chen 		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
137498686cd2SShayne Chen 		rate.legacy = sband->bitrates[rate.mcs].bitrate;
137598686cd2SShayne Chen 		break;
137698686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
137798686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
137898686cd2SShayne Chen 		if (rate.mcs > 31)
137998686cd2SShayne Chen 			goto out;
138098686cd2SShayne Chen 
138198686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_MCS;
138298686cd2SShayne Chen 		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
138398686cd2SShayne Chen 			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
138498686cd2SShayne Chen 		break;
138598686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
138698686cd2SShayne Chen 		if (rate.mcs > 9)
138798686cd2SShayne Chen 			goto out;
138898686cd2SShayne Chen 
138998686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
139098686cd2SShayne Chen 		break;
139198686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
139298686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
139398686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
139498686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
139598686cd2SShayne Chen 		if (rate.mcs > 11)
139698686cd2SShayne Chen 			goto out;
139798686cd2SShayne Chen 
139898686cd2SShayne Chen 		rate.he_gi = wcid->rate.he_gi;
139998686cd2SShayne Chen 		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
140098686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_HE_MCS;
140198686cd2SShayne Chen 		break;
140280f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
140380f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
140480f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
140580f5a31dSShayne Chen 		if (rate.mcs > 13)
140680f5a31dSShayne Chen 			goto out;
140780f5a31dSShayne Chen 
140880f5a31dSShayne Chen 		rate.eht_gi = wcid->rate.eht_gi;
140980f5a31dSShayne Chen 		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
141080f5a31dSShayne Chen 		break;
141198686cd2SShayne Chen 	default:
141298686cd2SShayne Chen 		goto out;
141398686cd2SShayne Chen 	}
141498686cd2SShayne Chen 
141598686cd2SShayne Chen 	stats->tx_mode[mode]++;
141698686cd2SShayne Chen 
141798686cd2SShayne Chen 	switch (FIELD_GET(MT_TXS0_BW, txs)) {
141880f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
141980f5a31dSShayne Chen 		rate.bw = RATE_INFO_BW_320;
142080f5a31dSShayne Chen 		stats->tx_bw[4]++;
142180f5a31dSShayne Chen 		break;
142298686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
142398686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_160;
142498686cd2SShayne Chen 		stats->tx_bw[3]++;
142598686cd2SShayne Chen 		break;
142698686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
142798686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_80;
142898686cd2SShayne Chen 		stats->tx_bw[2]++;
142998686cd2SShayne Chen 		break;
143098686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
143198686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_40;
143298686cd2SShayne Chen 		stats->tx_bw[1]++;
143398686cd2SShayne Chen 		break;
143498686cd2SShayne Chen 	default:
143598686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_20;
143698686cd2SShayne Chen 		stats->tx_bw[0]++;
143798686cd2SShayne Chen 		break;
143898686cd2SShayne Chen 	}
143998686cd2SShayne Chen 	wcid->rate = rate;
144098686cd2SShayne Chen 
144198686cd2SShayne Chen out:
144298686cd2SShayne Chen 	mt76_tx_status_skb_done(mdev, skb, &list);
144398686cd2SShayne Chen 
144498686cd2SShayne Chen out_no_skb:
144598686cd2SShayne Chen 	mt76_tx_status_unlock(mdev, &list);
144698686cd2SShayne Chen 
144798686cd2SShayne Chen 	return !!skb;
144898686cd2SShayne Chen }
144998686cd2SShayne Chen 
145098686cd2SShayne Chen static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
145198686cd2SShayne Chen {
145298686cd2SShayne Chen 	struct mt7996_sta *msta = NULL;
145398686cd2SShayne Chen 	struct mt76_wcid *wcid;
145498686cd2SShayne Chen 	__le32 *txs_data = data;
145598686cd2SShayne Chen 	u16 wcidx;
145698686cd2SShayne Chen 	u8 pid;
145798686cd2SShayne Chen 
145898686cd2SShayne Chen 	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
145998686cd2SShayne Chen 		return;
146098686cd2SShayne Chen 
146198686cd2SShayne Chen 	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
146298686cd2SShayne Chen 	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
146398686cd2SShayne Chen 
146498686cd2SShayne Chen 	if (pid < MT_PACKET_ID_FIRST)
146598686cd2SShayne Chen 		return;
146698686cd2SShayne Chen 
146743482540SShayne Chen 	if (wcidx >= mt7996_wtbl_size(dev))
146898686cd2SShayne Chen 		return;
146998686cd2SShayne Chen 
147098686cd2SShayne Chen 	rcu_read_lock();
147198686cd2SShayne Chen 
147298686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
147398686cd2SShayne Chen 	if (!wcid)
147498686cd2SShayne Chen 		goto out;
147598686cd2SShayne Chen 
147698686cd2SShayne Chen 	msta = container_of(wcid, struct mt7996_sta, wcid);
147798686cd2SShayne Chen 
147898686cd2SShayne Chen 	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats);
147998686cd2SShayne Chen 
148098686cd2SShayne Chen 	if (!wcid->sta)
148198686cd2SShayne Chen 		goto out;
148298686cd2SShayne Chen 
148398686cd2SShayne Chen 	spin_lock_bh(&dev->sta_poll_lock);
148498686cd2SShayne Chen 	if (list_empty(&msta->poll_list))
148598686cd2SShayne Chen 		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
148698686cd2SShayne Chen 	spin_unlock_bh(&dev->sta_poll_lock);
148798686cd2SShayne Chen 
148898686cd2SShayne Chen out:
148998686cd2SShayne Chen 	rcu_read_unlock();
149098686cd2SShayne Chen }
149198686cd2SShayne Chen 
149298686cd2SShayne Chen bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
149398686cd2SShayne Chen {
149498686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
149598686cd2SShayne Chen 	__le32 *rxd = (__le32 *)data;
149698686cd2SShayne Chen 	__le32 *end = (__le32 *)&rxd[len / 4];
149798686cd2SShayne Chen 	enum rx_pkt_type type;
149898686cd2SShayne Chen 
149998686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
150098686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
150198686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
150298686cd2SShayne Chen 
150398686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
150498686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
150598686cd2SShayne Chen 			return true;
150698686cd2SShayne Chen 	}
150798686cd2SShayne Chen 
150898686cd2SShayne Chen 	switch (type) {
150998686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
151098686cd2SShayne Chen 		mt7996_mac_tx_free(dev, data, len);
151198686cd2SShayne Chen 		return false;
151298686cd2SShayne Chen 	case PKT_TYPE_TXS:
151398686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
151498686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
151598686cd2SShayne Chen 		return false;
151698686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
151798686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, data, len);
151898686cd2SShayne Chen 		return false;
151998686cd2SShayne Chen 	default:
152098686cd2SShayne Chen 		return true;
152198686cd2SShayne Chen 	}
152298686cd2SShayne Chen }
152398686cd2SShayne Chen 
152498686cd2SShayne Chen void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
152598686cd2SShayne Chen 			 struct sk_buff *skb, u32 *info)
152698686cd2SShayne Chen {
152798686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
152898686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
152998686cd2SShayne Chen 	__le32 *end = (__le32 *)&skb->data[skb->len];
153098686cd2SShayne Chen 	enum rx_pkt_type type;
153198686cd2SShayne Chen 
153298686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
153398686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
153498686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
153598686cd2SShayne Chen 
153698686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
153798686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
153898686cd2SShayne Chen 			type = PKT_TYPE_NORMAL;
153998686cd2SShayne Chen 	}
154098686cd2SShayne Chen 
154198686cd2SShayne Chen 	switch (type) {
154298686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
154398686cd2SShayne Chen 		mt7996_mac_tx_free(dev, skb->data, skb->len);
154498686cd2SShayne Chen 		napi_consume_skb(skb, 1);
154598686cd2SShayne Chen 		break;
154698686cd2SShayne Chen 	case PKT_TYPE_RX_EVENT:
154798686cd2SShayne Chen 		mt7996_mcu_rx_event(dev, skb);
154898686cd2SShayne Chen 		break;
154998686cd2SShayne Chen 	case PKT_TYPE_TXS:
155098686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
155198686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
155298686cd2SShayne Chen 		dev_kfree_skb(skb);
155398686cd2SShayne Chen 		break;
155498686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
155598686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
155698686cd2SShayne Chen 		dev_kfree_skb(skb);
155798686cd2SShayne Chen 		break;
155898686cd2SShayne Chen 	case PKT_TYPE_NORMAL:
155998686cd2SShayne Chen 		if (!mt7996_mac_fill_rx(dev, skb)) {
156098686cd2SShayne Chen 			mt76_rx(&dev->mt76, q, skb);
156198686cd2SShayne Chen 			return;
156298686cd2SShayne Chen 		}
156398686cd2SShayne Chen 		fallthrough;
156498686cd2SShayne Chen 	default:
156598686cd2SShayne Chen 		dev_kfree_skb(skb);
156698686cd2SShayne Chen 		break;
156798686cd2SShayne Chen 	}
156898686cd2SShayne Chen }
156998686cd2SShayne Chen 
157098686cd2SShayne Chen void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
157198686cd2SShayne Chen {
157298686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
157398686cd2SShayne Chen 	u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx);
157498686cd2SShayne Chen 
157598686cd2SShayne Chen 	mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN);
157698686cd2SShayne Chen 	mt76_set(dev, reg, BIT(11) | BIT(9));
157798686cd2SShayne Chen }
157898686cd2SShayne Chen 
157998686cd2SShayne Chen void mt7996_mac_reset_counters(struct mt7996_phy *phy)
158098686cd2SShayne Chen {
158198686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
158298686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
158398686cd2SShayne Chen 	int i;
158498686cd2SShayne Chen 
158598686cd2SShayne Chen 	for (i = 0; i < 16; i++)
158698686cd2SShayne Chen 		mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
158798686cd2SShayne Chen 
158898686cd2SShayne Chen 	phy->mt76->survey_time = ktime_get_boottime();
158998686cd2SShayne Chen 
159098686cd2SShayne Chen 	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
159198686cd2SShayne Chen 
159298686cd2SShayne Chen 	/* reset airtime counters */
159398686cd2SShayne Chen 	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx),
159498686cd2SShayne Chen 		 MT_WF_RMAC_MIB_RXTIME_CLR);
159598686cd2SShayne Chen 
159698686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, true);
159798686cd2SShayne Chen }
159898686cd2SShayne Chen 
159998686cd2SShayne Chen void mt7996_mac_set_timing(struct mt7996_phy *phy)
160098686cd2SShayne Chen {
160198686cd2SShayne Chen 	s16 coverage_class = phy->coverage_class;
160298686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
160398686cd2SShayne Chen 	struct mt7996_phy *phy2 = mt7996_phy2(dev);
160498686cd2SShayne Chen 	struct mt7996_phy *phy3 = mt7996_phy3(dev);
160598686cd2SShayne Chen 	u32 val, reg_offset;
160698686cd2SShayne Chen 	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
160798686cd2SShayne Chen 		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
160898686cd2SShayne Chen 	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
160998686cd2SShayne Chen 		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
161098686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
161198686cd2SShayne Chen 	int offset;
161298686cd2SShayne Chen 	bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
161398686cd2SShayne Chen 
161498686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
161598686cd2SShayne Chen 		return;
161698686cd2SShayne Chen 
161798686cd2SShayne Chen 	if (phy2)
161898686cd2SShayne Chen 		coverage_class = max_t(s16, dev->phy.coverage_class,
161998686cd2SShayne Chen 				       phy2->coverage_class);
162098686cd2SShayne Chen 
162198686cd2SShayne Chen 	if (phy3)
162298686cd2SShayne Chen 		coverage_class = max_t(s16, coverage_class,
162398686cd2SShayne Chen 				       phy3->coverage_class);
162498686cd2SShayne Chen 
162598686cd2SShayne Chen 	mt76_set(dev, MT_ARB_SCR(band_idx),
162698686cd2SShayne Chen 		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
162798686cd2SShayne Chen 	udelay(1);
162898686cd2SShayne Chen 
162998686cd2SShayne Chen 	offset = 3 * coverage_class;
163098686cd2SShayne Chen 	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
163198686cd2SShayne Chen 		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
163298686cd2SShayne Chen 
163398686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
163498686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
163598686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_ICR0(band_idx),
163698686cd2SShayne Chen 		FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) |
163798686cd2SShayne Chen 		FIELD_PREP(MT_IFS_RIFS, 2) |
163898686cd2SShayne Chen 		FIELD_PREP(MT_IFS_SIFS, 10) |
163998686cd2SShayne Chen 		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
164098686cd2SShayne Chen 
164198686cd2SShayne Chen 	if (!a_band)
164298686cd2SShayne Chen 		mt76_wr(dev, MT_TMAC_ICR1(band_idx),
164398686cd2SShayne Chen 			FIELD_PREP(MT_IFS_EIFS_CCK, 314));
164498686cd2SShayne Chen 
164598686cd2SShayne Chen 	if (phy->slottime < 20 || a_band)
164698686cd2SShayne Chen 		val = MT7996_CFEND_RATE_DEFAULT;
164798686cd2SShayne Chen 	else
164898686cd2SShayne Chen 		val = MT7996_CFEND_RATE_11B;
164998686cd2SShayne Chen 
1650793445cfSShayne Chen 	mt76_rmw_field(dev, MT_RATE_HRCR0(band_idx), MT_RATE_HRCR0_CFEND_RATE, val);
165198686cd2SShayne Chen 	mt76_clear(dev, MT_ARB_SCR(band_idx),
165298686cd2SShayne Chen 		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
165398686cd2SShayne Chen }
165498686cd2SShayne Chen 
165598686cd2SShayne Chen void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
165698686cd2SShayne Chen {
165798686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band),
165898686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY |
165998686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR);
166098686cd2SShayne Chen 
166198686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band),
166298686cd2SShayne Chen 		 FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5));
166398686cd2SShayne Chen }
166498686cd2SShayne Chen 
166598686cd2SShayne Chen static u8
166698686cd2SShayne Chen mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
166798686cd2SShayne Chen {
166898686cd2SShayne Chen 	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
166998686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
167098686cd2SShayne Chen 	u32 val, sum = 0, n = 0;
167198686cd2SShayne Chen 	int ant, i;
167298686cd2SShayne Chen 
167398686cd2SShayne Chen 	for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) {
167498686cd2SShayne Chen 		u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant);
167598686cd2SShayne Chen 
167698686cd2SShayne Chen 		for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
167798686cd2SShayne Chen 			val = mt76_rr(dev, reg);
167898686cd2SShayne Chen 			sum += val * nf_power[i];
167998686cd2SShayne Chen 			n += val;
168098686cd2SShayne Chen 		}
168198686cd2SShayne Chen 	}
168298686cd2SShayne Chen 
168398686cd2SShayne Chen 	return n ? sum / n : 0;
168498686cd2SShayne Chen }
168598686cd2SShayne Chen 
168698686cd2SShayne Chen void mt7996_update_channel(struct mt76_phy *mphy)
168798686cd2SShayne Chen {
168898686cd2SShayne Chen 	struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
168998686cd2SShayne Chen 	struct mt76_channel_state *state = mphy->chan_state;
169098686cd2SShayne Chen 	int nf;
169198686cd2SShayne Chen 
169298686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, false);
169398686cd2SShayne Chen 
169498686cd2SShayne Chen 	nf = mt7996_phy_get_nf(phy, mphy->band_idx);
169598686cd2SShayne Chen 	if (!phy->noise)
169698686cd2SShayne Chen 		phy->noise = nf << 4;
169798686cd2SShayne Chen 	else if (nf)
169898686cd2SShayne Chen 		phy->noise += nf - (phy->noise >> 4);
169998686cd2SShayne Chen 
170098686cd2SShayne Chen 	state->noise = -(phy->noise >> 4);
170198686cd2SShayne Chen }
170298686cd2SShayne Chen 
170398686cd2SShayne Chen static bool
170498686cd2SShayne Chen mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
170598686cd2SShayne Chen {
170698686cd2SShayne Chen 	bool ret;
170798686cd2SShayne Chen 
170898686cd2SShayne Chen 	ret = wait_event_timeout(dev->reset_wait,
170998686cd2SShayne Chen 				 (READ_ONCE(dev->reset_state) & state),
171098686cd2SShayne Chen 				 MT7996_RESET_TIMEOUT);
171198686cd2SShayne Chen 
171298686cd2SShayne Chen 	WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
171398686cd2SShayne Chen 	return ret;
171498686cd2SShayne Chen }
171598686cd2SShayne Chen 
171698686cd2SShayne Chen static void
171798686cd2SShayne Chen mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
171898686cd2SShayne Chen {
171998686cd2SShayne Chen 	struct ieee80211_hw *hw = priv;
172098686cd2SShayne Chen 
172198686cd2SShayne Chen 	switch (vif->type) {
172298686cd2SShayne Chen 	case NL80211_IFTYPE_MESH_POINT:
172398686cd2SShayne Chen 	case NL80211_IFTYPE_ADHOC:
172498686cd2SShayne Chen 	case NL80211_IFTYPE_AP:
172598686cd2SShayne Chen 		mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
172698686cd2SShayne Chen 		break;
172798686cd2SShayne Chen 	default:
172898686cd2SShayne Chen 		break;
172998686cd2SShayne Chen 	}
173098686cd2SShayne Chen }
173198686cd2SShayne Chen 
173298686cd2SShayne Chen static void
173398686cd2SShayne Chen mt7996_update_beacons(struct mt7996_dev *dev)
173498686cd2SShayne Chen {
173598686cd2SShayne Chen 	struct mt76_phy *phy2, *phy3;
173698686cd2SShayne Chen 
173798686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(dev->mt76.hw,
173898686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
173998686cd2SShayne Chen 					    mt7996_update_vif_beacon, dev->mt76.hw);
174098686cd2SShayne Chen 
174198686cd2SShayne Chen 	phy2 = dev->mt76.phys[MT_BAND1];
174298686cd2SShayne Chen 	if (!phy2)
174398686cd2SShayne Chen 		return;
174498686cd2SShayne Chen 
174598686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy2->hw,
174698686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
174798686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy2->hw);
174898686cd2SShayne Chen 
174998686cd2SShayne Chen 	phy3 = dev->mt76.phys[MT_BAND2];
175098686cd2SShayne Chen 	if (!phy3)
175198686cd2SShayne Chen 		return;
175298686cd2SShayne Chen 
175398686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy3->hw,
175498686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
175598686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy3->hw);
175698686cd2SShayne Chen }
175798686cd2SShayne Chen 
175898686cd2SShayne Chen static void
175998686cd2SShayne Chen mt7996_dma_reset(struct mt7996_dev *dev)
176098686cd2SShayne Chen {
176198686cd2SShayne Chen 	struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
176298686cd2SShayne Chen 	struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
176398686cd2SShayne Chen 	u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
176498686cd2SShayne Chen 	int i;
176598686cd2SShayne Chen 
176698686cd2SShayne Chen 	mt76_clear(dev, MT_WFDMA0_GLO_CFG,
176798686cd2SShayne Chen 		   MT_WFDMA0_GLO_CFG_TX_DMA_EN |
176898686cd2SShayne Chen 		   MT_WFDMA0_GLO_CFG_RX_DMA_EN);
176998686cd2SShayne Chen 
177098686cd2SShayne Chen 	if (dev->hif2)
177198686cd2SShayne Chen 		mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
177298686cd2SShayne Chen 			   MT_WFDMA0_GLO_CFG_TX_DMA_EN |
177398686cd2SShayne Chen 			   MT_WFDMA0_GLO_CFG_RX_DMA_EN);
177498686cd2SShayne Chen 
177598686cd2SShayne Chen 	usleep_range(1000, 2000);
177698686cd2SShayne Chen 
177798686cd2SShayne Chen 	for (i = 0; i < __MT_TXQ_MAX; i++) {
177898686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
177998686cd2SShayne Chen 		if (phy2)
178098686cd2SShayne Chen 			mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
178198686cd2SShayne Chen 		if (phy3)
178298686cd2SShayne Chen 			mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
178398686cd2SShayne Chen 	}
178498686cd2SShayne Chen 
178598686cd2SShayne Chen 	for (i = 0; i < __MT_MCUQ_MAX; i++)
178698686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
178798686cd2SShayne Chen 
178898686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i)
178998686cd2SShayne Chen 		mt76_queue_rx_reset(dev, i);
179098686cd2SShayne Chen 
179198686cd2SShayne Chen 	mt76_tx_status_check(&dev->mt76, true);
179298686cd2SShayne Chen 
179398686cd2SShayne Chen 	/* re-init prefetch settings after reset */
179498686cd2SShayne Chen 	mt7996_dma_prefetch(dev);
179598686cd2SShayne Chen 
179698686cd2SShayne Chen 	mt76_set(dev, MT_WFDMA0_GLO_CFG,
179798686cd2SShayne Chen 		 MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
179898686cd2SShayne Chen 
179998686cd2SShayne Chen 	if (dev->hif2)
180098686cd2SShayne Chen 		mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
180198686cd2SShayne Chen 			 MT_WFDMA0_GLO_CFG_TX_DMA_EN |
180298686cd2SShayne Chen 			 MT_WFDMA0_GLO_CFG_RX_DMA_EN);
180398686cd2SShayne Chen }
180498686cd2SShayne Chen 
180598686cd2SShayne Chen void mt7996_tx_token_put(struct mt7996_dev *dev)
180698686cd2SShayne Chen {
180798686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
180898686cd2SShayne Chen 	int id;
180998686cd2SShayne Chen 
181098686cd2SShayne Chen 	spin_lock_bh(&dev->mt76.token_lock);
181198686cd2SShayne Chen 	idr_for_each_entry(&dev->mt76.token, txwi, id) {
181298686cd2SShayne Chen 		mt7996_txwi_free(dev, txwi, NULL, NULL);
181398686cd2SShayne Chen 		dev->mt76.token_count--;
181498686cd2SShayne Chen 	}
181598686cd2SShayne Chen 	spin_unlock_bh(&dev->mt76.token_lock);
181698686cd2SShayne Chen 	idr_destroy(&dev->mt76.token);
181798686cd2SShayne Chen }
181898686cd2SShayne Chen 
181998686cd2SShayne Chen /* system error recovery */
182098686cd2SShayne Chen void mt7996_mac_reset_work(struct work_struct *work)
182198686cd2SShayne Chen {
182298686cd2SShayne Chen 	struct mt7996_phy *phy2, *phy3;
182398686cd2SShayne Chen 	struct mt7996_dev *dev;
182498686cd2SShayne Chen 	int i;
182598686cd2SShayne Chen 
182698686cd2SShayne Chen 	dev = container_of(work, struct mt7996_dev, reset_work);
182798686cd2SShayne Chen 	phy2 = mt7996_phy2(dev);
182898686cd2SShayne Chen 	phy3 = mt7996_phy3(dev);
182998686cd2SShayne Chen 
183098686cd2SShayne Chen 	if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
183198686cd2SShayne Chen 		return;
183298686cd2SShayne Chen 
183398686cd2SShayne Chen 	ieee80211_stop_queues(mt76_hw(dev));
183498686cd2SShayne Chen 	if (phy2)
183598686cd2SShayne Chen 		ieee80211_stop_queues(phy2->mt76->hw);
183698686cd2SShayne Chen 	if (phy3)
183798686cd2SShayne Chen 		ieee80211_stop_queues(phy3->mt76->hw);
183898686cd2SShayne Chen 
183998686cd2SShayne Chen 	set_bit(MT76_RESET, &dev->mphy.state);
184098686cd2SShayne Chen 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
184198686cd2SShayne Chen 	wake_up(&dev->mt76.mcu.wait);
184298686cd2SShayne Chen 	cancel_delayed_work_sync(&dev->mphy.mac_work);
184398686cd2SShayne Chen 	if (phy2) {
184498686cd2SShayne Chen 		set_bit(MT76_RESET, &phy2->mt76->state);
184598686cd2SShayne Chen 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
184698686cd2SShayne Chen 	}
184798686cd2SShayne Chen 	if (phy3) {
184898686cd2SShayne Chen 		set_bit(MT76_RESET, &phy3->mt76->state);
184998686cd2SShayne Chen 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
185098686cd2SShayne Chen 	}
185198686cd2SShayne Chen 	mt76_worker_disable(&dev->mt76.tx_worker);
185298686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i)
185398686cd2SShayne Chen 		napi_disable(&dev->mt76.napi[i]);
185498686cd2SShayne Chen 	napi_disable(&dev->mt76.tx_napi);
185598686cd2SShayne Chen 
185698686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
185798686cd2SShayne Chen 
185898686cd2SShayne Chen 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
185998686cd2SShayne Chen 
186098686cd2SShayne Chen 	if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
186198686cd2SShayne Chen 		mt7996_dma_reset(dev);
186298686cd2SShayne Chen 
186398686cd2SShayne Chen 		mt7996_tx_token_put(dev);
186498686cd2SShayne Chen 		idr_init(&dev->mt76.token);
186598686cd2SShayne Chen 
186698686cd2SShayne Chen 		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
186798686cd2SShayne Chen 		mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
186898686cd2SShayne Chen 	}
186998686cd2SShayne Chen 
187098686cd2SShayne Chen 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
187198686cd2SShayne Chen 	clear_bit(MT76_RESET, &dev->mphy.state);
187298686cd2SShayne Chen 	if (phy2)
187398686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy2->mt76->state);
187498686cd2SShayne Chen 	if (phy3)
187598686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy3->mt76->state);
187698686cd2SShayne Chen 
187798686cd2SShayne Chen 	local_bh_disable();
187898686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i) {
187998686cd2SShayne Chen 		napi_enable(&dev->mt76.napi[i]);
188098686cd2SShayne Chen 		napi_schedule(&dev->mt76.napi[i]);
188198686cd2SShayne Chen 	}
188298686cd2SShayne Chen 	local_bh_enable();
188398686cd2SShayne Chen 
188498686cd2SShayne Chen 	tasklet_schedule(&dev->irq_tasklet);
188598686cd2SShayne Chen 
188698686cd2SShayne Chen 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
188798686cd2SShayne Chen 	mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
188898686cd2SShayne Chen 
188998686cd2SShayne Chen 	mt76_worker_enable(&dev->mt76.tx_worker);
189098686cd2SShayne Chen 
189198686cd2SShayne Chen 	local_bh_disable();
189298686cd2SShayne Chen 	napi_enable(&dev->mt76.tx_napi);
189398686cd2SShayne Chen 	napi_schedule(&dev->mt76.tx_napi);
189498686cd2SShayne Chen 	local_bh_enable();
189598686cd2SShayne Chen 
189698686cd2SShayne Chen 	ieee80211_wake_queues(mt76_hw(dev));
189798686cd2SShayne Chen 	if (phy2)
189898686cd2SShayne Chen 		ieee80211_wake_queues(phy2->mt76->hw);
189998686cd2SShayne Chen 	if (phy3)
190098686cd2SShayne Chen 		ieee80211_wake_queues(phy3->mt76->hw);
190198686cd2SShayne Chen 
190298686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
190398686cd2SShayne Chen 
190498686cd2SShayne Chen 	mt7996_update_beacons(dev);
190598686cd2SShayne Chen 
190698686cd2SShayne Chen 	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
190798686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
190898686cd2SShayne Chen 	if (phy2)
190998686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy2->mt76->hw,
191098686cd2SShayne Chen 					     &phy2->mt76->mac_work,
191198686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
191298686cd2SShayne Chen 	if (phy3)
191398686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy3->mt76->hw,
191498686cd2SShayne Chen 					     &phy3->mt76->mac_work,
191598686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
191698686cd2SShayne Chen }
191798686cd2SShayne Chen 
191898686cd2SShayne Chen void mt7996_mac_update_stats(struct mt7996_phy *phy)
191998686cd2SShayne Chen {
192098686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
192198686cd2SShayne Chen 	struct mib_stats *mib = &phy->mib;
192298686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
192398686cd2SShayne Chen 	u32 cnt;
192498686cd2SShayne Chen 	int i;
192598686cd2SShayne Chen 
192698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx));
192798686cd2SShayne Chen 	mib->fcs_err_cnt += cnt;
192898686cd2SShayne Chen 
192998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx));
193098686cd2SShayne Chen 	mib->rx_fifo_full_cnt += cnt;
193198686cd2SShayne Chen 
193298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx));
193398686cd2SShayne Chen 	mib->rx_mpdu_cnt += cnt;
193498686cd2SShayne Chen 
193598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx));
193698686cd2SShayne Chen 	mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
193798686cd2SShayne Chen 
193898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx));
193998686cd2SShayne Chen 	mib->rx_vector_mismatch_cnt += cnt;
194098686cd2SShayne Chen 
194198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx));
194298686cd2SShayne Chen 	mib->rx_delimiter_fail_cnt += cnt;
194398686cd2SShayne Chen 
194498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx));
194598686cd2SShayne Chen 	mib->rx_len_mismatch_cnt += cnt;
194698686cd2SShayne Chen 
194798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx));
194898686cd2SShayne Chen 	mib->tx_ampdu_cnt += cnt;
194998686cd2SShayne Chen 
195098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx));
195198686cd2SShayne Chen 	mib->tx_stop_q_empty_cnt += cnt;
195298686cd2SShayne Chen 
195398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx));
195498686cd2SShayne Chen 	mib->tx_mpdu_attempts_cnt += cnt;
195598686cd2SShayne Chen 
195698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx));
195798686cd2SShayne Chen 	mib->tx_mpdu_success_cnt += cnt;
195898686cd2SShayne Chen 
195998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx));
196098686cd2SShayne Chen 	mib->rx_ampdu_cnt += cnt;
196198686cd2SShayne Chen 
196298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx));
196398686cd2SShayne Chen 	mib->rx_ampdu_bytes_cnt += cnt;
196498686cd2SShayne Chen 
196598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx));
196698686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_cnt += cnt;
196798686cd2SShayne Chen 
196898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx));
196998686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
197098686cd2SShayne Chen 
197198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx));
197298686cd2SShayne Chen 	mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt);
197398686cd2SShayne Chen 
197498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx));
197598686cd2SShayne Chen 	mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt);
197698686cd2SShayne Chen 
197798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx));
197898686cd2SShayne Chen 	mib->rx_pfdrop_cnt += cnt;
197998686cd2SShayne Chen 
198098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx));
198198686cd2SShayne Chen 	mib->rx_vec_queue_overflow_drop_cnt += cnt;
198298686cd2SShayne Chen 
198398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx));
198498686cd2SShayne Chen 	mib->rx_ba_cnt += cnt;
198598686cd2SShayne Chen 
198698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx));
198798686cd2SShayne Chen 	mib->tx_bf_ebf_ppdu_cnt += cnt;
198898686cd2SShayne Chen 
198998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx));
199098686cd2SShayne Chen 	mib->tx_bf_ibf_ppdu_cnt += cnt;
199198686cd2SShayne Chen 
199298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx));
199398686cd2SShayne Chen 	mib->tx_mu_bf_cnt += cnt;
199498686cd2SShayne Chen 
199598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx));
199698686cd2SShayne Chen 	mib->tx_mu_mpdu_cnt += cnt;
199798686cd2SShayne Chen 
199898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx));
199998686cd2SShayne Chen 	mib->tx_mu_acked_mpdu_cnt += cnt;
200098686cd2SShayne Chen 
200198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx));
200298686cd2SShayne Chen 	mib->tx_su_acked_mpdu_cnt += cnt;
200398686cd2SShayne Chen 
200498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx));
200598686cd2SShayne Chen 	mib->tx_bf_rx_fb_ht_cnt += cnt;
200698686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
200798686cd2SShayne Chen 
200898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx));
200998686cd2SShayne Chen 	mib->tx_bf_rx_fb_vht_cnt += cnt;
201098686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
201198686cd2SShayne Chen 
201298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx));
201398686cd2SShayne Chen 	mib->tx_bf_rx_fb_he_cnt += cnt;
201498686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
201598686cd2SShayne Chen 
201698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx));
201798686cd2SShayne Chen 	mib->tx_bf_rx_fb_eht_cnt += cnt;
201898686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
201998686cd2SShayne Chen 
202098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx));
202198686cd2SShayne Chen 	mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt);
202298686cd2SShayne Chen 	mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt);
202398686cd2SShayne Chen 	mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt);
202498686cd2SShayne Chen 
202598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR7(band_idx));
202698686cd2SShayne Chen 	mib->tx_bf_fb_trig_cnt += cnt;
202798686cd2SShayne Chen 
202898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx));
202998686cd2SShayne Chen 	mib->tx_bf_fb_cpl_cnt += cnt;
203098686cd2SShayne Chen 
203198686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
203298686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
203398686cd2SShayne Chen 		mib->tx_amsdu[i] += cnt;
203498686cd2SShayne Chen 		mib->tx_amsdu_cnt += cnt;
203598686cd2SShayne Chen 	}
203698686cd2SShayne Chen 
203798686cd2SShayne Chen 	/* rts count */
203898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx));
203998686cd2SShayne Chen 	mib->rts_cnt += cnt;
204098686cd2SShayne Chen 
204198686cd2SShayne Chen 	/* rts retry count */
204298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx));
204398686cd2SShayne Chen 	mib->rts_retries_cnt += cnt;
204498686cd2SShayne Chen 
204598686cd2SShayne Chen 	/* ba miss count */
204698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx));
204798686cd2SShayne Chen 	mib->ba_miss_cnt += cnt;
204898686cd2SShayne Chen 
204998686cd2SShayne Chen 	/* ack fail count */
205098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx));
205198686cd2SShayne Chen 	mib->ack_fail_cnt += cnt;
205298686cd2SShayne Chen 
205398686cd2SShayne Chen 	for (i = 0; i < 16; i++) {
205498686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
205598686cd2SShayne Chen 		phy->mt76->aggr_stats[i] += cnt;
205698686cd2SShayne Chen 	}
205798686cd2SShayne Chen }
205898686cd2SShayne Chen 
205998686cd2SShayne Chen void mt7996_mac_sta_rc_work(struct work_struct *work)
206098686cd2SShayne Chen {
206198686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
206298686cd2SShayne Chen 	struct ieee80211_sta *sta;
206398686cd2SShayne Chen 	struct ieee80211_vif *vif;
206498686cd2SShayne Chen 	struct mt7996_sta *msta;
206598686cd2SShayne Chen 	u32 changed;
206698686cd2SShayne Chen 	LIST_HEAD(list);
206798686cd2SShayne Chen 
206898686cd2SShayne Chen 	spin_lock_bh(&dev->sta_poll_lock);
206998686cd2SShayne Chen 	list_splice_init(&dev->sta_rc_list, &list);
207098686cd2SShayne Chen 
207198686cd2SShayne Chen 	while (!list_empty(&list)) {
207298686cd2SShayne Chen 		msta = list_first_entry(&list, struct mt7996_sta, rc_list);
207398686cd2SShayne Chen 		list_del_init(&msta->rc_list);
207498686cd2SShayne Chen 		changed = msta->changed;
207598686cd2SShayne Chen 		msta->changed = 0;
207698686cd2SShayne Chen 		spin_unlock_bh(&dev->sta_poll_lock);
207798686cd2SShayne Chen 
207898686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
207998686cd2SShayne Chen 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
208098686cd2SShayne Chen 
208198686cd2SShayne Chen 		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
208298686cd2SShayne Chen 			       IEEE80211_RC_NSS_CHANGED |
208398686cd2SShayne Chen 			       IEEE80211_RC_BW_CHANGED))
208498686cd2SShayne Chen 			mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
208598686cd2SShayne Chen 
208698686cd2SShayne Chen 		/* TODO: smps change */
208798686cd2SShayne Chen 
208898686cd2SShayne Chen 		spin_lock_bh(&dev->sta_poll_lock);
208998686cd2SShayne Chen 	}
209098686cd2SShayne Chen 
209198686cd2SShayne Chen 	spin_unlock_bh(&dev->sta_poll_lock);
209298686cd2SShayne Chen }
209398686cd2SShayne Chen 
209498686cd2SShayne Chen void mt7996_mac_work(struct work_struct *work)
209598686cd2SShayne Chen {
209698686cd2SShayne Chen 	struct mt7996_phy *phy;
209798686cd2SShayne Chen 	struct mt76_phy *mphy;
209898686cd2SShayne Chen 
209998686cd2SShayne Chen 	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
210098686cd2SShayne Chen 					       mac_work.work);
210198686cd2SShayne Chen 	phy = mphy->priv;
210298686cd2SShayne Chen 
210398686cd2SShayne Chen 	mutex_lock(&mphy->dev->mutex);
210498686cd2SShayne Chen 
210598686cd2SShayne Chen 	mt76_update_survey(mphy);
210698686cd2SShayne Chen 	if (++mphy->mac_work_count == 5) {
210798686cd2SShayne Chen 		mphy->mac_work_count = 0;
210898686cd2SShayne Chen 
210998686cd2SShayne Chen 		mt7996_mac_update_stats(phy);
211098686cd2SShayne Chen 	}
211198686cd2SShayne Chen 
211298686cd2SShayne Chen 	mutex_unlock(&mphy->dev->mutex);
211398686cd2SShayne Chen 
211498686cd2SShayne Chen 	mt76_tx_status_check(mphy->dev, false);
211598686cd2SShayne Chen 
211698686cd2SShayne Chen 	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
211798686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
211898686cd2SShayne Chen }
211998686cd2SShayne Chen 
212098686cd2SShayne Chen static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
212198686cd2SShayne Chen {
212298686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
212398686cd2SShayne Chen 
212498686cd2SShayne Chen 	if (phy->rdd_state & BIT(0))
212598686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0,
212698686cd2SShayne Chen 				   MT_RX_SEL0, 0);
212798686cd2SShayne Chen 	if (phy->rdd_state & BIT(1))
212898686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1,
212998686cd2SShayne Chen 				   MT_RX_SEL0, 0);
213098686cd2SShayne Chen }
213198686cd2SShayne Chen 
213298686cd2SShayne Chen static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
213398686cd2SShayne Chen {
213498686cd2SShayne Chen 	int err, region;
213598686cd2SShayne Chen 
213698686cd2SShayne Chen 	switch (dev->mt76.region) {
213798686cd2SShayne Chen 	case NL80211_DFS_ETSI:
213898686cd2SShayne Chen 		region = 0;
213998686cd2SShayne Chen 		break;
214098686cd2SShayne Chen 	case NL80211_DFS_JP:
214198686cd2SShayne Chen 		region = 2;
214298686cd2SShayne Chen 		break;
214398686cd2SShayne Chen 	case NL80211_DFS_FCC:
214498686cd2SShayne Chen 	default:
214598686cd2SShayne Chen 		region = 1;
214698686cd2SShayne Chen 		break;
214798686cd2SShayne Chen 	}
214898686cd2SShayne Chen 
214998686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain,
215098686cd2SShayne Chen 				 MT_RX_SEL0, region);
215198686cd2SShayne Chen 	if (err < 0)
215298686cd2SShayne Chen 		return err;
215398686cd2SShayne Chen 
215498686cd2SShayne Chen 	return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
215598686cd2SShayne Chen 				 MT_RX_SEL0, 1);
215698686cd2SShayne Chen }
215798686cd2SShayne Chen 
215898686cd2SShayne Chen static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
215998686cd2SShayne Chen {
216098686cd2SShayne Chen 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
216198686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
216298686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
216398686cd2SShayne Chen 	int err;
216498686cd2SShayne Chen 
216598686cd2SShayne Chen 	/* start CAC */
216698686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx,
216798686cd2SShayne Chen 				 MT_RX_SEL0, 0);
216898686cd2SShayne Chen 	if (err < 0)
216998686cd2SShayne Chen 		return err;
217098686cd2SShayne Chen 
217198686cd2SShayne Chen 	err = mt7996_dfs_start_rdd(dev, band_idx);
217298686cd2SShayne Chen 	if (err < 0)
217398686cd2SShayne Chen 		return err;
217498686cd2SShayne Chen 
217598686cd2SShayne Chen 	phy->rdd_state |= BIT(band_idx);
217698686cd2SShayne Chen 
217798686cd2SShayne Chen 	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
217898686cd2SShayne Chen 	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
217998686cd2SShayne Chen 		err = mt7996_dfs_start_rdd(dev, 1);
218098686cd2SShayne Chen 		if (err < 0)
218198686cd2SShayne Chen 			return err;
218298686cd2SShayne Chen 
218398686cd2SShayne Chen 		phy->rdd_state |= BIT(1);
218498686cd2SShayne Chen 	}
218598686cd2SShayne Chen 
218698686cd2SShayne Chen 	return 0;
218798686cd2SShayne Chen }
218898686cd2SShayne Chen 
218998686cd2SShayne Chen static int
219098686cd2SShayne Chen mt7996_dfs_init_radar_specs(struct mt7996_phy *phy)
219198686cd2SShayne Chen {
219298686cd2SShayne Chen 	const struct mt7996_dfs_radar_spec *radar_specs;
219398686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
219498686cd2SShayne Chen 	int err, i;
219598686cd2SShayne Chen 
219698686cd2SShayne Chen 	switch (dev->mt76.region) {
219798686cd2SShayne Chen 	case NL80211_DFS_FCC:
219898686cd2SShayne Chen 		radar_specs = &fcc_radar_specs;
219998686cd2SShayne Chen 		err = mt7996_mcu_set_fcc5_lpn(dev, 8);
220098686cd2SShayne Chen 		if (err < 0)
220198686cd2SShayne Chen 			return err;
220298686cd2SShayne Chen 		break;
220398686cd2SShayne Chen 	case NL80211_DFS_ETSI:
220498686cd2SShayne Chen 		radar_specs = &etsi_radar_specs;
220598686cd2SShayne Chen 		break;
220698686cd2SShayne Chen 	case NL80211_DFS_JP:
220798686cd2SShayne Chen 		radar_specs = &jp_radar_specs;
220898686cd2SShayne Chen 		break;
220998686cd2SShayne Chen 	default:
221098686cd2SShayne Chen 		return -EINVAL;
221198686cd2SShayne Chen 	}
221298686cd2SShayne Chen 
221398686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
221498686cd2SShayne Chen 		err = mt7996_mcu_set_radar_th(dev, i,
221598686cd2SShayne Chen 					      &radar_specs->radar_pattern[i]);
221698686cd2SShayne Chen 		if (err < 0)
221798686cd2SShayne Chen 			return err;
221898686cd2SShayne Chen 	}
221998686cd2SShayne Chen 
222098686cd2SShayne Chen 	return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
222198686cd2SShayne Chen }
222298686cd2SShayne Chen 
222398686cd2SShayne Chen int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
222498686cd2SShayne Chen {
222598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
222698686cd2SShayne Chen 	enum mt76_dfs_state dfs_state, prev_state;
222798686cd2SShayne Chen 	int err;
222898686cd2SShayne Chen 
222998686cd2SShayne Chen 	prev_state = phy->mt76->dfs_state;
223098686cd2SShayne Chen 	dfs_state = mt76_phy_dfs_state(phy->mt76);
223198686cd2SShayne Chen 
223298686cd2SShayne Chen 	if (prev_state == dfs_state)
223398686cd2SShayne Chen 		return 0;
223498686cd2SShayne Chen 
223598686cd2SShayne Chen 	if (prev_state == MT_DFS_STATE_UNKNOWN)
223698686cd2SShayne Chen 		mt7996_dfs_stop_radar_detector(phy);
223798686cd2SShayne Chen 
223898686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_DISABLED)
223998686cd2SShayne Chen 		goto stop;
224098686cd2SShayne Chen 
224198686cd2SShayne Chen 	if (prev_state <= MT_DFS_STATE_DISABLED) {
224298686cd2SShayne Chen 		err = mt7996_dfs_init_radar_specs(phy);
224398686cd2SShayne Chen 		if (err < 0)
224498686cd2SShayne Chen 			return err;
224598686cd2SShayne Chen 
224698686cd2SShayne Chen 		err = mt7996_dfs_start_radar_detector(phy);
224798686cd2SShayne Chen 		if (err < 0)
224898686cd2SShayne Chen 			return err;
224998686cd2SShayne Chen 
225098686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_CAC;
225198686cd2SShayne Chen 	}
225298686cd2SShayne Chen 
225398686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_CAC)
225498686cd2SShayne Chen 		return 0;
225598686cd2SShayne Chen 
225698686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END,
225798686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
225898686cd2SShayne Chen 	if (err < 0) {
225998686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
226098686cd2SShayne Chen 		return err;
226198686cd2SShayne Chen 	}
226298686cd2SShayne Chen 
226398686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
226498686cd2SShayne Chen 	return 0;
226598686cd2SShayne Chen 
226698686cd2SShayne Chen stop:
226798686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START,
226898686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
226998686cd2SShayne Chen 	if (err < 0)
227098686cd2SShayne Chen 		return err;
227198686cd2SShayne Chen 
227298686cd2SShayne Chen 	mt7996_dfs_stop_radar_detector(phy);
227398686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
227498686cd2SShayne Chen 
227598686cd2SShayne Chen 	return 0;
227698686cd2SShayne Chen }
227798686cd2SShayne Chen 
227898686cd2SShayne Chen static int
227998686cd2SShayne Chen mt7996_mac_twt_duration_align(int duration)
228098686cd2SShayne Chen {
228198686cd2SShayne Chen 	return duration << 8;
228298686cd2SShayne Chen }
228398686cd2SShayne Chen 
228498686cd2SShayne Chen static u64
228598686cd2SShayne Chen mt7996_mac_twt_sched_list_add(struct mt7996_dev *dev,
228698686cd2SShayne Chen 			      struct mt7996_twt_flow *flow)
228798686cd2SShayne Chen {
228898686cd2SShayne Chen 	struct mt7996_twt_flow *iter, *iter_next;
228998686cd2SShayne Chen 	u32 duration = flow->duration << 8;
229098686cd2SShayne Chen 	u64 start_tsf;
229198686cd2SShayne Chen 
229298686cd2SShayne Chen 	iter = list_first_entry_or_null(&dev->twt_list,
229398686cd2SShayne Chen 					struct mt7996_twt_flow, list);
229498686cd2SShayne Chen 	if (!iter || !iter->sched || iter->start_tsf > duration) {
229598686cd2SShayne Chen 		/* add flow as first entry in the list */
229698686cd2SShayne Chen 		list_add(&flow->list, &dev->twt_list);
229798686cd2SShayne Chen 		return 0;
229898686cd2SShayne Chen 	}
229998686cd2SShayne Chen 
230098686cd2SShayne Chen 	list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
230198686cd2SShayne Chen 		start_tsf = iter->start_tsf +
230298686cd2SShayne Chen 			    mt7996_mac_twt_duration_align(iter->duration);
230398686cd2SShayne Chen 		if (list_is_last(&iter->list, &dev->twt_list))
230498686cd2SShayne Chen 			break;
230598686cd2SShayne Chen 
230698686cd2SShayne Chen 		if (!iter_next->sched ||
230798686cd2SShayne Chen 		    iter_next->start_tsf > start_tsf + duration) {
230898686cd2SShayne Chen 			list_add(&flow->list, &iter->list);
230998686cd2SShayne Chen 			goto out;
231098686cd2SShayne Chen 		}
231198686cd2SShayne Chen 	}
231298686cd2SShayne Chen 
231398686cd2SShayne Chen 	/* add flow as last entry in the list */
231498686cd2SShayne Chen 	list_add_tail(&flow->list, &dev->twt_list);
231598686cd2SShayne Chen out:
231698686cd2SShayne Chen 	return start_tsf;
231798686cd2SShayne Chen }
231898686cd2SShayne Chen 
231998686cd2SShayne Chen static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
232098686cd2SShayne Chen {
232198686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt;
232298686cd2SShayne Chen 	u64 interval, duration;
232398686cd2SShayne Chen 	u16 mantissa;
232498686cd2SShayne Chen 	u8 exp;
232598686cd2SShayne Chen 
232698686cd2SShayne Chen 	/* only individual agreement supported */
232798686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
232898686cd2SShayne Chen 		return -EOPNOTSUPP;
232998686cd2SShayne Chen 
233098686cd2SShayne Chen 	/* only 256us unit supported */
233198686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
233298686cd2SShayne Chen 		return -EOPNOTSUPP;
233398686cd2SShayne Chen 
233498686cd2SShayne Chen 	twt_agrt = (struct ieee80211_twt_params *)twt->params;
233598686cd2SShayne Chen 
233698686cd2SShayne Chen 	/* explicit agreement not supported */
233798686cd2SShayne Chen 	if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
233898686cd2SShayne Chen 		return -EOPNOTSUPP;
233998686cd2SShayne Chen 
234098686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
234198686cd2SShayne Chen 			le16_to_cpu(twt_agrt->req_type));
234298686cd2SShayne Chen 	mantissa = le16_to_cpu(twt_agrt->mantissa);
234398686cd2SShayne Chen 	duration = twt_agrt->min_twt_dur << 8;
234498686cd2SShayne Chen 
234598686cd2SShayne Chen 	interval = (u64)mantissa << exp;
234698686cd2SShayne Chen 	if (interval < duration)
234798686cd2SShayne Chen 		return -EOPNOTSUPP;
234898686cd2SShayne Chen 
234998686cd2SShayne Chen 	return 0;
235098686cd2SShayne Chen }
235198686cd2SShayne Chen 
235298686cd2SShayne Chen void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
235398686cd2SShayne Chen 			      struct ieee80211_sta *sta,
235498686cd2SShayne Chen 			      struct ieee80211_twt_setup *twt)
235598686cd2SShayne Chen {
235698686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
235798686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
235898686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
235998686cd2SShayne Chen 	u16 req_type = le16_to_cpu(twt_agrt->req_type);
236098686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd sta_setup_cmd;
236198686cd2SShayne Chen 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
236298686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
236398686cd2SShayne Chen 	int flowid, table_id;
236498686cd2SShayne Chen 	u8 exp;
236598686cd2SShayne Chen 
236698686cd2SShayne Chen 	if (mt7996_mac_check_twt_req(twt))
236798686cd2SShayne Chen 		goto out;
236898686cd2SShayne Chen 
236998686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
237098686cd2SShayne Chen 
237198686cd2SShayne Chen 	if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
237298686cd2SShayne Chen 		goto unlock;
237398686cd2SShayne Chen 
237498686cd2SShayne Chen 	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
237598686cd2SShayne Chen 		goto unlock;
237698686cd2SShayne Chen 
237798686cd2SShayne Chen 	flowid = ffs(~msta->twt.flowid_mask) - 1;
237898686cd2SShayne Chen 	le16p_replace_bits(&twt_agrt->req_type, flowid,
237998686cd2SShayne Chen 			   IEEE80211_TWT_REQTYPE_FLOWID);
238098686cd2SShayne Chen 
238198686cd2SShayne Chen 	table_id = ffs(~dev->twt.table_mask) - 1;
238298686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
238398686cd2SShayne Chen 	sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
238498686cd2SShayne Chen 
238598686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
238698686cd2SShayne Chen 	memset(flow, 0, sizeof(*flow));
238798686cd2SShayne Chen 	INIT_LIST_HEAD(&flow->list);
238898686cd2SShayne Chen 	flow->wcid = msta->wcid.idx;
238998686cd2SShayne Chen 	flow->table_id = table_id;
239098686cd2SShayne Chen 	flow->id = flowid;
239198686cd2SShayne Chen 	flow->duration = twt_agrt->min_twt_dur;
239298686cd2SShayne Chen 	flow->mantissa = twt_agrt->mantissa;
239398686cd2SShayne Chen 	flow->exp = exp;
239498686cd2SShayne Chen 	flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
239598686cd2SShayne Chen 	flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
239698686cd2SShayne Chen 	flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
239798686cd2SShayne Chen 
239898686cd2SShayne Chen 	if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
239998686cd2SShayne Chen 	    sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
240098686cd2SShayne Chen 		u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
240198686cd2SShayne Chen 		u64 flow_tsf, curr_tsf;
240298686cd2SShayne Chen 		u32 rem;
240398686cd2SShayne Chen 
240498686cd2SShayne Chen 		flow->sched = true;
240598686cd2SShayne Chen 		flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
240698686cd2SShayne Chen 		curr_tsf = __mt7996_get_tsf(hw, msta->vif);
240798686cd2SShayne Chen 		div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
240898686cd2SShayne Chen 		flow_tsf = curr_tsf + interval - rem;
240998686cd2SShayne Chen 		twt_agrt->twt = cpu_to_le64(flow_tsf);
241098686cd2SShayne Chen 	} else {
241198686cd2SShayne Chen 		list_add_tail(&flow->list, &dev->twt_list);
241298686cd2SShayne Chen 	}
241398686cd2SShayne Chen 	flow->tsf = le64_to_cpu(twt_agrt->twt);
241498686cd2SShayne Chen 
241598686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
241698686cd2SShayne Chen 		goto unlock;
241798686cd2SShayne Chen 
241898686cd2SShayne Chen 	setup_cmd = TWT_SETUP_CMD_ACCEPT;
241998686cd2SShayne Chen 	dev->twt.table_mask |= BIT(table_id);
242098686cd2SShayne Chen 	msta->twt.flowid_mask |= BIT(flowid);
242198686cd2SShayne Chen 	dev->twt.n_agrt++;
242298686cd2SShayne Chen 
242398686cd2SShayne Chen unlock:
242498686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
242598686cd2SShayne Chen out:
242698686cd2SShayne Chen 	le16p_replace_bits(&twt_agrt->req_type, setup_cmd,
242798686cd2SShayne Chen 			   IEEE80211_TWT_REQTYPE_SETUP_CMD);
242898686cd2SShayne Chen 	twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) |
242998686cd2SShayne Chen 		       (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED);
243098686cd2SShayne Chen }
243198686cd2SShayne Chen 
243298686cd2SShayne Chen void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
243398686cd2SShayne Chen 				  struct mt7996_sta *msta,
243498686cd2SShayne Chen 				  u8 flowid)
243598686cd2SShayne Chen {
243698686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
243798686cd2SShayne Chen 
243898686cd2SShayne Chen 	lockdep_assert_held(&dev->mt76.mutex);
243998686cd2SShayne Chen 
244098686cd2SShayne Chen 	if (flowid >= ARRAY_SIZE(msta->twt.flow))
244198686cd2SShayne Chen 		return;
244298686cd2SShayne Chen 
244398686cd2SShayne Chen 	if (!(msta->twt.flowid_mask & BIT(flowid)))
244498686cd2SShayne Chen 		return;
244598686cd2SShayne Chen 
244698686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
244798686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
244898686cd2SShayne Chen 				       MCU_TWT_AGRT_DELETE))
244998686cd2SShayne Chen 		return;
245098686cd2SShayne Chen 
245198686cd2SShayne Chen 	list_del_init(&flow->list);
245298686cd2SShayne Chen 	msta->twt.flowid_mask &= ~BIT(flowid);
245398686cd2SShayne Chen 	dev->twt.table_mask &= ~BIT(flow->table_id);
245498686cd2SShayne Chen 	dev->twt.n_agrt--;
245598686cd2SShayne Chen }
2456