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 
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 
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 
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 
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 
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 
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 */
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
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;
43680f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
43780f5a31dSShayne Chen 		status->bw = RATE_INFO_BW_320;
43880f5a31dSShayne Chen 		break;
43998686cd2SShayne Chen 	default:
44098686cd2SShayne Chen 		return -EINVAL;
44198686cd2SShayne Chen 	}
44298686cd2SShayne Chen 
44398686cd2SShayne Chen 	status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
44498686cd2SShayne Chen 	if (*mode < MT_PHY_TYPE_HE_SU && gi)
44598686cd2SShayne Chen 		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
44698686cd2SShayne Chen 
44798686cd2SShayne Chen 	return 0;
44898686cd2SShayne Chen }
44998686cd2SShayne Chen 
45098686cd2SShayne Chen static int
45198686cd2SShayne Chen mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
45298686cd2SShayne Chen {
45398686cd2SShayne Chen 	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
45498686cd2SShayne Chen 	struct mt76_phy *mphy = &dev->mt76.phy;
45598686cd2SShayne Chen 	struct mt7996_phy *phy = &dev->phy;
45698686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
45798686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
45898686cd2SShayne Chen 	__le32 *rxv = NULL;
45998686cd2SShayne Chen 	u32 rxd0 = le32_to_cpu(rxd[0]);
46098686cd2SShayne Chen 	u32 rxd1 = le32_to_cpu(rxd[1]);
46198686cd2SShayne Chen 	u32 rxd2 = le32_to_cpu(rxd[2]);
46298686cd2SShayne Chen 	u32 rxd3 = le32_to_cpu(rxd[3]);
46398686cd2SShayne Chen 	u32 rxd4 = le32_to_cpu(rxd[4]);
46498686cd2SShayne Chen 	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
46598686cd2SShayne Chen 	u32 csum_status = *(u32 *)skb->cb;
46627db47abSRyder Lee 	u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP;
46727db47abSRyder Lee 	bool is_mesh = (rxd0 & mesh_mask) == mesh_mask;
46898686cd2SShayne Chen 	bool unicast, insert_ccmp_hdr = false;
46998686cd2SShayne Chen 	u8 remove_pad, amsdu_info, band_idx;
47098686cd2SShayne Chen 	u8 mode = 0, qos_ctl = 0;
47198686cd2SShayne Chen 	bool hdr_trans;
47298686cd2SShayne Chen 	u16 hdr_gap;
47398686cd2SShayne Chen 	u16 seq_ctrl = 0;
47498686cd2SShayne Chen 	__le16 fc = 0;
47598686cd2SShayne Chen 	int idx;
47698686cd2SShayne Chen 
47798686cd2SShayne Chen 	memset(status, 0, sizeof(*status));
47898686cd2SShayne Chen 
47998686cd2SShayne Chen 	band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
48098686cd2SShayne Chen 	mphy = dev->mt76.phys[band_idx];
48198686cd2SShayne Chen 	phy = mphy->priv;
48298686cd2SShayne Chen 	status->phy_idx = mphy->band_idx;
48398686cd2SShayne Chen 
48498686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
48598686cd2SShayne Chen 		return -EINVAL;
48698686cd2SShayne Chen 
48798686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
48898686cd2SShayne Chen 		return -EINVAL;
48998686cd2SShayne Chen 
49098686cd2SShayne Chen 	hdr_trans = rxd2 & MT_RXD2_NORMAL_HDR_TRANS;
49198686cd2SShayne Chen 	if (hdr_trans && (rxd1 & MT_RXD1_NORMAL_CM))
49298686cd2SShayne Chen 		return -EINVAL;
49398686cd2SShayne Chen 
49498686cd2SShayne Chen 	/* ICV error or CCMP/BIP/WPI MIC error */
49598686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_ICV_ERR)
49698686cd2SShayne Chen 		status->flag |= RX_FLAG_ONLY_MONITOR;
49798686cd2SShayne Chen 
49898686cd2SShayne Chen 	unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
49998686cd2SShayne Chen 	idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
50098686cd2SShayne Chen 	status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
50198686cd2SShayne Chen 
50298686cd2SShayne Chen 	if (status->wcid) {
50398686cd2SShayne Chen 		struct mt7996_sta *msta;
50498686cd2SShayne Chen 
50598686cd2SShayne Chen 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
506ea0f3867SLorenzo Bianconi 		spin_lock_bh(&dev->mt76.sta_poll_lock);
507e3b0311fSLorenzo Bianconi 		if (list_empty(&msta->wcid.poll_list))
508e3b0311fSLorenzo Bianconi 			list_add_tail(&msta->wcid.poll_list,
509ea0f3867SLorenzo Bianconi 				      &dev->mt76.sta_poll_list);
510ea0f3867SLorenzo Bianconi 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
51198686cd2SShayne Chen 	}
51298686cd2SShayne Chen 
51398686cd2SShayne Chen 	status->freq = mphy->chandef.chan->center_freq;
51498686cd2SShayne Chen 	status->band = mphy->chandef.chan->band;
51598686cd2SShayne Chen 	if (status->band == NL80211_BAND_5GHZ)
51698686cd2SShayne Chen 		sband = &mphy->sband_5g.sband;
51798686cd2SShayne Chen 	else if (status->band == NL80211_BAND_6GHZ)
51898686cd2SShayne Chen 		sband = &mphy->sband_6g.sband;
51998686cd2SShayne Chen 	else
52098686cd2SShayne Chen 		sband = &mphy->sband_2g.sband;
52198686cd2SShayne Chen 
52298686cd2SShayne Chen 	if (!sband->channels)
52398686cd2SShayne Chen 		return -EINVAL;
52498686cd2SShayne Chen 
52598686cd2SShayne Chen 	if ((rxd0 & csum_mask) == csum_mask &&
52698686cd2SShayne Chen 	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
52798686cd2SShayne Chen 		skb->ip_summed = CHECKSUM_UNNECESSARY;
52898686cd2SShayne Chen 
52998686cd2SShayne Chen 	if (rxd1 & MT_RXD3_NORMAL_FCS_ERR)
53098686cd2SShayne Chen 		status->flag |= RX_FLAG_FAILED_FCS_CRC;
53198686cd2SShayne Chen 
53298686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR)
53398686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_ERROR;
53498686cd2SShayne Chen 
53598686cd2SShayne Chen 	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
53698686cd2SShayne Chen 	    !(rxd1 & (MT_RXD1_NORMAL_CLM | MT_RXD1_NORMAL_CM))) {
53798686cd2SShayne Chen 		status->flag |= RX_FLAG_DECRYPTED;
53898686cd2SShayne Chen 		status->flag |= RX_FLAG_IV_STRIPPED;
53998686cd2SShayne Chen 		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
54098686cd2SShayne Chen 	}
54198686cd2SShayne Chen 
54298686cd2SShayne Chen 	remove_pad = FIELD_GET(MT_RXD2_NORMAL_HDR_OFFSET, rxd2);
54398686cd2SShayne Chen 
54498686cd2SShayne Chen 	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
54598686cd2SShayne Chen 		return -EINVAL;
54698686cd2SShayne Chen 
54798686cd2SShayne Chen 	rxd += 8;
54898686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_4) {
54998686cd2SShayne Chen 		u32 v0 = le32_to_cpu(rxd[0]);
55098686cd2SShayne Chen 		u32 v2 = le32_to_cpu(rxd[2]);
55198686cd2SShayne Chen 
55298686cd2SShayne Chen 		fc = cpu_to_le16(FIELD_GET(MT_RXD8_FRAME_CONTROL, v0));
55398686cd2SShayne Chen 		qos_ctl = FIELD_GET(MT_RXD10_QOS_CTL, v2);
55498686cd2SShayne Chen 		seq_ctrl = FIELD_GET(MT_RXD10_SEQ_CTRL, v2);
55598686cd2SShayne Chen 
55698686cd2SShayne Chen 		rxd += 4;
55798686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
55898686cd2SShayne Chen 			return -EINVAL;
55998686cd2SShayne Chen 	}
56098686cd2SShayne Chen 
56198686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_1) {
56298686cd2SShayne Chen 		u8 *data = (u8 *)rxd;
56398686cd2SShayne Chen 
56498686cd2SShayne Chen 		if (status->flag & RX_FLAG_DECRYPTED) {
56598686cd2SShayne Chen 			switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
56698686cd2SShayne Chen 			case MT_CIPHER_AES_CCMP:
56798686cd2SShayne Chen 			case MT_CIPHER_CCMP_CCX:
56898686cd2SShayne Chen 			case MT_CIPHER_CCMP_256:
56998686cd2SShayne Chen 				insert_ccmp_hdr =
57098686cd2SShayne Chen 					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
57198686cd2SShayne Chen 				fallthrough;
57298686cd2SShayne Chen 			case MT_CIPHER_TKIP:
57398686cd2SShayne Chen 			case MT_CIPHER_TKIP_NO_MIC:
57498686cd2SShayne Chen 			case MT_CIPHER_GCMP:
57598686cd2SShayne Chen 			case MT_CIPHER_GCMP_256:
57698686cd2SShayne Chen 				status->iv[0] = data[5];
57798686cd2SShayne Chen 				status->iv[1] = data[4];
57898686cd2SShayne Chen 				status->iv[2] = data[3];
57998686cd2SShayne Chen 				status->iv[3] = data[2];
58098686cd2SShayne Chen 				status->iv[4] = data[1];
58198686cd2SShayne Chen 				status->iv[5] = data[0];
58298686cd2SShayne Chen 				break;
58398686cd2SShayne Chen 			default:
58498686cd2SShayne Chen 				break;
58598686cd2SShayne Chen 			}
58698686cd2SShayne Chen 		}
58798686cd2SShayne Chen 		rxd += 4;
58898686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
58998686cd2SShayne Chen 			return -EINVAL;
59098686cd2SShayne Chen 	}
59198686cd2SShayne Chen 
59298686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_2) {
59398686cd2SShayne Chen 		status->timestamp = le32_to_cpu(rxd[0]);
59498686cd2SShayne Chen 		status->flag |= RX_FLAG_MACTIME_START;
59598686cd2SShayne Chen 
59698686cd2SShayne Chen 		if (!(rxd2 & MT_RXD2_NORMAL_NON_AMPDU)) {
59798686cd2SShayne Chen 			status->flag |= RX_FLAG_AMPDU_DETAILS;
59898686cd2SShayne Chen 
59998686cd2SShayne Chen 			/* all subframes of an A-MPDU have the same timestamp */
60098686cd2SShayne Chen 			if (phy->rx_ampdu_ts != status->timestamp) {
60198686cd2SShayne Chen 				if (!++phy->ampdu_ref)
60298686cd2SShayne Chen 					phy->ampdu_ref++;
60398686cd2SShayne Chen 			}
60498686cd2SShayne Chen 			phy->rx_ampdu_ts = status->timestamp;
60598686cd2SShayne Chen 
60698686cd2SShayne Chen 			status->ampdu_ref = phy->ampdu_ref;
60798686cd2SShayne Chen 		}
60898686cd2SShayne Chen 
60998686cd2SShayne Chen 		rxd += 4;
61098686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
61198686cd2SShayne Chen 			return -EINVAL;
61298686cd2SShayne Chen 	}
61398686cd2SShayne Chen 
61498686cd2SShayne Chen 	/* RXD Group 3 - P-RXV */
61598686cd2SShayne Chen 	if (rxd1 & MT_RXD1_NORMAL_GROUP_3) {
61698686cd2SShayne Chen 		u32 v3;
61798686cd2SShayne Chen 		int ret;
61898686cd2SShayne Chen 
61998686cd2SShayne Chen 		rxv = rxd;
62098686cd2SShayne Chen 		rxd += 4;
62198686cd2SShayne Chen 		if ((u8 *)rxd - skb->data >= skb->len)
62298686cd2SShayne Chen 			return -EINVAL;
62398686cd2SShayne Chen 
62498686cd2SShayne Chen 		v3 = le32_to_cpu(rxv[3]);
62598686cd2SShayne Chen 
62698686cd2SShayne Chen 		status->chains = mphy->antenna_mask;
62798686cd2SShayne Chen 		status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v3);
62898686cd2SShayne Chen 		status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v3);
62998686cd2SShayne Chen 		status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v3);
63098686cd2SShayne Chen 		status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v3);
63198686cd2SShayne Chen 
63298686cd2SShayne Chen 		/* RXD Group 5 - C-RXV */
63398686cd2SShayne Chen 		if (rxd1 & MT_RXD1_NORMAL_GROUP_5) {
63498686cd2SShayne Chen 			rxd += 24;
63598686cd2SShayne Chen 			if ((u8 *)rxd - skb->data >= skb->len)
63698686cd2SShayne Chen 				return -EINVAL;
63798686cd2SShayne Chen 		}
63898686cd2SShayne Chen 
63998686cd2SShayne Chen 		ret = mt7996_mac_fill_rx_rate(dev, status, sband, rxv, &mode);
64098686cd2SShayne Chen 		if (ret < 0)
64198686cd2SShayne Chen 			return ret;
64298686cd2SShayne Chen 	}
64398686cd2SShayne Chen 
64498686cd2SShayne Chen 	amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
64598686cd2SShayne Chen 	status->amsdu = !!amsdu_info;
64698686cd2SShayne Chen 	if (status->amsdu) {
64798686cd2SShayne Chen 		status->first_amsdu = amsdu_info == MT_RXD4_FIRST_AMSDU_FRAME;
64898686cd2SShayne Chen 		status->last_amsdu = amsdu_info == MT_RXD4_LAST_AMSDU_FRAME;
64998686cd2SShayne Chen 	}
65098686cd2SShayne Chen 
65198686cd2SShayne Chen 	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
65298686cd2SShayne Chen 	if (hdr_trans && ieee80211_has_morefrags(fc)) {
65398686cd2SShayne Chen 		if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
65498686cd2SShayne Chen 			return -EINVAL;
65598686cd2SShayne Chen 		hdr_trans = false;
65698686cd2SShayne Chen 	} else {
65798686cd2SShayne Chen 		int pad_start = 0;
65898686cd2SShayne Chen 
65998686cd2SShayne Chen 		skb_pull(skb, hdr_gap);
66027db47abSRyder Lee 		if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
66198686cd2SShayne Chen 			pad_start = ieee80211_get_hdrlen_from_skb(skb);
662c55b4e78SRyder Lee 		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
66398686cd2SShayne Chen 			/* When header translation failure is indicated,
66498686cd2SShayne Chen 			 * the hardware will insert an extra 2-byte field
66598686cd2SShayne Chen 			 * containing the data length after the protocol
666c55b4e78SRyder Lee 			 * type field. This happens either when the LLC-SNAP
667c55b4e78SRyder Lee 			 * pattern did not match, or if a VLAN header was
668c55b4e78SRyder Lee 			 * detected.
66998686cd2SShayne Chen 			 */
670c55b4e78SRyder Lee 			pad_start = 12;
671c55b4e78SRyder Lee 			if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
672c55b4e78SRyder Lee 				pad_start += 4;
673c55b4e78SRyder Lee 			else
674c55b4e78SRyder Lee 				pad_start = 0;
67598686cd2SShayne Chen 		}
67698686cd2SShayne Chen 
67798686cd2SShayne Chen 		if (pad_start) {
67898686cd2SShayne Chen 			memmove(skb->data + 2, skb->data, pad_start);
67998686cd2SShayne Chen 			skb_pull(skb, 2);
68098686cd2SShayne Chen 		}
68198686cd2SShayne Chen 	}
68298686cd2SShayne Chen 
68398686cd2SShayne Chen 	if (!hdr_trans) {
68498686cd2SShayne Chen 		struct ieee80211_hdr *hdr;
68598686cd2SShayne Chen 
68698686cd2SShayne Chen 		if (insert_ccmp_hdr) {
68798686cd2SShayne Chen 			u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
68898686cd2SShayne Chen 
68998686cd2SShayne Chen 			mt76_insert_ccmp_hdr(skb, key_id);
69098686cd2SShayne Chen 		}
69198686cd2SShayne Chen 
69298686cd2SShayne Chen 		hdr = mt76_skb_get_hdr(skb);
69398686cd2SShayne Chen 		fc = hdr->frame_control;
69498686cd2SShayne Chen 		if (ieee80211_is_data_qos(fc)) {
69527db47abSRyder Lee 			u8 *qos = ieee80211_get_qos_ctl(hdr);
69627db47abSRyder Lee 
69798686cd2SShayne Chen 			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
69827db47abSRyder Lee 			qos_ctl = *qos;
69927db47abSRyder Lee 
70027db47abSRyder Lee 			/* Mesh DA/SA/Length will be stripped after hardware
70127db47abSRyder Lee 			 * de-amsdu, so here needs to clear amsdu present bit
70227db47abSRyder Lee 			 * to mark it as a normal mesh frame.
70327db47abSRyder Lee 			 */
70427db47abSRyder Lee 			if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
70527db47abSRyder Lee 				*qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
70698686cd2SShayne Chen 		}
70798686cd2SShayne Chen 	} else {
70898686cd2SShayne Chen 		status->flag |= RX_FLAG_8023;
70998686cd2SShayne Chen 	}
71098686cd2SShayne Chen 
71198686cd2SShayne Chen 	if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
712*46d3304dSLorenzo Bianconi 		mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
71398686cd2SShayne Chen 
71498686cd2SShayne Chen 	if (!status->wcid || !ieee80211_is_data_qos(fc))
71598686cd2SShayne Chen 		return 0;
71698686cd2SShayne Chen 
71798686cd2SShayne Chen 	status->aggr = unicast &&
71898686cd2SShayne Chen 		       !ieee80211_is_qos_nullfunc(fc);
71998686cd2SShayne Chen 	status->qos_ctl = qos_ctl;
72098686cd2SShayne Chen 	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
72198686cd2SShayne Chen 
72298686cd2SShayne Chen 	return 0;
72398686cd2SShayne Chen }
72498686cd2SShayne Chen 
72598686cd2SShayne Chen static void
72698686cd2SShayne Chen mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
72798686cd2SShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid)
72898686cd2SShayne Chen {
72998686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
73098686cd2SShayne Chen 	u8 fc_type, fc_stype;
73198686cd2SShayne Chen 	u16 ethertype;
73298686cd2SShayne Chen 	bool wmm = false;
73398686cd2SShayne Chen 	u32 val;
73498686cd2SShayne Chen 
73598686cd2SShayne Chen 	if (wcid->sta) {
73698686cd2SShayne Chen 		struct ieee80211_sta *sta;
73798686cd2SShayne Chen 
73898686cd2SShayne Chen 		sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
73998686cd2SShayne Chen 		wmm = sta->wme;
74098686cd2SShayne Chen 	}
74198686cd2SShayne Chen 
74298686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
74398686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
74498686cd2SShayne Chen 
74598686cd2SShayne Chen 	ethertype = get_unaligned_be16(&skb->data[12]);
74698686cd2SShayne Chen 	if (ethertype >= ETH_P_802_3_MIN)
74798686cd2SShayne Chen 		val |= MT_TXD1_ETH_802_3;
74898686cd2SShayne Chen 
74998686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
75098686cd2SShayne Chen 
75198686cd2SShayne Chen 	fc_type = IEEE80211_FTYPE_DATA >> 2;
75298686cd2SShayne Chen 	fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
75398686cd2SShayne Chen 
75498686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
75598686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
75698686cd2SShayne Chen 
75798686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
75898686cd2SShayne Chen }
75998686cd2SShayne Chen 
76098686cd2SShayne Chen static void
76198686cd2SShayne Chen mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
76298686cd2SShayne Chen 			    struct sk_buff *skb, struct ieee80211_key_conf *key)
76398686cd2SShayne Chen {
76498686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
76598686cd2SShayne Chen 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
76698686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
76798686cd2SShayne Chen 	bool multicast = is_multicast_ether_addr(hdr->addr1);
76898686cd2SShayne Chen 	u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
76998686cd2SShayne Chen 	__le16 fc = hdr->frame_control;
77098686cd2SShayne Chen 	u8 fc_type, fc_stype;
77198686cd2SShayne Chen 	u32 val;
77298686cd2SShayne Chen 
77398686cd2SShayne Chen 	if (ieee80211_is_action(fc) &&
77498686cd2SShayne Chen 	    mgmt->u.action.category == WLAN_CATEGORY_BACK &&
77598686cd2SShayne Chen 	    mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
77698686cd2SShayne Chen 		tid = MT_TX_ADDBA;
77798686cd2SShayne Chen 	else if (ieee80211_is_mgmt(hdr->frame_control))
77898686cd2SShayne Chen 		tid = MT_TX_NORMAL;
77998686cd2SShayne Chen 
78098686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
78198686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_HDR_INFO,
78298686cd2SShayne Chen 			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
78398686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_TID, tid);
78498686cd2SShayne Chen 
78598686cd2SShayne Chen 	if (!ieee80211_is_data(fc) || multicast ||
78698686cd2SShayne Chen 	    info->flags & IEEE80211_TX_CTL_USE_MINRATE)
78798686cd2SShayne Chen 		val |= MT_TXD1_FIXED_RATE;
78898686cd2SShayne Chen 
78998686cd2SShayne Chen 	if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
79098686cd2SShayne Chen 	    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
79198686cd2SShayne Chen 		val |= MT_TXD1_BIP;
79298686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
79398686cd2SShayne Chen 	}
79498686cd2SShayne Chen 
79598686cd2SShayne Chen 	txwi[1] |= cpu_to_le32(val);
79698686cd2SShayne Chen 
79798686cd2SShayne Chen 	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
79898686cd2SShayne Chen 	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
79998686cd2SShayne Chen 
80098686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
80198686cd2SShayne Chen 	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
80298686cd2SShayne Chen 
80398686cd2SShayne Chen 	txwi[2] |= cpu_to_le32(val);
80498686cd2SShayne Chen 
80598686cd2SShayne Chen 	txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast));
80698686cd2SShayne Chen 	if (ieee80211_is_beacon(fc)) {
80798686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
80898686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
80998686cd2SShayne Chen 	}
81098686cd2SShayne Chen 
81198686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
81298686cd2SShayne Chen 		u16 seqno = le16_to_cpu(hdr->seq_ctrl);
81398686cd2SShayne Chen 
81498686cd2SShayne Chen 		if (ieee80211_is_back_req(hdr->frame_control)) {
81598686cd2SShayne Chen 			struct ieee80211_bar *bar;
81698686cd2SShayne Chen 
81798686cd2SShayne Chen 			bar = (struct ieee80211_bar *)skb->data;
81898686cd2SShayne Chen 			seqno = le16_to_cpu(bar->start_seq_num);
81998686cd2SShayne Chen 		}
82098686cd2SShayne Chen 
82198686cd2SShayne Chen 		val = MT_TXD3_SN_VALID |
82298686cd2SShayne Chen 		      FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
82398686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(val);
82498686cd2SShayne Chen 		txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
82598686cd2SShayne Chen 	}
82698686cd2SShayne Chen }
82798686cd2SShayne Chen 
82898686cd2SShayne Chen void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
829d0b6f86fSShayne Chen 			   struct sk_buff *skb, struct mt76_wcid *wcid,
830d0b6f86fSShayne Chen 			   struct ieee80211_key_conf *key, int pid,
831d0b6f86fSShayne Chen 			   enum mt76_txq_id qid, u32 changed)
83298686cd2SShayne Chen {
83398686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
83498686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
83598686cd2SShayne Chen 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
83698686cd2SShayne Chen 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
83798686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
8380cb065b9SLorenzo Bianconi 	struct mt76_vif *mvif;
83998686cd2SShayne Chen 	u16 tx_count = 15;
84098686cd2SShayne Chen 	u32 val;
84198686cd2SShayne Chen 	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
84298686cd2SShayne Chen 				    BSS_CHANGED_BEACON_ENABLED));
84398686cd2SShayne Chen 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
84498686cd2SShayne Chen 					 BSS_CHANGED_FILS_DISCOVERY));
84598686cd2SShayne Chen 
8460cb065b9SLorenzo Bianconi 	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
847ead44902SLorenzo Bianconi 	if (mvif) {
8480cb065b9SLorenzo Bianconi 		omac_idx = mvif->omac_idx;
8490cb065b9SLorenzo Bianconi 		wmm_idx = mvif->wmm_idx;
8500cb065b9SLorenzo Bianconi 		band_idx = mvif->band_idx;
85198686cd2SShayne Chen 	}
85298686cd2SShayne Chen 
85398686cd2SShayne Chen 	if (inband_disc) {
85498686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
85598686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
85698686cd2SShayne Chen 	} else if (beacon) {
85798686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_FW;
85898686cd2SShayne Chen 		q_idx = MT_LMAC_BCN0;
859d0b6f86fSShayne Chen 	} else if (qid >= MT_TXQ_PSD) {
86098686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
86198686cd2SShayne Chen 		q_idx = MT_LMAC_ALTX0;
86298686cd2SShayne Chen 	} else {
86398686cd2SShayne Chen 		p_fmt = MT_TX_TYPE_CT;
86498686cd2SShayne Chen 		q_idx = wmm_idx * MT7996_MAX_WMM_SETS +
86598686cd2SShayne Chen 			mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
86698686cd2SShayne Chen 	}
86798686cd2SShayne Chen 
86898686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
86998686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
87098686cd2SShayne Chen 	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
87198686cd2SShayne Chen 	txwi[0] = cpu_to_le32(val);
87298686cd2SShayne Chen 
87398686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
87498686cd2SShayne Chen 	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
87598686cd2SShayne Chen 
87698686cd2SShayne Chen 	if (band_idx)
87798686cd2SShayne Chen 		val |= FIELD_PREP(MT_TXD1_TGID, band_idx);
87898686cd2SShayne Chen 
87998686cd2SShayne Chen 	txwi[1] = cpu_to_le32(val);
88098686cd2SShayne Chen 	txwi[2] = 0;
88198686cd2SShayne Chen 
88298686cd2SShayne Chen 	val = MT_TXD3_SW_POWER_MGMT |
88398686cd2SShayne Chen 	      FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
88498686cd2SShayne Chen 	if (key)
88598686cd2SShayne Chen 		val |= MT_TXD3_PROTECT_FRAME;
88698686cd2SShayne Chen 	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
88798686cd2SShayne Chen 		val |= MT_TXD3_NO_ACK;
88898686cd2SShayne Chen 	if (wcid->amsdu)
88998686cd2SShayne Chen 		val |= MT_TXD3_HW_AMSDU;
89098686cd2SShayne Chen 
89198686cd2SShayne Chen 	txwi[3] = cpu_to_le32(val);
89298686cd2SShayne Chen 	txwi[4] = 0;
89398686cd2SShayne Chen 
89498686cd2SShayne Chen 	val = FIELD_PREP(MT_TXD5_PID, pid);
89598686cd2SShayne Chen 	if (pid >= MT_PACKET_ID_FIRST)
89698686cd2SShayne Chen 		val |= MT_TXD5_TX_STATUS_HOST;
89798686cd2SShayne Chen 	txwi[5] = cpu_to_le32(val);
89898686cd2SShayne Chen 
89998686cd2SShayne Chen 	val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
90098686cd2SShayne Chen 	      FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
90198686cd2SShayne Chen 	txwi[6] = cpu_to_le32(val);
90298686cd2SShayne Chen 	txwi[7] = 0;
90398686cd2SShayne Chen 
90498686cd2SShayne Chen 	if (is_8023)
90598686cd2SShayne Chen 		mt7996_mac_write_txwi_8023(dev, txwi, skb, wcid);
90698686cd2SShayne Chen 	else
90798686cd2SShayne Chen 		mt7996_mac_write_txwi_80211(dev, txwi, skb, key);
90898686cd2SShayne Chen 
90998686cd2SShayne Chen 	if (txwi[1] & cpu_to_le32(MT_TXD1_FIXED_RATE)) {
910ab0eec4bSRyder Lee 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
911ab0eec4bSRyder Lee 		bool mcast = ieee80211_is_data(hdr->frame_control) &&
912ab0eec4bSRyder Lee 			     is_multicast_ether_addr(hdr->addr1);
913ead44902SLorenzo Bianconi 		u8 idx = MT7996_BASIC_RATES_TBL;
91498686cd2SShayne Chen 
915ead44902SLorenzo Bianconi 		if (mvif) {
916ab0eec4bSRyder Lee 			if (mcast && mvif->mcast_rates_idx)
917ab0eec4bSRyder Lee 				idx = mvif->mcast_rates_idx;
918c2171b06SRyder Lee 			else if (beacon && mvif->beacon_rates_idx)
919c2171b06SRyder Lee 				idx = mvif->beacon_rates_idx;
920ead44902SLorenzo Bianconi 			else
921ead44902SLorenzo Bianconi 				idx = mvif->basic_rates_idx;
922ead44902SLorenzo Bianconi 		}
923ab0eec4bSRyder Lee 
924cdc26ee8SRyder Lee 		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
92598686cd2SShayne Chen 		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
92698686cd2SShayne Chen 	}
92798686cd2SShayne Chen }
92898686cd2SShayne Chen 
92998686cd2SShayne Chen int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
93098686cd2SShayne Chen 			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
93198686cd2SShayne Chen 			  struct ieee80211_sta *sta,
93298686cd2SShayne Chen 			  struct mt76_tx_info *tx_info)
93398686cd2SShayne Chen {
93498686cd2SShayne Chen 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
93598686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
93698686cd2SShayne Chen 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
93798686cd2SShayne Chen 	struct ieee80211_key_conf *key = info->control.hw_key;
93898686cd2SShayne Chen 	struct ieee80211_vif *vif = info->control.vif;
9393c38dfc1SLorenzo Bianconi 	struct mt76_connac_txp_common *txp;
94098686cd2SShayne Chen 	struct mt76_txwi_cache *t;
94198686cd2SShayne Chen 	int id, i, pid, nbuf = tx_info->nbuf - 1;
94298686cd2SShayne Chen 	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
94398686cd2SShayne Chen 	u8 *txwi = (u8 *)txwi_ptr;
94498686cd2SShayne Chen 
94598686cd2SShayne Chen 	if (unlikely(tx_info->skb->len <= ETH_HLEN))
94698686cd2SShayne Chen 		return -EINVAL;
94798686cd2SShayne Chen 
94898686cd2SShayne Chen 	if (!wcid)
94998686cd2SShayne Chen 		wcid = &dev->mt76.global_wcid;
95098686cd2SShayne Chen 
95198686cd2SShayne Chen 	if (sta) {
95298686cd2SShayne Chen 		struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
95398686cd2SShayne Chen 
95498686cd2SShayne Chen 		if (time_after(jiffies, msta->jiffies + HZ / 4)) {
95598686cd2SShayne Chen 			info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
95698686cd2SShayne Chen 			msta->jiffies = jiffies;
95798686cd2SShayne Chen 		}
95898686cd2SShayne Chen 	}
95998686cd2SShayne Chen 
96098686cd2SShayne Chen 	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
96198686cd2SShayne Chen 	t->skb = tx_info->skb;
96298686cd2SShayne Chen 
96398686cd2SShayne Chen 	id = mt76_token_consume(mdev, &t);
96498686cd2SShayne Chen 	if (id < 0)
96598686cd2SShayne Chen 		return id;
96698686cd2SShayne Chen 
96798686cd2SShayne Chen 	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
968d0b6f86fSShayne Chen 	mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
969d0b6f86fSShayne Chen 			      pid, qid, 0);
97098686cd2SShayne Chen 
9713c38dfc1SLorenzo Bianconi 	txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
97298686cd2SShayne Chen 	for (i = 0; i < nbuf; i++) {
9733c38dfc1SLorenzo Bianconi 		txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
9743c38dfc1SLorenzo Bianconi 		txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
97598686cd2SShayne Chen 	}
9763c38dfc1SLorenzo Bianconi 	txp->fw.nbuf = nbuf;
97798686cd2SShayne Chen 
9783b522cadSRyder Lee 	txp->fw.flags =
9793b522cadSRyder Lee 		cpu_to_le16(MT_CT_INFO_FROM_HOST | MT_CT_INFO_APPLY_TXD);
98098686cd2SShayne Chen 
98198686cd2SShayne Chen 	if (!key)
9823c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
98398686cd2SShayne Chen 
98498686cd2SShayne Chen 	if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
9853c38dfc1SLorenzo Bianconi 		txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
98698686cd2SShayne Chen 
98798686cd2SShayne Chen 	if (vif) {
98898686cd2SShayne Chen 		struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
98998686cd2SShayne Chen 
9903c38dfc1SLorenzo Bianconi 		txp->fw.bss_idx = mvif->mt76.idx;
99198686cd2SShayne Chen 	}
99298686cd2SShayne Chen 
9933c38dfc1SLorenzo Bianconi 	txp->fw.token = cpu_to_le16(id);
99498686cd2SShayne Chen 	if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
9953c38dfc1SLorenzo Bianconi 		txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
99698686cd2SShayne Chen 	else
9973c38dfc1SLorenzo Bianconi 		txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
99898686cd2SShayne Chen 	tx_info->skb = DMA_DUMMY_DATA;
99998686cd2SShayne Chen 
100098686cd2SShayne Chen 	/* pass partial skb header to fw */
100198686cd2SShayne Chen 	tx_info->buf[1].len = MT_CT_PARSE_LEN;
100298686cd2SShayne Chen 	tx_info->buf[1].skip_unmap = true;
100398686cd2SShayne Chen 	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
100498686cd2SShayne Chen 
100598686cd2SShayne Chen 	return 0;
100698686cd2SShayne Chen }
100798686cd2SShayne Chen 
100898686cd2SShayne Chen static void
100998686cd2SShayne Chen mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
101098686cd2SShayne Chen {
101198686cd2SShayne Chen 	struct mt7996_sta *msta;
101298686cd2SShayne Chen 	u16 fc, tid;
101398686cd2SShayne Chen 	u32 val;
101498686cd2SShayne Chen 
101598686cd2SShayne Chen 	if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
101698686cd2SShayne Chen 		return;
101798686cd2SShayne Chen 
101898686cd2SShayne Chen 	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
101998686cd2SShayne Chen 	if (tid >= 6) /* skip VO queue */
102098686cd2SShayne Chen 		return;
102198686cd2SShayne Chen 
102298686cd2SShayne Chen 	val = le32_to_cpu(txwi[2]);
102398686cd2SShayne Chen 	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
102498686cd2SShayne Chen 	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
102598686cd2SShayne Chen 	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
102698686cd2SShayne Chen 		return;
102798686cd2SShayne Chen 
102898686cd2SShayne Chen 	msta = (struct mt7996_sta *)sta->drv_priv;
1029ef591d74SLorenzo Bianconi 	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
103098686cd2SShayne Chen 		ieee80211_start_tx_ba_session(sta, tid, 0);
103198686cd2SShayne Chen }
103298686cd2SShayne Chen 
103398686cd2SShayne Chen static void
103498686cd2SShayne Chen mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
103598686cd2SShayne Chen 		 struct ieee80211_sta *sta, struct list_head *free_list)
103698686cd2SShayne Chen {
103798686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
103898686cd2SShayne Chen 	struct mt76_wcid *wcid;
103998686cd2SShayne Chen 	__le32 *txwi;
104098686cd2SShayne Chen 	u16 wcid_idx;
104198686cd2SShayne Chen 
104230495864SLorenzo Bianconi 	mt76_connac_txp_skb_unmap(mdev, t);
104398686cd2SShayne Chen 	if (!t->skb)
104498686cd2SShayne Chen 		goto out;
104598686cd2SShayne Chen 
104698686cd2SShayne Chen 	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
104798686cd2SShayne Chen 	if (sta) {
104898686cd2SShayne Chen 		wcid = (struct mt76_wcid *)sta->drv_priv;
104998686cd2SShayne Chen 		wcid_idx = wcid->idx;
105098686cd2SShayne Chen 
105198686cd2SShayne Chen 		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
105298686cd2SShayne Chen 			mt7996_tx_check_aggr(sta, txwi);
105398686cd2SShayne Chen 	} else {
105498686cd2SShayne Chen 		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
105598686cd2SShayne Chen 	}
105698686cd2SShayne Chen 
105798686cd2SShayne Chen 	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
105898686cd2SShayne Chen 
105998686cd2SShayne Chen out:
106098686cd2SShayne Chen 	t->skb = NULL;
106198686cd2SShayne Chen 	mt76_put_txwi(mdev, t);
106298686cd2SShayne Chen }
106398686cd2SShayne Chen 
106498686cd2SShayne Chen static void
106598686cd2SShayne Chen mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
106698686cd2SShayne Chen {
106798686cd2SShayne Chen 	__le32 *tx_free = (__le32 *)data, *cur_info;
106898686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
106998686cd2SShayne Chen 	struct mt76_phy *phy2 = mdev->phys[MT_BAND1];
107098686cd2SShayne Chen 	struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
107198686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
107298686cd2SShayne Chen 	struct ieee80211_sta *sta = NULL;
107398686cd2SShayne Chen 	LIST_HEAD(free_list);
107498686cd2SShayne Chen 	struct sk_buff *skb, *tmp;
107598686cd2SShayne Chen 	void *end = data + len;
107698686cd2SShayne Chen 	bool wake = false;
107798686cd2SShayne Chen 	u16 total, count = 0;
107898686cd2SShayne Chen 
107998686cd2SShayne Chen 	/* clean DMA queues and unmap buffers first */
108098686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
108198686cd2SShayne Chen 	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
108298686cd2SShayne Chen 	if (phy2) {
108398686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_PSD], false);
108498686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy2->q_tx[MT_TXQ_BE], false);
108598686cd2SShayne Chen 	}
108698686cd2SShayne Chen 	if (phy3) {
108798686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_PSD], false);
108898686cd2SShayne Chen 		mt76_queue_tx_cleanup(dev, phy3->q_tx[MT_TXQ_BE], false);
108998686cd2SShayne Chen 	}
109098686cd2SShayne Chen 
109198686cd2SShayne Chen 	if (WARN_ON_ONCE(le32_get_bits(tx_free[1], MT_TXFREE1_VER) < 4))
109298686cd2SShayne Chen 		return;
109398686cd2SShayne Chen 
109498686cd2SShayne Chen 	total = le32_get_bits(tx_free[0], MT_TXFREE0_MSDU_CNT);
109598686cd2SShayne Chen 	for (cur_info = &tx_free[2]; count < total; cur_info++) {
109698686cd2SShayne Chen 		u32 msdu, info;
109798686cd2SShayne Chen 		u8 i;
109898686cd2SShayne Chen 
109998686cd2SShayne Chen 		if (WARN_ON_ONCE((void *)cur_info >= end))
110098686cd2SShayne Chen 			return;
110198686cd2SShayne Chen 		/* 1'b1: new wcid pair.
110298686cd2SShayne Chen 		 * 1'b0: msdu_id with the same 'wcid pair' as above.
110398686cd2SShayne Chen 		 */
110498686cd2SShayne Chen 		info = le32_to_cpu(*cur_info);
110598686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_PAIR) {
110698686cd2SShayne Chen 			struct mt7996_sta *msta;
110798686cd2SShayne Chen 			struct mt76_wcid *wcid;
110898686cd2SShayne Chen 			u16 idx;
110998686cd2SShayne Chen 
111098686cd2SShayne Chen 			idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
111198686cd2SShayne Chen 			wcid = rcu_dereference(dev->mt76.wcid[idx]);
111298686cd2SShayne Chen 			sta = wcid_to_sta(wcid);
111398686cd2SShayne Chen 			if (!sta)
111498686cd2SShayne Chen 				continue;
111598686cd2SShayne Chen 
111698686cd2SShayne Chen 			msta = container_of(wcid, struct mt7996_sta, wcid);
1117ea0f3867SLorenzo Bianconi 			spin_lock_bh(&mdev->sta_poll_lock);
1118e3b0311fSLorenzo Bianconi 			if (list_empty(&msta->wcid.poll_list))
1119e3b0311fSLorenzo Bianconi 				list_add_tail(&msta->wcid.poll_list,
1120ea0f3867SLorenzo Bianconi 					      &mdev->sta_poll_list);
1121ea0f3867SLorenzo Bianconi 			spin_unlock_bh(&mdev->sta_poll_lock);
112298686cd2SShayne Chen 			continue;
112398686cd2SShayne Chen 		}
112498686cd2SShayne Chen 
112598686cd2SShayne Chen 		if (info & MT_TXFREE_INFO_HEADER)
112698686cd2SShayne Chen 			continue;
112798686cd2SShayne Chen 
112898686cd2SShayne Chen 		for (i = 0; i < 2; i++) {
112998686cd2SShayne Chen 			msdu = (info >> (15 * i)) & MT_TXFREE_INFO_MSDU_ID;
113098686cd2SShayne Chen 			if (msdu == MT_TXFREE_INFO_MSDU_ID)
113198686cd2SShayne Chen 				continue;
113298686cd2SShayne Chen 
113398686cd2SShayne Chen 			count++;
113498686cd2SShayne Chen 			txwi = mt76_token_release(mdev, msdu, &wake);
113598686cd2SShayne Chen 			if (!txwi)
113698686cd2SShayne Chen 				continue;
113798686cd2SShayne Chen 
113898686cd2SShayne Chen 			mt7996_txwi_free(dev, txwi, sta, &free_list);
113998686cd2SShayne Chen 		}
114098686cd2SShayne Chen 	}
114198686cd2SShayne Chen 
114298686cd2SShayne Chen 	mt7996_mac_sta_poll(dev);
114398686cd2SShayne Chen 
114498686cd2SShayne Chen 	if (wake)
114598686cd2SShayne Chen 		mt76_set_tx_blocked(&dev->mt76, false);
114698686cd2SShayne Chen 
114798686cd2SShayne Chen 	mt76_worker_schedule(&dev->mt76.tx_worker);
114898686cd2SShayne Chen 
114998686cd2SShayne Chen 	list_for_each_entry_safe(skb, tmp, &free_list, list) {
115098686cd2SShayne Chen 		skb_list_del_init(skb);
115198686cd2SShayne Chen 		napi_consume_skb(skb, 1);
115298686cd2SShayne Chen 	}
115398686cd2SShayne Chen }
115498686cd2SShayne Chen 
115598686cd2SShayne Chen static bool
1156d82e7c67SLorenzo Bianconi mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
1157d82e7c67SLorenzo Bianconi 		       int pid, __le32 *txs_data)
115898686cd2SShayne Chen {
1159d82e7c67SLorenzo Bianconi 	struct mt76_sta_stats *stats = &wcid->stats;
116098686cd2SShayne Chen 	struct ieee80211_supported_band *sband;
116198686cd2SShayne Chen 	struct mt76_dev *mdev = &dev->mt76;
116298686cd2SShayne Chen 	struct mt76_phy *mphy;
116398686cd2SShayne Chen 	struct ieee80211_tx_info *info;
116498686cd2SShayne Chen 	struct sk_buff_head list;
116598686cd2SShayne Chen 	struct rate_info rate = {};
116698686cd2SShayne Chen 	struct sk_buff *skb;
116798686cd2SShayne Chen 	bool cck = false;
116898686cd2SShayne Chen 	u32 txrate, txs, mode, stbc;
116998686cd2SShayne Chen 
117098686cd2SShayne Chen 	mt76_tx_status_lock(mdev, &list);
117198686cd2SShayne Chen 	skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list);
117298686cd2SShayne Chen 	if (!skb)
117398686cd2SShayne Chen 		goto out_no_skb;
117498686cd2SShayne Chen 
117598686cd2SShayne Chen 	txs = le32_to_cpu(txs_data[0]);
117698686cd2SShayne Chen 
117798686cd2SShayne Chen 	info = IEEE80211_SKB_CB(skb);
117898686cd2SShayne Chen 	if (!(txs & MT_TXS0_ACK_ERROR_MASK))
117998686cd2SShayne Chen 		info->flags |= IEEE80211_TX_STAT_ACK;
118098686cd2SShayne Chen 
118198686cd2SShayne Chen 	info->status.ampdu_len = 1;
118298686cd2SShayne Chen 	info->status.ampdu_ack_len = !!(info->flags &
118398686cd2SShayne Chen 					IEEE80211_TX_STAT_ACK);
118498686cd2SShayne Chen 
118598686cd2SShayne Chen 	info->status.rates[0].idx = -1;
118698686cd2SShayne Chen 
118798686cd2SShayne Chen 	txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
118898686cd2SShayne Chen 
118998686cd2SShayne Chen 	rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
119098686cd2SShayne Chen 	rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
119198686cd2SShayne Chen 	stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
119298686cd2SShayne Chen 
119398686cd2SShayne Chen 	if (stbc && rate.nss > 1)
119498686cd2SShayne Chen 		rate.nss >>= 1;
119598686cd2SShayne Chen 
119698686cd2SShayne Chen 	if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
119798686cd2SShayne Chen 		stats->tx_nss[rate.nss - 1]++;
119898686cd2SShayne Chen 	if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
119998686cd2SShayne Chen 		stats->tx_mcs[rate.mcs]++;
120098686cd2SShayne Chen 
120198686cd2SShayne Chen 	mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
120298686cd2SShayne Chen 	switch (mode) {
120398686cd2SShayne Chen 	case MT_PHY_TYPE_CCK:
120498686cd2SShayne Chen 		cck = true;
120598686cd2SShayne Chen 		fallthrough;
120698686cd2SShayne Chen 	case MT_PHY_TYPE_OFDM:
120798686cd2SShayne Chen 		mphy = mt76_dev_phy(mdev, wcid->phy_idx);
120898686cd2SShayne Chen 
120998686cd2SShayne Chen 		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
121098686cd2SShayne Chen 			sband = &mphy->sband_5g.sband;
121198686cd2SShayne Chen 		else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
121298686cd2SShayne Chen 			sband = &mphy->sband_6g.sband;
121398686cd2SShayne Chen 		else
121498686cd2SShayne Chen 			sband = &mphy->sband_2g.sband;
121598686cd2SShayne Chen 
121698686cd2SShayne Chen 		rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
121798686cd2SShayne Chen 		rate.legacy = sband->bitrates[rate.mcs].bitrate;
121898686cd2SShayne Chen 		break;
121998686cd2SShayne Chen 	case MT_PHY_TYPE_HT:
122098686cd2SShayne Chen 	case MT_PHY_TYPE_HT_GF:
122198686cd2SShayne Chen 		if (rate.mcs > 31)
122298686cd2SShayne Chen 			goto out;
122398686cd2SShayne Chen 
122498686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_MCS;
122598686cd2SShayne Chen 		if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
122698686cd2SShayne Chen 			rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
122798686cd2SShayne Chen 		break;
122898686cd2SShayne Chen 	case MT_PHY_TYPE_VHT:
122998686cd2SShayne Chen 		if (rate.mcs > 9)
123098686cd2SShayne Chen 			goto out;
123198686cd2SShayne Chen 
123298686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_VHT_MCS;
123398686cd2SShayne Chen 		break;
123498686cd2SShayne Chen 	case MT_PHY_TYPE_HE_SU:
123598686cd2SShayne Chen 	case MT_PHY_TYPE_HE_EXT_SU:
123698686cd2SShayne Chen 	case MT_PHY_TYPE_HE_TB:
123798686cd2SShayne Chen 	case MT_PHY_TYPE_HE_MU:
123898686cd2SShayne Chen 		if (rate.mcs > 11)
123998686cd2SShayne Chen 			goto out;
124098686cd2SShayne Chen 
124198686cd2SShayne Chen 		rate.he_gi = wcid->rate.he_gi;
124298686cd2SShayne Chen 		rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
124398686cd2SShayne Chen 		rate.flags = RATE_INFO_FLAGS_HE_MCS;
124498686cd2SShayne Chen 		break;
124580f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_SU:
124680f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_TRIG:
124780f5a31dSShayne Chen 	case MT_PHY_TYPE_EHT_MU:
124880f5a31dSShayne Chen 		if (rate.mcs > 13)
124980f5a31dSShayne Chen 			goto out;
125080f5a31dSShayne Chen 
125180f5a31dSShayne Chen 		rate.eht_gi = wcid->rate.eht_gi;
125280f5a31dSShayne Chen 		rate.flags = RATE_INFO_FLAGS_EHT_MCS;
125380f5a31dSShayne Chen 		break;
125498686cd2SShayne Chen 	default:
125598686cd2SShayne Chen 		goto out;
125698686cd2SShayne Chen 	}
125798686cd2SShayne Chen 
125898686cd2SShayne Chen 	stats->tx_mode[mode]++;
125998686cd2SShayne Chen 
126098686cd2SShayne Chen 	switch (FIELD_GET(MT_TXS0_BW, txs)) {
126180f5a31dSShayne Chen 	case IEEE80211_STA_RX_BW_320:
126280f5a31dSShayne Chen 		rate.bw = RATE_INFO_BW_320;
126380f5a31dSShayne Chen 		stats->tx_bw[4]++;
126480f5a31dSShayne Chen 		break;
126598686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_160:
126698686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_160;
126798686cd2SShayne Chen 		stats->tx_bw[3]++;
126898686cd2SShayne Chen 		break;
126998686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_80:
127098686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_80;
127198686cd2SShayne Chen 		stats->tx_bw[2]++;
127298686cd2SShayne Chen 		break;
127398686cd2SShayne Chen 	case IEEE80211_STA_RX_BW_40:
127498686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_40;
127598686cd2SShayne Chen 		stats->tx_bw[1]++;
127698686cd2SShayne Chen 		break;
127798686cd2SShayne Chen 	default:
127898686cd2SShayne Chen 		rate.bw = RATE_INFO_BW_20;
127998686cd2SShayne Chen 		stats->tx_bw[0]++;
128098686cd2SShayne Chen 		break;
128198686cd2SShayne Chen 	}
128298686cd2SShayne Chen 	wcid->rate = rate;
128398686cd2SShayne Chen 
128498686cd2SShayne Chen out:
128598686cd2SShayne Chen 	mt76_tx_status_skb_done(mdev, skb, &list);
128698686cd2SShayne Chen 
128798686cd2SShayne Chen out_no_skb:
128898686cd2SShayne Chen 	mt76_tx_status_unlock(mdev, &list);
128998686cd2SShayne Chen 
129098686cd2SShayne Chen 	return !!skb;
129198686cd2SShayne Chen }
129298686cd2SShayne Chen 
129398686cd2SShayne Chen static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
129498686cd2SShayne Chen {
129598686cd2SShayne Chen 	struct mt7996_sta *msta = NULL;
129698686cd2SShayne Chen 	struct mt76_wcid *wcid;
129798686cd2SShayne Chen 	__le32 *txs_data = data;
129898686cd2SShayne Chen 	u16 wcidx;
129998686cd2SShayne Chen 	u8 pid;
130098686cd2SShayne Chen 
130198686cd2SShayne Chen 	if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
130298686cd2SShayne Chen 		return;
130398686cd2SShayne Chen 
130498686cd2SShayne Chen 	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
130598686cd2SShayne Chen 	pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
130698686cd2SShayne Chen 
130798686cd2SShayne Chen 	if (pid < MT_PACKET_ID_FIRST)
130898686cd2SShayne Chen 		return;
130998686cd2SShayne Chen 
131043482540SShayne Chen 	if (wcidx >= mt7996_wtbl_size(dev))
131198686cd2SShayne Chen 		return;
131298686cd2SShayne Chen 
131398686cd2SShayne Chen 	rcu_read_lock();
131498686cd2SShayne Chen 
131598686cd2SShayne Chen 	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
131698686cd2SShayne Chen 	if (!wcid)
131798686cd2SShayne Chen 		goto out;
131898686cd2SShayne Chen 
131998686cd2SShayne Chen 	msta = container_of(wcid, struct mt7996_sta, wcid);
132098686cd2SShayne Chen 
1321d82e7c67SLorenzo Bianconi 	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
132298686cd2SShayne Chen 
132398686cd2SShayne Chen 	if (!wcid->sta)
132498686cd2SShayne Chen 		goto out;
132598686cd2SShayne Chen 
1326ea0f3867SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.sta_poll_lock);
1327e3b0311fSLorenzo Bianconi 	if (list_empty(&msta->wcid.poll_list))
1328e3b0311fSLorenzo Bianconi 		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
1329ea0f3867SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
133098686cd2SShayne Chen 
133198686cd2SShayne Chen out:
133298686cd2SShayne Chen 	rcu_read_unlock();
133398686cd2SShayne Chen }
133498686cd2SShayne Chen 
133598686cd2SShayne Chen bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len)
133698686cd2SShayne Chen {
133798686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
133898686cd2SShayne Chen 	__le32 *rxd = (__le32 *)data;
133998686cd2SShayne Chen 	__le32 *end = (__le32 *)&rxd[len / 4];
134098686cd2SShayne Chen 	enum rx_pkt_type type;
134198686cd2SShayne Chen 
134298686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
134398686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
134498686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
134598686cd2SShayne Chen 
134698686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
134798686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
134898686cd2SShayne Chen 			return true;
134998686cd2SShayne Chen 	}
135098686cd2SShayne Chen 
135198686cd2SShayne Chen 	switch (type) {
135298686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
135398686cd2SShayne Chen 		mt7996_mac_tx_free(dev, data, len);
135498686cd2SShayne Chen 		return false;
135598686cd2SShayne Chen 	case PKT_TYPE_TXS:
135698686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
135798686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
135898686cd2SShayne Chen 		return false;
135998686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
136098686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, data, len);
136198686cd2SShayne Chen 		return false;
136298686cd2SShayne Chen 	default:
136398686cd2SShayne Chen 		return true;
136498686cd2SShayne Chen 	}
136598686cd2SShayne Chen }
136698686cd2SShayne Chen 
136798686cd2SShayne Chen void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
136898686cd2SShayne Chen 			 struct sk_buff *skb, u32 *info)
136998686cd2SShayne Chen {
137098686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
137198686cd2SShayne Chen 	__le32 *rxd = (__le32 *)skb->data;
137298686cd2SShayne Chen 	__le32 *end = (__le32 *)&skb->data[skb->len];
137398686cd2SShayne Chen 	enum rx_pkt_type type;
137498686cd2SShayne Chen 
137598686cd2SShayne Chen 	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
137698686cd2SShayne Chen 	if (type != PKT_TYPE_NORMAL) {
137798686cd2SShayne Chen 		u32 sw_type = le32_get_bits(rxd[0], MT_RXD0_SW_PKT_TYPE_MASK);
137898686cd2SShayne Chen 
137998686cd2SShayne Chen 		if (unlikely((sw_type & MT_RXD0_SW_PKT_TYPE_MAP) ==
138098686cd2SShayne Chen 			     MT_RXD0_SW_PKT_TYPE_FRAME))
138198686cd2SShayne Chen 			type = PKT_TYPE_NORMAL;
138298686cd2SShayne Chen 	}
138398686cd2SShayne Chen 
138498686cd2SShayne Chen 	switch (type) {
138598686cd2SShayne Chen 	case PKT_TYPE_TXRX_NOTIFY:
138698686cd2SShayne Chen 		mt7996_mac_tx_free(dev, skb->data, skb->len);
138798686cd2SShayne Chen 		napi_consume_skb(skb, 1);
138898686cd2SShayne Chen 		break;
138998686cd2SShayne Chen 	case PKT_TYPE_RX_EVENT:
139098686cd2SShayne Chen 		mt7996_mcu_rx_event(dev, skb);
139198686cd2SShayne Chen 		break;
139298686cd2SShayne Chen 	case PKT_TYPE_TXS:
139398686cd2SShayne Chen 		for (rxd += 4; rxd + 8 <= end; rxd += 8)
139498686cd2SShayne Chen 			mt7996_mac_add_txs(dev, rxd);
139598686cd2SShayne Chen 		dev_kfree_skb(skb);
139698686cd2SShayne Chen 		break;
139798686cd2SShayne Chen 	case PKT_TYPE_RX_FW_MONITOR:
139898686cd2SShayne Chen 		mt7996_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
139998686cd2SShayne Chen 		dev_kfree_skb(skb);
140098686cd2SShayne Chen 		break;
140198686cd2SShayne Chen 	case PKT_TYPE_NORMAL:
140298686cd2SShayne Chen 		if (!mt7996_mac_fill_rx(dev, skb)) {
140398686cd2SShayne Chen 			mt76_rx(&dev->mt76, q, skb);
140498686cd2SShayne Chen 			return;
140598686cd2SShayne Chen 		}
140698686cd2SShayne Chen 		fallthrough;
140798686cd2SShayne Chen 	default:
140898686cd2SShayne Chen 		dev_kfree_skb(skb);
140998686cd2SShayne Chen 		break;
141098686cd2SShayne Chen 	}
141198686cd2SShayne Chen }
141298686cd2SShayne Chen 
141398686cd2SShayne Chen void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
141498686cd2SShayne Chen {
141598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
141698686cd2SShayne Chen 	u32 reg = MT_WF_PHYRX_BAND_RX_CTRL1(phy->mt76->band_idx);
141798686cd2SShayne Chen 
141898686cd2SShayne Chen 	mt76_clear(dev, reg, MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN);
141998686cd2SShayne Chen 	mt76_set(dev, reg, BIT(11) | BIT(9));
142098686cd2SShayne Chen }
142198686cd2SShayne Chen 
142298686cd2SShayne Chen void mt7996_mac_reset_counters(struct mt7996_phy *phy)
142398686cd2SShayne Chen {
142498686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
142598686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
142698686cd2SShayne Chen 	int i;
142798686cd2SShayne Chen 
142898686cd2SShayne Chen 	for (i = 0; i < 16; i++)
142998686cd2SShayne Chen 		mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
143098686cd2SShayne Chen 
143198686cd2SShayne Chen 	phy->mt76->survey_time = ktime_get_boottime();
143298686cd2SShayne Chen 
143398686cd2SShayne Chen 	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
143498686cd2SShayne Chen 
143598686cd2SShayne Chen 	/* reset airtime counters */
143698686cd2SShayne Chen 	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band_idx),
143798686cd2SShayne Chen 		 MT_WF_RMAC_MIB_RXTIME_CLR);
143898686cd2SShayne Chen 
143998686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, true);
144098686cd2SShayne Chen }
144198686cd2SShayne Chen 
144283a10ae2SPeter Chiu void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
144398686cd2SShayne Chen {
144498686cd2SShayne Chen 	s16 coverage_class = phy->coverage_class;
144598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
144698686cd2SShayne Chen 	struct mt7996_phy *phy2 = mt7996_phy2(dev);
144798686cd2SShayne Chen 	struct mt7996_phy *phy3 = mt7996_phy3(dev);
144883a10ae2SPeter Chiu 	u32 reg_offset;
144998686cd2SShayne Chen 	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
145098686cd2SShayne Chen 		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
145198686cd2SShayne Chen 	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
145298686cd2SShayne Chen 		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
145398686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
145498686cd2SShayne Chen 	int offset;
145598686cd2SShayne Chen 
145698686cd2SShayne Chen 	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
145798686cd2SShayne Chen 		return;
145898686cd2SShayne Chen 
145998686cd2SShayne Chen 	if (phy2)
146098686cd2SShayne Chen 		coverage_class = max_t(s16, dev->phy.coverage_class,
146198686cd2SShayne Chen 				       phy2->coverage_class);
146298686cd2SShayne Chen 
146398686cd2SShayne Chen 	if (phy3)
146498686cd2SShayne Chen 		coverage_class = max_t(s16, coverage_class,
146598686cd2SShayne Chen 				       phy3->coverage_class);
146698686cd2SShayne Chen 
146798686cd2SShayne Chen 	offset = 3 * coverage_class;
146898686cd2SShayne Chen 	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
146998686cd2SShayne Chen 		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
147098686cd2SShayne Chen 
147198686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
147298686cd2SShayne Chen 	mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
147398686cd2SShayne Chen }
147498686cd2SShayne Chen 
147598686cd2SShayne Chen void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
147698686cd2SShayne Chen {
147798686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_CSD_BAND_RXTD12(band),
147898686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY |
147998686cd2SShayne Chen 		 MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR);
148098686cd2SShayne Chen 
148198686cd2SShayne Chen 	mt76_set(dev, MT_WF_PHYRX_BAND_RX_CTRL1(band),
148298686cd2SShayne Chen 		 FIELD_PREP(MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN, 0x5));
148398686cd2SShayne Chen }
148498686cd2SShayne Chen 
148598686cd2SShayne Chen static u8
148698686cd2SShayne Chen mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
148798686cd2SShayne Chen {
148898686cd2SShayne Chen 	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
148998686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
149098686cd2SShayne Chen 	u32 val, sum = 0, n = 0;
149198686cd2SShayne Chen 	int ant, i;
149298686cd2SShayne Chen 
149398686cd2SShayne Chen 	for (ant = 0; ant < hweight8(phy->mt76->antenna_mask); ant++) {
149498686cd2SShayne Chen 		u32 reg = MT_WF_PHYRX_CSD_IRPI(band_idx, ant);
149598686cd2SShayne Chen 
149698686cd2SShayne Chen 		for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
149798686cd2SShayne Chen 			val = mt76_rr(dev, reg);
149898686cd2SShayne Chen 			sum += val * nf_power[i];
149998686cd2SShayne Chen 			n += val;
150098686cd2SShayne Chen 		}
150198686cd2SShayne Chen 	}
150298686cd2SShayne Chen 
150398686cd2SShayne Chen 	return n ? sum / n : 0;
150498686cd2SShayne Chen }
150598686cd2SShayne Chen 
150698686cd2SShayne Chen void mt7996_update_channel(struct mt76_phy *mphy)
150798686cd2SShayne Chen {
150898686cd2SShayne Chen 	struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
150998686cd2SShayne Chen 	struct mt76_channel_state *state = mphy->chan_state;
151098686cd2SShayne Chen 	int nf;
151198686cd2SShayne Chen 
151298686cd2SShayne Chen 	mt7996_mcu_get_chan_mib_info(phy, false);
151398686cd2SShayne Chen 
151498686cd2SShayne Chen 	nf = mt7996_phy_get_nf(phy, mphy->band_idx);
151598686cd2SShayne Chen 	if (!phy->noise)
151698686cd2SShayne Chen 		phy->noise = nf << 4;
151798686cd2SShayne Chen 	else if (nf)
151898686cd2SShayne Chen 		phy->noise += nf - (phy->noise >> 4);
151998686cd2SShayne Chen 
152098686cd2SShayne Chen 	state->noise = -(phy->noise >> 4);
152198686cd2SShayne Chen }
152298686cd2SShayne Chen 
152398686cd2SShayne Chen static bool
152498686cd2SShayne Chen mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
152598686cd2SShayne Chen {
152698686cd2SShayne Chen 	bool ret;
152798686cd2SShayne Chen 
152898686cd2SShayne Chen 	ret = wait_event_timeout(dev->reset_wait,
152927015b6fSBo Jiao 				 (READ_ONCE(dev->recovery.state) & state),
153098686cd2SShayne Chen 				 MT7996_RESET_TIMEOUT);
153198686cd2SShayne Chen 
153298686cd2SShayne Chen 	WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
153398686cd2SShayne Chen 	return ret;
153498686cd2SShayne Chen }
153598686cd2SShayne Chen 
153698686cd2SShayne Chen static void
153798686cd2SShayne Chen mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
153898686cd2SShayne Chen {
153998686cd2SShayne Chen 	struct ieee80211_hw *hw = priv;
154098686cd2SShayne Chen 
154198686cd2SShayne Chen 	switch (vif->type) {
154298686cd2SShayne Chen 	case NL80211_IFTYPE_MESH_POINT:
154398686cd2SShayne Chen 	case NL80211_IFTYPE_ADHOC:
154498686cd2SShayne Chen 	case NL80211_IFTYPE_AP:
154598686cd2SShayne Chen 		mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
154698686cd2SShayne Chen 		break;
154798686cd2SShayne Chen 	default:
154898686cd2SShayne Chen 		break;
154998686cd2SShayne Chen 	}
155098686cd2SShayne Chen }
155198686cd2SShayne Chen 
155298686cd2SShayne Chen static void
155398686cd2SShayne Chen mt7996_update_beacons(struct mt7996_dev *dev)
155498686cd2SShayne Chen {
155598686cd2SShayne Chen 	struct mt76_phy *phy2, *phy3;
155698686cd2SShayne Chen 
155798686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(dev->mt76.hw,
155898686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
155998686cd2SShayne Chen 					    mt7996_update_vif_beacon, dev->mt76.hw);
156098686cd2SShayne Chen 
156198686cd2SShayne Chen 	phy2 = dev->mt76.phys[MT_BAND1];
156298686cd2SShayne Chen 	if (!phy2)
156398686cd2SShayne Chen 		return;
156498686cd2SShayne Chen 
156598686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy2->hw,
156698686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
156798686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy2->hw);
156898686cd2SShayne Chen 
156998686cd2SShayne Chen 	phy3 = dev->mt76.phys[MT_BAND2];
157098686cd2SShayne Chen 	if (!phy3)
157198686cd2SShayne Chen 		return;
157298686cd2SShayne Chen 
157398686cd2SShayne Chen 	ieee80211_iterate_active_interfaces(phy3->hw,
157498686cd2SShayne Chen 					    IEEE80211_IFACE_ITER_RESUME_ALL,
157598686cd2SShayne Chen 					    mt7996_update_vif_beacon, phy3->hw);
157698686cd2SShayne Chen }
157798686cd2SShayne Chen 
157898686cd2SShayne Chen void mt7996_tx_token_put(struct mt7996_dev *dev)
157998686cd2SShayne Chen {
158098686cd2SShayne Chen 	struct mt76_txwi_cache *txwi;
158198686cd2SShayne Chen 	int id;
158298686cd2SShayne Chen 
158398686cd2SShayne Chen 	spin_lock_bh(&dev->mt76.token_lock);
158498686cd2SShayne Chen 	idr_for_each_entry(&dev->mt76.token, txwi, id) {
158598686cd2SShayne Chen 		mt7996_txwi_free(dev, txwi, NULL, NULL);
158698686cd2SShayne Chen 		dev->mt76.token_count--;
158798686cd2SShayne Chen 	}
158898686cd2SShayne Chen 	spin_unlock_bh(&dev->mt76.token_lock);
158998686cd2SShayne Chen 	idr_destroy(&dev->mt76.token);
159098686cd2SShayne Chen }
159198686cd2SShayne Chen 
159227015b6fSBo Jiao static int
159327015b6fSBo Jiao mt7996_mac_restart(struct mt7996_dev *dev)
159427015b6fSBo Jiao {
159527015b6fSBo Jiao 	struct mt7996_phy *phy2, *phy3;
159627015b6fSBo Jiao 	struct mt76_dev *mdev = &dev->mt76;
159727015b6fSBo Jiao 	int i, ret;
159827015b6fSBo Jiao 
159927015b6fSBo Jiao 	phy2 = mt7996_phy2(dev);
160027015b6fSBo Jiao 	phy3 = mt7996_phy3(dev);
160127015b6fSBo Jiao 
160227015b6fSBo Jiao 	if (dev->hif2) {
160327015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
160427015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
160527015b6fSBo Jiao 	}
160627015b6fSBo Jiao 
160727015b6fSBo Jiao 	if (dev_is_pci(mdev->dev)) {
160827015b6fSBo Jiao 		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
160927015b6fSBo Jiao 		if (dev->hif2)
161027015b6fSBo Jiao 			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
161127015b6fSBo Jiao 	}
161227015b6fSBo Jiao 
161327015b6fSBo Jiao 	set_bit(MT76_RESET, &dev->mphy.state);
161427015b6fSBo Jiao 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
161527015b6fSBo Jiao 	wake_up(&dev->mt76.mcu.wait);
161627015b6fSBo Jiao 	if (phy2) {
161727015b6fSBo Jiao 		set_bit(MT76_RESET, &phy2->mt76->state);
161827015b6fSBo Jiao 		set_bit(MT76_MCU_RESET, &phy2->mt76->state);
161927015b6fSBo Jiao 	}
162027015b6fSBo Jiao 	if (phy3) {
162127015b6fSBo Jiao 		set_bit(MT76_RESET, &phy3->mt76->state);
162227015b6fSBo Jiao 		set_bit(MT76_MCU_RESET, &phy3->mt76->state);
162327015b6fSBo Jiao 	}
162427015b6fSBo Jiao 
162527015b6fSBo Jiao 	/* lock/unlock all queues to ensure that no tx is pending */
162627015b6fSBo Jiao 	mt76_txq_schedule_all(&dev->mphy);
162727015b6fSBo Jiao 	if (phy2)
162827015b6fSBo Jiao 		mt76_txq_schedule_all(phy2->mt76);
162927015b6fSBo Jiao 	if (phy3)
163027015b6fSBo Jiao 		mt76_txq_schedule_all(phy3->mt76);
163127015b6fSBo Jiao 
163227015b6fSBo Jiao 	/* disable all tx/rx napi */
163327015b6fSBo Jiao 	mt76_worker_disable(&dev->mt76.tx_worker);
163427015b6fSBo Jiao 	mt76_for_each_q_rx(mdev, i) {
163527015b6fSBo Jiao 		if (mdev->q_rx[i].ndesc)
163627015b6fSBo Jiao 			napi_disable(&dev->mt76.napi[i]);
163727015b6fSBo Jiao 	}
163827015b6fSBo Jiao 	napi_disable(&dev->mt76.tx_napi);
163927015b6fSBo Jiao 
164027015b6fSBo Jiao 	/* token reinit */
164127015b6fSBo Jiao 	mt7996_tx_token_put(dev);
164227015b6fSBo Jiao 	idr_init(&dev->mt76.token);
164327015b6fSBo Jiao 
164427015b6fSBo Jiao 	mt7996_dma_reset(dev, true);
164527015b6fSBo Jiao 
164627015b6fSBo Jiao 	local_bh_disable();
164727015b6fSBo Jiao 	mt76_for_each_q_rx(mdev, i) {
164827015b6fSBo Jiao 		if (mdev->q_rx[i].ndesc) {
164927015b6fSBo Jiao 			napi_enable(&dev->mt76.napi[i]);
165027015b6fSBo Jiao 			napi_schedule(&dev->mt76.napi[i]);
165127015b6fSBo Jiao 		}
165227015b6fSBo Jiao 	}
165327015b6fSBo Jiao 	local_bh_enable();
165427015b6fSBo Jiao 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
165527015b6fSBo Jiao 	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
165627015b6fSBo Jiao 
165727015b6fSBo Jiao 	mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
165827015b6fSBo Jiao 	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
165927015b6fSBo Jiao 	if (dev->hif2) {
166027015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
166127015b6fSBo Jiao 		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
166227015b6fSBo Jiao 	}
166327015b6fSBo Jiao 	if (dev_is_pci(mdev->dev)) {
166427015b6fSBo Jiao 		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
166527015b6fSBo Jiao 		if (dev->hif2)
166627015b6fSBo Jiao 			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
166727015b6fSBo Jiao 	}
166827015b6fSBo Jiao 
166927015b6fSBo Jiao 	/* load firmware */
167027015b6fSBo Jiao 	ret = mt7996_mcu_init_firmware(dev);
167127015b6fSBo Jiao 	if (ret)
167227015b6fSBo Jiao 		goto out;
167327015b6fSBo Jiao 
167427015b6fSBo Jiao 	/* set the necessary init items */
167527015b6fSBo Jiao 	ret = mt7996_mcu_set_eeprom(dev);
167627015b6fSBo Jiao 	if (ret)
167727015b6fSBo Jiao 		goto out;
167827015b6fSBo Jiao 
167927015b6fSBo Jiao 	mt7996_mac_init(dev);
168027015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
168127015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
168227015b6fSBo Jiao 	mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
168327015b6fSBo Jiao 	ret = mt7996_txbf_init(dev);
168427015b6fSBo Jiao 
168527015b6fSBo Jiao 	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
168627015b6fSBo Jiao 		ret = mt7996_run(dev->mphy.hw);
168727015b6fSBo Jiao 		if (ret)
168827015b6fSBo Jiao 			goto out;
168927015b6fSBo Jiao 	}
169027015b6fSBo Jiao 
169127015b6fSBo Jiao 	if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
169227015b6fSBo Jiao 		ret = mt7996_run(phy2->mt76->hw);
169327015b6fSBo Jiao 		if (ret)
169427015b6fSBo Jiao 			goto out;
169527015b6fSBo Jiao 	}
169627015b6fSBo Jiao 
169727015b6fSBo Jiao 	if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
169827015b6fSBo Jiao 		ret = mt7996_run(phy3->mt76->hw);
169927015b6fSBo Jiao 		if (ret)
170027015b6fSBo Jiao 			goto out;
170127015b6fSBo Jiao 	}
170227015b6fSBo Jiao 
170327015b6fSBo Jiao out:
170427015b6fSBo Jiao 	/* reset done */
170527015b6fSBo Jiao 	clear_bit(MT76_RESET, &dev->mphy.state);
170627015b6fSBo Jiao 	if (phy2)
170727015b6fSBo Jiao 		clear_bit(MT76_RESET, &phy2->mt76->state);
170827015b6fSBo Jiao 	if (phy3)
170927015b6fSBo Jiao 		clear_bit(MT76_RESET, &phy3->mt76->state);
171027015b6fSBo Jiao 
171127015b6fSBo Jiao 	local_bh_disable();
171227015b6fSBo Jiao 	napi_enable(&dev->mt76.tx_napi);
171327015b6fSBo Jiao 	napi_schedule(&dev->mt76.tx_napi);
171427015b6fSBo Jiao 	local_bh_enable();
171527015b6fSBo Jiao 
171627015b6fSBo Jiao 	mt76_worker_enable(&dev->mt76.tx_worker);
171727015b6fSBo Jiao 	return ret;
171827015b6fSBo Jiao }
171927015b6fSBo Jiao 
172027015b6fSBo Jiao static void
172127015b6fSBo Jiao mt7996_mac_full_reset(struct mt7996_dev *dev)
172227015b6fSBo Jiao {
172327015b6fSBo Jiao 	struct mt7996_phy *phy2, *phy3;
172427015b6fSBo Jiao 	int i;
172527015b6fSBo Jiao 
172627015b6fSBo Jiao 	phy2 = mt7996_phy2(dev);
172727015b6fSBo Jiao 	phy3 = mt7996_phy3(dev);
172827015b6fSBo Jiao 	dev->recovery.hw_full_reset = true;
172927015b6fSBo Jiao 
173027015b6fSBo Jiao 	wake_up(&dev->mt76.mcu.wait);
173127015b6fSBo Jiao 	ieee80211_stop_queues(mt76_hw(dev));
173227015b6fSBo Jiao 	if (phy2)
173327015b6fSBo Jiao 		ieee80211_stop_queues(phy2->mt76->hw);
173427015b6fSBo Jiao 	if (phy3)
173527015b6fSBo Jiao 		ieee80211_stop_queues(phy3->mt76->hw);
173627015b6fSBo Jiao 
173727015b6fSBo Jiao 	cancel_delayed_work_sync(&dev->mphy.mac_work);
173827015b6fSBo Jiao 	if (phy2)
173927015b6fSBo Jiao 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
174027015b6fSBo Jiao 	if (phy3)
174127015b6fSBo Jiao 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
174227015b6fSBo Jiao 
174327015b6fSBo Jiao 	mutex_lock(&dev->mt76.mutex);
174427015b6fSBo Jiao 	for (i = 0; i < 10; i++) {
174527015b6fSBo Jiao 		if (!mt7996_mac_restart(dev))
174627015b6fSBo Jiao 			break;
174727015b6fSBo Jiao 	}
174827015b6fSBo Jiao 	mutex_unlock(&dev->mt76.mutex);
174927015b6fSBo Jiao 
175027015b6fSBo Jiao 	if (i == 10)
175127015b6fSBo Jiao 		dev_err(dev->mt76.dev, "chip full reset failed\n");
175227015b6fSBo Jiao 
175327015b6fSBo Jiao 	ieee80211_restart_hw(mt76_hw(dev));
175427015b6fSBo Jiao 	if (phy2)
175527015b6fSBo Jiao 		ieee80211_restart_hw(phy2->mt76->hw);
175627015b6fSBo Jiao 	if (phy3)
175727015b6fSBo Jiao 		ieee80211_restart_hw(phy3->mt76->hw);
175827015b6fSBo Jiao 
175927015b6fSBo Jiao 	ieee80211_wake_queues(mt76_hw(dev));
176027015b6fSBo Jiao 	if (phy2)
176127015b6fSBo Jiao 		ieee80211_wake_queues(phy2->mt76->hw);
176227015b6fSBo Jiao 	if (phy3)
176327015b6fSBo Jiao 		ieee80211_wake_queues(phy3->mt76->hw);
176427015b6fSBo Jiao 
176527015b6fSBo Jiao 	dev->recovery.hw_full_reset = false;
176627015b6fSBo Jiao 	ieee80211_queue_delayed_work(mt76_hw(dev),
176727015b6fSBo Jiao 				     &dev->mphy.mac_work,
176827015b6fSBo Jiao 				     MT7996_WATCHDOG_TIME);
176927015b6fSBo Jiao 	if (phy2)
177027015b6fSBo Jiao 		ieee80211_queue_delayed_work(phy2->mt76->hw,
177127015b6fSBo Jiao 					     &phy2->mt76->mac_work,
177227015b6fSBo Jiao 					     MT7996_WATCHDOG_TIME);
177327015b6fSBo Jiao 	if (phy3)
177427015b6fSBo Jiao 		ieee80211_queue_delayed_work(phy3->mt76->hw,
177527015b6fSBo Jiao 					     &phy3->mt76->mac_work,
177627015b6fSBo Jiao 					     MT7996_WATCHDOG_TIME);
177727015b6fSBo Jiao }
177827015b6fSBo Jiao 
177998686cd2SShayne Chen void mt7996_mac_reset_work(struct work_struct *work)
178098686cd2SShayne Chen {
178198686cd2SShayne Chen 	struct mt7996_phy *phy2, *phy3;
178298686cd2SShayne Chen 	struct mt7996_dev *dev;
178398686cd2SShayne Chen 	int i;
178498686cd2SShayne Chen 
178598686cd2SShayne Chen 	dev = container_of(work, struct mt7996_dev, reset_work);
178698686cd2SShayne Chen 	phy2 = mt7996_phy2(dev);
178798686cd2SShayne Chen 	phy3 = mt7996_phy3(dev);
178898686cd2SShayne Chen 
178927015b6fSBo Jiao 	/* chip full reset */
179027015b6fSBo Jiao 	if (dev->recovery.restart) {
179127015b6fSBo Jiao 		/* disable WA/WM WDT */
179227015b6fSBo Jiao 		mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
179327015b6fSBo Jiao 			   MT_MCU_CMD_WDT_MASK);
179427015b6fSBo Jiao 
179527015b6fSBo Jiao 		if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
179627015b6fSBo Jiao 			dev->recovery.wa_reset_count++;
179727015b6fSBo Jiao 		else
179827015b6fSBo Jiao 			dev->recovery.wm_reset_count++;
179927015b6fSBo Jiao 
180027015b6fSBo Jiao 		mt7996_mac_full_reset(dev);
180127015b6fSBo Jiao 
180227015b6fSBo Jiao 		/* enable mcu irq */
180327015b6fSBo Jiao 		mt7996_irq_enable(dev, MT_INT_MCU_CMD);
180427015b6fSBo Jiao 		mt7996_irq_disable(dev, 0);
180527015b6fSBo Jiao 
180627015b6fSBo Jiao 		/* enable WA/WM WDT */
180727015b6fSBo Jiao 		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
180827015b6fSBo Jiao 
180927015b6fSBo Jiao 		dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
181027015b6fSBo Jiao 		dev->recovery.restart = false;
181127015b6fSBo Jiao 		return;
181227015b6fSBo Jiao 	}
181327015b6fSBo Jiao 
181427015b6fSBo Jiao 	if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
181598686cd2SShayne Chen 		return;
181698686cd2SShayne Chen 
181727015b6fSBo Jiao 	dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
181827015b6fSBo Jiao 		 wiphy_name(dev->mt76.hw->wiphy));
181998686cd2SShayne Chen 	ieee80211_stop_queues(mt76_hw(dev));
182098686cd2SShayne Chen 	if (phy2)
182198686cd2SShayne Chen 		ieee80211_stop_queues(phy2->mt76->hw);
182298686cd2SShayne Chen 	if (phy3)
182398686cd2SShayne Chen 		ieee80211_stop_queues(phy3->mt76->hw);
182498686cd2SShayne Chen 
182598686cd2SShayne Chen 	set_bit(MT76_RESET, &dev->mphy.state);
182698686cd2SShayne Chen 	set_bit(MT76_MCU_RESET, &dev->mphy.state);
182798686cd2SShayne Chen 	wake_up(&dev->mt76.mcu.wait);
182898686cd2SShayne Chen 	cancel_delayed_work_sync(&dev->mphy.mac_work);
182998686cd2SShayne Chen 	if (phy2) {
183098686cd2SShayne Chen 		set_bit(MT76_RESET, &phy2->mt76->state);
183198686cd2SShayne Chen 		cancel_delayed_work_sync(&phy2->mt76->mac_work);
183298686cd2SShayne Chen 	}
183398686cd2SShayne Chen 	if (phy3) {
183498686cd2SShayne Chen 		set_bit(MT76_RESET, &phy3->mt76->state);
183598686cd2SShayne Chen 		cancel_delayed_work_sync(&phy3->mt76->mac_work);
183698686cd2SShayne Chen 	}
183798686cd2SShayne Chen 	mt76_worker_disable(&dev->mt76.tx_worker);
183898686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i)
183998686cd2SShayne Chen 		napi_disable(&dev->mt76.napi[i]);
184098686cd2SShayne Chen 	napi_disable(&dev->mt76.tx_napi);
184198686cd2SShayne Chen 
184298686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
184398686cd2SShayne Chen 
184498686cd2SShayne Chen 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
184598686cd2SShayne Chen 
184698686cd2SShayne Chen 	if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
184727015b6fSBo Jiao 		mt7996_dma_reset(dev, false);
184898686cd2SShayne Chen 
184998686cd2SShayne Chen 		mt7996_tx_token_put(dev);
185098686cd2SShayne Chen 		idr_init(&dev->mt76.token);
185198686cd2SShayne Chen 
185298686cd2SShayne Chen 		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
185398686cd2SShayne Chen 		mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
185498686cd2SShayne Chen 	}
185598686cd2SShayne Chen 
18568e8c09c7SBo Jiao 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
18578e8c09c7SBo Jiao 	mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
18588e8c09c7SBo Jiao 
18598e8c09c7SBo Jiao 	/* enable DMA Tx/Tx and interrupt */
18608e8c09c7SBo Jiao 	mt7996_dma_start(dev, false);
18618e8c09c7SBo Jiao 
186298686cd2SShayne Chen 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
186398686cd2SShayne Chen 	clear_bit(MT76_RESET, &dev->mphy.state);
186498686cd2SShayne Chen 	if (phy2)
186598686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy2->mt76->state);
186698686cd2SShayne Chen 	if (phy3)
186798686cd2SShayne Chen 		clear_bit(MT76_RESET, &phy3->mt76->state);
186898686cd2SShayne Chen 
186998686cd2SShayne Chen 	local_bh_disable();
187098686cd2SShayne Chen 	mt76_for_each_q_rx(&dev->mt76, i) {
187198686cd2SShayne Chen 		napi_enable(&dev->mt76.napi[i]);
187298686cd2SShayne Chen 		napi_schedule(&dev->mt76.napi[i]);
187398686cd2SShayne Chen 	}
187498686cd2SShayne Chen 	local_bh_enable();
187598686cd2SShayne Chen 
1876ec193b41SLorenzo Bianconi 	tasklet_schedule(&dev->mt76.irq_tasklet);
187798686cd2SShayne Chen 
187898686cd2SShayne Chen 	mt76_worker_enable(&dev->mt76.tx_worker);
187998686cd2SShayne Chen 
188098686cd2SShayne Chen 	local_bh_disable();
188198686cd2SShayne Chen 	napi_enable(&dev->mt76.tx_napi);
188298686cd2SShayne Chen 	napi_schedule(&dev->mt76.tx_napi);
188398686cd2SShayne Chen 	local_bh_enable();
188498686cd2SShayne Chen 
188598686cd2SShayne Chen 	ieee80211_wake_queues(mt76_hw(dev));
188698686cd2SShayne Chen 	if (phy2)
188798686cd2SShayne Chen 		ieee80211_wake_queues(phy2->mt76->hw);
188898686cd2SShayne Chen 	if (phy3)
188998686cd2SShayne Chen 		ieee80211_wake_queues(phy3->mt76->hw);
189098686cd2SShayne Chen 
189198686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
189298686cd2SShayne Chen 
189398686cd2SShayne Chen 	mt7996_update_beacons(dev);
189498686cd2SShayne Chen 
189598686cd2SShayne Chen 	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
189698686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
189798686cd2SShayne Chen 	if (phy2)
189898686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy2->mt76->hw,
189998686cd2SShayne Chen 					     &phy2->mt76->mac_work,
190098686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
190198686cd2SShayne Chen 	if (phy3)
190298686cd2SShayne Chen 		ieee80211_queue_delayed_work(phy3->mt76->hw,
190398686cd2SShayne Chen 					     &phy3->mt76->mac_work,
190498686cd2SShayne Chen 					     MT7996_WATCHDOG_TIME);
190527015b6fSBo Jiao 	dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
190627015b6fSBo Jiao 		 wiphy_name(dev->mt76.hw->wiphy));
190727015b6fSBo Jiao }
190827015b6fSBo Jiao 
1909878161d5SRyder Lee /* firmware coredump */
1910878161d5SRyder Lee void mt7996_mac_dump_work(struct work_struct *work)
1911878161d5SRyder Lee {
1912878161d5SRyder Lee 	const struct mt7996_mem_region *mem_region;
1913878161d5SRyder Lee 	struct mt7996_crash_data *crash_data;
1914878161d5SRyder Lee 	struct mt7996_dev *dev;
1915878161d5SRyder Lee 	struct mt7996_mem_hdr *hdr;
1916878161d5SRyder Lee 	size_t buf_len;
1917878161d5SRyder Lee 	int i;
1918878161d5SRyder Lee 	u32 num;
1919878161d5SRyder Lee 	u8 *buf;
1920878161d5SRyder Lee 
1921878161d5SRyder Lee 	dev = container_of(work, struct mt7996_dev, dump_work);
1922878161d5SRyder Lee 
1923878161d5SRyder Lee 	mutex_lock(&dev->dump_mutex);
1924878161d5SRyder Lee 
1925878161d5SRyder Lee 	crash_data = mt7996_coredump_new(dev);
1926878161d5SRyder Lee 	if (!crash_data) {
1927878161d5SRyder Lee 		mutex_unlock(&dev->dump_mutex);
1928878161d5SRyder Lee 		goto skip_coredump;
1929878161d5SRyder Lee 	}
1930878161d5SRyder Lee 
1931878161d5SRyder Lee 	mem_region = mt7996_coredump_get_mem_layout(dev, &num);
1932878161d5SRyder Lee 	if (!mem_region || !crash_data->memdump_buf_len) {
1933878161d5SRyder Lee 		mutex_unlock(&dev->dump_mutex);
1934878161d5SRyder Lee 		goto skip_memdump;
1935878161d5SRyder Lee 	}
1936878161d5SRyder Lee 
1937878161d5SRyder Lee 	buf = crash_data->memdump_buf;
1938878161d5SRyder Lee 	buf_len = crash_data->memdump_buf_len;
1939878161d5SRyder Lee 
1940878161d5SRyder Lee 	/* dumping memory content... */
1941878161d5SRyder Lee 	memset(buf, 0, buf_len);
1942878161d5SRyder Lee 	for (i = 0; i < num; i++) {
1943878161d5SRyder Lee 		if (mem_region->len > buf_len) {
1944878161d5SRyder Lee 			dev_warn(dev->mt76.dev, "%s len %zu is too large\n",
1945878161d5SRyder Lee 				 mem_region->name, mem_region->len);
1946878161d5SRyder Lee 			break;
1947878161d5SRyder Lee 		}
1948878161d5SRyder Lee 
1949878161d5SRyder Lee 		/* reserve space for the header */
1950878161d5SRyder Lee 		hdr = (void *)buf;
1951878161d5SRyder Lee 		buf += sizeof(*hdr);
1952878161d5SRyder Lee 		buf_len -= sizeof(*hdr);
1953878161d5SRyder Lee 
1954878161d5SRyder Lee 		mt7996_memcpy_fromio(dev, buf, mem_region->start,
1955878161d5SRyder Lee 				     mem_region->len);
1956878161d5SRyder Lee 
1957878161d5SRyder Lee 		hdr->start = mem_region->start;
1958878161d5SRyder Lee 		hdr->len = mem_region->len;
1959878161d5SRyder Lee 
1960878161d5SRyder Lee 		if (!mem_region->len)
1961878161d5SRyder Lee 			/* note: the header remains, just with zero length */
1962878161d5SRyder Lee 			break;
1963878161d5SRyder Lee 
1964878161d5SRyder Lee 		buf += mem_region->len;
1965878161d5SRyder Lee 		buf_len -= mem_region->len;
1966878161d5SRyder Lee 
1967878161d5SRyder Lee 		mem_region++;
1968878161d5SRyder Lee 	}
1969878161d5SRyder Lee 
1970878161d5SRyder Lee 	mutex_unlock(&dev->dump_mutex);
1971878161d5SRyder Lee 
1972878161d5SRyder Lee skip_memdump:
1973878161d5SRyder Lee 	mt7996_coredump_submit(dev);
1974878161d5SRyder Lee skip_coredump:
1975878161d5SRyder Lee 	queue_work(dev->mt76.wq, &dev->reset_work);
1976878161d5SRyder Lee }
1977878161d5SRyder Lee 
197827015b6fSBo Jiao void mt7996_reset(struct mt7996_dev *dev)
197927015b6fSBo Jiao {
198027015b6fSBo Jiao 	if (!dev->recovery.hw_init_done)
198127015b6fSBo Jiao 		return;
198227015b6fSBo Jiao 
198327015b6fSBo Jiao 	if (dev->recovery.hw_full_reset)
198427015b6fSBo Jiao 		return;
198527015b6fSBo Jiao 
198627015b6fSBo Jiao 	/* wm/wa exception: do full recovery */
198727015b6fSBo Jiao 	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
198827015b6fSBo Jiao 		dev->recovery.restart = true;
198927015b6fSBo Jiao 		dev_info(dev->mt76.dev,
199027015b6fSBo Jiao 			 "%s indicated firmware crash, attempting recovery\n",
199127015b6fSBo Jiao 			 wiphy_name(dev->mt76.hw->wiphy));
199227015b6fSBo Jiao 
199327015b6fSBo Jiao 		mt7996_irq_disable(dev, MT_INT_MCU_CMD);
1994878161d5SRyder Lee 		queue_work(dev->mt76.wq, &dev->dump_work);
199527015b6fSBo Jiao 		return;
199627015b6fSBo Jiao 	}
199727015b6fSBo Jiao 
199827015b6fSBo Jiao 	queue_work(dev->mt76.wq, &dev->reset_work);
199927015b6fSBo Jiao 	wake_up(&dev->reset_wait);
200098686cd2SShayne Chen }
200198686cd2SShayne Chen 
200298686cd2SShayne Chen void mt7996_mac_update_stats(struct mt7996_phy *phy)
200398686cd2SShayne Chen {
200498214484SLorenzo Bianconi 	struct mt76_mib_stats *mib = &phy->mib;
200598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
200698686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
200798686cd2SShayne Chen 	u32 cnt;
200898686cd2SShayne Chen 	int i;
200998686cd2SShayne Chen 
201098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR1(band_idx));
201198686cd2SShayne Chen 	mib->fcs_err_cnt += cnt;
201298686cd2SShayne Chen 
201398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR33(band_idx));
201498686cd2SShayne Chen 	mib->rx_fifo_full_cnt += cnt;
201598686cd2SShayne Chen 
201698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR31(band_idx));
201798686cd2SShayne Chen 	mib->rx_mpdu_cnt += cnt;
201898686cd2SShayne Chen 
201998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR6(band_idx));
202098686cd2SShayne Chen 	mib->channel_idle_cnt += FIELD_GET(MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK, cnt);
202198686cd2SShayne Chen 
202298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR0(band_idx));
202398686cd2SShayne Chen 	mib->rx_vector_mismatch_cnt += cnt;
202498686cd2SShayne Chen 
202598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR35(band_idx));
202698686cd2SShayne Chen 	mib->rx_delimiter_fail_cnt += cnt;
202798686cd2SShayne Chen 
202898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR36(band_idx));
202998686cd2SShayne Chen 	mib->rx_len_mismatch_cnt += cnt;
203098686cd2SShayne Chen 
203198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR0(band_idx));
203298686cd2SShayne Chen 	mib->tx_ampdu_cnt += cnt;
203398686cd2SShayne Chen 
203498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR2(band_idx));
203598686cd2SShayne Chen 	mib->tx_stop_q_empty_cnt += cnt;
203698686cd2SShayne Chen 
203798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR3(band_idx));
203898686cd2SShayne Chen 	mib->tx_mpdu_attempts_cnt += cnt;
203998686cd2SShayne Chen 
204098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR4(band_idx));
204198686cd2SShayne Chen 	mib->tx_mpdu_success_cnt += cnt;
204298686cd2SShayne Chen 
204398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR27(band_idx));
204498686cd2SShayne Chen 	mib->rx_ampdu_cnt += cnt;
204598686cd2SShayne Chen 
204698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR28(band_idx));
204798686cd2SShayne Chen 	mib->rx_ampdu_bytes_cnt += cnt;
204898686cd2SShayne Chen 
204998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR29(band_idx));
205098686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_cnt += cnt;
205198686cd2SShayne Chen 
205298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RSCR30(band_idx));
205398686cd2SShayne Chen 	mib->rx_ampdu_valid_subframe_bytes_cnt += cnt;
205498686cd2SShayne Chen 
205598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR27(band_idx));
205698686cd2SShayne Chen 	mib->tx_rwp_fail_cnt += FIELD_GET(MT_MIB_SDR27_TX_RWP_FAIL_CNT, cnt);
205798686cd2SShayne Chen 
205898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_SDR28(band_idx));
205998686cd2SShayne Chen 	mib->tx_rwp_need_cnt += FIELD_GET(MT_MIB_SDR28_TX_RWP_NEED_CNT, cnt);
206098686cd2SShayne Chen 
206198686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_UMIB_RPDCR(band_idx));
206298686cd2SShayne Chen 	mib->rx_pfdrop_cnt += cnt;
206398686cd2SShayne Chen 
206498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_RVSR1(band_idx));
206598686cd2SShayne Chen 	mib->rx_vec_queue_overflow_drop_cnt += cnt;
206698686cd2SShayne Chen 
206798686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR1(band_idx));
206898686cd2SShayne Chen 	mib->rx_ba_cnt += cnt;
206998686cd2SShayne Chen 
207098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR0(band_idx));
207198686cd2SShayne Chen 	mib->tx_bf_ebf_ppdu_cnt += cnt;
207298686cd2SShayne Chen 
207398686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR1(band_idx));
207498686cd2SShayne Chen 	mib->tx_bf_ibf_ppdu_cnt += cnt;
207598686cd2SShayne Chen 
207698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR2(band_idx));
207798686cd2SShayne Chen 	mib->tx_mu_bf_cnt += cnt;
207898686cd2SShayne Chen 
207998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR5(band_idx));
208098686cd2SShayne Chen 	mib->tx_mu_mpdu_cnt += cnt;
208198686cd2SShayne Chen 
208298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR6(band_idx));
208398686cd2SShayne Chen 	mib->tx_mu_acked_mpdu_cnt += cnt;
208498686cd2SShayne Chen 
208598686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_TSCR7(band_idx));
208698686cd2SShayne Chen 	mib->tx_su_acked_mpdu_cnt += cnt;
208798686cd2SShayne Chen 
208898686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR3(band_idx));
208998686cd2SShayne Chen 	mib->tx_bf_rx_fb_ht_cnt += cnt;
209098686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
209198686cd2SShayne Chen 
209298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR4(band_idx));
209398686cd2SShayne Chen 	mib->tx_bf_rx_fb_vht_cnt += cnt;
209498686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
209598686cd2SShayne Chen 
209698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR5(band_idx));
209798686cd2SShayne Chen 	mib->tx_bf_rx_fb_he_cnt += cnt;
209898686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
209998686cd2SShayne Chen 
210098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR6(band_idx));
210198686cd2SShayne Chen 	mib->tx_bf_rx_fb_eht_cnt += cnt;
210298686cd2SShayne Chen 	mib->tx_bf_rx_fb_all_cnt += cnt;
210398686cd2SShayne Chen 
210498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_ETBF_RX_FB_CONT(band_idx));
210598686cd2SShayne Chen 	mib->tx_bf_rx_fb_bw = FIELD_GET(MT_ETBF_RX_FB_BW, cnt);
210698686cd2SShayne Chen 	mib->tx_bf_rx_fb_nc_cnt += FIELD_GET(MT_ETBF_RX_FB_NC, cnt);
210798686cd2SShayne Chen 	mib->tx_bf_rx_fb_nr_cnt += FIELD_GET(MT_ETBF_RX_FB_NR, cnt);
210898686cd2SShayne Chen 
210998686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR7(band_idx));
211098686cd2SShayne Chen 	mib->tx_bf_fb_trig_cnt += cnt;
211198686cd2SShayne Chen 
211298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BSCR17(band_idx));
211398686cd2SShayne Chen 	mib->tx_bf_fb_cpl_cnt += cnt;
211498686cd2SShayne Chen 
211598686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(mib->tx_amsdu); i++) {
211698686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
211798686cd2SShayne Chen 		mib->tx_amsdu[i] += cnt;
211898686cd2SShayne Chen 		mib->tx_amsdu_cnt += cnt;
211998686cd2SShayne Chen 	}
212098686cd2SShayne Chen 
212198686cd2SShayne Chen 	/* rts count */
212298686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR5(band_idx));
212398686cd2SShayne Chen 	mib->rts_cnt += cnt;
212498686cd2SShayne Chen 
212598686cd2SShayne Chen 	/* rts retry count */
212698686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR6(band_idx));
212798686cd2SShayne Chen 	mib->rts_retries_cnt += cnt;
212898686cd2SShayne Chen 
212998686cd2SShayne Chen 	/* ba miss count */
213098686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BTSCR0(band_idx));
213198686cd2SShayne Chen 	mib->ba_miss_cnt += cnt;
213298686cd2SShayne Chen 
213398686cd2SShayne Chen 	/* ack fail count */
213498686cd2SShayne Chen 	cnt = mt76_rr(dev, MT_MIB_BFTFCR(band_idx));
213598686cd2SShayne Chen 	mib->ack_fail_cnt += cnt;
213698686cd2SShayne Chen 
213798686cd2SShayne Chen 	for (i = 0; i < 16; i++) {
213898686cd2SShayne Chen 		cnt = mt76_rr(dev, MT_TX_AGG_CNT(band_idx, i));
213998686cd2SShayne Chen 		phy->mt76->aggr_stats[i] += cnt;
214098686cd2SShayne Chen 	}
214198686cd2SShayne Chen }
214298686cd2SShayne Chen 
214398686cd2SShayne Chen void mt7996_mac_sta_rc_work(struct work_struct *work)
214498686cd2SShayne Chen {
214598686cd2SShayne Chen 	struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
214698686cd2SShayne Chen 	struct ieee80211_sta *sta;
214798686cd2SShayne Chen 	struct ieee80211_vif *vif;
214898686cd2SShayne Chen 	struct mt7996_sta *msta;
214998686cd2SShayne Chen 	u32 changed;
215098686cd2SShayne Chen 	LIST_HEAD(list);
215198686cd2SShayne Chen 
2152ea0f3867SLorenzo Bianconi 	spin_lock_bh(&dev->mt76.sta_poll_lock);
215398686cd2SShayne Chen 	list_splice_init(&dev->sta_rc_list, &list);
215498686cd2SShayne Chen 
215598686cd2SShayne Chen 	while (!list_empty(&list)) {
215698686cd2SShayne Chen 		msta = list_first_entry(&list, struct mt7996_sta, rc_list);
215798686cd2SShayne Chen 		list_del_init(&msta->rc_list);
215898686cd2SShayne Chen 		changed = msta->changed;
215998686cd2SShayne Chen 		msta->changed = 0;
2160ea0f3867SLorenzo Bianconi 		spin_unlock_bh(&dev->mt76.sta_poll_lock);
216198686cd2SShayne Chen 
216298686cd2SShayne Chen 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
216398686cd2SShayne Chen 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
216498686cd2SShayne Chen 
216598686cd2SShayne Chen 		if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
216698686cd2SShayne Chen 			       IEEE80211_RC_NSS_CHANGED |
216798686cd2SShayne Chen 			       IEEE80211_RC_BW_CHANGED))
216898686cd2SShayne Chen 			mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
216998686cd2SShayne Chen 
217098686cd2SShayne Chen 		/* TODO: smps change */
217198686cd2SShayne Chen 
2172ea0f3867SLorenzo Bianconi 		spin_lock_bh(&dev->mt76.sta_poll_lock);
217398686cd2SShayne Chen 	}
217498686cd2SShayne Chen 
2175ea0f3867SLorenzo Bianconi 	spin_unlock_bh(&dev->mt76.sta_poll_lock);
217698686cd2SShayne Chen }
217798686cd2SShayne Chen 
217898686cd2SShayne Chen void mt7996_mac_work(struct work_struct *work)
217998686cd2SShayne Chen {
218098686cd2SShayne Chen 	struct mt7996_phy *phy;
218198686cd2SShayne Chen 	struct mt76_phy *mphy;
218298686cd2SShayne Chen 
218398686cd2SShayne Chen 	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
218498686cd2SShayne Chen 					       mac_work.work);
218598686cd2SShayne Chen 	phy = mphy->priv;
218698686cd2SShayne Chen 
218798686cd2SShayne Chen 	mutex_lock(&mphy->dev->mutex);
218898686cd2SShayne Chen 
218998686cd2SShayne Chen 	mt76_update_survey(mphy);
219098686cd2SShayne Chen 	if (++mphy->mac_work_count == 5) {
219198686cd2SShayne Chen 		mphy->mac_work_count = 0;
219298686cd2SShayne Chen 
219398686cd2SShayne Chen 		mt7996_mac_update_stats(phy);
219498686cd2SShayne Chen 	}
219598686cd2SShayne Chen 
219698686cd2SShayne Chen 	mutex_unlock(&mphy->dev->mutex);
219798686cd2SShayne Chen 
219898686cd2SShayne Chen 	mt76_tx_status_check(mphy->dev, false);
219998686cd2SShayne Chen 
220098686cd2SShayne Chen 	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
220198686cd2SShayne Chen 				     MT7996_WATCHDOG_TIME);
220298686cd2SShayne Chen }
220398686cd2SShayne Chen 
220498686cd2SShayne Chen static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy)
220598686cd2SShayne Chen {
220698686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
220798686cd2SShayne Chen 
220898686cd2SShayne Chen 	if (phy->rdd_state & BIT(0))
220998686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 0,
221098686cd2SShayne Chen 				   MT_RX_SEL0, 0);
221198686cd2SShayne Chen 	if (phy->rdd_state & BIT(1))
221298686cd2SShayne Chen 		mt7996_mcu_rdd_cmd(dev, RDD_STOP, 1,
221398686cd2SShayne Chen 				   MT_RX_SEL0, 0);
221498686cd2SShayne Chen }
221598686cd2SShayne Chen 
221698686cd2SShayne Chen static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int chain)
221798686cd2SShayne Chen {
221898686cd2SShayne Chen 	int err, region;
221998686cd2SShayne Chen 
222098686cd2SShayne Chen 	switch (dev->mt76.region) {
222198686cd2SShayne Chen 	case NL80211_DFS_ETSI:
222298686cd2SShayne Chen 		region = 0;
222398686cd2SShayne Chen 		break;
222498686cd2SShayne Chen 	case NL80211_DFS_JP:
222598686cd2SShayne Chen 		region = 2;
222698686cd2SShayne Chen 		break;
222798686cd2SShayne Chen 	case NL80211_DFS_FCC:
222898686cd2SShayne Chen 	default:
222998686cd2SShayne Chen 		region = 1;
223098686cd2SShayne Chen 		break;
223198686cd2SShayne Chen 	}
223298686cd2SShayne Chen 
223398686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_START, chain,
223498686cd2SShayne Chen 				 MT_RX_SEL0, region);
223598686cd2SShayne Chen 	if (err < 0)
223698686cd2SShayne Chen 		return err;
223798686cd2SShayne Chen 
223898686cd2SShayne Chen 	return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
223998686cd2SShayne Chen 				 MT_RX_SEL0, 1);
224098686cd2SShayne Chen }
224198686cd2SShayne Chen 
224298686cd2SShayne Chen static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy)
224398686cd2SShayne Chen {
224498686cd2SShayne Chen 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
224598686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
224698686cd2SShayne Chen 	u8 band_idx = phy->mt76->band_idx;
224798686cd2SShayne Chen 	int err;
224898686cd2SShayne Chen 
224998686cd2SShayne Chen 	/* start CAC */
225098686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_START, band_idx,
225198686cd2SShayne Chen 				 MT_RX_SEL0, 0);
225298686cd2SShayne Chen 	if (err < 0)
225398686cd2SShayne Chen 		return err;
225498686cd2SShayne Chen 
225598686cd2SShayne Chen 	err = mt7996_dfs_start_rdd(dev, band_idx);
225698686cd2SShayne Chen 	if (err < 0)
225798686cd2SShayne Chen 		return err;
225898686cd2SShayne Chen 
225998686cd2SShayne Chen 	phy->rdd_state |= BIT(band_idx);
226098686cd2SShayne Chen 
226198686cd2SShayne Chen 	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
226298686cd2SShayne Chen 	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
226398686cd2SShayne Chen 		err = mt7996_dfs_start_rdd(dev, 1);
226498686cd2SShayne Chen 		if (err < 0)
226598686cd2SShayne Chen 			return err;
226698686cd2SShayne Chen 
226798686cd2SShayne Chen 		phy->rdd_state |= BIT(1);
226898686cd2SShayne Chen 	}
226998686cd2SShayne Chen 
227098686cd2SShayne Chen 	return 0;
227198686cd2SShayne Chen }
227298686cd2SShayne Chen 
227398686cd2SShayne Chen static int
227498686cd2SShayne Chen mt7996_dfs_init_radar_specs(struct mt7996_phy *phy)
227598686cd2SShayne Chen {
227698686cd2SShayne Chen 	const struct mt7996_dfs_radar_spec *radar_specs;
227798686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
227898686cd2SShayne Chen 	int err, i;
227998686cd2SShayne Chen 
228098686cd2SShayne Chen 	switch (dev->mt76.region) {
228198686cd2SShayne Chen 	case NL80211_DFS_FCC:
228298686cd2SShayne Chen 		radar_specs = &fcc_radar_specs;
228398686cd2SShayne Chen 		err = mt7996_mcu_set_fcc5_lpn(dev, 8);
228498686cd2SShayne Chen 		if (err < 0)
228598686cd2SShayne Chen 			return err;
228698686cd2SShayne Chen 		break;
228798686cd2SShayne Chen 	case NL80211_DFS_ETSI:
228898686cd2SShayne Chen 		radar_specs = &etsi_radar_specs;
228998686cd2SShayne Chen 		break;
229098686cd2SShayne Chen 	case NL80211_DFS_JP:
229198686cd2SShayne Chen 		radar_specs = &jp_radar_specs;
229298686cd2SShayne Chen 		break;
229398686cd2SShayne Chen 	default:
229498686cd2SShayne Chen 		return -EINVAL;
229598686cd2SShayne Chen 	}
229698686cd2SShayne Chen 
229798686cd2SShayne Chen 	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
229898686cd2SShayne Chen 		err = mt7996_mcu_set_radar_th(dev, i,
229998686cd2SShayne Chen 					      &radar_specs->radar_pattern[i]);
230098686cd2SShayne Chen 		if (err < 0)
230198686cd2SShayne Chen 			return err;
230298686cd2SShayne Chen 	}
230398686cd2SShayne Chen 
230498686cd2SShayne Chen 	return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
230598686cd2SShayne Chen }
230698686cd2SShayne Chen 
230798686cd2SShayne Chen int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy)
230898686cd2SShayne Chen {
230998686cd2SShayne Chen 	struct mt7996_dev *dev = phy->dev;
231098686cd2SShayne Chen 	enum mt76_dfs_state dfs_state, prev_state;
231198686cd2SShayne Chen 	int err;
231298686cd2SShayne Chen 
231398686cd2SShayne Chen 	prev_state = phy->mt76->dfs_state;
231498686cd2SShayne Chen 	dfs_state = mt76_phy_dfs_state(phy->mt76);
231598686cd2SShayne Chen 
231698686cd2SShayne Chen 	if (prev_state == dfs_state)
231798686cd2SShayne Chen 		return 0;
231898686cd2SShayne Chen 
231998686cd2SShayne Chen 	if (prev_state == MT_DFS_STATE_UNKNOWN)
232098686cd2SShayne Chen 		mt7996_dfs_stop_radar_detector(phy);
232198686cd2SShayne Chen 
232298686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_DISABLED)
232398686cd2SShayne Chen 		goto stop;
232498686cd2SShayne Chen 
232598686cd2SShayne Chen 	if (prev_state <= MT_DFS_STATE_DISABLED) {
232698686cd2SShayne Chen 		err = mt7996_dfs_init_radar_specs(phy);
232798686cd2SShayne Chen 		if (err < 0)
232898686cd2SShayne Chen 			return err;
232998686cd2SShayne Chen 
233098686cd2SShayne Chen 		err = mt7996_dfs_start_radar_detector(phy);
233198686cd2SShayne Chen 		if (err < 0)
233298686cd2SShayne Chen 			return err;
233398686cd2SShayne Chen 
233498686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_CAC;
233598686cd2SShayne Chen 	}
233698686cd2SShayne Chen 
233798686cd2SShayne Chen 	if (dfs_state == MT_DFS_STATE_CAC)
233898686cd2SShayne Chen 		return 0;
233998686cd2SShayne Chen 
234098686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_CAC_END,
234198686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
234298686cd2SShayne Chen 	if (err < 0) {
234398686cd2SShayne Chen 		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
234498686cd2SShayne Chen 		return err;
234598686cd2SShayne Chen 	}
234698686cd2SShayne Chen 
234798686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
234898686cd2SShayne Chen 	return 0;
234998686cd2SShayne Chen 
235098686cd2SShayne Chen stop:
235198686cd2SShayne Chen 	err = mt7996_mcu_rdd_cmd(dev, RDD_NORMAL_START,
235298686cd2SShayne Chen 				 phy->mt76->band_idx, MT_RX_SEL0, 0);
235398686cd2SShayne Chen 	if (err < 0)
235498686cd2SShayne Chen 		return err;
235598686cd2SShayne Chen 
235698686cd2SShayne Chen 	mt7996_dfs_stop_radar_detector(phy);
235798686cd2SShayne Chen 	phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
235898686cd2SShayne Chen 
235998686cd2SShayne Chen 	return 0;
236098686cd2SShayne Chen }
236198686cd2SShayne Chen 
236298686cd2SShayne Chen static int
236398686cd2SShayne Chen mt7996_mac_twt_duration_align(int duration)
236498686cd2SShayne Chen {
236598686cd2SShayne Chen 	return duration << 8;
236698686cd2SShayne Chen }
236798686cd2SShayne Chen 
236898686cd2SShayne Chen static u64
236998686cd2SShayne Chen mt7996_mac_twt_sched_list_add(struct mt7996_dev *dev,
237098686cd2SShayne Chen 			      struct mt7996_twt_flow *flow)
237198686cd2SShayne Chen {
237298686cd2SShayne Chen 	struct mt7996_twt_flow *iter, *iter_next;
237398686cd2SShayne Chen 	u32 duration = flow->duration << 8;
237498686cd2SShayne Chen 	u64 start_tsf;
237598686cd2SShayne Chen 
237698686cd2SShayne Chen 	iter = list_first_entry_or_null(&dev->twt_list,
237798686cd2SShayne Chen 					struct mt7996_twt_flow, list);
237898686cd2SShayne Chen 	if (!iter || !iter->sched || iter->start_tsf > duration) {
237998686cd2SShayne Chen 		/* add flow as first entry in the list */
238098686cd2SShayne Chen 		list_add(&flow->list, &dev->twt_list);
238198686cd2SShayne Chen 		return 0;
238298686cd2SShayne Chen 	}
238398686cd2SShayne Chen 
238498686cd2SShayne Chen 	list_for_each_entry_safe(iter, iter_next, &dev->twt_list, list) {
238598686cd2SShayne Chen 		start_tsf = iter->start_tsf +
238698686cd2SShayne Chen 			    mt7996_mac_twt_duration_align(iter->duration);
238798686cd2SShayne Chen 		if (list_is_last(&iter->list, &dev->twt_list))
238898686cd2SShayne Chen 			break;
238998686cd2SShayne Chen 
239098686cd2SShayne Chen 		if (!iter_next->sched ||
239198686cd2SShayne Chen 		    iter_next->start_tsf > start_tsf + duration) {
239298686cd2SShayne Chen 			list_add(&flow->list, &iter->list);
239398686cd2SShayne Chen 			goto out;
239498686cd2SShayne Chen 		}
239598686cd2SShayne Chen 	}
239698686cd2SShayne Chen 
239798686cd2SShayne Chen 	/* add flow as last entry in the list */
239898686cd2SShayne Chen 	list_add_tail(&flow->list, &dev->twt_list);
239998686cd2SShayne Chen out:
240098686cd2SShayne Chen 	return start_tsf;
240198686cd2SShayne Chen }
240298686cd2SShayne Chen 
240398686cd2SShayne Chen static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
240498686cd2SShayne Chen {
240598686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt;
240698686cd2SShayne Chen 	u64 interval, duration;
240798686cd2SShayne Chen 	u16 mantissa;
240898686cd2SShayne Chen 	u8 exp;
240998686cd2SShayne Chen 
241098686cd2SShayne Chen 	/* only individual agreement supported */
241198686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST)
241298686cd2SShayne Chen 		return -EOPNOTSUPP;
241398686cd2SShayne Chen 
241498686cd2SShayne Chen 	/* only 256us unit supported */
241598686cd2SShayne Chen 	if (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT)
241698686cd2SShayne Chen 		return -EOPNOTSUPP;
241798686cd2SShayne Chen 
241898686cd2SShayne Chen 	twt_agrt = (struct ieee80211_twt_params *)twt->params;
241998686cd2SShayne Chen 
242098686cd2SShayne Chen 	/* explicit agreement not supported */
242198686cd2SShayne Chen 	if (!(twt_agrt->req_type & cpu_to_le16(IEEE80211_TWT_REQTYPE_IMPLICIT)))
242298686cd2SShayne Chen 		return -EOPNOTSUPP;
242398686cd2SShayne Chen 
242498686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP,
242598686cd2SShayne Chen 			le16_to_cpu(twt_agrt->req_type));
242698686cd2SShayne Chen 	mantissa = le16_to_cpu(twt_agrt->mantissa);
242798686cd2SShayne Chen 	duration = twt_agrt->min_twt_dur << 8;
242898686cd2SShayne Chen 
242998686cd2SShayne Chen 	interval = (u64)mantissa << exp;
243098686cd2SShayne Chen 	if (interval < duration)
243198686cd2SShayne Chen 		return -EOPNOTSUPP;
243298686cd2SShayne Chen 
243398686cd2SShayne Chen 	return 0;
243498686cd2SShayne Chen }
243598686cd2SShayne Chen 
243698686cd2SShayne Chen void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
243798686cd2SShayne Chen 			      struct ieee80211_sta *sta,
243898686cd2SShayne Chen 			      struct ieee80211_twt_setup *twt)
243998686cd2SShayne Chen {
244098686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
244198686cd2SShayne Chen 	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
244298686cd2SShayne Chen 	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
244398686cd2SShayne Chen 	u16 req_type = le16_to_cpu(twt_agrt->req_type);
244498686cd2SShayne Chen 	enum ieee80211_twt_setup_cmd sta_setup_cmd;
244598686cd2SShayne Chen 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
244698686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
244798686cd2SShayne Chen 	int flowid, table_id;
244898686cd2SShayne Chen 	u8 exp;
244998686cd2SShayne Chen 
245098686cd2SShayne Chen 	if (mt7996_mac_check_twt_req(twt))
245198686cd2SShayne Chen 		goto out;
245298686cd2SShayne Chen 
245398686cd2SShayne Chen 	mutex_lock(&dev->mt76.mutex);
245498686cd2SShayne Chen 
245598686cd2SShayne Chen 	if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
245698686cd2SShayne Chen 		goto unlock;
245798686cd2SShayne Chen 
245898686cd2SShayne Chen 	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
245998686cd2SShayne Chen 		goto unlock;
246098686cd2SShayne Chen 
246198686cd2SShayne Chen 	flowid = ffs(~msta->twt.flowid_mask) - 1;
246298686cd2SShayne Chen 	le16p_replace_bits(&twt_agrt->req_type, flowid,
246398686cd2SShayne Chen 			   IEEE80211_TWT_REQTYPE_FLOWID);
246498686cd2SShayne Chen 
246598686cd2SShayne Chen 	table_id = ffs(~dev->twt.table_mask) - 1;
246698686cd2SShayne Chen 	exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
246798686cd2SShayne Chen 	sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
246898686cd2SShayne Chen 
246998686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
247098686cd2SShayne Chen 	memset(flow, 0, sizeof(*flow));
247198686cd2SShayne Chen 	INIT_LIST_HEAD(&flow->list);
247298686cd2SShayne Chen 	flow->wcid = msta->wcid.idx;
247398686cd2SShayne Chen 	flow->table_id = table_id;
247498686cd2SShayne Chen 	flow->id = flowid;
247598686cd2SShayne Chen 	flow->duration = twt_agrt->min_twt_dur;
247698686cd2SShayne Chen 	flow->mantissa = twt_agrt->mantissa;
247798686cd2SShayne Chen 	flow->exp = exp;
247898686cd2SShayne Chen 	flow->protection = !!(req_type & IEEE80211_TWT_REQTYPE_PROTECTION);
247998686cd2SShayne Chen 	flow->flowtype = !!(req_type & IEEE80211_TWT_REQTYPE_FLOWTYPE);
248098686cd2SShayne Chen 	flow->trigger = !!(req_type & IEEE80211_TWT_REQTYPE_TRIGGER);
248198686cd2SShayne Chen 
248298686cd2SShayne Chen 	if (sta_setup_cmd == TWT_SETUP_CMD_REQUEST ||
248398686cd2SShayne Chen 	    sta_setup_cmd == TWT_SETUP_CMD_SUGGEST) {
248498686cd2SShayne Chen 		u64 interval = (u64)le16_to_cpu(twt_agrt->mantissa) << exp;
248598686cd2SShayne Chen 		u64 flow_tsf, curr_tsf;
248698686cd2SShayne Chen 		u32 rem;
248798686cd2SShayne Chen 
248898686cd2SShayne Chen 		flow->sched = true;
248998686cd2SShayne Chen 		flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
249098686cd2SShayne Chen 		curr_tsf = __mt7996_get_tsf(hw, msta->vif);
249198686cd2SShayne Chen 		div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
249298686cd2SShayne Chen 		flow_tsf = curr_tsf + interval - rem;
249398686cd2SShayne Chen 		twt_agrt->twt = cpu_to_le64(flow_tsf);
249498686cd2SShayne Chen 	} else {
249598686cd2SShayne Chen 		list_add_tail(&flow->list, &dev->twt_list);
249698686cd2SShayne Chen 	}
249798686cd2SShayne Chen 	flow->tsf = le64_to_cpu(twt_agrt->twt);
249898686cd2SShayne Chen 
249998686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
250098686cd2SShayne Chen 		goto unlock;
250198686cd2SShayne Chen 
250298686cd2SShayne Chen 	setup_cmd = TWT_SETUP_CMD_ACCEPT;
250398686cd2SShayne Chen 	dev->twt.table_mask |= BIT(table_id);
250498686cd2SShayne Chen 	msta->twt.flowid_mask |= BIT(flowid);
250598686cd2SShayne Chen 	dev->twt.n_agrt++;
250698686cd2SShayne Chen 
250798686cd2SShayne Chen unlock:
250898686cd2SShayne Chen 	mutex_unlock(&dev->mt76.mutex);
250998686cd2SShayne Chen out:
251098686cd2SShayne Chen 	le16p_replace_bits(&twt_agrt->req_type, setup_cmd,
251198686cd2SShayne Chen 			   IEEE80211_TWT_REQTYPE_SETUP_CMD);
251298686cd2SShayne Chen 	twt->control = (twt->control & IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT) |
251398686cd2SShayne Chen 		       (twt->control & IEEE80211_TWT_CONTROL_RX_DISABLED);
251498686cd2SShayne Chen }
251598686cd2SShayne Chen 
251698686cd2SShayne Chen void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
251798686cd2SShayne Chen 				  struct mt7996_sta *msta,
251898686cd2SShayne Chen 				  u8 flowid)
251998686cd2SShayne Chen {
252098686cd2SShayne Chen 	struct mt7996_twt_flow *flow;
252198686cd2SShayne Chen 
252298686cd2SShayne Chen 	lockdep_assert_held(&dev->mt76.mutex);
252398686cd2SShayne Chen 
252498686cd2SShayne Chen 	if (flowid >= ARRAY_SIZE(msta->twt.flow))
252598686cd2SShayne Chen 		return;
252698686cd2SShayne Chen 
252798686cd2SShayne Chen 	if (!(msta->twt.flowid_mask & BIT(flowid)))
252898686cd2SShayne Chen 		return;
252998686cd2SShayne Chen 
253098686cd2SShayne Chen 	flow = &msta->twt.flow[flowid];
253198686cd2SShayne Chen 	if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
253298686cd2SShayne Chen 				       MCU_TWT_AGRT_DELETE))
253398686cd2SShayne Chen 		return;
253498686cd2SShayne Chen 
253598686cd2SShayne Chen 	list_del_init(&flow->list);
253698686cd2SShayne Chen 	msta->twt.flowid_mask &= ~BIT(flowid);
253798686cd2SShayne Chen 	dev->twt.table_mask &= ~BIT(flow->table_id);
253898686cd2SShayne Chen 	dev->twt.n_agrt--;
253998686cd2SShayne Chen }
2540