198686cd2SShayne Chen // SPDX-License-Identifier: ISC
298686cd2SShayne Chen /*
398686cd2SShayne Chen  * Copyright (C) 2022 MediaTek Inc.
498686cd2SShayne Chen  */
598686cd2SShayne Chen 
698686cd2SShayne Chen #include <linux/etherdevice.h>
798686cd2SShayne Chen #include <linux/timekeeping.h>
8878161d5SRyder Lee #include "coredump.h"
998686cd2SShayne Chen #include "mt7996.h"
1098686cd2SShayne Chen #include "../dma.h"
1198686cd2SShayne Chen #include "mac.h"
1298686cd2SShayne Chen #include "mcu.h"
1398686cd2SShayne Chen 
14ea5d99d0SRyder Lee #define to_rssi(field, rcpi)	((FIELD_GET(field, rcpi) - 220) / 2)
1598686cd2SShayne Chen 
1698686cd2SShayne Chen static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
1798686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
1898686cd2SShayne Chen 	.radar_pattern = {
1998686cd2SShayne Chen 		[5] =  { 1, 0,  6, 32, 28, 0,  990, 5010, 17, 1, 1 },
2098686cd2SShayne Chen 		[6] =  { 1, 0,  9, 32, 28, 0,  615, 5010, 27, 1, 1 },
2198686cd2SShayne Chen 		[7] =  { 1, 0, 15, 32, 28, 0,  240,  445, 27, 1, 1 },
2298686cd2SShayne Chen 		[8] =  { 1, 0, 12, 32, 28, 0,  240,  510, 42, 1, 1 },
2398686cd2SShayne Chen 		[9] =  { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 },
2498686cd2SShayne Chen 		[10] = { 1, 1,  0,  0,  0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 },
2598686cd2SShayne Chen 		[11] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 18, 32, 28, { },  54 },
2698686cd2SShayne Chen 		[12] = { 1, 1,  0,  0,  0, 0,  823, 2510, 14, 0, 0, 27, 32, 24, { },  54 },
2798686cd2SShayne Chen 	},
2898686cd2SShayne Chen };
2998686cd2SShayne Chen 
3098686cd2SShayne Chen static const struct mt7996_dfs_radar_spec fcc_radar_specs = {
3198686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
3298686cd2SShayne Chen 	.radar_pattern = {
3398686cd2SShayne Chen 		[0] = { 1, 0,  8,  32, 28, 0, 508, 3076, 13, 1,  1 },
3498686cd2SShayne Chen 		[1] = { 1, 0, 12,  32, 28, 0, 140,  240, 17, 1,  1 },
3598686cd2SShayne Chen 		[2] = { 1, 0,  8,  32, 28, 0, 190,  510, 22, 1,  1 },
3698686cd2SShayne Chen 		[3] = { 1, 0,  6,  32, 28, 0, 190,  510, 32, 1,  1 },
3798686cd2SShayne Chen 		[4] = { 1, 0,  9, 255, 28, 0, 323,  343, 13, 1, 32 },
3898686cd2SShayne Chen 	},
3998686cd2SShayne Chen };
4098686cd2SShayne Chen 
4198686cd2SShayne Chen static const struct mt7996_dfs_radar_spec jp_radar_specs = {
4298686cd2SShayne Chen 	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
4398686cd2SShayne Chen 	.radar_pattern = {
4498686cd2SShayne Chen 		[0] =  { 1, 0,  8,  32, 28, 0,  508, 3076,  13, 1,  1 },
4598686cd2SShayne Chen 		[1] =  { 1, 0, 12,  32, 28, 0,  140,  240,  17, 1,  1 },
4698686cd2SShayne Chen 		[2] =  { 1, 0,  8,  32, 28, 0,  190,  510,  22, 1,  1 },
4798686cd2SShayne Chen 		[3] =  { 1, 0,  6,  32, 28, 0,  190,  510,  32, 1,  1 },
4898686cd2SShayne Chen 		[4] =  { 1, 0,  9, 255, 28, 0,  323,  343,  13, 1, 32 },
4998686cd2SShayne Chen 		[13] = { 1, 0,  7,  32, 28, 0, 3836, 3856,  14, 1,  1 },
5098686cd2SShayne Chen 		[14] = { 1, 0,  6,  32, 28, 0,  615, 5010, 110, 1,  1 },
5198686cd2SShayne Chen 		[15] = { 1, 1,  0,   0,  0, 0,   15, 5010, 110, 0,  0, 12, 32, 28 },
5298686cd2SShayne Chen 	},
5398686cd2SShayne Chen };
5498686cd2SShayne Chen 
mt7996_rx_get_wcid(struct mt7996_dev * dev,u16 idx,bool unicast)5598686cd2SShayne Chen static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
5698686cd2SShayne Chen 					    u16 idx, bool unicast)
5798686cd2SShayne Chen {
5898686cd2SShayne Chen 	struct mt7996_sta *sta;
5998686cd2SShayne Chen 	struct mt76_wcid *wcid;
6098686cd2SShayne Chen 
6198686cd2SShayne Chen 	if (idx >= ARRAY_SIZE(dev->mt76.wcid))
6298686cd2SShayne Chen 		return NULL;
6398686cd2SShayne Chen 
6498686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[idx]);
6598686cd2SShayne Chen 	if (unicast || !wcid)
6698686cd2SShayne Chen 		return wcid;
6798686cd2SShayne Chen 
6898686cd2SShayne Chen 	if (!wcid->sta)
6998686cd2SShayne Chen 		return NULL;
7098686cd2SShayne Chen 
7198686cd2SShayne Chen 	sta = container_of(wcid, struct mt7996_sta, wcid);
7298686cd2SShayne Chen 	if (!sta->vif)
7398686cd2SShayne Chen 		return NULL;
7498686cd2SShayne Chen 
7598686cd2SShayne Chen 	return &sta->vif->sta.wcid;
7698686cd2SShayne Chen }
7798686cd2SShayne Chen 
mt7996_mac_wtbl_update(struct mt7996_dev * dev,int idx,u32 mask)7898686cd2SShayne Chen bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
7998686cd2SShayne Chen {
8098686cd2SShayne Chen 	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
8198686cd2SShayne Chen 		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
8298686cd2SShayne Chen 
8398686cd2SShayne Chen 	return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
8498686cd2SShayne Chen 			 0, 5000);
8598686cd2SShayne Chen }
8698686cd2SShayne Chen 
mt7996_mac_wtbl_lmac_addr(struct mt7996_dev * dev,u16 wcid,u8 dw)8798686cd2SShayne Chen u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
8898686cd2SShayne Chen {
8998686cd2SShayne Chen 	mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
9098686cd2SShayne Chen 		FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
9198686cd2SShayne Chen 
9298686cd2SShayne Chen 	return MT_WTBL_LMAC_OFFS(wcid, dw);
9398686cd2SShayne Chen }
9498686cd2SShayne Chen 
mt7996_mac_sta_poll(struct mt7996_dev * dev)9598686cd2SShayne Chen static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
9698686cd2SShayne Chen {
9798686cd2SShayne Chen 	static const u8 ac_to_tid[] = {
9898686cd2SShayne Chen 		[IEEE80211_AC_BE] = 0,
9998686cd2SShayne Chen 		[IEEE80211_AC_BK] = 1,
10098686cd2SShayne Chen 		[IEEE80211_AC_VI] = 4,
10198686cd2SShayne Chen 		[IEEE80211_AC_VO] = 6
10298686cd2SShayne Chen 	};
10398686cd2SShayne Chen 	struct ieee80211_sta *sta;
10498686cd2SShayne Chen 	struct mt7996_sta *msta;
10598686cd2SShayne Chen 	struct rate_info *rate;
10698686cd2SShayne Chen 	u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
10798686cd2SShayne Chen 	LIST_HEAD(sta_poll_list);
10898686cd2SShayne Chen 	int i;
10998686cd2SShayne Chen 
110ea0f3867SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.sta_poll_lock);
111ea0f3867SLorenzo Bianconi 	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
112ea0f3867SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
11398686cd2SShayne Chen 
11498686cd2SShayne Chen 	rcu_read_lock();
11598686cd2SShayne Chen 
11698686cd2SShayne Chen 	while (true) {
11798686cd2SShayne Chen 		bool clear = false;
11898686cd2SShayne Chen 		u32 addr, val;
11998686cd2SShayne Chen 		u16 idx;
120ea5d99d0SRyder Lee 		s8 rssi[4];
12198686cd2SShayne Chen 		u8 bw;
12298686cd2SShayne Chen 
123ea0f3867SLorenzo Bianconi 		spin_lock_bh(&dev->mt76.sta_poll_lock);
12498686cd2SShayne Chen 		if (list_empty(&sta_poll_list)) {
125ea0f3867SLorenzo Bianconi 			spin_unlock_bh(&dev->mt76.sta_poll_lock);
12698686cd2SShayne Chen 			break;
12798686cd2SShayne Chen 		}
12898686cd2SShayne Chen 		msta = list_first_entry(&sta_poll_list,
129e3b0311fSLorenzo Bianconi 					struct mt7996_sta, wcid.poll_list);
130e3b0311fSLorenzo Bianconi 		list_del_init(&msta->wcid.poll_list);
131ea0f3867SLorenzo Bianconi 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
13298686cd2SShayne Chen 
13398686cd2SShayne Chen 		idx = msta->wcid.idx;
134ea5d99d0SRyder Lee 
135ea5d99d0SRyder Lee 		/* refresh peer's airtime reporting */
13698686cd2SShayne Chen 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
13798686cd2SShayne Chen 
13898686cd2SShayne Chen 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
13998686cd2SShayne Chen 			u32 tx_last = msta->airtime_ac[i];
14098686cd2SShayne Chen 			u32 rx_last = msta->airtime_ac[i + 4];
14198686cd2SShayne Chen 
14298686cd2SShayne Chen 			msta->airtime_ac[i] = mt76_rr(dev, addr);
14398686cd2SShayne Chen 			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
14498686cd2SShayne Chen 
14598686cd2SShayne Chen 			tx_time[i] = msta->airtime_ac[i] - tx_last;
14698686cd2SShayne Chen 			rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
14798686cd2SShayne Chen 
14898686cd2SShayne Chen 			if ((tx_last | rx_last) & BIT(30))
14998686cd2SShayne Chen 				clear = true;
15098686cd2SShayne Chen 
15198686cd2SShayne Chen 			addr += 8;
15298686cd2SShayne Chen 		}
15398686cd2SShayne Chen 
15498686cd2SShayne Chen 		if (clear) {
15598686cd2SShayne Chen 			mt7996_mac_wtbl_update(dev, idx,
15698686cd2SShayne Chen 					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
15798686cd2SShayne Chen 			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
15898686cd2SShayne Chen 		}
15998686cd2SShayne Chen 
16098686cd2SShayne Chen 		if (!msta->wcid.sta)
16198686cd2SShayne Chen 			continue;
16298686cd2SShayne Chen 
16398686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta,
16498686cd2SShayne Chen 				   drv_priv);
16598686cd2SShayne Chen 		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
16698686cd2SShayne Chen 			u8 q = mt76_connac_lmac_mapping(i);
16798686cd2SShayne Chen 			u32 tx_cur = tx_time[q];
16898686cd2SShayne Chen 			u32 rx_cur = rx_time[q];
16998686cd2SShayne Chen 			u8 tid = ac_to_tid[i];
17098686cd2SShayne Chen 
17198686cd2SShayne Chen 			if (!tx_cur && !rx_cur)
17298686cd2SShayne Chen 				continue;
17398686cd2SShayne Chen 
17498686cd2SShayne Chen 			ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
17598686cd2SShayne Chen 		}
17698686cd2SShayne Chen 
17798686cd2SShayne Chen 		/* We don't support reading GI info from txs packets.
17898686cd2SShayne Chen 		 * For accurate tx status reporting and AQL improvement,
17998686cd2SShayne Chen 		 * we need to make sure that flags match so polling GI
18098686cd2SShayne Chen 		 * from per-sta counters directly.
18198686cd2SShayne Chen 		 */
18298686cd2SShayne Chen 		rate = &msta->wcid.rate;
18398686cd2SShayne Chen 
18498686cd2SShayne Chen 		switch (rate->bw) {
18580f5a31dSShayne Chen 		case RATE_INFO_BW_320:
18680f5a31dSShayne Chen 			bw = IEEE80211_STA_RX_BW_320;
18780f5a31dSShayne Chen 			break;
18898686cd2SShayne Chen 		case RATE_INFO_BW_160:
18998686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_160;
19098686cd2SShayne Chen 			break;
19198686cd2SShayne Chen 		case RATE_INFO_BW_80:
19298686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_80;
19398686cd2SShayne Chen 			break;
19498686cd2SShayne Chen 		case RATE_INFO_BW_40:
19598686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_40;
19698686cd2SShayne Chen 			break;
19798686cd2SShayne Chen 		default:
19898686cd2SShayne Chen 			bw = IEEE80211_STA_RX_BW_20;
19998686cd2SShayne Chen 			break;
20098686cd2SShayne Chen 		}
20198686cd2SShayne Chen 
20298686cd2SShayne Chen 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
20398686cd2SShayne Chen 		val = mt76_rr(dev, addr);
20480f5a31dSShayne Chen 		if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
20580f5a31dSShayne Chen 			addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
20680f5a31dSShayne Chen 			val = mt76_rr(dev, addr);
20780f5a31dSShayne Chen 			rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
20880f5a31dSShayne Chen 		} else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
20998686cd2SShayne Chen 			u8 offs = 24 + 2 * bw;
21098686cd2SShayne Chen 
21198686cd2SShayne Chen 			rate->he_gi = (val & (0x3 << offs)) >> offs;
21298686cd2SShayne Chen 		} else if (rate->flags &
21398686cd2SShayne Chen 			   (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
21498686cd2SShayne Chen 			if (val & BIT(12 + bw))
21598686cd2SShayne Chen 				rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
21698686cd2SShayne Chen 			else
21798686cd2SShayne Chen 				rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
21898686cd2SShayne Chen 		}
219ea5d99d0SRyder Lee 
220ea5d99d0SRyder Lee 		/* get signal strength of resp frames (CTS/BA/ACK) */
221ea5d99d0SRyder Lee 		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
222ea5d99d0SRyder Lee 		val = mt76_rr(dev, addr);
223ea5d99d0SRyder Lee 
224ea5d99d0SRyder Lee 		rssi[0] = to_rssi(GENMASK(7, 0), val);
225ea5d99d0SRyder Lee 		rssi[1] = to_rssi(GENMASK(15, 8), val);
226ea5d99d0SRyder Lee 		rssi[2] = to_rssi(GENMASK(23, 16), val);
227ea5d99d0SRyder Lee 		rssi[3] = to_rssi(GENMASK(31, 14), val);
228ea5d99d0SRyder Lee 
229ea5d99d0SRyder Lee 		msta->ack_signal =
230ea5d99d0SRyder Lee 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
231ea5d99d0SRyder Lee 
232ea5d99d0SRyder Lee 		ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
23398686cd2SShayne Chen 	}
23498686cd2SShayne Chen 
23598686cd2SShayne Chen 	rcu_read_unlock();
23698686cd2SShayne Chen }
23798686cd2SShayne Chen 
mt7996_mac_enable_rtscts(struct mt7996_dev * dev,struct ieee80211_vif * vif,bool enable)238d75e739bSRyder Lee void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
239d75e739bSRyder Lee 			      struct ieee80211_vif *vif, bool enable)
240d75e739bSRyder Lee {
241d75e739bSRyder Lee 	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
242d75e739bSRyder Lee 	u32 addr;
243d75e739bSRyder Lee 
244d75e739bSRyder Lee 	addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
245d75e739bSRyder Lee 	if (enable)
246d75e739bSRyder Lee 		mt76_set(dev, addr, BIT(5));
247d75e739bSRyder Lee 	else
248d75e739bSRyder Lee 		mt76_clear(dev, addr, BIT(5));
249d75e739bSRyder Lee }
250d75e739bSRyder Lee 
mt7996_mac_set_fixed_rate_table(struct mt7996_dev * dev,u8 tbl_idx,u16 rate_idx)25115ee62e7SRyder Lee void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
25215ee62e7SRyder Lee 				     u8 tbl_idx, u16 rate_idx)
25315ee62e7SRyder Lee {
25415ee62e7SRyder Lee 	u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;
25515ee62e7SRyder Lee 
25615ee62e7SRyder Lee 	mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);
25715ee62e7SRyder Lee 	/* use wtbl spe idx */
25815ee62e7SRyder Lee 	mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);
25915ee62e7SRyder Lee 	mt76_wr(dev, MT_WTBL_ITCR, ctrl);
26015ee62e7SRyder Lee }
26115ee62e7SRyder Lee 
26298686cd2SShayne Chen /* The HW does not translate the mac header to 802.3 for mesh point */
mt7996_reverse_frag0_hdr_trans(struct sk_buff * skb,u16 hdr_gap)26398686cd2SShayne Chen static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
26498686cd2SShayne Chen {
26598686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
26698686cd2SShayne Chen 	struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
26798686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid;
26898686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
26998686cd2SShayne Chen 	struct ieee80211_sta *sta;
27098686cd2SShayne Chen 	struct ieee80211_vif *vif;
27198686cd2SShayne Chen 	struct ieee80211_hdr hdr;
27298686cd2SShayne Chen 	u16 frame_control;
27398686cd2SShayne Chen 
27498686cd2SShayne Chen 	if (le32_get_bits(rxd[3], MT_RXD3_NORMAL_ADDR_TYPE) !=
27598686cd2SShayne Chen 	    MT_RXD3_NORMAL_U2M)
27698686cd2SShayne Chen 		return -EINVAL;
27798686cd2SShayne Chen 
27898686cd2SShayne Chen 	if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
27998686cd2SShayne Chen 		return -EINVAL;
28098686cd2SShayne Chen 
28198686cd2SShayne Chen 	if (!msta || !msta->vif)
28298686cd2SShayne Chen 		return -EINVAL;
28398686cd2SShayne Chen 
28498686cd2SShayne Chen 	sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
28598686cd2SShayne Chen 	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
28698686cd2SShayne Chen 
28798686cd2SShayne Chen 	/* store the info from RXD and ethhdr to avoid being overridden */
28898686cd2SShayne Chen 	frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);
28998686cd2SShayne Chen 	hdr.frame_control = cpu_to_le16(frame_control);
29098686cd2SShayne Chen 	hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_SEQ_CTRL));
29198686cd2SShayne Chen 	hdr.duration_id = 0;
29298686cd2SShayne Chen 
29398686cd2SShayne Chen 	ether_addr_copy(hdr.addr1, vif->addr);
29498686cd2SShayne Chen 	ether_addr_copy(hdr.addr2, sta->addr);
29598686cd2SShayne Chen 	switch (frame_control & (IEEE80211_FCTL_TODS |
29698686cd2SShayne Chen 				 IEEE80211_FCTL_FROMDS)) {
29798686cd2SShayne Chen 	case 0:
29898686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
29998686cd2SShayne Chen 		break;
30098686cd2SShayne Chen 	case IEEE80211_FCTL_FROMDS:
30198686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_source);
30298686cd2SShayne Chen 		break;
30398686cd2SShayne Chen 	case IEEE80211_FCTL_TODS:
30498686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
30598686cd2SShayne Chen 		break;
30698686cd2SShayne Chen 	case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
30798686cd2SShayne Chen 		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
30898686cd2SShayne Chen 		ether_addr_copy(hdr.addr4, eth_hdr->h_source);
30998686cd2SShayne Chen 		break;
31098686cd2SShayne Chen 	default:
311aed8d9b5SLorenzo Bianconi 		return -EINVAL;
31298686cd2SShayne Chen 	}
31398686cd2SShayne Chen 
31498686cd2SShayne Chen 	skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
31598686cd2SShayne Chen 	if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
31698686cd2SShayne Chen 	    eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
31798686cd2SShayne Chen 		ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
31898686cd2SShayne Chen 	else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
31998686cd2SShayne Chen 		ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
32098686cd2SShayne Chen 	else
32198686cd2SShayne Chen 		skb_pull(skb, 2);
32298686cd2SShayne Chen 
32398686cd2SShayne Chen 	if (ieee80211_has_order(hdr.frame_control))
32498686cd2SShayne Chen 		memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[11],
32598686cd2SShayne Chen 		       IEEE80211_HT_CTL_LEN);
32698686cd2SShayne Chen 	if (ieee80211_is_data_qos(hdr.frame_control)) {
32798686cd2SShayne Chen 		__le16 qos_ctrl;
32898686cd2SShayne Chen 
32998686cd2SShayne Chen 		qos_ctrl = cpu_to_le16(le32_get_bits(rxd[10], MT_RXD10_QOS_CTL));
33098686cd2SShayne Chen 		memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
33198686cd2SShayne Chen 		       IEEE80211_QOS_CTL_LEN);
33298686cd2SShayne Chen 	}
33398686cd2SShayne Chen 
33498686cd2SShayne Chen 	if (ieee80211_has_a4(hdr.frame_control))
33598686cd2SShayne Chen 		memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
33698686cd2SShayne Chen 	else
33798686cd2SShayne Chen 		memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
33898686cd2SShayne Chen 
33998686cd2SShayne Chen 	return 0;
34098686cd2SShayne Chen }
34198686cd2SShayne Chen 
34298686cd2SShayne Chen static int
mt7996_mac_fill_rx_rate(struct mt7996_dev * dev,struct mt76_rx_status * status,struct ieee80211_supported_band * sband,__le32 * rxv,u8 * mode)34398686cd2SShayne Chen mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
34498686cd2SShayne Chen 			struct mt76_rx_status *status,
34598686cd2SShayne Chen 			struct ieee80211_supported_band *sband,
34698686cd2SShayne Chen 			__le32 *rxv, u8 *mode)
34798686cd2SShayne Chen {
34898686cd2SShayne Chen 	u32 v0, v2;
34998686cd2SShayne Chen 	u8 stbc, gi, bw, dcm, nss;
35098686cd2SShayne Chen 	int i, idx;
35198686cd2SShayne Chen 	bool cck = false;
35298686cd2SShayne Chen 
35398686cd2SShayne Chen 	v0 = le32_to_cpu(rxv[0]);
35498686cd2SShayne Chen 	v2 = le32_to_cpu(rxv[2]);
35598686cd2SShayne Chen 
35698686cd2SShayne Chen 	idx = FIELD_GET(MT_PRXV_TX_RATE, v0);
35798686cd2SShayne Chen 	i = idx;
35898686cd2SShayne Chen 	nss = FIELD_GET(MT_PRXV_NSTS, v0) + 1;
35998686cd2SShayne Chen 
36098686cd2SShayne Chen 	stbc = FIELD_GET(MT_PRXV_HT_STBC, v2);
36198686cd2SShayne Chen 	gi = FIELD_GET(MT_PRXV_HT_SHORT_GI, v2);
36298686cd2SShayne Chen 	*mode = FIELD_GET(MT_PRXV_TX_MODE, v2);
36398686cd2SShayne Chen 	dcm = FIELD_GET(MT_PRXV_DCM, v2);
36498686cd2SShayne Chen 	bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2);
36598686cd2SShayne Chen 
36698686cd2SShayne Chen 	switch (*mode) {
36798686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
36898686cd2SShayne Chen 		cck = true;
36998686cd2SShayne Chen 		fallthrough;
37098686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
37198686cd2SShayne Chen 		i = mt76_get_rate(&dev->mt76, sband, i, cck);
37298686cd2SShayne Chen 		break;
37398686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
37498686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
37598686cd2SShayne Chen 		status->encoding = RX_ENC_HT;
37698686cd2SShayne Chen 		if (gi)
37798686cd2SShayne Chen 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
37898686cd2SShayne Chen 		if (i > 31)
37998686cd2SShayne Chen 			return -EINVAL;
38098686cd2SShayne Chen 		break;
38198686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
38298686cd2SShayne Chen 		status->nss = nss;
38398686cd2SShayne Chen 		status->encoding = RX_ENC_VHT;
38498686cd2SShayne Chen 		if (gi)
38598686cd2SShayne Chen 			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
38698686cd2SShayne Chen 		if (i > 11)
38798686cd2SShayne Chen 			return -EINVAL;
38898686cd2SShayne Chen 		break;
38998686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
39098686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
39198686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
39298686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
39398686cd2SShayne Chen 		status->nss = nss;
39498686cd2SShayne Chen 		status->encoding = RX_ENC_HE;
39598686cd2SShayne Chen 		i &= GENMASK(3, 0);
39698686cd2SShayne Chen 
39798686cd2SShayne Chen 		if (gi <= NL80211_RATE_INFO_HE_GI_3_2)
39898686cd2SShayne Chen 			status->he_gi = gi;
39998686cd2SShayne Chen 
40098686cd2SShayne Chen 		status->he_dcm = dcm;
40198686cd2SShayne Chen 		break;
40280f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
40380f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
40480f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
40580f5a31dSShayne Chen 		status->nss = nss;
406021af945SShayne Chen 		status->encoding = RX_ENC_EHT;
407021af945SShayne Chen 		i &= GENMASK(3, 0);
408021af945SShayne Chen 
409021af945SShayne Chen 		if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
410021af945SShayne Chen 			status->eht.gi = gi;
41180f5a31dSShayne Chen 		break;
41298686cd2SShayne Chen 	default:
41398686cd2SShayne Chen 		return -EINVAL;
41498686cd2SShayne Chen 	}
41598686cd2SShayne Chen 	status->rate_idx = i;
41698686cd2SShayne Chen 
41798686cd2SShayne Chen 	switch (bw) {
41898686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_20:
41998686cd2SShayne Chen 		break;
42098686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
42198686cd2SShayne Chen 		if (*mode & MT_PHY_TYPE_HE_EXT_SU &&
42298686cd2SShayne Chen 		    (idx & MT_PRXV_TX_ER_SU_106T)) {
42398686cd2SShayne Chen 			status->bw = RATE_INFO_BW_HE_RU;
42498686cd2SShayne Chen 			status->he_ru =
42598686cd2SShayne Chen 				NL80211_RATE_INFO_HE_RU_ALLOC_106;
42698686cd2SShayne Chen 		} else {
42798686cd2SShayne Chen 			status->bw = RATE_INFO_BW_40;
42898686cd2SShayne Chen 		}
42998686cd2SShayne Chen 		break;
43098686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
43198686cd2SShayne Chen 		status->bw = RATE_INFO_BW_80;
43298686cd2SShayne Chen 		break;
43398686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
43498686cd2SShayne Chen 		status->bw = RATE_INFO_BW_160;
43598686cd2SShayne Chen 		break;
436a4fcd1caSPeter Chiu 	/* rxv reports bw 320-1 and 320-2 separately */
43780f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
438a4fcd1caSPeter Chiu 	case IEEE80211_STA_RX_BW_320 + 1:
43980f5a31dSShayne Chen 		status->bw = RATE_INFO_BW_320;
44080f5a31dSShayne Chen 		break;
44198686cd2SShayne Chen 	default:
44298686cd2SShayne Chen 		return -EINVAL;
44398686cd2SShayne Chen 	}
44498686cd2SShayne Chen 
44598686cd2SShayne Chen 	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
44698686cd2SShayne Chen 	if (*mode < MT_PHY_TYPE_HE_SU && gi)
44798686cd2SShayne Chen 		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
44898686cd2SShayne Chen 
44998686cd2SShayne Chen 	return 0;
45098686cd2SShayne Chen }
45198686cd2SShayne Chen 
45298686cd2SShayne Chen static int
mt7996_mac_fill_rx(struct mt7996_dev * dev,struct sk_buff * skb)45398686cd2SShayne Chen mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
45498686cd2SShayne Chen {
45598686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
45698686cd2SShayne Chen 	struct mt76_phy *mphy = &dev->mt76.phy;
45798686cd2SShayne Chen 	struct mt7996_phy *phy = &dev->phy;
45898686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
45998686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
46098686cd2SShayne Chen 	__le32 *rxv = NULL;
46198686cd2SShayne Chen 	u32 rxd0 = le32_to_cpu(rxd[0]);
46298686cd2SShayne Chen 	u32 rxd1 = le32_to_cpu(rxd[1]);
46398686cd2SShayne Chen 	u32 rxd2 = le32_to_cpu(rxd[2]);
46498686cd2SShayne Chen 	u32 rxd3 = le32_to_cpu(rxd[3]);
46598686cd2SShayne Chen 	u32 rxd4 = le32_to_cpu(rxd[4]);
46698686cd2SShayne Chen 	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
46798686cd2SShayne Chen 	u32 csum_status = *(u32 *)skb->cb;
46827db47abSRyder Lee 	u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP;
46927db47abSRyder Lee 	bool is_mesh = (rxd0 & mesh_mask) == mesh_mask;
47098686cd2SShayne Chen 	bool unicast, insert_ccmp_hdr = false;
47198686cd2SShayne Chen 	u8 remove_pad, amsdu_info, band_idx;
47298686cd2SShayne Chen 	u8 mode = 0, qos_ctl = 0;
47398686cd2SShayne Chen 	bool hdr_trans;
47498686cd2SShayne Chen 	u16 hdr_gap;
47598686cd2SShayne Chen 	u16 seq_ctrl = 0;
47698686cd2SShayne Chen 	__le16 fc = 0;
47798686cd2SShayne Chen 	int idx;
47898686cd2SShayne Chen 
47998686cd2SShayne Chen 	memset(status, 0, sizeof(*status));
48098686cd2SShayne Chen 
48198686cd2SShayne Chen 	band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
48298686cd2SShayne Chen 	mphy = dev->mt76.phys[band_idx];
48398686cd2SShayne Chen 	phy = mphy->priv;
48498686cd2SShayne Chen 	status->phy_idx = mphy->band_idx;
48598686cd2SShayne Chen 
48698686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
48798686cd2SShayne Chen 		return -EINVAL;
48898686cd2SShayne Chen 
48998686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
49098686cd2SShayne Chen 		return -EINVAL;
49198686cd2SShayne Chen 
49298686cd2SShayne Chen 	hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
49398686cd2SShayne Chen 	if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
49498686cd2SShayne Chen 		return -EINVAL;
49598686cd2SShayne Chen 
49698686cd2SShayne Chen 	/* ICV error or CCMP/BIP/WPI MIC error */
49798686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
49898686cd2SShayne Chen 		status->flag |= RX_FLAG_ONLY_MONITOR;
49998686cd2SShayne Chen 
50098686cd2SShayne Chen 	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
50198686cd2SShayne Chen 	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
50298686cd2SShayne Chen 	status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
50398686cd2SShayne Chen 
50498686cd2SShayne Chen 	if (status->wcid) {
50598686cd2SShayne Chen 		struct mt7996_sta *msta;
50698686cd2SShayne Chen 
50798686cd2SShayne Chen 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
508ea0f3867SLorenzo Bianconi 		spin_lock_bh(&dev->mt76.sta_poll_lock);
509e3b0311fSLorenzo Bianconi 		if (list_empty(&msta->wcid.poll_list))
510e3b0311fSLorenzo Bianconi 			list_add_tail(&msta->wcid.poll_list,
511ea0f3867SLorenzo Bianconi 				      &dev->mt76.sta_poll_list);
512ea0f3867SLorenzo Bianconi 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
51398686cd2SShayne Chen 	}
51498686cd2SShayne Chen 
51598686cd2SShayne Chen 	status->freq = mphy->chandef.chan->center_freq;
51698686cd2SShayne Chen 	status->band = mphy->chandef.chan->band;
51798686cd2SShayne Chen 	if (status->band == NL80211_BAND_5GHZ)
51898686cd2SShayne Chen 		sband = &mphy->sband_5g.sband;
51998686cd2SShayne Chen 	else if (status->band == NL80211_BAND_6GHZ)
52098686cd2SShayne Chen 		sband = &mphy->sband_6g.sband;
52198686cd2SShayne Chen 	else
52298686cd2SShayne Chen 		sband = &mphy->sband_2g.sband;
52398686cd2SShayne Chen 
52498686cd2SShayne Chen 	if (!sband->channels)
52598686cd2SShayne Chen 		return -EINVAL;
52698686cd2SShayne Chen 
52798686cd2SShayne Chen 	if ((rxd0 & csum_mask) == csum_mask &&
52898686cd2SShayne Chen 	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
52998686cd2SShayne Chen 		skb->ip_summed = CHECKSUM_UNNECESSARY;
53098686cd2SShayne Chen 
53198686cd2SShayne Chen 	if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
53298686cd2SShayne Chen 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
53398686cd2SShayne Chen 
53498686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
53598686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_ERROR;
53698686cd2SShayne Chen 
53798686cd2SShayne Chen 	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
53898686cd2SShayne Chen 	    !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
53998686cd2SShayne Chen 		status->flag |= RX_FLAG_DECRYPTED;
54098686cd2SShayne Chen 		status->flag |= RX_FLAG_IV_STRIPPED;
54198686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
54298686cd2SShayne Chen 	}
54398686cd2SShayne Chen 
54498686cd2SShayne Chen 	remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
54598686cd2SShayne Chen 
54698686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
54798686cd2SShayne Chen 		return -EINVAL;
54898686cd2SShayne Chen 
54998686cd2SShayne Chen 	rxd += 8;
55098686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
55198686cd2SShayne Chen 		u32 v0 = le32_to_cpu(rxd[0]);
55298686cd2SShayne Chen 		u32 v2 = le32_to_cpu(rxd[2]);
55398686cd2SShayne Chen 
55498686cd2SShayne Chen 		fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));
55598686cd2SShayne Chen 		qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);
55698686cd2SShayne Chen 		seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);
55798686cd2SShayne Chen 
55898686cd2SShayne Chen 		rxd += 4;
55998686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
56098686cd2SShayne Chen 			return -EINVAL;
56198686cd2SShayne Chen 	}
56298686cd2SShayne Chen 
56398686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
56498686cd2SShayne Chen 		u8 *data = (u8 *)rxd;
56598686cd2SShayne Chen 
56698686cd2SShayne Chen 		if (status->flag & RX_FLAG_DECRYPTED) {
56798686cd2SShayne Chen 			switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
56898686cd2SShayne Chen 			case MT_CIPHER_AES_CCMP:
56998686cd2SShayne Chen 			case MT_CIPHER_CCMP_CCX:
57098686cd2SShayne Chen 			case MT_CIPHER_CCMP_256:
57198686cd2SShayne Chen 				insert_ccmp_hdr =
57298686cd2SShayne Chen 					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
57398686cd2SShayne Chen 				fallthrough;
57498686cd2SShayne Chen 			case MT_CIPHER_TKIP:
57598686cd2SShayne Chen 			case MT_CIPHER_TKIP_NO_MIC:
57698686cd2SShayne Chen 			case MT_CIPHER_GCMP:
57798686cd2SShayne Chen 			case MT_CIPHER_GCMP_256:
57898686cd2SShayne Chen 				status->iv[0] = data[5];
57998686cd2SShayne Chen 				status->iv[1] = data[4];
58098686cd2SShayne Chen 				status->iv[2] = data[3];
58198686cd2SShayne Chen 				status->iv[3] = data[2];
58298686cd2SShayne Chen 				status->iv[4] = data[1];
58398686cd2SShayne Chen 				status->iv[5] = data[0];
58498686cd2SShayne Chen 				break;
58598686cd2SShayne Chen 			default:
58698686cd2SShayne Chen 				break;
58798686cd2SShayne Chen 			}
58898686cd2SShayne Chen 		}
58998686cd2SShayne Chen 		rxd += 4;
59098686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
59198686cd2SShayne Chen 			return -EINVAL;
59298686cd2SShayne Chen 	}
59398686cd2SShayne Chen 
59498686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
59598686cd2SShayne Chen 		status->timestamp = le32_to_cpu(rxd[0]);
59698686cd2SShayne Chen 		status->flag |= RX_FLAG_MACTIME_START;
59798686cd2SShayne Chen 
59898686cd2SShayne Chen 		if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
59998686cd2SShayne Chen 			status->flag |= RX_FLAG_AMPDU_DETAILS;
60098686cd2SShayne Chen 
60198686cd2SShayne Chen 			/* all subframes of an A-MPDU have the same timestamp */
60298686cd2SShayne Chen 			if (phy->rx_ampdu_ts != status->timestamp) {
60398686cd2SShayne Chen 				if (!++phy->ampdu_ref)
60498686cd2SShayne Chen 					phy->ampdu_ref++;
60598686cd2SShayne Chen 			}
60698686cd2SShayne Chen 			phy->rx_ampdu_ts = status->timestamp;
60798686cd2SShayne Chen 
60898686cd2SShayne Chen 			status->ampdu_ref = phy->ampdu_ref;
60998686cd2SShayne Chen 		}
61098686cd2SShayne Chen 
61198686cd2SShayne Chen 		rxd += 4;
61298686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
61398686cd2SShayne Chen 			return -EINVAL;
61498686cd2SShayne Chen 	}
61598686cd2SShayne Chen 
61698686cd2SShayne Chen 	/* RXD Group 3 - P-RXV */
61798686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
61898686cd2SShayne Chen 		u32 v3;
61998686cd2SShayne Chen 		int ret;
62098686cd2SShayne Chen 
62198686cd2SShayne Chen 		rxv = rxd;
62298686cd2SShayne Chen 		rxd += 4;
62398686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
62498686cd2SShayne Chen 			return -EINVAL;
62598686cd2SShayne Chen 
62698686cd2SShayne Chen 		v3 = le32_to_cpu(rxv[3]);
62798686cd2SShayne Chen 
62898686cd2SShayne Chen 		status->chains = mphy->antenna_mask;
62998686cd2SShayne Chen 		status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);
63098686cd2SShayne Chen 		status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);
63198686cd2SShayne Chen 		status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);
63298686cd2SShayne Chen 		status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);
63398686cd2SShayne Chen 
63498686cd2SShayne Chen 		/* RXD Group 5 - C-RXV */
63598686cd2SShayne Chen 		if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
63698686cd2SShayne Chen 			rxd += 24;
63798686cd2SShayne Chen 			if ((u8 *)rxd - skb->data >= skb->len)
63898686cd2SShayne Chen 				return -EINVAL;
63998686cd2SShayne Chen 		}
64098686cd2SShayne Chen 
64198686cd2SShayne Chen 		ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode);
64298686cd2SShayne Chen 		if (ret < 0)
64398686cd2SShayne Chen 			return ret;
64498686cd2SShayne Chen 	}
64598686cd2SShayne Chen 
64698686cd2SShayne Chen 	amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
64798686cd2SShayne Chen 	status->amsdu = !!amsdu_info;
64898686cd2SShayne Chen 	if (status->amsdu) {
64998686cd2SShayne Chen 		status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
65098686cd2SShayne Chen 		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
65198686cd2SShayne Chen 	}
65298686cd2SShayne Chen 
65398686cd2SShayne Chen 	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
65498686cd2SShayne Chen 	if (hdr_trans && ieee80211_has_morefrags(fc)) {
65598686cd2SShayne Chen 		if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
65698686cd2SShayne Chen 			return -EINVAL;
65798686cd2SShayne Chen 		hdr_trans = false;
65898686cd2SShayne Chen 	} else {
65998686cd2SShayne Chen 		int pad_start = 0;
66098686cd2SShayne Chen 
66198686cd2SShayne Chen 		skb_pull(skb, hdr_gap);
66227db47abSRyder Lee 		if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
66398686cd2SShayne Chen 			pad_start = ieee80211_get_hdrlen_from_skb(skb);
664c55b4e78SRyder Lee 		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
66598686cd2SShayne Chen 			/* When header translation failure is indicated,
66698686cd2SShayne Chen 			 * the hardware will insert an extra 2-byte field
66798686cd2SShayne Chen 			 * containing the data length after the protocol
668c55b4e78SRyder Lee 			 * type field. This happens either when the LLC-SNAP
669c55b4e78SRyder Lee 			 * pattern did not match, or if a VLAN header was
670c55b4e78SRyder Lee 			 * detected.
67198686cd2SShayne Chen 			 */
672c55b4e78SRyder Lee 			pad_start = 12;
673c55b4e78SRyder Lee 			if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
674c55b4e78SRyder Lee 				pad_start += 4;
675c55b4e78SRyder Lee 			else
676c55b4e78SRyder Lee 				pad_start = 0;
67798686cd2SShayne Chen 		}
67898686cd2SShayne Chen 
67998686cd2SShayne Chen 		if (pad_start) {
68098686cd2SShayne Chen 			memmove(skb->data + 2, skb->data, pad_start);
68198686cd2SShayne Chen 			skb_pull(skb, 2);
68298686cd2SShayne Chen 		}
68398686cd2SShayne Chen 	}
68498686cd2SShayne Chen 
68598686cd2SShayne Chen 	if (!hdr_trans) {
68698686cd2SShayne Chen 		struct ieee80211_hdr *hdr;
68798686cd2SShayne Chen 
68898686cd2SShayne Chen 		if (insert_ccmp_hdr) {
68998686cd2SShayne Chen 			u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
69098686cd2SShayne Chen 
69198686cd2SShayne Chen 			mt76_insert_ccmp_hdr(skb, key_id);
69298686cd2SShayne Chen 		}
69398686cd2SShayne Chen 
69498686cd2SShayne Chen 		hdr = mt76_skb_get_hdr(skb);
69598686cd2SShayne Chen 		fc = hdr->frame_control;
69698686cd2SShayne Chen 		if (ieee80211_is_data_qos(fc)) {
69727db47abSRyder Lee 			u8 *qos = ieee80211_get_qos_ctl(hdr);
69827db47abSRyder Lee 
69998686cd2SShayne Chen 			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
70027db47abSRyder Lee 			qos_ctl = *qos;
70127db47abSRyder Lee 
70227db47abSRyder Lee 			/* Mesh DA/SA/Length will be stripped after hardware
70327db47abSRyder Lee 			 * de-amsdu, so here needs to clear amsdu present bit
70427db47abSRyder Lee 			 * to mark it as a normal mesh frame.
70527db47abSRyder Lee 			 */
70627db47abSRyder Lee 			if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
70727db47abSRyder Lee 				*qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
70898686cd2SShayne Chen 		}
70998686cd2SShayne Chen 	} else {
71098686cd2SShayne Chen 		status->flag |= RX_FLAG_8023;
71198686cd2SShayne Chen 	}
71298686cd2SShayne Chen 
71398686cd2SShayne Chen 	if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
71446d3304dSLorenzo Bianconi 		mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
71598686cd2SShayne Chen 
71698686cd2SShayne Chen 	if (!status->wcid || !ieee80211_is_data_qos(fc))
71798686cd2SShayne Chen 		return 0;
71898686cd2SShayne Chen 
71998686cd2SShayne Chen 	status->aggr = unicast &&
72098686cd2SShayne Chen 		       !ieee80211_is_qos_nullfunc(fc);
72198686cd2SShayne Chen 	status->qos_ctl = qos_ctl;
72298686cd2SShayne Chen 	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
72398686cd2SShayne Chen 
72498686cd2SShayne Chen 	return 0;
72598686cd2SShayne Chen }
72698686cd2SShayne Chen 
72798686cd2SShayne Chen static void
mt7996_mac_write_txwi_8023(struct mt7996_dev * dev,__le32 * txwi,struct sk_buff * skb,struct mt76_wcid * wcid)72898686cd2SShayne Chen mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
72998686cd2SShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid)
73098686cd2SShayne Chen {
73198686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
73298686cd2SShayne Chen 	u8 fc_type, fc_stype;
73398686cd2SShayne Chen 	u16 ethertype;
73498686cd2SShayne Chen 	bool wmm = false;
73598686cd2SShayne Chen 	u32 val;
73698686cd2SShayne Chen 
73798686cd2SShayne Chen 	if (wcid->sta) {
73898686cd2SShayne Chen 		struct ieee80211_sta *sta;
73998686cd2SShayne Chen 
74098686cd2SShayne Chen 		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
74198686cd2SShayne Chen 		wmm = sta->wme;
74298686cd2SShayne Chen 	}
74398686cd2SShayne Chen 
74498686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
74598686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
74698686cd2SShayne Chen 
74798686cd2SShayne Chen 	ethertype = get_unaligned_be16(&skb->data[12]);
74898686cd2SShayne Chen 	if (ethertype >= ETH_P_802_3_MIN)
74998686cd2SShayne Chen 		val |= MT_TXD1_ETH_802_3;
75098686cd2SShayne Chen 
75198686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
75298686cd2SShayne Chen 
75398686cd2SShayne Chen 	fc_type = IEEE80211_FTYPE_DATA >> 2;
75498686cd2SShayne Chen 	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
75598686cd2SShayne Chen 
75698686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
75798686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
75898686cd2SShayne Chen 
75998686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
7601152c2cdSPeter Chiu 
7611152c2cdSPeter Chiu 	if (wcid->amsdu)
7621152c2cdSPeter Chiu 		txwi[3] |= cpu_to_le32(MT_TXD3_HW_AMSDU);
76398686cd2SShayne Chen }
76498686cd2SShayne Chen 
76598686cd2SShayne Chen static void
mt7996_mac_write_txwi_80211(struct mt7996_dev * dev,__le32 * txwi,struct sk_buff * skb,struct ieee80211_key_conf * key)76698686cd2SShayne Chen mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
76798686cd2SShayne Chen 			    struct sk_buff *skb, struct ieee80211_key_conf *key)
76898686cd2SShayne Chen {
76998686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
77098686cd2SShayne Chen 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
77198686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
77298686cd2SShayne Chen 	bool multicast = is_multicast_ether_addr(hdr->addr1);
77398686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
77498686cd2SShayne Chen 	__le16 fc = hdr->frame_control;
77598686cd2SShayne Chen 	u8 fc_type, fc_stype;
77698686cd2SShayne Chen 	u32 val;
77798686cd2SShayne Chen 
77898686cd2SShayne Chen 	if (ieee80211_is_action(fc) &&
77998686cd2SShayne Chen 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
78098686cd2SShayne Chen 	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
78198686cd2SShayne Chen 		tid = MT_TX_ADDBA;
78298686cd2SShayne Chen 	else if (ieee80211_is_mgmt(hdr->frame_control))
78398686cd2SShayne Chen 		tid = MT_TX_NORMAL;
78498686cd2SShayne Chen 
78598686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
78698686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_HDR_INFO,
78798686cd2SShayne Chen 			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
78898686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
78998686cd2SShayne Chen 
79098686cd2SShayne Chen 	if (!ieee80211_is_data(fc) || multicast ||
79198686cd2SShayne Chen 	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
79298686cd2SShayne Chen 		val |= MT_TXD1_FIXED_RATE;
79398686cd2SShayne Chen 
79498686cd2SShayne Chen 	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
79598686cd2SShayne Chen 	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
79698686cd2SShayne Chen 		val |= MT_TXD1_BIP;
79798686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
79898686cd2SShayne Chen 	}
79998686cd2SShayne Chen 
80098686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
80198686cd2SShayne Chen 
80298686cd2SShayne Chen 	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
80398686cd2SShayne Chen 	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
80498686cd2SShayne Chen 
80598686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
80698686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
80798686cd2SShayne Chen 
80898686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
80998686cd2SShayne Chen 
81098686cd2SShayne Chen 	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
81198686cd2SShayne Chen 	if (ieee80211_is_beacon(fc)) {
81298686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
81398686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
81498686cd2SShayne Chen 	}
81598686cd2SShayne Chen 
81698686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
81798686cd2SShayne Chen 		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
81898686cd2SShayne Chen 
81998686cd2SShayne Chen 		if (ieee80211_is_back_req(hdr->frame_control)) {
82098686cd2SShayne Chen 			struct ieee80211_bar *bar;
82198686cd2SShayne Chen 
82298686cd2SShayne Chen 			bar = (struct ieee80211_bar *)skb->data;
82398686cd2SShayne Chen 			seqno = le16_to_cpu(bar->start_seq_num);
82498686cd2SShayne Chen 		}
82598686cd2SShayne Chen 
82698686cd2SShayne Chen 		val = MT_TXD3_SN_VALID |
82798686cd2SShayne Chen 		      FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
82898686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(val);
82998686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
83098686cd2SShayne Chen 	}
83198686cd2SShayne Chen }
83298686cd2SShayne Chen 
mt7996_mac_write_txwi(struct mt7996_dev * dev,__le32 * txwi,struct sk_buff * skb,struct mt76_wcid * wcid,struct ieee80211_key_conf * key,int pid,enum mt76_txq_id qid,u32 changed)83398686cd2SShayne Chen void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
834d0b6f86fSShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid,
835d0b6f86fSShayne Chen 			   struct ieee80211_key_conf *key, int pid,
836d0b6f86fSShayne Chen 			   enum mt76_txq_id qid, u32 changed)
83798686cd2SShayne Chen {
83898686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
83998686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
84098686cd2SShayne Chen 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
84198686cd2SShayne Chen 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
84298686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
8430cb065b9SLorenzo Bianconi 	struct mt76_vif *mvif;
84498686cd2SShayne Chen 	u16 tx_count = 15;
84598686cd2SShayne Chen 	u32 val;
84698686cd2SShayne Chen 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
84798686cd2SShayne Chen 					 BSS_CHANGED_FILS_DISCOVERY));
848d0355945SMeiChia Chiu 	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
849d0355945SMeiChia Chiu 				    BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
85098686cd2SShayne Chen 
8510cb065b9SLorenzo Bianconi 	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
852ead44902SLorenzo Bianconi 	if (mvif) {
8530cb065b9SLorenzo Bianconi 		omac_idx = mvif->omac_idx;
8540cb065b9SLorenzo Bianconi 		wmm_idx = mvif->wmm_idx;
8550cb065b9SLorenzo Bianconi 		band_idx = mvif->band_idx;
85698686cd2SShayne Chen 	}
85798686cd2SShayne Chen 
85898686cd2SShayne Chen 	if (inband_disc) {
85998686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
86098686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
86198686cd2SShayne Chen 	} else if (beacon) {
86298686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
86398686cd2SShayne Chen 		q_idx = MT_LMAC_BCN0;
864d0b6f86fSShayne Chen 	} else if (qid >= MT_TXQ_PSD) {
86598686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
86698686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
86798686cd2SShayne Chen 	} else {
86898686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
86998686cd2SShayne Chen 		q_idx = wmm_idx * MT7996_MAX_WMM_SETS +
87098686cd2SShayne Chen 			mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
87198686cd2SShayne Chen 	}
87298686cd2SShayne Chen 
87398686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
87498686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
87598686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
87698686cd2SShayne Chen 	txwi[0] = cpu_to_le32(val);
87798686cd2SShayne Chen 
87898686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
87998686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
88098686cd2SShayne Chen 
88198686cd2SShayne Chen 	if (band_idx)
88298686cd2SShayne Chen 		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
88398686cd2SShayne Chen 
88498686cd2SShayne Chen 	txwi[1] = cpu_to_le32(val);
88598686cd2SShayne Chen 	txwi[2] = 0;
88698686cd2SShayne Chen 
88798686cd2SShayne Chen 	val = MT_TXD3_SW_POWER_MGMT |
88898686cd2SShayne Chen 	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
88998686cd2SShayne Chen 	if (key)
89098686cd2SShayne Chen 		val |= MT_TXD3_PROTECT_FRAME;
89198686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
89298686cd2SShayne Chen 		val |= MT_TXD3_NO_ACK;
89398686cd2SShayne Chen 
89498686cd2SShayne Chen 	txwi[3] = cpu_to_le32(val);
89598686cd2SShayne Chen 	txwi[4] = 0;
89698686cd2SShayne Chen 
89798686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD5_PID, pid);
89898686cd2SShayne Chen 	if (pid >= MT_PACKET_ID_FIRST)
89998686cd2SShayne Chen 		val |= MT_TXD5_TX_STATUS_HOST;
90098686cd2SShayne Chen 	txwi[5] = cpu_to_le32(val);
90198686cd2SShayne Chen 
90298686cd2SShayne Chen 	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
90398686cd2SShayne Chen 	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
90498686cd2SShayne Chen 	txwi[6] = cpu_to_le32(val);
90598686cd2SShayne Chen 	txwi[7] = 0;
90698686cd2SShayne Chen 
90798686cd2SShayne Chen 	if (is_8023)
90898686cd2SShayne Chen 		mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);
90998686cd2SShayne Chen 	else
91098686cd2SShayne Chen 		mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
91198686cd2SShayne Chen 
91298686cd2SShayne Chen 	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
913ab0eec4bSRyder Lee 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
914ab0eec4bSRyder Lee 		bool mcast = ieee80211_is_data(hdr->frame_control) &&
915ab0eec4bSRyder Lee 			     is_multicast_ether_addr(hdr->addr1);
916ead44902SLorenzo Bianconi 		u8 idx = MT7996_BASIC_RATES_TBL;
91798686cd2SShayne Chen 
918ead44902SLorenzo Bianconi 		if (mvif) {
919ab0eec4bSRyder Lee 			if (mcast && mvif->mcast_rates_idx)
920ab0eec4bSRyder Lee 				idx = mvif->mcast_rates_idx;
921c2171b06SRyder Lee 			else if (beacon && mvif->beacon_rates_idx)
922c2171b06SRyder Lee 				idx = mvif->beacon_rates_idx;
923ead44902SLorenzo Bianconi 			else
924ead44902SLorenzo Bianconi 				idx = mvif->basic_rates_idx;
925ead44902SLorenzo Bianconi 		}
926ab0eec4bSRyder Lee 
927cdc26ee8SRyder Lee 		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
92898686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
92998686cd2SShayne Chen 	}
93098686cd2SShayne Chen }
93198686cd2SShayne Chen 
mt7996_tx_prepare_skb(struct mt76_dev * mdev,void * txwi_ptr,enum mt76_txq_id qid,struct mt76_wcid * wcid,struct ieee80211_sta * sta,struct mt76_tx_info * tx_info)93298686cd2SShayne Chen int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
93398686cd2SShayne Chen 			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
93498686cd2SShayne Chen 			  struct ieee80211_sta *sta,
93598686cd2SShayne Chen 			  struct mt76_tx_info *tx_info)
93698686cd2SShayne Chen {
93798686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
93898686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
93998686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
94098686cd2SShayne Chen 	struct ieee80211_key_conf *key = info->control.hw_key;
94198686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
9423c38dfc1SLorenzo Bianconi 	struct mt76_connac_txp_common *txp;
94398686cd2SShayne Chen 	struct mt76_txwi_cache *t;
94498686cd2SShayne Chen 	int id, i, pid, nbuf = tx_info->nbuf - 1;
94598686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
94698686cd2SShayne Chen 	u8 *txwi = (u8 *)txwi_ptr;
94798686cd2SShayne Chen 
94898686cd2SShayne Chen 	if (unlikely(tx_info->skb->len <= ETH_HLEN))
94998686cd2SShayne Chen 		return -EINVAL;
95098686cd2SShayne Chen 
95198686cd2SShayne Chen 	if (!wcid)
95298686cd2SShayne Chen 		wcid = &dev->mt76.global_wcid;
95398686cd2SShayne Chen 
95498686cd2SShayne Chen 	if (sta) {
95598686cd2SShayne Chen 		struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
95698686cd2SShayne Chen 
95798686cd2SShayne Chen 		if (time_after(jiffies, msta->jiffies + HZ / 4)) {
95898686cd2SShayne Chen 			info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
95998686cd2SShayne Chen 			msta->jiffies = jiffies;
96098686cd2SShayne Chen 		}
96198686cd2SShayne Chen 	}
96298686cd2SShayne Chen 
96398686cd2SShayne Chen 	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
96498686cd2SShayne Chen 	t->skb = tx_info->skb;
96598686cd2SShayne Chen 
96698686cd2SShayne Chen 	id = mt76_token_consume(mdev, &t);
96798686cd2SShayne Chen 	if (id < 0)
96898686cd2SShayne Chen 		return id;
96998686cd2SShayne Chen 
97098686cd2SShayne Chen 	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
971d0b6f86fSShayne Chen 	mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
972d0b6f86fSShayne Chen 			      pid, qid, 0);
97398686cd2SShayne Chen 
9743c38dfc1SLorenzo Bianconi 	txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
97598686cd2SShayne Chen 	for (i = 0; i < nbuf; i++) {
9763c38dfc1SLorenzo Bianconi 		txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
9773c38dfc1SLorenzo Bianconi 		txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
97898686cd2SShayne Chen 	}
9793c38dfc1SLorenzo Bianconi 	txp->fw.nbuf = nbuf;
98098686cd2SShayne Chen 
9813b522cadSRyder Lee 	txp->fw.flags =
9823b522cadSRyder Lee 		cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD);
98398686cd2SShayne Chen 
98498686cd2SShayne Chen 	if (!key)
9853c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
98698686cd2SShayne Chen 
98798686cd2SShayne Chen 	if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
9883c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
98998686cd2SShayne Chen 
99098686cd2SShayne Chen 	if (vif) {
99198686cd2SShayne Chen 		struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
99298686cd2SShayne Chen 
9933c38dfc1SLorenzo Bianconi 		txp->fw.bss_idx = mvif->mt76.idx;
99498686cd2SShayne Chen 	}
99598686cd2SShayne Chen 
9963c38dfc1SLorenzo Bianconi 	txp->fw.token = cpu_to_le16(id);
9975ac5fbdcSPeter Chiu 	txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff);
9985ac5fbdcSPeter Chiu 
999730be160SFelix Fietkau 	tx_info->skb = NULL;
100098686cd2SShayne Chen 
100198686cd2SShayne Chen 	/* pass partial skb header to fw */
100298686cd2SShayne Chen 	tx_info->buf[1].len = MT_CT_PARSE_LEN;
100398686cd2SShayne Chen 	tx_info->buf[1].skip_unmap = true;
100498686cd2SShayne Chen 	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
100598686cd2SShayne Chen 
100698686cd2SShayne Chen 	return 0;
100798686cd2SShayne Chen }
100898686cd2SShayne Chen 
100998686cd2SShayne Chen static void
mt7996_tx_check_aggr(struct ieee80211_sta * sta,__le32 * txwi)101098686cd2SShayne Chen mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
101198686cd2SShayne Chen {
101298686cd2SShayne Chen 	struct mt7996_sta *msta;
101398686cd2SShayne Chen 	u16 fc, tid;
101498686cd2SShayne Chen 	u32 val;
101598686cd2SShayne Chen 
101698686cd2SShayne Chen 	if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
101798686cd2SShayne Chen 		return;
101898686cd2SShayne Chen 
101998686cd2SShayne Chen 	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
102098686cd2SShayne Chen 	if (tid >= 6) /* skip VO queue */
102198686cd2SShayne Chen 		return;
102298686cd2SShayne Chen 
102398686cd2SShayne Chen 	val = le32_to_cpu(txwi[2]);
102498686cd2SShayne Chen 	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
102598686cd2SShayne Chen 	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
102698686cd2SShayne Chen 	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
102798686cd2SShayne Chen 		return;
102898686cd2SShayne Chen 
102998686cd2SShayne Chen 	msta = (struct mt7996_sta *)sta->drv_priv;
1030ef591d74SLorenzo Bianconi 	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
103198686cd2SShayne Chen 		ieee80211_start_tx_ba_session(sta, tid, 0);
103298686cd2SShayne Chen }
103398686cd2SShayne Chen 
103498686cd2SShayne Chen static void
mt7996_txwi_free(struct mt7996_dev * dev,struct mt76_txwi_cache * t,struct ieee80211_sta * sta,struct list_head * free_list)103598686cd2SShayne Chen mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
103698686cd2SShayne Chen 		 struct ieee80211_sta *sta, struct list_head *free_list)
103798686cd2SShayne Chen {
103898686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
103998686cd2SShayne Chen 	struct mt76_wcid *wcid;
104098686cd2SShayne Chen 	__le32 *txwi;
104198686cd2SShayne Chen 	u16 wcid_idx;
104298686cd2SShayne Chen 
104330495864SLorenzo Bianconi 	mt76_connac_txp_skb_unmap(mdev, t);
104498686cd2SShayne Chen 	if (!t->skb)
104598686cd2SShayne Chen 		goto out;
104698686cd2SShayne Chen 
104798686cd2SShayne Chen 	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
104898686cd2SShayne Chen 	if (sta) {
104998686cd2SShayne Chen 		wcid = (struct mt76_wcid *)sta->drv_priv;
105098686cd2SShayne Chen 		wcid_idx = wcid->idx;
105198686cd2SShayne Chen 
105298686cd2SShayne Chen 		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
105398686cd2SShayne Chen 			mt7996_tx_check_aggr(sta, txwi);
105498686cd2SShayne Chen 	} else {
10555ac5fbdcSPeter Chiu 		wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);
105698686cd2SShayne Chen 	}
105798686cd2SShayne Chen 
105898686cd2SShayne Chen 	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
105998686cd2SShayne Chen 
106098686cd2SShayne Chen out:
106198686cd2SShayne Chen 	t->skb = NULL;
106298686cd2SShayne Chen 	mt76_put_txwi(mdev, t);
106398686cd2SShayne Chen }
106498686cd2SShayne Chen 
106598686cd2SShayne Chen static void
mt7996_mac_tx_free(struct mt7996_dev * dev,void * data,int len)106698686cd2SShayne Chen mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
106798686cd2SShayne Chen {
106898686cd2SShayne Chen 	__le32 *tx_free = (__le32 *)data, *cur_info;
106998686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
107098686cd2SShayne Chen 	struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
107198686cd2SShayne Chen 	struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
107298686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
107398686cd2SShayne Chen 	struct ieee80211_sta *sta = NULL;
107498686cd2SShayne Chen 	LIST_HEAD(free_list);
107598686cd2SShayne Chen 	struct sk_buff *skb, *tmp;
107698686cd2SShayne Chen 	void *end = data + len;
107798686cd2SShayne Chen 	bool wake = false;
107898686cd2SShayne Chen 	u16 total, count = 0;
107998686cd2SShayne Chen 
108098686cd2SShayne Chen 	/* clean DMA queues and unmap buffers first */
108198686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
108298686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
108398686cd2SShayne Chen 	if (phy2) {
108498686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false);
108598686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false);
108698686cd2SShayne Chen 	}
108798686cd2SShayne Chen 	if (phy3) {
108898686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false);
108998686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);
109098686cd2SShayne Chen 	}
109198686cd2SShayne Chen 
109298686cd2SShayne Chen 	if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))
109398686cd2SShayne Chen 		return;
109498686cd2SShayne Chen 
109598686cd2SShayne Chen 	total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);
109698686cd2SShayne Chen 	for (cur_info = &tx_free[2]; count < total; cur_info++) {
109798686cd2SShayne Chen 		u32 msdu, info;
109898686cd2SShayne Chen 		u8 i;
109998686cd2SShayne Chen 
110098686cd2SShayne Chen 		if (WARN_ON_ONCE((void *)cur_info >= end))
110198686cd2SShayne Chen 			return;
110298686cd2SShayne Chen 		/* 1'b1: new wcid pair.
110398686cd2SShayne Chen 		 * 1'b0: msdu_id with the same 'wcid pair' as above.
110498686cd2SShayne Chen 		 */
110598686cd2SShayne Chen 		info = le32_to_cpu(*cur_info);
110698686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_PAIR) {
110798686cd2SShayne Chen 			struct mt7996_sta *msta;
110898686cd2SShayne Chen 			struct mt76_wcid *wcid;
110998686cd2SShayne Chen 			u16 idx;
111098686cd2SShayne Chen 
111198686cd2SShayne Chen 			idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
111298686cd2SShayne Chen 			wcid = rcu_dereference(dev->mt76.wcid[idx]);
111398686cd2SShayne Chen 			sta = wcid_to_sta(wcid);
111498686cd2SShayne Chen 			if (!sta)
111598686cd2SShayne Chen 				continue;
111698686cd2SShayne Chen 
111798686cd2SShayne Chen 			msta = container_of(wcid, struct mt7996_sta, wcid);
1118ea0f3867SLorenzo Bianconi 			spin_lock_bh(&mdev->sta_poll_lock);
1119e3b0311fSLorenzo Bianconi 			if (list_empty(&msta->wcid.poll_list))
1120e3b0311fSLorenzo Bianconi 				list_add_tail(&msta->wcid.poll_list,
1121ea0f3867SLorenzo Bianconi 					      &mdev->sta_poll_list);
1122ea0f3867SLorenzo Bianconi 			spin_unlock_bh(&mdev->sta_poll_lock);
112398686cd2SShayne Chen 			continue;
112498686cd2SShayne Chen 		}
112598686cd2SShayne Chen 
112698686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_HEADER)
112798686cd2SShayne Chen 			continue;
112898686cd2SShayne Chen 
112998686cd2SShayne Chen 		for (i = 0; i < 2; i++) {
113098686cd2SShayne Chen 			msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;
113198686cd2SShayne Chen 			if (msdu == MT_TXFREE_INFO_MSDU_ID)
113298686cd2SShayne Chen 				continue;
113398686cd2SShayne Chen 
113498686cd2SShayne Chen 			count++;
113598686cd2SShayne Chen 			txwi = mt76_token_release(mdev, msdu, &wake);
113698686cd2SShayne Chen 			if (!txwi)
113798686cd2SShayne Chen 				continue;
113898686cd2SShayne Chen 
113998686cd2SShayne Chen 			mt7996_txwi_free(dev, txwi, sta, &free_list);
114098686cd2SShayne Chen 		}
114198686cd2SShayne Chen 	}
114298686cd2SShayne Chen 
114398686cd2SShayne Chen 	mt7996_mac_sta_poll(dev);
114498686cd2SShayne Chen 
114598686cd2SShayne Chen 	if (wake)
114698686cd2SShayne Chen 		mt76_set_tx_blocked(&dev->mt76, false);
114798686cd2SShayne Chen 
114898686cd2SShayne Chen 	mt76_worker_schedule(&dev->mt76.tx_worker);
114998686cd2SShayne Chen 
115098686cd2SShayne Chen 	list_for_each_entry_safe(skb, tmp, &free_list, list) {
115198686cd2SShayne Chen 		skb_list_del_init(skb);
115298686cd2SShayne Chen 		napi_consume_skb(skb, 1);
115398686cd2SShayne Chen 	}
115498686cd2SShayne Chen }
115598686cd2SShayne Chen 
115698686cd2SShayne Chen static bool
mt7996_mac_add_txs_skb(struct mt7996_dev * dev,struct mt76_wcid * wcid,int pid,__le32 * txs_data)1157d82e7c67SLorenzo Bianconi mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
1158d82e7c67SLorenzo Bianconi 		       int pid, __le32 *txs_data)
115998686cd2SShayne Chen {
1160d82e7c67SLorenzo Bianconi 	struct mt76_sta_stats *stats = &wcid->stats;
116198686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
116298686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
116398686cd2SShayne Chen 	struct mt76_phy *mphy;
116498686cd2SShayne Chen 	struct ieee80211_tx_info *info;
116598686cd2SShayne Chen 	struct sk_buff_head list;
116698686cd2SShayne Chen 	struct rate_info rate = {};
116798686cd2SShayne Chen 	struct sk_buff *skb;
116898686cd2SShayne Chen 	bool cck = false;
116998686cd2SShayne Chen 	u32 txrate, txs, mode, stbc;
117098686cd2SShayne Chen 
117198686cd2SShayne Chen 	mt76_tx_status_lock(mdev, &list);
117298686cd2SShayne Chen 	skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
117398686cd2SShayne Chen 	if (!skb)
117498686cd2SShayne Chen 		goto out_no_skb;
117598686cd2SShayne Chen 
117698686cd2SShayne Chen 	txs = le32_to_cpu(txs_data[0]);
117798686cd2SShayne Chen 
117898686cd2SShayne Chen 	info = IEEE80211_SKB_CB(skb);
117998686cd2SShayne Chen 	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
118098686cd2SShayne Chen 		info->flags |= IEEE80211_TX_STAT_ACK;
118198686cd2SShayne Chen 
118298686cd2SShayne Chen 	info->status.ampdu_len = 1;
118398686cd2SShayne Chen 	info->status.ampdu_ack_len = !!(info->flags &
118498686cd2SShayne Chen 					IEEE80211_TX_STAT_ACK);
118598686cd2SShayne Chen 
118698686cd2SShayne Chen 	info->status.rates[0].idx = -1;
118798686cd2SShayne Chen 
118898686cd2SShayne Chen 	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
118998686cd2SShayne Chen 
119098686cd2SShayne Chen 	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
119198686cd2SShayne Chen 	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
119298686cd2SShayne Chen 	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
119398686cd2SShayne Chen 
119498686cd2SShayne Chen 	if (stbc && rate.nss > 1)
119598686cd2SShayne Chen 		rate.nss >>= 1;
119698686cd2SShayne Chen 
119798686cd2SShayne Chen 	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
119898686cd2SShayne Chen 		stats->tx_nss[rate.nss - 1]++;
119998686cd2SShayne Chen 	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
120098686cd2SShayne Chen 		stats->tx_mcs[rate.mcs]++;
120198686cd2SShayne Chen 
120298686cd2SShayne Chen 	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
120398686cd2SShayne Chen 	switch (mode) {
120498686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
120598686cd2SShayne Chen 		cck = true;
120698686cd2SShayne Chen 		fallthrough;
120798686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
120898686cd2SShayne Chen 		mphy = mt76_dev_phy(mdev, wcid->phy_idx);
120998686cd2SShayne Chen 
121098686cd2SShayne Chen 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
121198686cd2SShayne Chen 			sband = &mphy->sband_5g.sband;
121298686cd2SShayne Chen 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
121398686cd2SShayne Chen 			sband = &mphy->sband_6g.sband;
121498686cd2SShayne Chen 		else
121598686cd2SShayne Chen 			sband = &mphy->sband_2g.sband;
121698686cd2SShayne Chen 
121798686cd2SShayne Chen 		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
121898686cd2SShayne Chen 		rate.legacy = sband->bitrates[rate.mcs].bitrate;
121998686cd2SShayne Chen 		break;
122098686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
122198686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
122298686cd2SShayne Chen 		if (rate.mcs > 31)
122398686cd2SShayne Chen 			goto out;
122498686cd2SShayne Chen 
122598686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_MCS;
122698686cd2SShayne Chen 		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
122798686cd2SShayne Chen 			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
122898686cd2SShayne Chen 		break;
122998686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
123098686cd2SShayne Chen 		if (rate.mcs > 9)
123198686cd2SShayne Chen 			goto out;
123298686cd2SShayne Chen 
123398686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
123498686cd2SShayne Chen 		break;
123598686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
123698686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
123798686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
123898686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
123998686cd2SShayne Chen 		if (rate.mcs > 11)
124098686cd2SShayne Chen 			goto out;
124198686cd2SShayne Chen 
124298686cd2SShayne Chen 		rate.he_gi = wcid->rate.he_gi;
124398686cd2SShayne Chen 		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
124498686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_HE_MCS;
124598686cd2SShayne Chen 		break;
124680f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
124780f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
124880f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
124980f5a31dSShayne Chen 		if (rate.mcs > 13)
125080f5a31dSShayne Chen 			goto out;
125180f5a31dSShayne Chen 
125280f5a31dSShayne Chen 		rate.eht_gi = wcid->rate.eht_gi;
125380f5a31dSShayne Chen 		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
125480f5a31dSShayne Chen 		break;
125598686cd2SShayne Chen 	default:
125698686cd2SShayne Chen 		goto out;
125798686cd2SShayne Chen 	}
125898686cd2SShayne Chen 
125998686cd2SShayne Chen 	stats->tx_mode[mode]++;
126098686cd2SShayne Chen 
126198686cd2SShayne Chen 	switch (FIELD_GET(MT_TXS0_BW, txs)) {
126280f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
126380f5a31dSShayne Chen 		rate.bw = RATE_INFO_BW_320;
126480f5a31dSShayne Chen 		stats->tx_bw[4]++;
126580f5a31dSShayne Chen 		break;
126698686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
126798686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_160;
126898686cd2SShayne Chen 		stats->tx_bw[3]++;
126998686cd2SShayne Chen 		break;
127098686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
127198686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_80;
127298686cd2SShayne Chen 		stats->tx_bw[2]++;
127398686cd2SShayne Chen 		break;
127498686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
127598686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_40;
127698686cd2SShayne Chen 		stats->tx_bw[1]++;
127798686cd2SShayne Chen 		break;
127898686cd2SShayne Chen 	default:
127998686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_20;
128098686cd2SShayne Chen 		stats->tx_bw[0]++;
128198686cd2SShayne Chen 		break;
128298686cd2SShayne Chen 	}
128398686cd2SShayne Chen 	wcid->rate = rate;
128498686cd2SShayne Chen 
128598686cd2SShayne Chen out:
128698686cd2SShayne Chen 	mt76_tx_status_skb_done(mdev, skb, &list);
128798686cd2SShayne Chen 
128898686cd2SShayne Chen out_no_skb:
128998686cd2SShayne Chen 	mt76_tx_status_unlock(mdev, &list);
129098686cd2SShayne Chen 
129198686cd2SShayne Chen 	return !!skb;
129298686cd2SShayne Chen }
129398686cd2SShayne Chen 
mt7996_mac_add_txs(struct mt7996_dev * dev,void * data)129498686cd2SShayne Chen static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
129598686cd2SShayne Chen {
129698686cd2SShayne Chen 	struct mt7996_sta *msta = NULL;
129798686cd2SShayne Chen 	struct mt76_wcid *wcid;
129898686cd2SShayne Chen 	__le32 *txs_data = data;
129998686cd2SShayne Chen 	u16 wcidx;
130098686cd2SShayne Chen 	u8 pid;
130198686cd2SShayne Chen 
130298686cd2SShayne Chen 	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
130398686cd2SShayne Chen 		return;
130498686cd2SShayne Chen 
130598686cd2SShayne Chen 	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
130698686cd2SShayne Chen 	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
130798686cd2SShayne Chen 
130898686cd2SShayne Chen 	if (pid < MT_PACKET_ID_FIRST)
130998686cd2SShayne Chen 		return;
131098686cd2SShayne Chen 
131143482540SShayne Chen 	if (wcidx >= mt7996_wtbl_size(dev))
131298686cd2SShayne Chen 		return;
131398686cd2SShayne Chen 
131498686cd2SShayne Chen 	rcu_read_lock();
131598686cd2SShayne Chen 
131698686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
131798686cd2SShayne Chen 	if (!wcid)
131898686cd2SShayne Chen 		goto out;
131998686cd2SShayne Chen 
132098686cd2SShayne Chen 	msta = container_of(wcid, struct mt7996_sta, wcid);
132198686cd2SShayne Chen 
1322d82e7c67SLorenzo Bianconi 	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
132398686cd2SShayne Chen 
132498686cd2SShayne Chen 	if (!wcid->sta)
132598686cd2SShayne Chen 		goto out;
132698686cd2SShayne Chen 
1327ea0f3867SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.sta_poll_lock);
1328e3b0311fSLorenzo Bianconi 	if (list_empty(&msta->wcid.poll_list))
1329e3b0311fSLorenzo Bianconi 		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
1330ea0f3867SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
133198686cd2SShayne Chen 
133298686cd2SShayne Chen out:
133398686cd2SShayne Chen 	rcu_read_unlock();
133498686cd2SShayne Chen }
133598686cd2SShayne Chen 
mt7996_rx_check(struct mt76_dev * mdev,void * data,int len)133698686cd2SShayne Chen bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
133798686cd2SShayne Chen {
133898686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
133998686cd2SShayne Chen 	__le32 *rxd = (__le32 *)data;
134098686cd2SShayne Chen 	__le32 *end = (__le32 *)&rxd[len / 4];
134198686cd2SShayne Chen 	enum rx_pkt_type type;
134298686cd2SShayne Chen 
134398686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
134498686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
134598686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
134698686cd2SShayne Chen 
134798686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
134898686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
134998686cd2SShayne Chen 			return true;
135098686cd2SShayne Chen 	}
135198686cd2SShayne Chen 
135298686cd2SShayne Chen 	switch (type) {
135398686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
135498686cd2SShayne Chen 		mt7996_mac_tx_free(dev, data, len);
135598686cd2SShayne Chen 		return false;
135698686cd2SShayne Chen 	case PKT_TYPE_TXS:
135798686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
135898686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
135998686cd2SShayne Chen 		return false;
136098686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
136198686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, data, len);
136298686cd2SShayne Chen 		return false;
136398686cd2SShayne Chen 	default:
136498686cd2SShayne Chen 		return true;
136598686cd2SShayne Chen 	}
136698686cd2SShayne Chen }
136798686cd2SShayne Chen 
mt7996_queue_rx_skb(struct mt76_dev * mdev,enum mt76_rxq_id q,struct sk_buff * skb,u32 * info)136898686cd2SShayne Chen void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
136998686cd2SShayne Chen 			 struct sk_buff *skb, u32 *info)
137098686cd2SShayne Chen {
137198686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
137298686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
137398686cd2SShayne Chen 	__le32 *end = (__le32 *)&skb->data[skb->len];
137498686cd2SShayne Chen 	enum rx_pkt_type type;
137598686cd2SShayne Chen 
137698686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
137798686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
137898686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
137998686cd2SShayne Chen 
138098686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
138198686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
138298686cd2SShayne Chen 			type = PKT_TYPE_NORMAL;
138398686cd2SShayne Chen 	}
138498686cd2SShayne Chen 
138598686cd2SShayne Chen 	switch (type) {
138698686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
138798686cd2SShayne Chen 		mt7996_mac_tx_free(dev, skb->data, skb->len);
138898686cd2SShayne Chen 		napi_consume_skb(skb, 1);
138998686cd2SShayne Chen 		break;
139098686cd2SShayne Chen 	case PKT_TYPE_RX_EVENT:
139198686cd2SShayne Chen 		mt7996_mcu_rx_event(dev, skb);
139298686cd2SShayne Chen 		break;
139398686cd2SShayne Chen 	case PKT_TYPE_TXS:
139498686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
139598686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
139698686cd2SShayne Chen 		dev_kfree_skb(skb);
139798686cd2SShayne Chen 		break;
139898686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
139998686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
140098686cd2SShayne Chen 		dev_kfree_skb(skb);
140198686cd2SShayne Chen 		break;
140298686cd2SShayne Chen 	case PKT_TYPE_NORMAL:
140398686cd2SShayne Chen 		if (!mt7996_mac_fill_rx(dev, skb)) {
140498686cd2SShayne Chen 			mt76_rx(&dev->mt76, q, skb);
140598686cd2SShayne Chen 			return;
140698686cd2SShayne Chen 		}
140798686cd2SShayne Chen 		fallthrough;
140898686cd2SShayne Chen 	default:
140998686cd2SShayne Chen 		dev_kfree_skb(skb);
141098686cd2SShayne Chen 		break;
141198686cd2SShayne Chen 	}
141298686cd2SShayne Chen }
141398686cd2SShayne Chen 
mt7996_mac_cca_stats_reset(struct mt7996_phy * phy)141498686cd2SShayne Chen void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
141598686cd2SShayne Chen {
141698686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
141798686cd2SShayne Chen 	u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx);
141898686cd2SShayne Chen 
141998686cd2SShayne Chen 	mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN);
142098686cd2SShayne Chen 	mt76_set(dev, reg, BIT(11) | BIT(9));
142198686cd2SShayne Chen }
142298686cd2SShayne Chen 
mt7996_mac_reset_counters(struct mt7996_phy * phy)142398686cd2SShayne Chen void mt7996_mac_reset_counters(struct mt7996_phy *phy)
142498686cd2SShayne Chen {
142598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
142698686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
142798686cd2SShayne Chen 	int i;
142898686cd2SShayne Chen 
142998686cd2SShayne Chen 	for (i = 0; i < 16; i++)
143098686cd2SShayne Chen 		mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
143198686cd2SShayne Chen 
143298686cd2SShayne Chen 	phy->mt76->survey_time = ktime_get_boottime();
143398686cd2SShayne Chen 
143498686cd2SShayne Chen 	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
143598686cd2SShayne Chen 
143698686cd2SShayne Chen 	/* reset airtime counters */
143798686cd2SShayne Chen 	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx),
143898686cd2SShayne Chen 		 MT_WF_RMAC_MIB_RXTIME_CLR);
143998686cd2SShayne Chen 
144098686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, true);
144198686cd2SShayne Chen }
144298686cd2SShayne Chen 
mt7996_mac_set_coverage_class(struct mt7996_phy * phy)144383a10ae2SPeter Chiu void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
144498686cd2SShayne Chen {
144598686cd2SShayne Chen 	s16 coverage_class = phy->coverage_class;
144698686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
144798686cd2SShayne Chen 	struct mt7996_phy *phy2 = mt7996_phy2(dev);
144898686cd2SShayne Chen 	struct mt7996_phy *phy3 = mt7996_phy3(dev);
144983a10ae2SPeter Chiu 	u32 reg_offset;
145098686cd2SShayne Chen 	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
145198686cd2SShayne Chen 		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
145298686cd2SShayne Chen 	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
145398686cd2SShayne Chen 		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
145498686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
145598686cd2SShayne Chen 	int offset;
145698686cd2SShayne Chen 
145798686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
145898686cd2SShayne Chen 		return;
145998686cd2SShayne Chen 
146098686cd2SShayne Chen 	if (phy2)
146198686cd2SShayne Chen 		coverage_class = max_t(s16, dev->phy.coverage_class,
146298686cd2SShayne Chen 				       phy2->coverage_class);
146398686cd2SShayne Chen 
146498686cd2SShayne Chen 	if (phy3)
146598686cd2SShayne Chen 		coverage_class = max_t(s16, coverage_class,
146698686cd2SShayne Chen 				       phy3->coverage_class);
146798686cd2SShayne Chen 
146898686cd2SShayne Chen 	offset = 3 * coverage_class;
146998686cd2SShayne Chen 	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
147098686cd2SShayne Chen 		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
147198686cd2SShayne Chen 
147298686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
147398686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
147498686cd2SShayne Chen }
147598686cd2SShayne Chen 
mt7996_mac_enable_nf(struct mt7996_dev * dev,u8 band)147698686cd2SShayne Chen void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
147798686cd2SShayne Chen {
147898686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band),
147998686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY |
148098686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR);
148198686cd2SShayne Chen 
148298686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band),
148398686cd2SShayne Chen 		 FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5));
148498686cd2SShayne Chen }
148598686cd2SShayne Chen 
148698686cd2SShayne Chen static u8
mt7996_phy_get_nf(struct mt7996_phy * phy,u8 band_idx)148798686cd2SShayne Chen mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
148898686cd2SShayne Chen {
148998686cd2SShayne Chen 	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
149098686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
149198686cd2SShayne Chen 	u32 val, sum = 0, n = 0;
149298686cd2SShayne Chen 	int ant, i;
149398686cd2SShayne Chen 
149498686cd2SShayne Chen 	for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) {
149598686cd2SShayne Chen 		u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant);
149698686cd2SShayne Chen 
149798686cd2SShayne Chen 		for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
149898686cd2SShayne Chen 			val = mt76_rr(dev, reg);
149998686cd2SShayne Chen 			sum += val * nf_power[i];
150098686cd2SShayne Chen 			n += val;
150198686cd2SShayne Chen 		}
150298686cd2SShayne Chen 	}
150398686cd2SShayne Chen 
150498686cd2SShayne Chen 	return n ? sum / n : 0;
150598686cd2SShayne Chen }
150698686cd2SShayne Chen 
mt7996_update_channel(struct mt76_phy * mphy)150798686cd2SShayne Chen void mt7996_update_channel(struct mt76_phy *mphy)
150898686cd2SShayne Chen {
150998686cd2SShayne Chen 	struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
151098686cd2SShayne Chen 	struct mt76_channel_state *state = mphy->chan_state;
151198686cd2SShayne Chen 	int nf;
151298686cd2SShayne Chen 
151398686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, false);
151498686cd2SShayne Chen 
151598686cd2SShayne Chen 	nf = mt7996_phy_get_nf(phy, mphy->band_idx);
151698686cd2SShayne Chen 	if (!phy->noise)
151798686cd2SShayne Chen 		phy->noise = nf << 4;
151898686cd2SShayne Chen 	else if (nf)
151998686cd2SShayne Chen 		phy->noise += nf - (phy->noise >> 4);
152098686cd2SShayne Chen 
152198686cd2SShayne Chen 	state->noise = -(phy->noise >> 4);
152298686cd2SShayne Chen }
152398686cd2SShayne Chen 
152498686cd2SShayne Chen static bool
mt7996_wait_reset_state(struct mt7996_dev * dev,u32 state)152598686cd2SShayne Chen mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
152698686cd2SShayne Chen {
152798686cd2SShayne Chen 	bool ret;
152898686cd2SShayne Chen 
152998686cd2SShayne Chen 	ret = wait_event_timeout(dev->reset_wait,
153027015b6fSBo Jiao 				 (READ_ONCE(dev->recovery.state) & state),
153198686cd2SShayne Chen 				 MT7996_RESET_TIMEOUT);
153298686cd2SShayne Chen 
153398686cd2SShayne Chen 	WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
153498686cd2SShayne Chen 	return ret;
153598686cd2SShayne Chen }
153698686cd2SShayne Chen 
153798686cd2SShayne Chen static void
mt7996_update_vif_beacon(void * priv,u8 * mac,struct ieee80211_vif * vif)153898686cd2SShayne Chen mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
153998686cd2SShayne Chen {
154098686cd2SShayne Chen 	struct ieee80211_hw *hw = priv;
154198686cd2SShayne Chen 
154298686cd2SShayne Chen 	switch (vif->type) {
154398686cd2SShayne Chen 	case NL80211_IFTYPE_MESH_POINT:
154498686cd2SShayne Chen 	case NL80211_IFTYPE_ADHOC:
154598686cd2SShayne Chen 	case NL80211_IFTYPE_AP:
154698686cd2SShayne Chen 		mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
154798686cd2SShayne Chen 		break;
154898686cd2SShayne Chen 	default:
154998686cd2SShayne Chen 		break;
155098686cd2SShayne Chen 	}
155198686cd2SShayne Chen }
155298686cd2SShayne Chen 
155398686cd2SShayne Chen static void
mt7996_update_beacons(struct mt7996_dev * dev)155498686cd2SShayne Chen mt7996_update_beacons(struct mt7996_dev *dev)
155598686cd2SShayne Chen {
155698686cd2SShayne Chen 	struct mt76_phy *phy2, *phy3;
155798686cd2SShayne Chen 
155898686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(dev->mt76.hw,
155998686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
156098686cd2SShayne Chen 					    mt7996_update_vif_beacon, dev->mt76.hw);
156198686cd2SShayne Chen 
156298686cd2SShayne Chen 	phy2 = dev->mt76.phys[MT_BAND1];
156398686cd2SShayne Chen 	if (!phy2)
156498686cd2SShayne Chen 		return;
156598686cd2SShayne Chen 
156698686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy2->hw,
156798686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
156898686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy2->hw);
156998686cd2SShayne Chen 
157098686cd2SShayne Chen 	phy3 = dev->mt76.phys[MT_BAND2];
157198686cd2SShayne Chen 	if (!phy3)
157298686cd2SShayne Chen 		return;
157398686cd2SShayne Chen 
157498686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy3->hw,
157598686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
157698686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy3->hw);
157798686cd2SShayne Chen }
157898686cd2SShayne Chen 
mt7996_tx_token_put(struct mt7996_dev * dev)157998686cd2SShayne Chen void mt7996_tx_token_put(struct mt7996_dev *dev)
158098686cd2SShayne Chen {
158198686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
158298686cd2SShayne Chen 	int id;
158398686cd2SShayne Chen 
158498686cd2SShayne Chen 	spin_lock_bh(&dev->mt76.token_lock);
158598686cd2SShayne Chen 	idr_for_each_entry(&dev->mt76.token, txwi, id) {
158698686cd2SShayne Chen 		mt7996_txwi_free(dev, txwi, NULL, NULL);
158798686cd2SShayne Chen 		dev->mt76.token_count--;
158898686cd2SShayne Chen 	}
158998686cd2SShayne Chen 	spin_unlock_bh(&dev->mt76.token_lock);
159098686cd2SShayne Chen 	idr_destroy(&dev->mt76.token);
159198686cd2SShayne Chen }
159298686cd2SShayne Chen 
159327015b6fSBo Jiao static int
mt7996_mac_restart(struct mt7996_dev * dev)159427015b6fSBo Jiao mt7996_mac_restart(struct mt7996_dev *dev)
159527015b6fSBo Jiao {
159627015b6fSBo Jiao 	struct mt7996_phy *phy2, *phy3;
159727015b6fSBo Jiao 	struct mt76_dev *mdev = &dev->mt76;
159827015b6fSBo Jiao 	int i, ret;
159927015b6fSBo Jiao 
160027015b6fSBo Jiao 	phy2 = mt7996_phy2(dev);
160127015b6fSBo Jiao 	phy3 = mt7996_phy3(dev);
160227015b6fSBo Jiao 
160327015b6fSBo Jiao 	if (dev->hif2) {
160427015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
160527015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
160627015b6fSBo Jiao 	}
160727015b6fSBo Jiao 
160827015b6fSBo Jiao 	if (dev_is_pci(mdev->dev)) {
160927015b6fSBo Jiao 		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
161027015b6fSBo Jiao 		if (dev->hif2)
161127015b6fSBo Jiao 			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
161227015b6fSBo Jiao 	}
161327015b6fSBo Jiao 
161427015b6fSBo Jiao 	set_bit(MT76_RESET, &dev->mphy.state);
161527015b6fSBo Jiao 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
161627015b6fSBo Jiao 	wake_up(&dev->mt76.mcu.wait);
161727015b6fSBo Jiao 	if (phy2) {
161827015b6fSBo Jiao 		set_bit(MT76_RESET, &phy2->mt76->state);
161927015b6fSBo Jiao 		set_bit(MT76_MCU_RESET, &phy2->mt76->state);
162027015b6fSBo Jiao 	}
162127015b6fSBo Jiao 	if (phy3) {
162227015b6fSBo Jiao 		set_bit(MT76_RESET, &phy3->mt76->state);
162327015b6fSBo Jiao 		set_bit(MT76_MCU_RESET, &phy3->mt76->state);
162427015b6fSBo Jiao 	}
162527015b6fSBo Jiao 
162627015b6fSBo Jiao 	/* lock/unlock all queues to ensure that no tx is pending */
162727015b6fSBo Jiao 	mt76_txq_schedule_all(&dev->mphy);
162827015b6fSBo Jiao 	if (phy2)
162927015b6fSBo Jiao 		mt76_txq_schedule_all(phy2->mt76);
163027015b6fSBo Jiao 	if (phy3)
163127015b6fSBo Jiao 		mt76_txq_schedule_all(phy3->mt76);
163227015b6fSBo Jiao 
163327015b6fSBo Jiao 	/* disable all tx/rx napi */
163427015b6fSBo Jiao 	mt76_worker_disable(&dev->mt76.tx_worker);
163527015b6fSBo Jiao 	mt76_for_each_q_rx(mdev, i) {
163627015b6fSBo Jiao 		if (mdev->q_rx[i].ndesc)
163727015b6fSBo Jiao 			napi_disable(&dev->mt76.napi[i]);
163827015b6fSBo Jiao 	}
163927015b6fSBo Jiao 	napi_disable(&dev->mt76.tx_napi);
164027015b6fSBo Jiao 
164127015b6fSBo Jiao 	/* token reinit */
164227015b6fSBo Jiao 	mt7996_tx_token_put(dev);
164327015b6fSBo Jiao 	idr_init(&dev->mt76.token);
164427015b6fSBo Jiao 
164527015b6fSBo Jiao 	mt7996_dma_reset(dev, true);
164627015b6fSBo Jiao 
164727015b6fSBo Jiao 	local_bh_disable();
164827015b6fSBo Jiao 	mt76_for_each_q_rx(mdev, i) {
164927015b6fSBo Jiao 		if (mdev->q_rx[i].ndesc) {
165027015b6fSBo Jiao 			napi_enable(&dev->mt76.napi[i]);
165127015b6fSBo Jiao 			napi_schedule(&dev->mt76.napi[i]);
165227015b6fSBo Jiao 		}
165327015b6fSBo Jiao 	}
165427015b6fSBo Jiao 	local_bh_enable();
165527015b6fSBo Jiao 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
165627015b6fSBo Jiao 	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
165727015b6fSBo Jiao 
165827015b6fSBo Jiao 	mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
165927015b6fSBo Jiao 	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
166027015b6fSBo Jiao 	if (dev->hif2) {
166127015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
166227015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
166327015b6fSBo Jiao 	}
166427015b6fSBo Jiao 	if (dev_is_pci(mdev->dev)) {
166527015b6fSBo Jiao 		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
166627015b6fSBo Jiao 		if (dev->hif2)
166727015b6fSBo Jiao 			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
166827015b6fSBo Jiao 	}
166927015b6fSBo Jiao 
167027015b6fSBo Jiao 	/* load firmware */
167127015b6fSBo Jiao 	ret = mt7996_mcu_init_firmware(dev);
167227015b6fSBo Jiao 	if (ret)
167327015b6fSBo Jiao 		goto out;
167427015b6fSBo Jiao 
167527015b6fSBo Jiao 	/* set the necessary init items */
167627015b6fSBo Jiao 	ret = mt7996_mcu_set_eeprom(dev);
167727015b6fSBo Jiao 	if (ret)
167827015b6fSBo Jiao 		goto out;
167927015b6fSBo Jiao 
168027015b6fSBo Jiao 	mt7996_mac_init(dev);
168127015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
168227015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
168327015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
168427015b6fSBo Jiao 	ret = mt7996_txbf_init(dev);
168527015b6fSBo Jiao 
168627015b6fSBo Jiao 	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
168727015b6fSBo Jiao 		ret = mt7996_run(dev->mphy.hw);
168827015b6fSBo Jiao 		if (ret)
168927015b6fSBo Jiao 			goto out;
169027015b6fSBo Jiao 	}
169127015b6fSBo Jiao 
169227015b6fSBo Jiao 	if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
169327015b6fSBo Jiao 		ret = mt7996_run(phy2->mt76->hw);
169427015b6fSBo Jiao 		if (ret)
169527015b6fSBo Jiao 			goto out;
169627015b6fSBo Jiao 	}
169727015b6fSBo Jiao 
169827015b6fSBo Jiao 	if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
169927015b6fSBo Jiao 		ret = mt7996_run(phy3->mt76->hw);
170027015b6fSBo Jiao 		if (ret)
170127015b6fSBo Jiao 			goto out;
170227015b6fSBo Jiao 	}
170327015b6fSBo Jiao 
170427015b6fSBo Jiao out:
170527015b6fSBo Jiao 	/* reset done */
170627015b6fSBo Jiao 	clear_bit(MT76_RESET, &dev->mphy.state);
170727015b6fSBo Jiao 	if (phy2)
170827015b6fSBo Jiao 		clear_bit(MT76_RESET, &phy2->mt76->state);
170927015b6fSBo Jiao 	if (phy3)
171027015b6fSBo Jiao 		clear_bit(MT76_RESET, &phy3->mt76->state);
171127015b6fSBo Jiao 
171227015b6fSBo Jiao 	local_bh_disable();
171327015b6fSBo Jiao 	napi_enable(&dev->mt76.tx_napi);
171427015b6fSBo Jiao 	napi_schedule(&dev->mt76.tx_napi);
171527015b6fSBo Jiao 	local_bh_enable();
171627015b6fSBo Jiao 
171727015b6fSBo Jiao 	mt76_worker_enable(&dev->mt76.tx_worker);
171827015b6fSBo Jiao 	return ret;
171927015b6fSBo Jiao }
172027015b6fSBo Jiao 
172127015b6fSBo Jiao static void
mt7996_mac_full_reset(struct mt7996_dev * dev)172227015b6fSBo Jiao mt7996_mac_full_reset(struct mt7996_dev *dev)
172327015b6fSBo Jiao {
172427015b6fSBo Jiao 	struct mt7996_phy *phy2, *phy3;
172527015b6fSBo Jiao 	int i;
172627015b6fSBo Jiao 
172727015b6fSBo Jiao 	phy2 = mt7996_phy2(dev);
172827015b6fSBo Jiao 	phy3 = mt7996_phy3(dev);
172927015b6fSBo Jiao 	dev->recovery.hw_full_reset = true;
173027015b6fSBo Jiao 
173127015b6fSBo Jiao 	wake_up(&dev->mt76.mcu.wait);
173227015b6fSBo Jiao 	ieee80211_stop_queues(mt76_hw(dev));
173327015b6fSBo Jiao 	if (phy2)
173427015b6fSBo Jiao 		ieee80211_stop_queues(phy2->mt76->hw);
173527015b6fSBo Jiao 	if (phy3)
173627015b6fSBo Jiao 		ieee80211_stop_queues(phy3->mt76->hw);
173727015b6fSBo Jiao 
173827015b6fSBo Jiao 	cancel_delayed_work_sync(&dev->mphy.mac_work);
173927015b6fSBo Jiao 	if (phy2)
174027015b6fSBo Jiao 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
174127015b6fSBo Jiao 	if (phy3)
174227015b6fSBo Jiao 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
174327015b6fSBo Jiao 
174427015b6fSBo Jiao 	mutex_lock(&dev->mt76.mutex);
174527015b6fSBo Jiao 	for (i = 0; i < 10; i++) {
174627015b6fSBo Jiao 		if (!mt7996_mac_restart(dev))
174727015b6fSBo Jiao 			break;
174827015b6fSBo Jiao 	}
174927015b6fSBo Jiao 	mutex_unlock(&dev->mt76.mutex);
175027015b6fSBo Jiao 
175127015b6fSBo Jiao 	if (i == 10)
175227015b6fSBo Jiao 		dev_err(dev->mt76.dev, "chip full reset failed\n");
175327015b6fSBo Jiao 
175427015b6fSBo Jiao 	ieee80211_restart_hw(mt76_hw(dev));
175527015b6fSBo Jiao 	if (phy2)
175627015b6fSBo Jiao 		ieee80211_restart_hw(phy2->mt76->hw);
175727015b6fSBo Jiao 	if (phy3)
175827015b6fSBo Jiao 		ieee80211_restart_hw(phy3->mt76->hw);
175927015b6fSBo Jiao 
176027015b6fSBo Jiao 	ieee80211_wake_queues(mt76_hw(dev));
176127015b6fSBo Jiao 	if (phy2)
176227015b6fSBo Jiao 		ieee80211_wake_queues(phy2->mt76->hw);
176327015b6fSBo Jiao 	if (phy3)
176427015b6fSBo Jiao 		ieee80211_wake_queues(phy3->mt76->hw);
176527015b6fSBo Jiao 
176627015b6fSBo Jiao 	dev->recovery.hw_full_reset = false;
176727015b6fSBo Jiao 	ieee80211_queue_delayed_work(mt76_hw(dev),
176827015b6fSBo Jiao 				     &dev->mphy.mac_work,
176927015b6fSBo Jiao 				     MT7996_WATCHDOG_TIME);
177027015b6fSBo Jiao 	if (phy2)
177127015b6fSBo Jiao 		ieee80211_queue_delayed_work(phy2->mt76->hw,
177227015b6fSBo Jiao 					     &phy2->mt76->mac_work,
177327015b6fSBo Jiao 					     MT7996_WATCHDOG_TIME);
177427015b6fSBo Jiao 	if (phy3)
177527015b6fSBo Jiao 		ieee80211_queue_delayed_work(phy3->mt76->hw,
177627015b6fSBo Jiao 					     &phy3->mt76->mac_work,
177727015b6fSBo Jiao 					     MT7996_WATCHDOG_TIME);
177827015b6fSBo Jiao }
177927015b6fSBo Jiao 
mt7996_mac_reset_work(struct work_struct * work)178098686cd2SShayne Chen void mt7996_mac_reset_work(struct work_struct *work)
178198686cd2SShayne Chen {
178298686cd2SShayne Chen 	struct mt7996_phy *phy2, *phy3;
178398686cd2SShayne Chen 	struct mt7996_dev *dev;
178498686cd2SShayne Chen 	int i;
178598686cd2SShayne Chen 
178698686cd2SShayne Chen 	dev = container_of(work, struct mt7996_dev, reset_work);
178798686cd2SShayne Chen 	phy2 = mt7996_phy2(dev);
178898686cd2SShayne Chen 	phy3 = mt7996_phy3(dev);
178998686cd2SShayne Chen 
179027015b6fSBo Jiao 	/* chip full reset */
179127015b6fSBo Jiao 	if (dev->recovery.restart) {
179227015b6fSBo Jiao 		/* disable WA/WM WDT */
179327015b6fSBo Jiao 		mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
179427015b6fSBo Jiao 			   MT_MCU_CMD_WDT_MASK);
179527015b6fSBo Jiao 
179627015b6fSBo Jiao 		if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
179727015b6fSBo Jiao 			dev->recovery.wa_reset_count++;
179827015b6fSBo Jiao 		else
179927015b6fSBo Jiao 			dev->recovery.wm_reset_count++;
180027015b6fSBo Jiao 
180127015b6fSBo Jiao 		mt7996_mac_full_reset(dev);
180227015b6fSBo Jiao 
180327015b6fSBo Jiao 		/* enable mcu irq */
180427015b6fSBo Jiao 		mt7996_irq_enable(dev, MT_INT_MCU_CMD);
180527015b6fSBo Jiao 		mt7996_irq_disable(dev, 0);
180627015b6fSBo Jiao 
180727015b6fSBo Jiao 		/* enable WA/WM WDT */
180827015b6fSBo Jiao 		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
180927015b6fSBo Jiao 
181027015b6fSBo Jiao 		dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
181127015b6fSBo Jiao 		dev->recovery.restart = false;
181227015b6fSBo Jiao 		return;
181327015b6fSBo Jiao 	}
181427015b6fSBo Jiao 
181527015b6fSBo Jiao 	if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
181698686cd2SShayne Chen 		return;
181798686cd2SShayne Chen 
181827015b6fSBo Jiao 	dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
181927015b6fSBo Jiao 		 wiphy_name(dev->mt76.hw->wiphy));
182098686cd2SShayne Chen 	ieee80211_stop_queues(mt76_hw(dev));
182198686cd2SShayne Chen 	if (phy2)
182298686cd2SShayne Chen 		ieee80211_stop_queues(phy2->mt76->hw);
182398686cd2SShayne Chen 	if (phy3)
182498686cd2SShayne Chen 		ieee80211_stop_queues(phy3->mt76->hw);
182598686cd2SShayne Chen 
182698686cd2SShayne Chen 	set_bit(MT76_RESET, &dev->mphy.state);
182798686cd2SShayne Chen 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
182898686cd2SShayne Chen 	wake_up(&dev->mt76.mcu.wait);
182998686cd2SShayne Chen 	cancel_delayed_work_sync(&dev->mphy.mac_work);
183098686cd2SShayne Chen 	if (phy2) {
183198686cd2SShayne Chen 		set_bit(MT76_RESET, &phy2->mt76->state);
183298686cd2SShayne Chen 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
183398686cd2SShayne Chen 	}
183498686cd2SShayne Chen 	if (phy3) {
183598686cd2SShayne Chen 		set_bit(MT76_RESET, &phy3->mt76->state);
183698686cd2SShayne Chen 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
183798686cd2SShayne Chen 	}
183898686cd2SShayne Chen 	mt76_worker_disable(&dev->mt76.tx_worker);
183998686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i)
184098686cd2SShayne Chen 		napi_disable(&dev->mt76.napi[i]);
184198686cd2SShayne Chen 	napi_disable(&dev->mt76.tx_napi);
184298686cd2SShayne Chen 
184398686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
184498686cd2SShayne Chen 
184598686cd2SShayne Chen 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
184698686cd2SShayne Chen 
184798686cd2SShayne Chen 	if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
184827015b6fSBo Jiao 		mt7996_dma_reset(dev, false);
184998686cd2SShayne Chen 
185098686cd2SShayne Chen 		mt7996_tx_token_put(dev);
185198686cd2SShayne Chen 		idr_init(&dev->mt76.token);
185298686cd2SShayne Chen 
185398686cd2SShayne Chen 		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
185498686cd2SShayne Chen 		mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
185598686cd2SShayne Chen 	}
185698686cd2SShayne Chen 
18578e8c09c7SBo Jiao 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
18588e8c09c7SBo Jiao 	mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
18598e8c09c7SBo Jiao 
18608e8c09c7SBo Jiao 	/* enable DMA Tx/Tx and interrupt */
18618e8c09c7SBo Jiao 	mt7996_dma_start(dev, false);
18628e8c09c7SBo Jiao 
186398686cd2SShayne Chen 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
186498686cd2SShayne Chen 	clear_bit(MT76_RESET, &dev->mphy.state);
186598686cd2SShayne Chen 	if (phy2)
186698686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy2->mt76->state);
186798686cd2SShayne Chen 	if (phy3)
186898686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy3->mt76->state);
186998686cd2SShayne Chen 
187098686cd2SShayne Chen 	local_bh_disable();
187198686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i) {
187298686cd2SShayne Chen 		napi_enable(&dev->mt76.napi[i]);
187398686cd2SShayne Chen 		napi_schedule(&dev->mt76.napi[i]);
187498686cd2SShayne Chen 	}
187598686cd2SShayne Chen 	local_bh_enable();
187698686cd2SShayne Chen 
1877ec193b41SLorenzo Bianconi 	tasklet_schedule(&dev->mt76.irq_tasklet);
187898686cd2SShayne Chen 
187998686cd2SShayne Chen 	mt76_worker_enable(&dev->mt76.tx_worker);
188098686cd2SShayne Chen 
188198686cd2SShayne Chen 	local_bh_disable();
188298686cd2SShayne Chen 	napi_enable(&dev->mt76.tx_napi);
188398686cd2SShayne Chen 	napi_schedule(&dev->mt76.tx_napi);
188498686cd2SShayne Chen 	local_bh_enable();
188598686cd2SShayne Chen 
188698686cd2SShayne Chen 	ieee80211_wake_queues(mt76_hw(dev));
188798686cd2SShayne Chen 	if (phy2)
188898686cd2SShayne Chen 		ieee80211_wake_queues(phy2->mt76->hw);
188998686cd2SShayne Chen 	if (phy3)
189098686cd2SShayne Chen 		ieee80211_wake_queues(phy3->mt76->hw);
189198686cd2SShayne Chen 
189298686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
189398686cd2SShayne Chen 
189498686cd2SShayne Chen 	mt7996_update_beacons(dev);
189598686cd2SShayne Chen 
189698686cd2SShayne Chen 	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
189798686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
189898686cd2SShayne Chen 	if (phy2)
189998686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy2->mt76->hw,
190098686cd2SShayne Chen 					     &phy2->mt76->mac_work,
190198686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
190298686cd2SShayne Chen 	if (phy3)
190398686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy3->mt76->hw,
190498686cd2SShayne Chen 					     &phy3->mt76->mac_work,
190598686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
190627015b6fSBo Jiao 	dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
190727015b6fSBo Jiao 		 wiphy_name(dev->mt76.hw->wiphy));
190827015b6fSBo Jiao }
190927015b6fSBo Jiao 
1910878161d5SRyder Lee /* firmware coredump */
mt7996_mac_dump_work(struct work_struct * work)1911878161d5SRyder Lee void mt7996_mac_dump_work(struct work_struct *work)
1912878161d5SRyder Lee {
1913878161d5SRyder Lee 	const struct mt7996_mem_region *mem_region;
1914878161d5SRyder Lee 	struct mt7996_crash_data *crash_data;
1915878161d5SRyder Lee 	struct mt7996_dev *dev;
1916878161d5SRyder Lee 	struct mt7996_mem_hdr *hdr;
1917878161d5SRyder Lee 	size_t buf_len;
1918878161d5SRyder Lee 	int i;
1919878161d5SRyder Lee 	u32 num;
1920878161d5SRyder Lee 	u8 *buf;
1921878161d5SRyder Lee 
1922878161d5SRyder Lee 	dev = container_of(work, struct mt7996_dev, dump_work);
1923878161d5SRyder Lee 
1924878161d5SRyder Lee 	mutex_lock(&dev->dump_mutex);
1925878161d5SRyder Lee 
1926878161d5SRyder Lee 	crash_data = mt7996_coredump_new(dev);
1927878161d5SRyder Lee 	if (!crash_data) {
1928878161d5SRyder Lee 		mutex_unlock(&dev->dump_mutex);
1929878161d5SRyder Lee 		goto skip_coredump;
1930878161d5SRyder Lee 	}
1931878161d5SRyder Lee 
1932878161d5SRyder Lee 	mem_region = mt7996_coredump_get_mem_layout(dev, &num);
1933878161d5SRyder Lee 	if (!mem_region || !crash_data->memdump_buf_len) {
1934878161d5SRyder Lee 		mutex_unlock(&dev->dump_mutex);
1935878161d5SRyder Lee 		goto skip_memdump;
1936878161d5SRyder Lee 	}
1937878161d5SRyder Lee 
1938878161d5SRyder Lee 	buf = crash_data->memdump_buf;
1939878161d5SRyder Lee 	buf_len = crash_data->memdump_buf_len;
1940878161d5SRyder Lee 
1941878161d5SRyder Lee 	/* dumping memory content... */
1942878161d5SRyder Lee 	memset(buf, 0, buf_len);
1943878161d5SRyder Lee 	for (i = 0; i < num; i++) {
1944878161d5SRyder Lee 		if (mem_region->len > buf_len) {
1945878161d5SRyder Lee 			dev_warn(dev->mt76.dev, "%s len %zu is too large\n",
1946878161d5SRyder Lee 				 mem_region->name, mem_region->len);
1947878161d5SRyder Lee 			break;
1948878161d5SRyder Lee 		}
1949878161d5SRyder Lee 
1950878161d5SRyder Lee 		/* reserve space for the header */
1951878161d5SRyder Lee 		hdr = (void *)buf;
1952878161d5SRyder Lee 		buf += sizeof(*hdr);
1953878161d5SRyder Lee 		buf_len -= sizeof(*hdr);
1954878161d5SRyder Lee 
1955878161d5SRyder Lee 		mt7996_memcpy_fromio(dev, buf, mem_region->start,
1956878161d5SRyder Lee 				     mem_region->len);
1957878161d5SRyder Lee 
1958878161d5SRyder Lee 		hdr->start = mem_region->start;
1959878161d5SRyder Lee 		hdr->len = mem_region->len;
1960878161d5SRyder Lee 
1961878161d5SRyder Lee 		if (!mem_region->len)
1962878161d5SRyder Lee 			/* note: the header remains, just with zero length */
1963878161d5SRyder Lee 			break;
1964878161d5SRyder Lee 
1965878161d5SRyder Lee 		buf += mem_region->len;
1966878161d5SRyder Lee 		buf_len -= mem_region->len;
1967878161d5SRyder Lee 
1968878161d5SRyder Lee 		mem_region++;
1969878161d5SRyder Lee 	}
1970878161d5SRyder Lee 
1971878161d5SRyder Lee 	mutex_unlock(&dev->dump_mutex);
1972878161d5SRyder Lee 
1973878161d5SRyder Lee skip_memdump:
1974878161d5SRyder Lee 	mt7996_coredump_submit(dev);
1975878161d5SRyder Lee skip_coredump:
1976878161d5SRyder Lee 	queue_work(dev->mt76.wq, &dev->reset_work);
1977878161d5SRyder Lee }
1978878161d5SRyder Lee 
mt7996_reset(struct mt7996_dev * dev)197927015b6fSBo Jiao void mt7996_reset(struct mt7996_dev *dev)
198027015b6fSBo Jiao {
198127015b6fSBo Jiao 	if (!dev->recovery.hw_init_done)
198227015b6fSBo Jiao 		return;
198327015b6fSBo Jiao 
198427015b6fSBo Jiao 	if (dev->recovery.hw_full_reset)
198527015b6fSBo Jiao 		return;
198627015b6fSBo Jiao 
198727015b6fSBo Jiao 	/* wm/wa exception: do full recovery */
198827015b6fSBo Jiao 	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
198927015b6fSBo Jiao 		dev->recovery.restart = true;
199027015b6fSBo Jiao 		dev_info(dev->mt76.dev,
199127015b6fSBo Jiao 			 "%s indicated firmware crash, attempting recovery\n",
199227015b6fSBo Jiao 			 wiphy_name(dev->mt76.hw->wiphy));
199327015b6fSBo Jiao 
199427015b6fSBo Jiao 		mt7996_irq_disable(dev, MT_INT_MCU_CMD);
1995878161d5SRyder Lee 		queue_work(dev->mt76.wq, &dev->dump_work);
199627015b6fSBo Jiao 		return;
199727015b6fSBo Jiao 	}
199827015b6fSBo Jiao 
199927015b6fSBo Jiao 	queue_work(dev->mt76.wq, &dev->reset_work);
200027015b6fSBo Jiao 	wake_up(&dev->reset_wait);
200198686cd2SShayne Chen }
200298686cd2SShayne Chen 
mt7996_mac_update_stats(struct mt7996_phy * phy)200398686cd2SShayne Chen void mt7996_mac_update_stats(struct mt7996_phy *phy)
200498686cd2SShayne Chen {
200598214484SLorenzo Bianconi 	struct mt76_mib_stats *mib = &phy->mib;
200698686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
200798686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
200898686cd2SShayne Chen 	u32 cnt;
200998686cd2SShayne Chen 	int i;
201098686cd2SShayne Chen 
201198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx));
201298686cd2SShayne Chen 	mib->fcs_err_cnt += cnt;
201398686cd2SShayne Chen 
201498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx));
201598686cd2SShayne Chen 	mib->rx_fifo_full_cnt += cnt;
201698686cd2SShayne Chen 
201798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx));
201898686cd2SShayne Chen 	mib->rx_mpdu_cnt += cnt;
201998686cd2SShayne Chen 
202098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx));
202198686cd2SShayne Chen 	mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
202298686cd2SShayne Chen 
202398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx));
202498686cd2SShayne Chen 	mib->rx_vector_mismatch_cnt += cnt;
202598686cd2SShayne Chen 
202698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx));
202798686cd2SShayne Chen 	mib->rx_delimiter_fail_cnt += cnt;
202898686cd2SShayne Chen 
202998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx));
203098686cd2SShayne Chen 	mib->rx_len_mismatch_cnt += cnt;
203198686cd2SShayne Chen 
203298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx));
203398686cd2SShayne Chen 	mib->tx_ampdu_cnt += cnt;
203498686cd2SShayne Chen 
203598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx));
203698686cd2SShayne Chen 	mib->tx_stop_q_empty_cnt += cnt;
203798686cd2SShayne Chen 
203898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx));
203998686cd2SShayne Chen 	mib->tx_mpdu_attempts_cnt += cnt;
204098686cd2SShayne Chen 
204198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx));
204298686cd2SShayne Chen 	mib->tx_mpdu_success_cnt += cnt;
204398686cd2SShayne Chen 
204498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx));
204598686cd2SShayne Chen 	mib->rx_ampdu_cnt += cnt;
204698686cd2SShayne Chen 
204798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx));
204898686cd2SShayne Chen 	mib->rx_ampdu_bytes_cnt += cnt;
204998686cd2SShayne Chen 
205098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx));
205198686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_cnt += cnt;
205298686cd2SShayne Chen 
205398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx));
205498686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
205598686cd2SShayne Chen 
205698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx));
205798686cd2SShayne Chen 	mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt);
205898686cd2SShayne Chen 
205998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx));
206098686cd2SShayne Chen 	mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt);
206198686cd2SShayne Chen 
206298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx));
206398686cd2SShayne Chen 	mib->rx_pfdrop_cnt += cnt;
206498686cd2SShayne Chen 
206598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx));
206698686cd2SShayne Chen 	mib->rx_vec_queue_overflow_drop_cnt += cnt;
206798686cd2SShayne Chen 
206898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx));
206998686cd2SShayne Chen 	mib->rx_ba_cnt += cnt;
207098686cd2SShayne Chen 
207198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx));
207298686cd2SShayne Chen 	mib->tx_bf_ebf_ppdu_cnt += cnt;
207398686cd2SShayne Chen 
207498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx));
207598686cd2SShayne Chen 	mib->tx_bf_ibf_ppdu_cnt += cnt;
207698686cd2SShayne Chen 
207798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx));
207898686cd2SShayne Chen 	mib->tx_mu_bf_cnt += cnt;
207998686cd2SShayne Chen 
208098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx));
208198686cd2SShayne Chen 	mib->tx_mu_mpdu_cnt += cnt;
208298686cd2SShayne Chen 
208398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx));
208498686cd2SShayne Chen 	mib->tx_mu_acked_mpdu_cnt += cnt;
208598686cd2SShayne Chen 
208698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx));
208798686cd2SShayne Chen 	mib->tx_su_acked_mpdu_cnt += cnt;
208898686cd2SShayne Chen 
208998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx));
209098686cd2SShayne Chen 	mib->tx_bf_rx_fb_ht_cnt += cnt;
209198686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
209298686cd2SShayne Chen 
209398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx));
209498686cd2SShayne Chen 	mib->tx_bf_rx_fb_vht_cnt += cnt;
209598686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
209698686cd2SShayne Chen 
209798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx));
209898686cd2SShayne Chen 	mib->tx_bf_rx_fb_he_cnt += cnt;
209998686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
210098686cd2SShayne Chen 
210198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx));
210298686cd2SShayne Chen 	mib->tx_bf_rx_fb_eht_cnt += cnt;
210398686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
210498686cd2SShayne Chen 
210598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx));
210698686cd2SShayne Chen 	mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt);
210798686cd2SShayne Chen 	mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt);
210898686cd2SShayne Chen 	mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt);
210998686cd2SShayne Chen 
211098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR7(band_idx));
211198686cd2SShayne Chen 	mib->tx_bf_fb_trig_cnt += cnt;
211298686cd2SShayne Chen 
211398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx));
211498686cd2SShayne Chen 	mib->tx_bf_fb_cpl_cnt += cnt;
211598686cd2SShayne Chen 
211698686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
211798686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
211898686cd2SShayne Chen 		mib->tx_amsdu[i] += cnt;
211998686cd2SShayne Chen 		mib->tx_amsdu_cnt += cnt;
212098686cd2SShayne Chen 	}
212198686cd2SShayne Chen 
212298686cd2SShayne Chen 	/* rts count */
212398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx));
212498686cd2SShayne Chen 	mib->rts_cnt += cnt;
212598686cd2SShayne Chen 
212698686cd2SShayne Chen 	/* rts retry count */
212798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx));
212898686cd2SShayne Chen 	mib->rts_retries_cnt += cnt;
212998686cd2SShayne Chen 
213098686cd2SShayne Chen 	/* ba miss count */
213198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx));
213298686cd2SShayne Chen 	mib->ba_miss_cnt += cnt;
213398686cd2SShayne Chen 
213498686cd2SShayne Chen 	/* ack fail count */
213598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx));
213698686cd2SShayne Chen 	mib->ack_fail_cnt += cnt;
213798686cd2SShayne Chen 
213898686cd2SShayne Chen 	for (i = 0; i < 16; i++) {
213998686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
214098686cd2SShayne Chen 		phy->mt76->aggr_stats[i] += cnt;
214198686cd2SShayne Chen 	}
214298686cd2SShayne Chen }
214398686cd2SShayne Chen 
mt7996_mac_sta_rc_work(struct work_struct * work)214498686cd2SShayne Chen void mt7996_mac_sta_rc_work(struct work_struct *work)
214598686cd2SShayne Chen {
214698686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
214798686cd2SShayne Chen 	struct ieee80211_sta *sta;
214898686cd2SShayne Chen 	struct ieee80211_vif *vif;
214998686cd2SShayne Chen 	struct mt7996_sta *msta;
215098686cd2SShayne Chen 	u32 changed;
215198686cd2SShayne Chen 	LIST_HEAD(list);
215298686cd2SShayne Chen 
2153ea0f3867SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.sta_poll_lock);
215498686cd2SShayne Chen 	list_splice_init(&dev->sta_rc_list, &list);
215598686cd2SShayne Chen 
215698686cd2SShayne Chen 	while (!list_empty(&list)) {
215798686cd2SShayne Chen 		msta = list_first_entry(&list, struct mt7996_sta, rc_list);
215898686cd2SShayne Chen 		list_del_init(&msta->rc_list);
215998686cd2SShayne Chen 		changed = msta->changed;
216098686cd2SShayne Chen 		msta->changed = 0;
2161ea0f3867SLorenzo Bianconi 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
216298686cd2SShayne Chen 
216398686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
216498686cd2SShayne Chen 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
216598686cd2SShayne Chen 
216698686cd2SShayne Chen 		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
216798686cd2SShayne Chen 			       IEEE80211_RC_NSS_CHANGED |
216898686cd2SShayne Chen 			       IEEE80211_RC_BW_CHANGED))
216998686cd2SShayne Chen 			mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
217098686cd2SShayne Chen 
217198686cd2SShayne Chen 		/* TODO: smps change */
217298686cd2SShayne Chen 
2173ea0f3867SLorenzo Bianconi 		spin_lock_bh(&dev->mt76.sta_poll_lock);
217498686cd2SShayne Chen 	}
217598686cd2SShayne Chen 
2176ea0f3867SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
217798686cd2SShayne Chen }
217898686cd2SShayne Chen 
mt7996_mac_work(struct work_struct * work)217998686cd2SShayne Chen void mt7996_mac_work(struct work_struct *work)
218098686cd2SShayne Chen {
218198686cd2SShayne Chen 	struct mt7996_phy *phy;
218298686cd2SShayne Chen 	struct mt76_phy *mphy;
218398686cd2SShayne Chen 
218498686cd2SShayne Chen 	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
218598686cd2SShayne Chen 					       mac_work.work);
218698686cd2SShayne Chen 	phy = mphy->priv;
218798686cd2SShayne Chen 
218898686cd2SShayne Chen 	mutex_lock(&mphy->dev->mutex);
218998686cd2SShayne Chen 
219098686cd2SShayne Chen 	mt76_update_survey(mphy);
219198686cd2SShayne Chen 	if (++mphy->mac_work_count == 5) {
219298686cd2SShayne Chen 		mphy->mac_work_count = 0;
219398686cd2SShayne Chen 
219498686cd2SShayne Chen 		mt7996_mac_update_stats(phy);
219598686cd2SShayne Chen 	}
219698686cd2SShayne Chen 
219798686cd2SShayne Chen 	mutex_unlock(&mphy->dev->mutex);
219898686cd2SShayne Chen 
219998686cd2SShayne Chen 	mt76_tx_status_check(mphy->dev, false);
220098686cd2SShayne Chen 
220198686cd2SShayne Chen 	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
220298686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
220398686cd2SShayne Chen }
220498686cd2SShayne Chen 
mt7996_dfs_stop_radar_detector(struct mt7996_phy * phy)220598686cd2SShayne Chen static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
220698686cd2SShayne Chen {
220798686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
220898686cd2SShayne Chen 
220998686cd2SShayne Chen 	if (phy->rdd_state & BIT(0))
221098686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0,
221198686cd2SShayne Chen 				   MT_RX_SEL0, 0);
221298686cd2SShayne Chen 	if (phy->rdd_state & BIT(1))
221398686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1,
221498686cd2SShayne Chen 				   MT_RX_SEL0, 0);
221598686cd2SShayne Chen }
221698686cd2SShayne Chen 
mt7996_dfs_start_rdd(struct mt7996_dev * dev,int chain)221798686cd2SShayne Chen static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
221898686cd2SShayne Chen {
221998686cd2SShayne Chen 	int err, region;
222098686cd2SShayne Chen 
222198686cd2SShayne Chen 	switch (dev->mt76.region) {
222298686cd2SShayne Chen 	case NL80211_DFS_ETSI:
222398686cd2SShayne Chen 		region = 0;
222498686cd2SShayne Chen 		break;
222598686cd2SShayne Chen 	case NL80211_DFS_JP:
222698686cd2SShayne Chen 		region = 2;
222798686cd2SShayne Chen 		break;
222898686cd2SShayne Chen 	case NL80211_DFS_FCC:
222998686cd2SShayne Chen 	default:
223098686cd2SShayne Chen 		region = 1;
223198686cd2SShayne Chen 		break;
223298686cd2SShayne Chen 	}
223398686cd2SShayne Chen 
223498686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain,
223598686cd2SShayne Chen 				 MT_RX_SEL0, region);
223698686cd2SShayne Chen 	if (err < 0)
223798686cd2SShayne Chen 		return err;
223898686cd2SShayne Chen 
223998686cd2SShayne Chen 	return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
224098686cd2SShayne Chen 				 MT_RX_SEL0, 1);
224198686cd2SShayne Chen }
224298686cd2SShayne Chen 
mt7996_dfs_start_radar_detector(struct mt7996_phy * phy)224398686cd2SShayne Chen static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
224498686cd2SShayne Chen {
224598686cd2SShayne Chen 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
224698686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
224798686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
224898686cd2SShayne Chen 	int err;
224998686cd2SShayne Chen 
225098686cd2SShayne Chen 	/* start CAC */
225198686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx,
225298686cd2SShayne Chen 				 MT_RX_SEL0, 0);
225398686cd2SShayne Chen 	if (err < 0)
225498686cd2SShayne Chen 		return err;
225598686cd2SShayne Chen 
225698686cd2SShayne Chen 	err = mt7996_dfs_start_rdd(dev, band_idx);
225798686cd2SShayne Chen 	if (err < 0)
225898686cd2SShayne Chen 		return err;
225998686cd2SShayne Chen 
226098686cd2SShayne Chen 	phy->rdd_state |= BIT(band_idx);
226198686cd2SShayne Chen 
226298686cd2SShayne Chen 	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
226398686cd2SShayne Chen 	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
226498686cd2SShayne Chen 		err = mt7996_dfs_start_rdd(dev, 1);
226598686cd2SShayne Chen 		if (err < 0)
226698686cd2SShayne Chen 			return err;
226798686cd2SShayne Chen 
226898686cd2SShayne Chen 		phy->rdd_state |= BIT(1);
226998686cd2SShayne Chen 	}
227098686cd2SShayne Chen 
227198686cd2SShayne Chen 	return 0;
227298686cd2SShayne Chen }
227398686cd2SShayne Chen 
227498686cd2SShayne Chen static int
mt7996_dfs_init_radar_specs(struct mt7996_phy * phy)227598686cd2SShayne Chen mt7996_dfs_init_radar_specs(struct mt7996_phy *phy)
227698686cd2SShayne Chen {
227798686cd2SShayne Chen 	const struct mt7996_dfs_radar_spec *radar_specs;
227898686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
227998686cd2SShayne Chen 	int err, i;
228098686cd2SShayne Chen 
228198686cd2SShayne Chen 	switch (dev->mt76.region) {
228298686cd2SShayne Chen 	case NL80211_DFS_FCC:
228398686cd2SShayne Chen 		radar_specs = &fcc_radar_specs;
228498686cd2SShayne Chen 		err = mt7996_mcu_set_fcc5_lpn(dev, 8);
228598686cd2SShayne Chen 		if (err < 0)
228698686cd2SShayne Chen 			return err;
228798686cd2SShayne Chen 		break;
228898686cd2SShayne Chen 	case NL80211_DFS_ETSI:
228998686cd2SShayne Chen 		radar_specs = &etsi_radar_specs;
229098686cd2SShayne Chen 		break;
229198686cd2SShayne Chen 	case NL80211_DFS_JP:
229298686cd2SShayne Chen 		radar_specs = &jp_radar_specs;
229398686cd2SShayne Chen 		break;
229498686cd2SShayne Chen 	default:
229598686cd2SShayne Chen 		return -EINVAL;
229698686cd2SShayne Chen 	}
229798686cd2SShayne Chen 
229898686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
229998686cd2SShayne Chen 		err = mt7996_mcu_set_radar_th(dev, i,
230098686cd2SShayne Chen 					      &radar_specs->radar_pattern[i]);
230198686cd2SShayne Chen 		if (err < 0)
230298686cd2SShayne Chen 			return err;
230398686cd2SShayne Chen 	}
230498686cd2SShayne Chen 
230598686cd2SShayne Chen 	return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
230698686cd2SShayne Chen }
230798686cd2SShayne Chen 
mt7996_dfs_init_radar_detector(struct mt7996_phy * phy)230898686cd2SShayne Chen int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
230998686cd2SShayne Chen {
231098686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
231198686cd2SShayne Chen 	enum mt76_dfs_state dfs_state, prev_state;
231298686cd2SShayne Chen 	int err;
231398686cd2SShayne Chen 
231498686cd2SShayne Chen 	prev_state = phy->mt76->dfs_state;
231598686cd2SShayne Chen 	dfs_state = mt76_phy_dfs_state(phy->mt76);
231698686cd2SShayne Chen 
231798686cd2SShayne Chen 	if (prev_state == dfs_state)
231898686cd2SShayne Chen 		return 0;
231998686cd2SShayne Chen 
232098686cd2SShayne Chen 	if (prev_state == MT_DFS_STATE_UNKNOWN)
232198686cd2SShayne Chen 		mt7996_dfs_stop_radar_detector(phy);
232298686cd2SShayne Chen 
232398686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_DISABLED)
232498686cd2SShayne Chen 		goto stop;
232598686cd2SShayne Chen 
232698686cd2SShayne Chen 	if (prev_state <= MT_DFS_STATE_DISABLED) {
232798686cd2SShayne Chen 		err = mt7996_dfs_init_radar_specs(phy);
232898686cd2SShayne Chen 		if (err < 0)
232998686cd2SShayne Chen 			return err;
233098686cd2SShayne Chen 
233198686cd2SShayne Chen 		err = mt7996_dfs_start_radar_detector(phy);
233298686cd2SShayne Chen 		if (err < 0)
233398686cd2SShayne Chen 			return err;
233498686cd2SShayne Chen 
233598686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_CAC;
233698686cd2SShayne Chen 	}
233798686cd2SShayne Chen 
233898686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_CAC)
233998686cd2SShayne Chen 		return 0;
234098686cd2SShayne Chen 
234198686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END,
234298686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
234398686cd2SShayne Chen 	if (err < 0) {
234498686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
234598686cd2SShayne Chen 		return err;
234698686cd2SShayne Chen 	}
234798686cd2SShayne Chen 
234898686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
234998686cd2SShayne Chen 	return 0;
235098686cd2SShayne Chen 
235198686cd2SShayne Chen stop:
235298686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START,
235398686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
235498686cd2SShayne Chen 	if (err < 0)
235598686cd2SShayne Chen 		return err;
235698686cd2SShayne Chen 
235798686cd2SShayne Chen 	mt7996_dfs_stop_radar_detector(phy);
235898686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
235998686cd2SShayne Chen 
236098686cd2SShayne Chen 	return 0;
236198686cd2SShayne Chen }
236298686cd2SShayne Chen 
236398686cd2SShayne Chen static int
mt7996_mac_twt_duration_align(int duration)236498686cd2SShayne Chen mt7996_mac_twt_duration_align(int duration)
236598686cd2SShayne Chen {
236698686cd2SShayne Chen 	return duration << 8;
236798686cd2SShayne Chen }
236898686cd2SShayne Chen 
236998686cd2SShayne Chen static u64
mt7996_mac_twt_sched_list_add(struct mt7996_dev * dev,struct mt7996_twt_flow * flow)237098686cd2SShayne Chen mt7996_mac_twt_sched_list_add(struct mt7996_dev *dev,
237198686cd2SShayne Chen 			      struct mt7996_twt_flow *flow)
237298686cd2SShayne Chen {
237398686cd2SShayne Chen 	struct mt7996_twt_flow *iter, *iter_next;
237498686cd2SShayne Chen 	u32 duration = flow->duration << 8;
237598686cd2SShayne Chen 	u64 start_tsf;
237698686cd2SShayne Chen 
237798686cd2SShayne Chen 	iter = list_first_entry_or_null(&dev->twt_list,
237898686cd2SShayne Chen 					struct mt7996_twt_flow, list);
237998686cd2SShayne Chen 	if (!iter || !iter->sched || iter->start_tsf > duration) {
238098686cd2SShayne Chen 		/* add flow as first entry in the list */
238198686cd2SShayne Chen 		list_add(&flow->list, &dev->twt_list);
238298686cd2SShayne Chen 		return 0;
238398686cd2SShayne Chen 	}
238498686cd2SShayne Chen 
238598686cd2SShayne Chen 	list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
238698686cd2SShayne Chen 		start_tsf = iter->start_tsf +
238798686cd2SShayne Chen 			    mt7996_mac_twt_duration_align(iter->duration);
238898686cd2SShayne Chen 		if (list_is_last(&iter->list, &dev->twt_list))
238998686cd2SShayne Chen 			break;
239098686cd2SShayne Chen 
239198686cd2SShayne Chen 		if (!iter_next->sched ||
239298686cd2SShayne Chen 		    iter_next->start_tsf > start_tsf + duration) {
239398686cd2SShayne Chen 			list_add(&flow->list, &iter->list);
239498686cd2SShayne Chen 			goto out;
239598686cd2SShayne Chen 		}
239698686cd2SShayne Chen 	}
239798686cd2SShayne Chen 
239898686cd2SShayne Chen 	/* add flow as last entry in the list */
239998686cd2SShayne Chen 	list_add_tail(&flow->list, &dev->twt_list);
240098686cd2SShayne Chen out:
240198686cd2SShayne Chen 	return start_tsf;
240298686cd2SShayne Chen }
240398686cd2SShayne Chen 
mt7996_mac_check_twt_req(struct ieee80211_twt_setup * twt)240498686cd2SShayne Chen static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
240598686cd2SShayne Chen {
240698686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt;
240798686cd2SShayne Chen 	u64 interval, duration;
240898686cd2SShayne Chen 	u16 mantissa;
240998686cd2SShayne Chen 	u8 exp;
241098686cd2SShayne Chen 
241198686cd2SShayne Chen 	/* only individual agreement supported */
241298686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
241398686cd2SShayne Chen 		return -EOPNOTSUPP;
241498686cd2SShayne Chen 
241598686cd2SShayne Chen 	/* only 256us unit supported */
241698686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
241798686cd2SShayne Chen 		return -EOPNOTSUPP;
241898686cd2SShayne Chen 
241998686cd2SShayne Chen 	twt_agrt = (struct ieee80211_twt_params *)twt->params;
242098686cd2SShayne Chen 
242198686cd2SShayne Chen 	/* explicit agreement not supported */
242298686cd2SShayne Chen 	if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
242398686cd2SShayne Chen 		return -EOPNOTSUPP;
242498686cd2SShayne Chen 
242598686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
242698686cd2SShayne Chen 			le16_to_cpu(twt_agrt->req_type));
242798686cd2SShayne Chen 	mantissa = le16_to_cpu(twt_agrt->mantissa);
242898686cd2SShayne Chen 	duration = twt_agrt->min_twt_dur << 8;
242998686cd2SShayne Chen 
243098686cd2SShayne Chen 	interval = (u64)mantissa << exp;
243198686cd2SShayne Chen 	if (interval < duration)
243298686cd2SShayne Chen 		return -EOPNOTSUPP;
243398686cd2SShayne Chen 
243498686cd2SShayne Chen 	return 0;
243598686cd2SShayne Chen }
243698686cd2SShayne Chen 
2437e6ed68cbSPeter Chiu static bool
mt7996_mac_twt_param_equal(struct mt7996_sta * msta,struct ieee80211_twt_params * twt_agrt)2438e6ed68cbSPeter Chiu mt7996_mac_twt_param_equal(struct mt7996_sta *msta,
2439e6ed68cbSPeter Chiu 			   struct ieee80211_twt_params *twt_agrt)
2440e6ed68cbSPeter Chiu {
2441e6ed68cbSPeter Chiu 	u16 type = le16_to_cpu(twt_agrt->req_type);
2442e6ed68cbSPeter Chiu 	u8 exp;
2443e6ed68cbSPeter Chiu 	int i;
2444e6ed68cbSPeter Chiu 
2445e6ed68cbSPeter Chiu 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, type);
2446e6ed68cbSPeter Chiu 	for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) {
2447e6ed68cbSPeter Chiu 		struct mt7996_twt_flow *f;
2448e6ed68cbSPeter Chiu 
2449e6ed68cbSPeter Chiu 		if (!(msta->twt.flowid_mask & BIT(i)))
2450e6ed68cbSPeter Chiu 			continue;
2451e6ed68cbSPeter Chiu 
2452e6ed68cbSPeter Chiu 		f = &msta->twt.flow[i];
2453e6ed68cbSPeter Chiu 		if (f->duration == twt_agrt->min_twt_dur &&
2454e6ed68cbSPeter Chiu 		    f->mantissa == twt_agrt->mantissa &&
2455e6ed68cbSPeter Chiu 		    f->exp == exp &&
2456e6ed68cbSPeter Chiu 		    f->protection == !!(type & IEEE80211_TWT_REQTYPE_PROTECTION) &&
2457e6ed68cbSPeter Chiu 		    f->flowtype == !!(type & IEEE80211_TWT_REQTYPE_FLOWTYPE) &&
2458e6ed68cbSPeter Chiu 		    f->trigger == !!(type & IEEE80211_TWT_REQTYPE_TRIGGER))
2459e6ed68cbSPeter Chiu 			return true;
2460e6ed68cbSPeter Chiu 	}
2461e6ed68cbSPeter Chiu 
2462e6ed68cbSPeter Chiu 	return false;
2463e6ed68cbSPeter Chiu }
2464e6ed68cbSPeter Chiu 
mt7996_mac_add_twt_setup(struct ieee80211_hw * hw,struct ieee80211_sta * sta,struct ieee80211_twt_setup * twt)246598686cd2SShayne Chen void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
246698686cd2SShayne Chen 			      struct ieee80211_sta *sta,
246798686cd2SShayne Chen 			      struct ieee80211_twt_setup *twt)
246898686cd2SShayne Chen {
246998686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
247098686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
247198686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
247298686cd2SShayne Chen 	u16 req_type = le16_to_cpu(twt_agrt->req_type);
247398686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd sta_setup_cmd;
247498686cd2SShayne Chen 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
247598686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
2476e6ed68cbSPeter Chiu 	u8 flowid, table_id, exp;
247798686cd2SShayne Chen 
247898686cd2SShayne Chen 	if (mt7996_mac_check_twt_req(twt))
247998686cd2SShayne Chen 		goto out;
248098686cd2SShayne Chen 
248198686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
248298686cd2SShayne Chen 
248398686cd2SShayne Chen 	if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
248498686cd2SShayne Chen 		goto unlock;
248598686cd2SShayne Chen 
248698686cd2SShayne Chen 	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
248798686cd2SShayne Chen 		goto unlock;
248898686cd2SShayne Chen 
2489e6ed68cbSPeter Chiu 	if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) {
2490e6ed68cbSPeter Chiu 		setup_cmd = TWT_SETUP_CMD_DICTATE;
2491e6ed68cbSPeter Chiu 		twt_agrt->min_twt_dur = MT7996_MIN_TWT_DUR;
2492e6ed68cbSPeter Chiu 		goto unlock;
2493e6ed68cbSPeter Chiu 	}
2494e6ed68cbSPeter Chiu 
2495e6ed68cbSPeter Chiu 	if (mt7996_mac_twt_param_equal(msta, twt_agrt))
2496e6ed68cbSPeter Chiu 		goto unlock;
2497e6ed68cbSPeter Chiu 
249898686cd2SShayne Chen 	flowid = ffs(~msta->twt.flowid_mask) - 1;
2499e6ed68cbSPeter Chiu 	twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID);
2500e6ed68cbSPeter Chiu 	twt_agrt->req_type |= le16_encode_bits(flowid,
250198686cd2SShayne Chen 					       IEEE80211_TWT_REQTYPE_FLOWID);
250298686cd2SShayne Chen 
250398686cd2SShayne Chen 	table_id = ffs(~dev->twt.table_mask) - 1;
250498686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
250598686cd2SShayne Chen 	sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
250698686cd2SShayne Chen 
250798686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
250898686cd2SShayne Chen 	memset(flow, 0, sizeof(*flow));
250998686cd2SShayne Chen 	INIT_LIST_HEAD(&flow->list);
251098686cd2SShayne Chen 	flow->wcid = msta->wcid.idx;
251198686cd2SShayne Chen 	flow->table_id = table_id;
251298686cd2SShayne Chen 	flow->id = flowid;
251398686cd2SShayne Chen 	flow->duration = twt_agrt->min_twt_dur;
251498686cd2SShayne Chen 	flow->mantissa = twt_agrt->mantissa;
251598686cd2SShayne Chen 	flow->exp = exp;
251698686cd2SShayne Chen 	flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
251798686cd2SShayne Chen 	flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
251898686cd2SShayne Chen 	flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
251998686cd2SShayne Chen 
252098686cd2SShayne Chen 	if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
252198686cd2SShayne Chen 	    sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
252298686cd2SShayne Chen 		u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
252398686cd2SShayne Chen 		u64 flow_tsf, curr_tsf;
252498686cd2SShayne Chen 		u32 rem;
252598686cd2SShayne Chen 
252698686cd2SShayne Chen 		flow->sched = true;
252798686cd2SShayne Chen 		flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
252898686cd2SShayne Chen 		curr_tsf = __mt7996_get_tsf(hw, msta->vif);
252998686cd2SShayne Chen 		div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
253098686cd2SShayne Chen 		flow_tsf = curr_tsf + interval - rem;
253198686cd2SShayne Chen 		twt_agrt->twt = cpu_to_le64(flow_tsf);
253298686cd2SShayne Chen 	} else {
253398686cd2SShayne Chen 		list_add_tail(&flow->list, &dev->twt_list);
253498686cd2SShayne Chen 	}
253598686cd2SShayne Chen 	flow->tsf = le64_to_cpu(twt_agrt->twt);
253698686cd2SShayne Chen 
253798686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
253898686cd2SShayne Chen 		goto unlock;
253998686cd2SShayne Chen 
254098686cd2SShayne Chen 	setup_cmd = TWT_SETUP_CMD_ACCEPT;
254198686cd2SShayne Chen 	dev->twt.table_mask |= BIT(table_id);
254298686cd2SShayne Chen 	msta->twt.flowid_mask |= BIT(flowid);
254398686cd2SShayne Chen 	dev->twt.n_agrt++;
254498686cd2SShayne Chen 
254598686cd2SShayne Chen unlock:
254698686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
254798686cd2SShayne Chen out:
2548e6ed68cbSPeter Chiu 	twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_SETUP_CMD);
2549e6ed68cbSPeter Chiu 	twt_agrt->req_type |=
2550e6ed68cbSPeter Chiu 		le16_encode_bits(setup_cmd, IEEE80211_TWT_REQTYPE_SETUP_CMD);
2551e6ed68cbSPeter Chiu 	twt->control = twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED;
255298686cd2SShayne Chen }
255398686cd2SShayne Chen 
mt7996_mac_twt_teardown_flow(struct mt7996_dev * dev,struct mt7996_sta * msta,u8 flowid)255498686cd2SShayne Chen void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
255598686cd2SShayne Chen 				  struct mt7996_sta *msta,
255698686cd2SShayne Chen 				  u8 flowid)
255798686cd2SShayne Chen {
255898686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
255998686cd2SShayne Chen 
256098686cd2SShayne Chen 	lockdep_assert_held(&dev->mt76.mutex);
256198686cd2SShayne Chen 
256298686cd2SShayne Chen 	if (flowid >= ARRAY_SIZE(msta->twt.flow))
256398686cd2SShayne Chen 		return;
256498686cd2SShayne Chen 
256598686cd2SShayne Chen 	if (!(msta->twt.flowid_mask & BIT(flowid)))
256698686cd2SShayne Chen 		return;
256798686cd2SShayne Chen 
256898686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
256998686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
257098686cd2SShayne Chen 				       MCU_TWT_AGRT_DELETE))
257198686cd2SShayne Chen 		return;
257298686cd2SShayne Chen 
257398686cd2SShayne Chen 	list_del_init(&flow->list);
257498686cd2SShayne Chen 	msta->twt.flowid_mask &= ~BIT(flowid);
257598686cd2SShayne Chen 	dev->twt.table_mask &= ~BIT(flow->table_id);
257698686cd2SShayne Chen 	dev->twt.n_agrt--;
257798686cd2SShayne Chen }
2578