18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
48c2ecf20Sopenharmony_ci#include <linux/timekeeping.h>
58c2ecf20Sopenharmony_ci#include "mt7603.h"
68c2ecf20Sopenharmony_ci#include "mac.h"
78c2ecf20Sopenharmony_ci#include "../trace.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define MT_PSE_PAGE_SIZE	128
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic u32
128c2ecf20Sopenharmony_cimt7603_ac_queue_mask0(u32 mask)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	u32 ret = 0;
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	ret |= GENMASK(3, 0) * !!(mask & BIT(0));
178c2ecf20Sopenharmony_ci	ret |= GENMASK(8, 5) * !!(mask & BIT(1));
188c2ecf20Sopenharmony_ci	ret |= GENMASK(13, 10) * !!(mask & BIT(2));
198c2ecf20Sopenharmony_ci	ret |= GENMASK(19, 16) * !!(mask & BIT(3));
208c2ecf20Sopenharmony_ci	return ret;
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic void
248c2ecf20Sopenharmony_cimt76_stop_tx_ac(struct mt7603_dev *dev, u32 mask)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WF_ARB_TX_STOP_0, mt7603_ac_queue_mask0(mask));
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void
308c2ecf20Sopenharmony_cimt76_start_tx_ac(struct mt7603_dev *dev, u32 mask)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask));
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_civoid mt7603_mac_reset_counters(struct mt7603_dev *dev)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	int i;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++)
408c2ecf20Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(i));
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_civoid mt7603_mac_set_timing(struct mt7603_dev *dev)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
488c2ecf20Sopenharmony_ci		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
498c2ecf20Sopenharmony_ci	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
508c2ecf20Sopenharmony_ci		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 24);
518c2ecf20Sopenharmony_ci	int offset = 3 * dev->coverage_class;
528c2ecf20Sopenharmony_ci	u32 reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
538c2ecf20Sopenharmony_ci			 FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
548c2ecf20Sopenharmony_ci	bool is_5ghz = dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ;
558c2ecf20Sopenharmony_ci	int sifs;
568c2ecf20Sopenharmony_ci	u32 val;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (is_5ghz)
598c2ecf20Sopenharmony_ci		sifs = 16;
608c2ecf20Sopenharmony_ci	else
618c2ecf20Sopenharmony_ci		sifs = 10;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	mt76_set(dev, MT_ARB_SCR,
648c2ecf20Sopenharmony_ci		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
658c2ecf20Sopenharmony_ci	udelay(1);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TIMEOUT_CCK, cck + reg_offset);
688c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TIMEOUT_OFDM, ofdm + reg_offset);
698c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_IFS,
708c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_EIFS, 360) |
718c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_RIFS, 2) |
728c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_SIFS, sifs) |
738c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_SLOT, dev->slottime));
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (dev->slottime < 20 || is_5ghz)
768c2ecf20Sopenharmony_ci		val = MT7603_CFEND_RATE_DEFAULT;
778c2ecf20Sopenharmony_ci	else
788c2ecf20Sopenharmony_ci		val = MT7603_CFEND_RATE_11B;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_AGG_CONTROL, MT_AGG_CONTROL_CFEND_RATE, val);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_ARB_SCR,
838c2ecf20Sopenharmony_ci		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void
878c2ecf20Sopenharmony_cimt7603_wtbl_update(struct mt7603_dev *dev, int idx, u32 mask)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
908c2ecf20Sopenharmony_ci		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic u32
968c2ecf20Sopenharmony_cimt7603_wtbl1_addr(int idx)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	return MT_WTBL1_BASE + idx * MT_WTBL1_SIZE;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic u32
1028c2ecf20Sopenharmony_cimt7603_wtbl2_addr(int idx)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	/* Mapped to WTBL2 */
1058c2ecf20Sopenharmony_ci	return MT_PCIE_REMAP_BASE_1 + idx * MT_WTBL2_SIZE;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic u32
1098c2ecf20Sopenharmony_cimt7603_wtbl3_addr(int idx)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 base = mt7603_wtbl2_addr(MT7603_WTBL_SIZE);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return base + idx * MT_WTBL3_SIZE;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic u32
1178c2ecf20Sopenharmony_cimt7603_wtbl4_addr(int idx)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	u32 base = mt7603_wtbl3_addr(MT7603_WTBL_SIZE);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return base + idx * MT_WTBL4_SIZE;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_civoid mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif,
1258c2ecf20Sopenharmony_ci		      const u8 *mac_addr)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	const void *_mac = mac_addr;
1288c2ecf20Sopenharmony_ci	u32 addr = mt7603_wtbl1_addr(idx);
1298c2ecf20Sopenharmony_ci	u32 w0 = 0, w1 = 0;
1308c2ecf20Sopenharmony_ci	int i;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (_mac) {
1338c2ecf20Sopenharmony_ci		w0 = FIELD_PREP(MT_WTBL1_W0_ADDR_HI,
1348c2ecf20Sopenharmony_ci				get_unaligned_le16(_mac + 4));
1358c2ecf20Sopenharmony_ci		w1 = FIELD_PREP(MT_WTBL1_W1_ADDR_LO,
1368c2ecf20Sopenharmony_ci				get_unaligned_le32(_mac));
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (vif < 0)
1408c2ecf20Sopenharmony_ci		vif = 0;
1418c2ecf20Sopenharmony_ci	else
1428c2ecf20Sopenharmony_ci		w0 |= MT_WTBL1_W0_RX_CHECK_A1;
1438c2ecf20Sopenharmony_ci	w0 |= FIELD_PREP(MT_WTBL1_W0_MUAR_IDX, vif);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	mt76_set(dev, addr + 0 * 4, w0);
1488c2ecf20Sopenharmony_ci	mt76_set(dev, addr + 1 * 4, w1);
1498c2ecf20Sopenharmony_ci	mt76_set(dev, addr + 2 * 4, MT_WTBL1_W2_ADMISSION_CONTROL);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	mt76_stop_tx_ac(dev, GENMASK(3, 0));
1528c2ecf20Sopenharmony_ci	addr = mt7603_wtbl2_addr(idx);
1538c2ecf20Sopenharmony_ci	for (i = 0; i < MT_WTBL2_SIZE; i += 4)
1548c2ecf20Sopenharmony_ci		mt76_wr(dev, addr + i, 0);
1558c2ecf20Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2);
1568c2ecf20Sopenharmony_ci	mt76_start_tx_ac(dev, GENMASK(3, 0));
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	addr = mt7603_wtbl3_addr(idx);
1598c2ecf20Sopenharmony_ci	for (i = 0; i < MT_WTBL3_SIZE; i += 4)
1608c2ecf20Sopenharmony_ci		mt76_wr(dev, addr + i, 0);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	addr = mt7603_wtbl4_addr(idx);
1638c2ecf20Sopenharmony_ci	for (i = 0; i < MT_WTBL4_SIZE; i += 4)
1648c2ecf20Sopenharmony_ci		mt76_wr(dev, addr + i, 0);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic void
1708c2ecf20Sopenharmony_cimt7603_wtbl_set_skip_tx(struct mt7603_dev *dev, int idx, bool enabled)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	u32 addr = mt7603_wtbl1_addr(idx);
1738c2ecf20Sopenharmony_ci	u32 val = mt76_rr(dev, addr + 3 * 4);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	val &= ~MT_WTBL1_W3_SKIP_TX;
1768c2ecf20Sopenharmony_ci	val |= enabled * MT_WTBL1_W3_SKIP_TX;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 3 * 4, val);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_civoid mt7603_filter_tx(struct mt7603_dev *dev, int idx, bool abort)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	int i, port, queue;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (abort) {
1868c2ecf20Sopenharmony_ci		port = 3; /* PSE */
1878c2ecf20Sopenharmony_ci		queue = 8; /* free queue */
1888c2ecf20Sopenharmony_ci	} else {
1898c2ecf20Sopenharmony_ci		port = 0; /* HIF */
1908c2ecf20Sopenharmony_ci		queue = 1; /* MCU queue */
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	mt7603_wtbl_set_skip_tx(dev, idx, true);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TX_ABORT, MT_TX_ABORT_EN |
1968c2ecf20Sopenharmony_ci			FIELD_PREP(MT_TX_ABORT_WCID, idx));
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
1998c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
2008c2ecf20Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, idx) |
2018c2ecf20Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, i) |
2028c2ecf20Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, port) |
2038c2ecf20Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, queue));
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		WARN_ON_ONCE(!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY,
2068c2ecf20Sopenharmony_ci					0, 5000));
2078c2ecf20Sopenharmony_ci	}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TX_ABORT, 0);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	mt7603_wtbl_set_skip_tx(dev, idx, false);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_civoid mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
2158c2ecf20Sopenharmony_ci			  bool enabled)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	u32 addr = mt7603_wtbl1_addr(sta->wcid.idx);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (sta->smps == enabled)
2208c2ecf20Sopenharmony_ci		return;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_SMPS, enabled);
2238c2ecf20Sopenharmony_ci	sta->smps = enabled;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_civoid mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
2278c2ecf20Sopenharmony_ci			bool enabled)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	int idx = sta->wcid.idx;
2308c2ecf20Sopenharmony_ci	u32 addr;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->ps_lock);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (sta->ps == enabled)
2358c2ecf20Sopenharmony_ci		goto out;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_PSE_RTA,
2388c2ecf20Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_TAG_ID, idx) |
2398c2ecf20Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_PORT_ID, 0) |
2408c2ecf20Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_QUEUE_ID, 1) |
2418c2ecf20Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_REDIRECT_EN, enabled) |
2428c2ecf20Sopenharmony_ci		MT_PSE_RTA_WRITE | MT_PSE_RTA_BUSY);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (enabled)
2478c2ecf20Sopenharmony_ci		mt7603_filter_tx(dev, idx, false);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	addr = mt7603_wtbl1_addr(idx);
2508c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
2518c2ecf20Sopenharmony_ci	mt76_rmw(dev, addr + 3 * 4, MT_WTBL1_W3_POWER_SAVE,
2528c2ecf20Sopenharmony_ci		 enabled * MT_WTBL1_W3_POWER_SAVE);
2538c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
2548c2ecf20Sopenharmony_ci	sta->ps = enabled;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciout:
2578c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->ps_lock);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_civoid mt7603_wtbl_clear(struct mt7603_dev *dev, int idx)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	int wtbl2_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL2_SIZE;
2638c2ecf20Sopenharmony_ci	int wtbl2_frame = idx / wtbl2_frame_size;
2648c2ecf20Sopenharmony_ci	int wtbl2_entry = idx % wtbl2_frame_size;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	int wtbl3_base_frame = MT_WTBL3_OFFSET / MT_PSE_PAGE_SIZE;
2678c2ecf20Sopenharmony_ci	int wtbl3_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL3_SIZE;
2688c2ecf20Sopenharmony_ci	int wtbl3_frame = wtbl3_base_frame + idx / wtbl3_frame_size;
2698c2ecf20Sopenharmony_ci	int wtbl3_entry = (idx % wtbl3_frame_size) * 2;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	int wtbl4_base_frame = MT_WTBL4_OFFSET / MT_PSE_PAGE_SIZE;
2728c2ecf20Sopenharmony_ci	int wtbl4_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL4_SIZE;
2738c2ecf20Sopenharmony_ci	int wtbl4_frame = wtbl4_base_frame + idx / wtbl4_frame_size;
2748c2ecf20Sopenharmony_ci	int wtbl4_entry = idx % wtbl4_frame_size;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	u32 addr = MT_WTBL1_BASE + idx * MT_WTBL1_SIZE;
2778c2ecf20Sopenharmony_ci	int i;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 0 * 4,
2828c2ecf20Sopenharmony_ci		MT_WTBL1_W0_RX_CHECK_A1 |
2838c2ecf20Sopenharmony_ci		MT_WTBL1_W0_RX_CHECK_A2 |
2848c2ecf20Sopenharmony_ci		MT_WTBL1_W0_RX_VALID);
2858c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 1 * 4, 0);
2868c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 2 * 4, 0);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 3 * 4,
2918c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W3_WTBL2_FRAME_ID, wtbl2_frame) |
2928c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W3_WTBL2_ENTRY_ID, wtbl2_entry) |
2938c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W3_WTBL4_FRAME_ID, wtbl4_frame) |
2948c2ecf20Sopenharmony_ci		MT_WTBL1_W3_I_PSM | MT_WTBL1_W3_KEEP_I_PSM);
2958c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 4 * 4,
2968c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W4_WTBL3_FRAME_ID, wtbl3_frame) |
2978c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W4_WTBL3_ENTRY_ID, wtbl3_entry) |
2988c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W4_WTBL4_ENTRY_ID, wtbl4_entry));
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	addr = mt7603_wtbl2_addr(idx);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Clear BA information */
3058c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + (15 * 4), 0);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	mt76_stop_tx_ac(dev, GENMASK(3, 0));
3088c2ecf20Sopenharmony_ci	for (i = 2; i <= 4; i++)
3098c2ecf20Sopenharmony_ci		mt76_wr(dev, addr + (i * 4), 0);
3108c2ecf20Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2);
3118c2ecf20Sopenharmony_ci	mt76_start_tx_ac(dev, GENMASK(3, 0));
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_RX_COUNT_CLEAR);
3148c2ecf20Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_TX_COUNT_CLEAR);
3158c2ecf20Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_civoid mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
3218c2ecf20Sopenharmony_ci	int idx = msta->wcid.idx;
3228c2ecf20Sopenharmony_ci	u8 ampdu_density;
3238c2ecf20Sopenharmony_ci	u32 addr;
3248c2ecf20Sopenharmony_ci	u32 val;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	addr = mt7603_wtbl1_addr(idx);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	ampdu_density = sta->ht_cap.ampdu_density;
3298c2ecf20Sopenharmony_ci	if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4)
3308c2ecf20Sopenharmony_ci		ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	val = mt76_rr(dev, addr + 2 * 4);
3338c2ecf20Sopenharmony_ci	val &= MT_WTBL1_W2_KEY_TYPE | MT_WTBL1_W2_ADMISSION_CONTROL;
3348c2ecf20Sopenharmony_ci	val |= FIELD_PREP(MT_WTBL1_W2_AMPDU_FACTOR, sta->ht_cap.ampdu_factor) |
3358c2ecf20Sopenharmony_ci	       FIELD_PREP(MT_WTBL1_W2_MPDU_DENSITY, sta->ht_cap.ampdu_density) |
3368c2ecf20Sopenharmony_ci	       MT_WTBL1_W2_TXS_BAF_REPORT;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (sta->ht_cap.cap)
3398c2ecf20Sopenharmony_ci		val |= MT_WTBL1_W2_HT;
3408c2ecf20Sopenharmony_ci	if (sta->vht_cap.cap)
3418c2ecf20Sopenharmony_ci		val |= MT_WTBL1_W2_VHT;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 2 * 4, val);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	addr = mt7603_wtbl2_addr(idx);
3468c2ecf20Sopenharmony_ci	val = mt76_rr(dev, addr + 9 * 4);
3478c2ecf20Sopenharmony_ci	val &= ~(MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 |
3488c2ecf20Sopenharmony_ci		 MT_WTBL2_W9_SHORT_GI_80);
3498c2ecf20Sopenharmony_ci	if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
3508c2ecf20Sopenharmony_ci		val |= MT_WTBL2_W9_SHORT_GI_20;
3518c2ecf20Sopenharmony_ci	if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
3528c2ecf20Sopenharmony_ci		val |= MT_WTBL2_W9_SHORT_GI_40;
3538c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 9 * 4, val);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_civoid mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_BA_CONTROL_0, get_unaligned_le32(addr));
3598c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_BA_CONTROL_1,
3608c2ecf20Sopenharmony_ci		(get_unaligned_le16(addr + 4) |
3618c2ecf20Sopenharmony_ci		 FIELD_PREP(MT_BA_CONTROL_1_TID, tid) |
3628c2ecf20Sopenharmony_ci		 MT_BA_CONTROL_1_RESET));
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_civoid mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
3668c2ecf20Sopenharmony_ci			    int ba_size)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	u32 addr = mt7603_wtbl2_addr(wcid);
3698c2ecf20Sopenharmony_ci	u32 tid_mask = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) |
3708c2ecf20Sopenharmony_ci		       (MT_WTBL2_W15_BA_WIN_SIZE <<
3718c2ecf20Sopenharmony_ci			(tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT));
3728c2ecf20Sopenharmony_ci	u32 tid_val;
3738c2ecf20Sopenharmony_ci	int i;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	if (ba_size < 0) {
3768c2ecf20Sopenharmony_ci		/* disable */
3778c2ecf20Sopenharmony_ci		mt76_clear(dev, addr + (15 * 4), tid_mask);
3788c2ecf20Sopenharmony_ci		return;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	for (i = 7; i > 0; i--) {
3828c2ecf20Sopenharmony_ci		if (ba_size >= MT_AGG_SIZE_LIMIT(i))
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	tid_val = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) |
3878c2ecf20Sopenharmony_ci		  i << (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_civoid mt7603_mac_sta_poll(struct mt7603_dev *dev)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	static const u8 ac_to_tid[4] = {
3958c2ecf20Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
3968c2ecf20Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
3978c2ecf20Sopenharmony_ci		[IEEE80211_AC_VI] = 4,
3988c2ecf20Sopenharmony_ci		[IEEE80211_AC_VO] = 6
3998c2ecf20Sopenharmony_ci	};
4008c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
4018c2ecf20Sopenharmony_ci	struct mt7603_sta *msta;
4028c2ecf20Sopenharmony_ci	u32 total_airtime = 0;
4038c2ecf20Sopenharmony_ci	u32 airtime[4];
4048c2ecf20Sopenharmony_ci	u32 addr;
4058c2ecf20Sopenharmony_ci	int i;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	rcu_read_lock();
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	while (1) {
4108c2ecf20Sopenharmony_ci		bool clear = false;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->sta_poll_lock);
4138c2ecf20Sopenharmony_ci		if (list_empty(&dev->sta_poll_list)) {
4148c2ecf20Sopenharmony_ci			spin_unlock_bh(&dev->sta_poll_lock);
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta,
4198c2ecf20Sopenharmony_ci					poll_list);
4208c2ecf20Sopenharmony_ci		list_del_init(&msta->poll_list);
4218c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->sta_poll_lock);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		addr = mt7603_wtbl4_addr(msta->wcid.idx);
4248c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++) {
4258c2ecf20Sopenharmony_ci			u32 airtime_last = msta->tx_airtime_ac[i];
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci			msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8);
4288c2ecf20Sopenharmony_ci			airtime[i] = msta->tx_airtime_ac[i] - airtime_last;
4298c2ecf20Sopenharmony_ci			airtime[i] *= 32;
4308c2ecf20Sopenharmony_ci			total_airtime += airtime[i];
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci			if (msta->tx_airtime_ac[i] & BIT(22))
4338c2ecf20Sopenharmony_ci				clear = true;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		if (clear) {
4378c2ecf20Sopenharmony_ci			mt7603_wtbl_update(dev, msta->wcid.idx,
4388c2ecf20Sopenharmony_ci					   MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
4398c2ecf20Sopenharmony_ci			memset(msta->tx_airtime_ac, 0,
4408c2ecf20Sopenharmony_ci			       sizeof(msta->tx_airtime_ac));
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		if (!msta->wcid.sta)
4448c2ecf20Sopenharmony_ci			continue;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
4478c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++) {
4488c2ecf20Sopenharmony_ci			struct mt76_queue *q = dev->mt76.q_tx[i];
4498c2ecf20Sopenharmony_ci			u8 qidx = q->hw_idx;
4508c2ecf20Sopenharmony_ci			u8 tid = ac_to_tid[i];
4518c2ecf20Sopenharmony_ci			u32 txtime = airtime[qidx];
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci			if (!txtime)
4548c2ecf20Sopenharmony_ci				continue;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci			ieee80211_sta_register_airtime(sta, tid, txtime, 0);
4578c2ecf20Sopenharmony_ci		}
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	rcu_read_unlock();
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	if (!total_airtime)
4638c2ecf20Sopenharmony_ci		return;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->mt76.cc_lock);
4668c2ecf20Sopenharmony_ci	dev->mphy.chan_state->cc_tx += total_airtime;
4678c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->mt76.cc_lock);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic struct mt76_wcid *
4718c2ecf20Sopenharmony_cimt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct mt7603_sta *sta;
4748c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (idx >= MT7603_WTBL_SIZE)
4778c2ecf20Sopenharmony_ci		return NULL;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[idx]);
4808c2ecf20Sopenharmony_ci	if (unicast || !wcid)
4818c2ecf20Sopenharmony_ci		return wcid;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (!wcid->sta)
4848c2ecf20Sopenharmony_ci		return NULL;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	sta = container_of(wcid, struct mt7603_sta, wcid);
4878c2ecf20Sopenharmony_ci	if (!sta->vif)
4888c2ecf20Sopenharmony_ci		return NULL;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	return &sta->vif->sta.wcid;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ciint
4948c2ecf20Sopenharmony_cimt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
4978c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
4988c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
4998c2ecf20Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
5008c2ecf20Sopenharmony_ci	u32 rxd0 = le32_to_cpu(rxd[0]);
5018c2ecf20Sopenharmony_ci	u32 rxd1 = le32_to_cpu(rxd[1]);
5028c2ecf20Sopenharmony_ci	u32 rxd2 = le32_to_cpu(rxd[2]);
5038c2ecf20Sopenharmony_ci	bool unicast = rxd1 & MT_RXD1_NORMAL_U2M;
5048c2ecf20Sopenharmony_ci	bool insert_ccmp_hdr = false;
5058c2ecf20Sopenharmony_ci	bool remove_pad;
5068c2ecf20Sopenharmony_ci	int idx;
5078c2ecf20Sopenharmony_ci	int i;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	memset(status, 0, sizeof(*status));
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	i = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1);
5128c2ecf20Sopenharmony_ci	sband = (i & 1) ? &dev->mphy.sband_5g.sband : &dev->mphy.sband_2g.sband;
5138c2ecf20Sopenharmony_ci	i >>= 1;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
5168c2ecf20Sopenharmony_ci	status->wcid = mt7603_rx_get_wcid(dev, idx, unicast);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	status->band = sband->band;
5198c2ecf20Sopenharmony_ci	if (i < sband->n_channels)
5208c2ecf20Sopenharmony_ci		status->freq = sband->channels[i].center_freq;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_FCS_ERR)
5238c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_FAILED_FCS_CRC;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR)
5268c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_ERROR;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
5298c2ecf20Sopenharmony_ci	    !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) {
5308c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
5318c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
5328c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
5368c2ecf20Sopenharmony_ci		      MT_RXD2_NORMAL_NON_AMPDU))) {
5378c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_AMPDU_DETAILS;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		/* all subframes of an A-MPDU have the same timestamp */
5408c2ecf20Sopenharmony_ci		if (dev->rx_ampdu_ts != rxd[12]) {
5418c2ecf20Sopenharmony_ci			if (!++dev->ampdu_ref)
5428c2ecf20Sopenharmony_ci				dev->ampdu_ref++;
5438c2ecf20Sopenharmony_ci		}
5448c2ecf20Sopenharmony_ci		dev->rx_ampdu_ts = rxd[12];
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		status->ampdu_ref = dev->ampdu_ref;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
5528c2ecf20Sopenharmony_ci		return -EINVAL;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (!sband->channels)
5558c2ecf20Sopenharmony_ci		return -EINVAL;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	rxd += 4;
5588c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
5598c2ecf20Sopenharmony_ci		rxd += 4;
5608c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
5618c2ecf20Sopenharmony_ci			return -EINVAL;
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_1) {
5648c2ecf20Sopenharmony_ci		u8 *data = (u8 *)rxd;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci		if (status->flag & RX_FLAG_DECRYPTED) {
5678c2ecf20Sopenharmony_ci			status->iv[0] = data[5];
5688c2ecf20Sopenharmony_ci			status->iv[1] = data[4];
5698c2ecf20Sopenharmony_ci			status->iv[2] = data[3];
5708c2ecf20Sopenharmony_ci			status->iv[3] = data[2];
5718c2ecf20Sopenharmony_ci			status->iv[4] = data[1];
5728c2ecf20Sopenharmony_ci			status->iv[5] = data[0];
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci			insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
5758c2ecf20Sopenharmony_ci		}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci		rxd += 4;
5788c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
5798c2ecf20Sopenharmony_ci			return -EINVAL;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_2) {
5828c2ecf20Sopenharmony_ci		rxd += 2;
5838c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
5848c2ecf20Sopenharmony_ci			return -EINVAL;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
5878c2ecf20Sopenharmony_ci		u32 rxdg0 = le32_to_cpu(rxd[0]);
5888c2ecf20Sopenharmony_ci		u32 rxdg3 = le32_to_cpu(rxd[3]);
5898c2ecf20Sopenharmony_ci		bool cck = false;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci		i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0);
5928c2ecf20Sopenharmony_ci		switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
5938c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_CCK:
5948c2ecf20Sopenharmony_ci			cck = true;
5958c2ecf20Sopenharmony_ci			fallthrough;
5968c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_OFDM:
5978c2ecf20Sopenharmony_ci			i = mt76_get_rate(&dev->mt76, sband, i, cck);
5988c2ecf20Sopenharmony_ci			break;
5998c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_HT_GF:
6008c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_HT:
6018c2ecf20Sopenharmony_ci			status->encoding = RX_ENC_HT;
6028c2ecf20Sopenharmony_ci			if (i > 15)
6038c2ecf20Sopenharmony_ci				return -EINVAL;
6048c2ecf20Sopenharmony_ci			break;
6058c2ecf20Sopenharmony_ci		default:
6068c2ecf20Sopenharmony_ci			return -EINVAL;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_SHORT_GI)
6108c2ecf20Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
6118c2ecf20Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_AD_CODE)
6128c2ecf20Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_LDPC;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_STBC_MASK *
6158c2ecf20Sopenharmony_ci				    FIELD_GET(MT_RXV1_HT_STBC, rxdg0);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci		status->rate_idx = i;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci		status->chains = dev->mphy.antenna_mask;
6208c2ecf20Sopenharmony_ci		status->chain_signal[0] = FIELD_GET(MT_RXV4_IB_RSSI0, rxdg3) +
6218c2ecf20Sopenharmony_ci					  dev->rssi_offset[0];
6228c2ecf20Sopenharmony_ci		status->chain_signal[1] = FIELD_GET(MT_RXV4_IB_RSSI1, rxdg3) +
6238c2ecf20Sopenharmony_ci					  dev->rssi_offset[1];
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		status->signal = status->chain_signal[0];
6268c2ecf20Sopenharmony_ci		if (status->chains & BIT(1))
6278c2ecf20Sopenharmony_ci			status->signal = max(status->signal,
6288c2ecf20Sopenharmony_ci					     status->chain_signal[1]);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		if (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0) == 1)
6318c2ecf20Sopenharmony_ci			status->bw = RATE_INFO_BW_40;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		rxd += 6;
6348c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
6358c2ecf20Sopenharmony_ci			return -EINVAL;
6368c2ecf20Sopenharmony_ci	} else {
6378c2ecf20Sopenharmony_ci		return -EINVAL;
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if (insert_ccmp_hdr) {
6438c2ecf20Sopenharmony_ci		u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		mt76_insert_ccmp_hdr(skb, key_id);
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)skb->data;
6498c2ecf20Sopenharmony_ci	if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
6508c2ecf20Sopenharmony_ci		return 0;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	status->aggr = unicast &&
6538c2ecf20Sopenharmony_ci		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
6548c2ecf20Sopenharmony_ci	status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
6558c2ecf20Sopenharmony_ci	status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	return 0;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic u16
6618c2ecf20Sopenharmony_cimt7603_mac_tx_rate_val(struct mt7603_dev *dev,
6628c2ecf20Sopenharmony_ci		       const struct ieee80211_tx_rate *rate, bool stbc, u8 *bw)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	u8 phy, nss, rate_idx;
6658c2ecf20Sopenharmony_ci	u16 rateval;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	*bw = 0;
6688c2ecf20Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_MCS) {
6698c2ecf20Sopenharmony_ci		rate_idx = rate->idx;
6708c2ecf20Sopenharmony_ci		nss = 1 + (rate->idx >> 3);
6718c2ecf20Sopenharmony_ci		phy = MT_PHY_TYPE_HT;
6728c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
6738c2ecf20Sopenharmony_ci			phy = MT_PHY_TYPE_HT_GF;
6748c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
6758c2ecf20Sopenharmony_ci			*bw = 1;
6768c2ecf20Sopenharmony_ci	} else {
6778c2ecf20Sopenharmony_ci		const struct ieee80211_rate *r;
6788c2ecf20Sopenharmony_ci		int band = dev->mphy.chandef.chan->band;
6798c2ecf20Sopenharmony_ci		u16 val;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		nss = 1;
6828c2ecf20Sopenharmony_ci		r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx];
6838c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
6848c2ecf20Sopenharmony_ci			val = r->hw_value_short;
6858c2ecf20Sopenharmony_ci		else
6868c2ecf20Sopenharmony_ci			val = r->hw_value;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		phy = val >> 8;
6898c2ecf20Sopenharmony_ci		rate_idx = val & 0xff;
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
6938c2ecf20Sopenharmony_ci		   FIELD_PREP(MT_TX_RATE_MODE, phy));
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (stbc && nss == 1)
6968c2ecf20Sopenharmony_ci		rateval |= MT_TX_RATE_STBC;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	return rateval;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_civoid mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
7028c2ecf20Sopenharmony_ci			   struct ieee80211_tx_rate *probe_rate,
7038c2ecf20Sopenharmony_ci			   struct ieee80211_tx_rate *rates)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate *ref;
7068c2ecf20Sopenharmony_ci	int wcid = sta->wcid.idx;
7078c2ecf20Sopenharmony_ci	u32 addr = mt7603_wtbl2_addr(wcid);
7088c2ecf20Sopenharmony_ci	bool stbc = false;
7098c2ecf20Sopenharmony_ci	int n_rates = sta->n_rates;
7108c2ecf20Sopenharmony_ci	u8 bw, bw_prev, bw_idx = 0;
7118c2ecf20Sopenharmony_ci	u16 val[4];
7128c2ecf20Sopenharmony_ci	u16 probe_val;
7138c2ecf20Sopenharmony_ci	u32 w9 = mt76_rr(dev, addr + 9 * 4);
7148c2ecf20Sopenharmony_ci	bool rateset;
7158c2ecf20Sopenharmony_ci	int i, k;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
7188c2ecf20Sopenharmony_ci		return;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	for (i = n_rates; i < 4; i++)
7218c2ecf20Sopenharmony_ci		rates[i] = rates[n_rates - 1];
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	rateset = !(sta->rate_set_tsf & BIT(0));
7248c2ecf20Sopenharmony_ci	memcpy(sta->rateset[rateset].rates, rates,
7258c2ecf20Sopenharmony_ci	       sizeof(sta->rateset[rateset].rates));
7268c2ecf20Sopenharmony_ci	if (probe_rate) {
7278c2ecf20Sopenharmony_ci		sta->rateset[rateset].probe_rate = *probe_rate;
7288c2ecf20Sopenharmony_ci		ref = &sta->rateset[rateset].probe_rate;
7298c2ecf20Sopenharmony_ci	} else {
7308c2ecf20Sopenharmony_ci		sta->rateset[rateset].probe_rate.idx = -1;
7318c2ecf20Sopenharmony_ci		ref = &sta->rateset[rateset].rates[0];
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	rates = sta->rateset[rateset].rates;
7358c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) {
7368c2ecf20Sopenharmony_ci		/*
7378c2ecf20Sopenharmony_ci		 * We don't support switching between short and long GI
7388c2ecf20Sopenharmony_ci		 * within the rate set. For accurate tx status reporting, we
7398c2ecf20Sopenharmony_ci		 * need to make sure that flags match.
7408c2ecf20Sopenharmony_ci		 * For improved performance, avoid duplicate entries by
7418c2ecf20Sopenharmony_ci		 * decrementing the MCS index if necessary
7428c2ecf20Sopenharmony_ci		 */
7438c2ecf20Sopenharmony_ci		if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI)
7448c2ecf20Sopenharmony_ci			rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci		for (k = 0; k < i; k++) {
7478c2ecf20Sopenharmony_ci			if (rates[i].idx != rates[k].idx)
7488c2ecf20Sopenharmony_ci				continue;
7498c2ecf20Sopenharmony_ci			if ((rates[i].flags ^ rates[k].flags) &
7508c2ecf20Sopenharmony_ci			    IEEE80211_TX_RC_40_MHZ_WIDTH)
7518c2ecf20Sopenharmony_ci				continue;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci			if (!rates[i].idx)
7548c2ecf20Sopenharmony_ci				continue;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci			rates[i].idx--;
7578c2ecf20Sopenharmony_ci		}
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 |
7618c2ecf20Sopenharmony_ci	      MT_WTBL2_W9_SHORT_GI_80;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	val[0] = mt7603_mac_tx_rate_val(dev, &rates[0], stbc, &bw);
7648c2ecf20Sopenharmony_ci	bw_prev = bw;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	if (probe_rate) {
7678c2ecf20Sopenharmony_ci		probe_val = mt7603_mac_tx_rate_val(dev, probe_rate, stbc, &bw);
7688c2ecf20Sopenharmony_ci		if (bw)
7698c2ecf20Sopenharmony_ci			bw_idx = 1;
7708c2ecf20Sopenharmony_ci		else
7718c2ecf20Sopenharmony_ci			bw_prev = 0;
7728c2ecf20Sopenharmony_ci	} else {
7738c2ecf20Sopenharmony_ci		probe_val = val[0];
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	w9 |= FIELD_PREP(MT_WTBL2_W9_CC_BW_SEL, bw);
7778c2ecf20Sopenharmony_ci	w9 |= FIELD_PREP(MT_WTBL2_W9_BW_CAP, bw);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	val[1] = mt7603_mac_tx_rate_val(dev, &rates[1], stbc, &bw);
7808c2ecf20Sopenharmony_ci	if (bw_prev) {
7818c2ecf20Sopenharmony_ci		bw_idx = 3;
7828c2ecf20Sopenharmony_ci		bw_prev = bw;
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	val[2] = mt7603_mac_tx_rate_val(dev, &rates[2], stbc, &bw);
7868c2ecf20Sopenharmony_ci	if (bw_prev) {
7878c2ecf20Sopenharmony_ci		bw_idx = 5;
7888c2ecf20Sopenharmony_ci		bw_prev = bw;
7898c2ecf20Sopenharmony_ci	}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	val[3] = mt7603_mac_tx_rate_val(dev, &rates[3], stbc, &bw);
7928c2ecf20Sopenharmony_ci	if (bw_prev)
7938c2ecf20Sopenharmony_ci		bw_idx = 7;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	w9 |= FIELD_PREP(MT_WTBL2_W9_CHANGE_BW_RATE,
7968c2ecf20Sopenharmony_ci		       bw_idx ? bw_idx - 1 : 7);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR0, w9);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR1,
8018c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) |
8028c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) |
8038c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1]));
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR2,
8068c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) |
8078c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) |
8088c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) |
8098c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2]));
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR3,
8128c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) |
8138c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) |
8148c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3]));
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */
8178c2ecf20Sopenharmony_ci	sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_UPDATE,
8208c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
8218c2ecf20Sopenharmony_ci		MT_WTBL_UPDATE_RATE_UPDATE |
8228c2ecf20Sopenharmony_ci		MT_WTBL_UPDATE_TX_COUNT_CLEAR);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
8258c2ecf20Sopenharmony_ci		mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	sta->rate_count = 2 * MT7603_RATE_RETRY * n_rates;
8288c2ecf20Sopenharmony_ci	sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
8298c2ecf20Sopenharmony_ci}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic enum mt7603_cipher_type
8328c2ecf20Sopenharmony_cimt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	memset(key_data, 0, 32);
8358c2ecf20Sopenharmony_ci	if (!key)
8368c2ecf20Sopenharmony_ci		return MT_CIPHER_NONE;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	if (key->keylen > 32)
8398c2ecf20Sopenharmony_ci		return MT_CIPHER_NONE;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	memcpy(key_data, key->key, key->keylen);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	switch (key->cipher) {
8448c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
8458c2ecf20Sopenharmony_ci		return MT_CIPHER_WEP40;
8468c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
8478c2ecf20Sopenharmony_ci		return MT_CIPHER_WEP104;
8488c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
8498c2ecf20Sopenharmony_ci		/* Rx/Tx MIC keys are swapped */
8508c2ecf20Sopenharmony_ci		memcpy(key_data + 16, key->key + 24, 8);
8518c2ecf20Sopenharmony_ci		memcpy(key_data + 24, key->key + 16, 8);
8528c2ecf20Sopenharmony_ci		return MT_CIPHER_TKIP;
8538c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
8548c2ecf20Sopenharmony_ci		return MT_CIPHER_AES_CCMP;
8558c2ecf20Sopenharmony_ci	default:
8568c2ecf20Sopenharmony_ci		return MT_CIPHER_NONE;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ciint mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid,
8618c2ecf20Sopenharmony_ci			struct ieee80211_key_conf *key)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	enum mt7603_cipher_type cipher;
8648c2ecf20Sopenharmony_ci	u32 addr = mt7603_wtbl3_addr(wcid);
8658c2ecf20Sopenharmony_ci	u8 key_data[32];
8668c2ecf20Sopenharmony_ci	int key_len = sizeof(key_data);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	cipher = mt7603_mac_get_key_info(key, key_data);
8698c2ecf20Sopenharmony_ci	if (cipher == MT_CIPHER_NONE && key)
8708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (key && (cipher == MT_CIPHER_WEP40 || cipher == MT_CIPHER_WEP104)) {
8738c2ecf20Sopenharmony_ci		addr += key->keyidx * 16;
8748c2ecf20Sopenharmony_ci		key_len = 16;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	mt76_wr_copy(dev, addr, key_data, key_len);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	addr = mt7603_wtbl1_addr(wcid);
8808c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_KEY_TYPE, cipher);
8818c2ecf20Sopenharmony_ci	if (key)
8828c2ecf20Sopenharmony_ci		mt76_rmw_field(dev, addr, MT_WTBL1_W0_KEY_IDX, key->keyidx);
8838c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, addr, MT_WTBL1_W0_RX_KEY_VALID, !!key);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	return 0;
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistatic int
8898c2ecf20Sopenharmony_cimt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
8908c2ecf20Sopenharmony_ci		      struct sk_buff *skb, enum mt76_txq_id qid,
8918c2ecf20Sopenharmony_ci		      struct mt76_wcid *wcid, struct ieee80211_sta *sta,
8928c2ecf20Sopenharmony_ci		      int pid, struct ieee80211_key_conf *key)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
8958c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate *rate = &info->control.rates[0];
8968c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
8978c2ecf20Sopenharmony_ci	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
8988c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = info->control.vif;
8998c2ecf20Sopenharmony_ci	struct mt76_queue *q = dev->mt76.q_tx[qid];
9008c2ecf20Sopenharmony_ci	struct mt7603_vif *mvif;
9018c2ecf20Sopenharmony_ci	int wlan_idx;
9028c2ecf20Sopenharmony_ci	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
9038c2ecf20Sopenharmony_ci	int tx_count = 8;
9048c2ecf20Sopenharmony_ci	u8 frame_type, frame_subtype;
9058c2ecf20Sopenharmony_ci	u16 fc = le16_to_cpu(hdr->frame_control);
9068c2ecf20Sopenharmony_ci	u16 seqno = 0;
9078c2ecf20Sopenharmony_ci	u8 vif_idx = 0;
9088c2ecf20Sopenharmony_ci	u32 val;
9098c2ecf20Sopenharmony_ci	u8 bw;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	if (vif) {
9128c2ecf20Sopenharmony_ci		mvif = (struct mt7603_vif *)vif->drv_priv;
9138c2ecf20Sopenharmony_ci		vif_idx = mvif->idx;
9148c2ecf20Sopenharmony_ci		if (vif_idx && qid >= MT_TXQ_BEACON)
9158c2ecf20Sopenharmony_ci			vif_idx += 0x10;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (sta) {
9198c2ecf20Sopenharmony_ci		struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci		tx_count = msta->rate_count;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	if (wcid)
9258c2ecf20Sopenharmony_ci		wlan_idx = wcid->idx;
9268c2ecf20Sopenharmony_ci	else
9278c2ecf20Sopenharmony_ci		wlan_idx = MT7603_WTBL_RESERVED;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	frame_type = (fc & IEEE80211_FCTL_FTYPE) >> 2;
9308c2ecf20Sopenharmony_ci	frame_subtype = (fc & IEEE80211_FCTL_STYPE) >> 4;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
9338c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD0_Q_IDX, q->hw_idx);
9348c2ecf20Sopenharmony_ci	txwi[0] = cpu_to_le32(val);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	val = MT_TXD1_LONG_FORMAT |
9378c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_OWN_MAC, vif_idx) |
9388c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_TID,
9398c2ecf20Sopenharmony_ci			 skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
9408c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
9418c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_INFO, hdr_len / 2) |
9428c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_WLAN_IDX, wlan_idx) |
9438c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_PROTECTED, !!key);
9448c2ecf20Sopenharmony_ci	txwi[1] = cpu_to_le32(val);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
9478c2ecf20Sopenharmony_ci		txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK);
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, frame_type) |
9508c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD2_SUB_TYPE, frame_subtype) |
9518c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD2_MULTICAST,
9528c2ecf20Sopenharmony_ci			 is_multicast_ether_addr(hdr->addr1));
9538c2ecf20Sopenharmony_ci	txwi[2] = cpu_to_le32(val);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
9568c2ecf20Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	txwi[4] = 0;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	val = MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT |
9618c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD5_PID, pid);
9628c2ecf20Sopenharmony_ci	txwi[5] = cpu_to_le32(val);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	txwi[6] = 0;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	if (rate->idx >= 0 && rate->count &&
9678c2ecf20Sopenharmony_ci	    !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
9688c2ecf20Sopenharmony_ci		bool stbc = info->flags & IEEE80211_TX_CTL_STBC;
9698c2ecf20Sopenharmony_ci		u16 rateval = mt7603_mac_tx_rate_val(dev, rate, stbc, &bw);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		val = MT_TXD6_FIXED_BW |
9748c2ecf20Sopenharmony_ci		      FIELD_PREP(MT_TXD6_BW, bw) |
9758c2ecf20Sopenharmony_ci		      FIELD_PREP(MT_TXD6_TX_RATE, rateval);
9768c2ecf20Sopenharmony_ci		txwi[6] |= cpu_to_le32(val);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
9798c2ecf20Sopenharmony_ci			txwi[6] |= cpu_to_le32(MT_TXD6_SGI);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		if (!(rate->flags & IEEE80211_TX_RC_MCS))
9828c2ecf20Sopenharmony_ci			txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci		tx_count = rate->count;
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	/* use maximum tx count for beacons and buffered multicast */
9888c2ecf20Sopenharmony_ci	if (qid >= MT_TXQ_BEACON)
9898c2ecf20Sopenharmony_ci		tx_count = 0x1f;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count) |
9928c2ecf20Sopenharmony_ci		  MT_TXD3_SN_VALID;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	if (ieee80211_is_data_qos(hdr->frame_control))
9958c2ecf20Sopenharmony_ci		seqno = le16_to_cpu(hdr->seq_ctrl);
9968c2ecf20Sopenharmony_ci	else if (ieee80211_is_back_req(hdr->frame_control))
9978c2ecf20Sopenharmony_ci		seqno = le16_to_cpu(bar->start_seq_num);
9988c2ecf20Sopenharmony_ci	else
9998c2ecf20Sopenharmony_ci		val &= ~MT_TXD3_SN_VALID;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	val |= FIELD_PREP(MT_TXD3_SEQ, seqno >> 4);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	txwi[3] = cpu_to_le32(val);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (key) {
10068c2ecf20Sopenharmony_ci		u64 pn = atomic64_inc_return(&key->tx_pn);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci		txwi[3] |= cpu_to_le32(MT_TXD3_PN_VALID);
10098c2ecf20Sopenharmony_ci		txwi[4] = cpu_to_le32(pn & GENMASK(31, 0));
10108c2ecf20Sopenharmony_ci		txwi[5] |= cpu_to_le32(FIELD_PREP(MT_TXD5_PN_HIGH, pn >> 32));
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	txwi[7] = 0;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	return 0;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ciint mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
10198c2ecf20Sopenharmony_ci			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
10208c2ecf20Sopenharmony_ci			  struct ieee80211_sta *sta,
10218c2ecf20Sopenharmony_ci			  struct mt76_tx_info *tx_info)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
10248c2ecf20Sopenharmony_ci	struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid);
10258c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
10268c2ecf20Sopenharmony_ci	struct ieee80211_key_conf *key = info->control.hw_key;
10278c2ecf20Sopenharmony_ci	int pid;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (!wcid)
10308c2ecf20Sopenharmony_ci		wcid = &dev->global_sta.wcid;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (sta) {
10338c2ecf20Sopenharmony_ci		msta = (struct mt7603_sta *)sta->drv_priv;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci		if ((info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
10368c2ecf20Sopenharmony_ci				    IEEE80211_TX_CTL_CLEAR_PS_FILT)) ||
10378c2ecf20Sopenharmony_ci		    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
10388c2ecf20Sopenharmony_ci			mt7603_wtbl_set_ps(dev, msta, false);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci		mt76_tx_check_agg_ssn(sta, tx_info->skb);
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
10468c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
10478c2ecf20Sopenharmony_ci		mt7603_wtbl_set_rates(dev, msta, &info->control.rates[0],
10488c2ecf20Sopenharmony_ci				      msta->rates);
10498c2ecf20Sopenharmony_ci		msta->rate_probe = true;
10508c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	mt7603_mac_write_txwi(dev, txwi_ptr, tx_info->skb, qid, wcid,
10548c2ecf20Sopenharmony_ci			      sta, pid, key);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	return 0;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic bool
10608c2ecf20Sopenharmony_cimt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
10618c2ecf20Sopenharmony_ci		struct ieee80211_tx_info *info, __le32 *txs_data)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
10648c2ecf20Sopenharmony_ci	struct mt7603_rate_set *rs;
10658c2ecf20Sopenharmony_ci	int first_idx = 0, last_idx;
10668c2ecf20Sopenharmony_ci	u32 rate_set_tsf;
10678c2ecf20Sopenharmony_ci	u32 final_rate;
10688c2ecf20Sopenharmony_ci	u32 final_rate_flags;
10698c2ecf20Sopenharmony_ci	bool rs_idx;
10708c2ecf20Sopenharmony_ci	bool ack_timeout;
10718c2ecf20Sopenharmony_ci	bool fixed_rate;
10728c2ecf20Sopenharmony_ci	bool probe;
10738c2ecf20Sopenharmony_ci	bool ampdu;
10748c2ecf20Sopenharmony_ci	bool cck = false;
10758c2ecf20Sopenharmony_ci	int count;
10768c2ecf20Sopenharmony_ci	u32 txs;
10778c2ecf20Sopenharmony_ci	int idx;
10788c2ecf20Sopenharmony_ci	int i;
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	fixed_rate = info->status.rates[0].count;
10818c2ecf20Sopenharmony_ci	probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[4]);
10848c2ecf20Sopenharmony_ci	ampdu = !fixed_rate && (txs & MT_TXS4_AMPDU);
10858c2ecf20Sopenharmony_ci	count = FIELD_GET(MT_TXS4_TX_COUNT, txs);
10868c2ecf20Sopenharmony_ci	last_idx = FIELD_GET(MT_TXS4_LAST_TX_RATE, txs);
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[0]);
10898c2ecf20Sopenharmony_ci	final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
10908c2ecf20Sopenharmony_ci	ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT))
10938c2ecf20Sopenharmony_ci		return false;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	if (txs & MT_TXS0_QUEUE_TIMEOUT)
10968c2ecf20Sopenharmony_ci		return false;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (!ack_timeout)
10998c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	info->status.ampdu_len = 1;
11028c2ecf20Sopenharmony_ci	info->status.ampdu_ack_len = !!(info->flags &
11038c2ecf20Sopenharmony_ci					IEEE80211_TX_STAT_ACK);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
11068c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	first_idx = max_t(int, 0, last_idx - (count - 1) / MT7603_RATE_RETRY);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	if (fixed_rate && !probe) {
11118c2ecf20Sopenharmony_ci		info->status.rates[0].count = count;
11128c2ecf20Sopenharmony_ci		i = 0;
11138c2ecf20Sopenharmony_ci		goto out;
11148c2ecf20Sopenharmony_ci	}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	rate_set_tsf = READ_ONCE(sta->rate_set_tsf);
11178c2ecf20Sopenharmony_ci	rs_idx = !((u32)(FIELD_GET(MT_TXS1_F0_TIMESTAMP, le32_to_cpu(txs_data[1])) -
11188c2ecf20Sopenharmony_ci			 rate_set_tsf) < 1000000);
11198c2ecf20Sopenharmony_ci	rs_idx ^= rate_set_tsf & BIT(0);
11208c2ecf20Sopenharmony_ci	rs = &sta->rateset[rs_idx];
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	if (!first_idx && rs->probe_rate.idx >= 0) {
11238c2ecf20Sopenharmony_ci		info->status.rates[0] = rs->probe_rate;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
11268c2ecf20Sopenharmony_ci		if (sta->rate_probe) {
11278c2ecf20Sopenharmony_ci			mt7603_wtbl_set_rates(dev, sta, NULL,
11288c2ecf20Sopenharmony_ci					      sta->rates);
11298c2ecf20Sopenharmony_ci			sta->rate_probe = false;
11308c2ecf20Sopenharmony_ci		}
11318c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
11328c2ecf20Sopenharmony_ci	} else {
11338c2ecf20Sopenharmony_ci		info->status.rates[0] = rs->rates[first_idx / 2];
11348c2ecf20Sopenharmony_ci	}
11358c2ecf20Sopenharmony_ci	info->status.rates[0].count = 0;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) {
11388c2ecf20Sopenharmony_ci		struct ieee80211_tx_rate *cur_rate;
11398c2ecf20Sopenharmony_ci		int cur_count;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci		cur_rate = &rs->rates[idx / 2];
11428c2ecf20Sopenharmony_ci		cur_count = min_t(int, MT7603_RATE_RETRY, count);
11438c2ecf20Sopenharmony_ci		count -= cur_count;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci		if (idx && (cur_rate->idx != info->status.rates[i].idx ||
11468c2ecf20Sopenharmony_ci			    cur_rate->flags != info->status.rates[i].flags)) {
11478c2ecf20Sopenharmony_ci			i++;
11488c2ecf20Sopenharmony_ci			if (i == ARRAY_SIZE(info->status.rates)) {
11498c2ecf20Sopenharmony_ci				i--;
11508c2ecf20Sopenharmony_ci				break;
11518c2ecf20Sopenharmony_ci			}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci			info->status.rates[i] = *cur_rate;
11548c2ecf20Sopenharmony_ci			info->status.rates[i].count = 0;
11558c2ecf20Sopenharmony_ci		}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci		info->status.rates[i].count += cur_count;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ciout:
11618c2ecf20Sopenharmony_ci	final_rate_flags = info->status.rates[i].flags;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
11648c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_CCK:
11658c2ecf20Sopenharmony_ci		cck = true;
11668c2ecf20Sopenharmony_ci		fallthrough;
11678c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
11688c2ecf20Sopenharmony_ci		if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ)
11698c2ecf20Sopenharmony_ci			sband = &dev->mphy.sband_5g.sband;
11708c2ecf20Sopenharmony_ci		else
11718c2ecf20Sopenharmony_ci			sband = &dev->mphy.sband_2g.sband;
11728c2ecf20Sopenharmony_ci		final_rate &= GENMASK(5, 0);
11738c2ecf20Sopenharmony_ci		final_rate = mt76_get_rate(&dev->mt76, sband, final_rate,
11748c2ecf20Sopenharmony_ci					   cck);
11758c2ecf20Sopenharmony_ci		final_rate_flags = 0;
11768c2ecf20Sopenharmony_ci		break;
11778c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
11788c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT:
11798c2ecf20Sopenharmony_ci		final_rate_flags |= IEEE80211_TX_RC_MCS;
11808c2ecf20Sopenharmony_ci		final_rate &= GENMASK(5, 0);
11818c2ecf20Sopenharmony_ci		if (final_rate > 15)
11828c2ecf20Sopenharmony_ci			return false;
11838c2ecf20Sopenharmony_ci		break;
11848c2ecf20Sopenharmony_ci	default:
11858c2ecf20Sopenharmony_ci		return false;
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	info->status.rates[i].idx = final_rate;
11898c2ecf20Sopenharmony_ci	info->status.rates[i].flags = final_rate_flags;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	return true;
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistatic bool
11958c2ecf20Sopenharmony_cimt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid,
11968c2ecf20Sopenharmony_ci		       __le32 *txs_data)
11978c2ecf20Sopenharmony_ci{
11988c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
11998c2ecf20Sopenharmony_ci	struct sk_buff_head list;
12008c2ecf20Sopenharmony_ci	struct sk_buff *skb;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	if (pid < MT_PACKET_ID_FIRST)
12038c2ecf20Sopenharmony_ci		return false;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	trace_mac_txdone(mdev, sta->wcid.idx, pid);
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	mt76_tx_status_lock(mdev, &list);
12088c2ecf20Sopenharmony_ci	skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list);
12098c2ecf20Sopenharmony_ci	if (skb) {
12108c2ecf20Sopenharmony_ci		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci		if (!mt7603_fill_txs(dev, sta, info, txs_data)) {
12138c2ecf20Sopenharmony_ci			ieee80211_tx_info_clear_status(info);
12148c2ecf20Sopenharmony_ci			info->status.rates[0].idx = -1;
12158c2ecf20Sopenharmony_ci		}
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci		mt76_tx_status_skb_done(mdev, skb, &list);
12188c2ecf20Sopenharmony_ci	}
12198c2ecf20Sopenharmony_ci	mt76_tx_status_unlock(mdev, &list);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	return !!skb;
12228c2ecf20Sopenharmony_ci}
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_civoid mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	struct ieee80211_tx_info info = {};
12278c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta = NULL;
12288c2ecf20Sopenharmony_ci	struct mt7603_sta *msta = NULL;
12298c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
12308c2ecf20Sopenharmony_ci	__le32 *txs_data = data;
12318c2ecf20Sopenharmony_ci	u32 txs;
12328c2ecf20Sopenharmony_ci	u8 wcidx;
12338c2ecf20Sopenharmony_ci	u8 pid;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[4]);
12368c2ecf20Sopenharmony_ci	pid = FIELD_GET(MT_TXS4_PID, txs);
12378c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[3]);
12388c2ecf20Sopenharmony_ci	wcidx = FIELD_GET(MT_TXS3_WCID, txs);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	if (pid == MT_PACKET_ID_NO_ACK)
12418c2ecf20Sopenharmony_ci		return;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	if (wcidx >= MT7603_WTBL_SIZE)
12448c2ecf20Sopenharmony_ci		return;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	rcu_read_lock();
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
12498c2ecf20Sopenharmony_ci	if (!wcid)
12508c2ecf20Sopenharmony_ci		goto out;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	msta = container_of(wcid, struct mt7603_sta, wcid);
12538c2ecf20Sopenharmony_ci	sta = wcid_to_sta(wcid);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	if (list_empty(&msta->poll_list)) {
12568c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->sta_poll_lock);
12578c2ecf20Sopenharmony_ci		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
12588c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->sta_poll_lock);
12598c2ecf20Sopenharmony_ci	}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
12628c2ecf20Sopenharmony_ci		goto out;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	if (wcidx >= MT7603_WTBL_STA || !sta)
12658c2ecf20Sopenharmony_ci		goto out;
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	if (mt7603_fill_txs(dev, msta, &info, txs_data))
12688c2ecf20Sopenharmony_ci		ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ciout:
12718c2ecf20Sopenharmony_ci	rcu_read_unlock();
12728c2ecf20Sopenharmony_ci}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_civoid mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
12758c2ecf20Sopenharmony_ci{
12768c2ecf20Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
12778c2ecf20Sopenharmony_ci	struct sk_buff *skb = e->skb;
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (!e->txwi) {
12808c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
12818c2ecf20Sopenharmony_ci		return;
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	dev->tx_hang_check = 0;
12858c2ecf20Sopenharmony_ci	mt76_tx_complete_skb(mdev, e->wcid, skb);
12868c2ecf20Sopenharmony_ci}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_cistatic bool
12898c2ecf20Sopenharmony_ciwait_for_wpdma(struct mt7603_dev *dev)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	return mt76_poll(dev, MT_WPDMA_GLO_CFG,
12928c2ecf20Sopenharmony_ci			 MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
12938c2ecf20Sopenharmony_ci			 MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
12948c2ecf20Sopenharmony_ci			 0, 1000);
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_cistatic void mt7603_pse_reset(struct mt7603_dev *dev)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	/* Clear previous reset result */
13008c2ecf20Sopenharmony_ci	if (!dev->reset_cause[RESET_CAUSE_RESET_FAILED])
13018c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE_S);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	/* Reset PSE */
13048c2ecf20Sopenharmony_ci	mt76_set(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE);
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_MCU_DEBUG_RESET,
13078c2ecf20Sopenharmony_ci			    MT_MCU_DEBUG_RESET_PSE_S,
13088c2ecf20Sopenharmony_ci			    MT_MCU_DEBUG_RESET_PSE_S, 500)) {
13098c2ecf20Sopenharmony_ci		dev->reset_cause[RESET_CAUSE_RESET_FAILED]++;
13108c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE);
13118c2ecf20Sopenharmony_ci	} else {
13128c2ecf20Sopenharmony_ci		dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0;
13138c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_QUEUES);
13148c2ecf20Sopenharmony_ci	}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] >= 3)
13178c2ecf20Sopenharmony_ci		dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0;
13188c2ecf20Sopenharmony_ci}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_civoid mt7603_mac_dma_start(struct mt7603_dev *dev)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	mt7603_mac_start(dev);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	wait_for_wpdma(dev);
13258c2ecf20Sopenharmony_ci	usleep_range(50, 100);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG,
13288c2ecf20Sopenharmony_ci		 (MT_WPDMA_GLO_CFG_TX_DMA_EN |
13298c2ecf20Sopenharmony_ci		  MT_WPDMA_GLO_CFG_RX_DMA_EN |
13308c2ecf20Sopenharmony_ci		  FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) |
13318c2ecf20Sopenharmony_ci		  MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE));
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	mt7603_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL);
13348c2ecf20Sopenharmony_ci}
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_civoid mt7603_mac_start(struct mt7603_dev *dev)
13378c2ecf20Sopenharmony_ci{
13388c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_ARB_SCR,
13398c2ecf20Sopenharmony_ci		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
13408c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WF_ARB_TX_START_0, ~0);
13418c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START);
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_civoid mt7603_mac_stop(struct mt7603_dev *dev)
13458c2ecf20Sopenharmony_ci{
13468c2ecf20Sopenharmony_ci	mt76_set(dev, MT_ARB_SCR,
13478c2ecf20Sopenharmony_ci		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
13488c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WF_ARB_TX_START_0, 0);
13498c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START);
13508c2ecf20Sopenharmony_ci}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_civoid mt7603_pse_client_reset(struct mt7603_dev *dev)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	u32 addr;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR +
13578c2ecf20Sopenharmony_ci				   MT_CLIENT_RESET_TX);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	/* Clear previous reset state */
13608c2ecf20Sopenharmony_ci	mt76_clear(dev, addr,
13618c2ecf20Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_1 |
13628c2ecf20Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_2 |
13638c2ecf20Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_1_S |
13648c2ecf20Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_2_S);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	/* Start PSE client TX abort */
13678c2ecf20Sopenharmony_ci	mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_1);
13688c2ecf20Sopenharmony_ci	mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_1_S,
13698c2ecf20Sopenharmony_ci		       MT_CLIENT_RESET_TX_R_E_1_S, 500);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_2);
13728c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/* Wait for PSE client to clear TX FIFO */
13758c2ecf20Sopenharmony_ci	mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_2_S,
13768c2ecf20Sopenharmony_ci		       MT_CLIENT_RESET_TX_R_E_2_S, 500);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	/* Clear PSE client TX abort state */
13798c2ecf20Sopenharmony_ci	mt76_clear(dev, addr,
13808c2ecf20Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_1 |
13818c2ecf20Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_2);
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic void mt7603_dma_sched_reset(struct mt7603_dev *dev)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	if (!is_mt7628(dev))
13878c2ecf20Sopenharmony_ci		return;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	mt76_set(dev, MT_SCH_4, MT_SCH_4_RESET);
13908c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_SCH_4, MT_SCH_4_RESET);
13918c2ecf20Sopenharmony_ci}
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cistatic void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	int beacon_int = dev->mt76.beacon_int;
13968c2ecf20Sopenharmony_ci	u32 mask = dev->mt76.mmio.irqmask;
13978c2ecf20Sopenharmony_ci	int i;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	ieee80211_stop_queues(dev->mt76.hw);
14008c2ecf20Sopenharmony_ci	set_bit(MT76_RESET, &dev->mphy.state);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* lock/unlock all queues to ensure that no tx is pending */
14038c2ecf20Sopenharmony_ci	mt76_txq_schedule_all(&dev->mphy);
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	mt76_worker_disable(&dev->mt76.tx_worker);
14068c2ecf20Sopenharmony_ci	tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
14078c2ecf20Sopenharmony_ci	napi_disable(&dev->mt76.napi[0]);
14088c2ecf20Sopenharmony_ci	napi_disable(&dev->mt76.napi[1]);
14098c2ecf20Sopenharmony_ci	napi_disable(&dev->mt76.tx_napi);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	mt7603_beacon_set_timer(dev, -1, 0);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] ||
14168c2ecf20Sopenharmony_ci	    dev->cur_reset_cause == RESET_CAUSE_RX_PSE_BUSY ||
14178c2ecf20Sopenharmony_ci	    dev->cur_reset_cause == RESET_CAUSE_BEACON_STUCK ||
14188c2ecf20Sopenharmony_ci	    dev->cur_reset_cause == RESET_CAUSE_TX_HANG)
14198c2ecf20Sopenharmony_ci		mt7603_pse_reset(dev);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	if (dev->reset_cause[RESET_CAUSE_RESET_FAILED])
14228c2ecf20Sopenharmony_ci		goto skip_dma_reset;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	mt7603_mac_stop(dev);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_WPDMA_GLO_CFG,
14278c2ecf20Sopenharmony_ci		   MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN |
14288c2ecf20Sopenharmony_ci		   MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
14298c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	mt7603_irq_disable(dev, mask);
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_FORCE_TX_EOF);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	mt7603_pse_client_reset(dev);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	for (i = 0; i < __MT_TXQ_MAX; i++)
14388c2ecf20Sopenharmony_ci		mt76_queue_tx_cleanup(dev, i, true);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	mt76_for_each_q_rx(&dev->mt76, i) {
14418c2ecf20Sopenharmony_ci		mt76_queue_rx_reset(dev, i);
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	mt7603_dma_sched_reset(dev);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	mt7603_mac_dma_start(dev);
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	mt7603_irq_enable(dev, mask);
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ciskip_dma_reset:
14518c2ecf20Sopenharmony_ci	clear_bit(MT76_RESET, &dev->mphy.state);
14528c2ecf20Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	mt76_worker_enable(&dev->mt76.tx_worker);
14558c2ecf20Sopenharmony_ci	napi_enable(&dev->mt76.tx_napi);
14568c2ecf20Sopenharmony_ci	napi_schedule(&dev->mt76.tx_napi);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
14598c2ecf20Sopenharmony_ci	mt7603_beacon_set_timer(dev, -1, beacon_int);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	napi_enable(&dev->mt76.napi[0]);
14628c2ecf20Sopenharmony_ci	napi_schedule(&dev->mt76.napi[0]);
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	napi_enable(&dev->mt76.napi[1]);
14658c2ecf20Sopenharmony_ci	napi_schedule(&dev->mt76.napi[1]);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	ieee80211_wake_queues(dev->mt76.hw);
14688c2ecf20Sopenharmony_ci	mt76_txq_schedule_all(&dev->mphy);
14698c2ecf20Sopenharmony_ci}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_cistatic u32 mt7603_dma_debug(struct mt7603_dev *dev, u8 index)
14728c2ecf20Sopenharmony_ci{
14738c2ecf20Sopenharmony_ci	u32 val;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WPDMA_DEBUG,
14768c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WPDMA_DEBUG_IDX, index) |
14778c2ecf20Sopenharmony_ci		MT_WPDMA_DEBUG_SEL);
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_WPDMA_DEBUG);
14808c2ecf20Sopenharmony_ci	return FIELD_GET(MT_WPDMA_DEBUG_VALUE, val);
14818c2ecf20Sopenharmony_ci}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_cistatic bool mt7603_rx_fifo_busy(struct mt7603_dev *dev)
14848c2ecf20Sopenharmony_ci{
14858c2ecf20Sopenharmony_ci	if (is_mt7628(dev))
14868c2ecf20Sopenharmony_ci		return mt7603_dma_debug(dev, 9) & BIT(9);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	return mt7603_dma_debug(dev, 2) & BIT(8);
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_cistatic bool mt7603_rx_dma_busy(struct mt7603_dev *dev)
14928c2ecf20Sopenharmony_ci{
14938c2ecf20Sopenharmony_ci	if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_RX_DMA_BUSY))
14948c2ecf20Sopenharmony_ci		return false;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	return mt7603_rx_fifo_busy(dev);
14978c2ecf20Sopenharmony_ci}
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_cistatic bool mt7603_tx_dma_busy(struct mt7603_dev *dev)
15008c2ecf20Sopenharmony_ci{
15018c2ecf20Sopenharmony_ci	u32 val;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_TX_DMA_BUSY))
15048c2ecf20Sopenharmony_ci		return false;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	val = mt7603_dma_debug(dev, 9);
15078c2ecf20Sopenharmony_ci	return (val & BIT(8)) && (val & 0xf) != 0xf;
15088c2ecf20Sopenharmony_ci}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_cistatic bool mt7603_tx_hang(struct mt7603_dev *dev)
15118c2ecf20Sopenharmony_ci{
15128c2ecf20Sopenharmony_ci	struct mt76_queue *q;
15138c2ecf20Sopenharmony_ci	u32 dma_idx, prev_dma_idx;
15148c2ecf20Sopenharmony_ci	int i;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
15178c2ecf20Sopenharmony_ci		q = dev->mt76.q_tx[i];
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci		if (!q->queued)
15208c2ecf20Sopenharmony_ci			continue;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci		prev_dma_idx = dev->tx_dma_idx[i];
15238c2ecf20Sopenharmony_ci		dma_idx = readl(&q->regs->dma_idx);
15248c2ecf20Sopenharmony_ci		dev->tx_dma_idx[i] = dma_idx;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci		if (dma_idx == prev_dma_idx &&
15278c2ecf20Sopenharmony_ci		    dma_idx != readl(&q->regs->cpu_idx))
15288c2ecf20Sopenharmony_ci			break;
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	return i < 4;
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cistatic bool mt7603_rx_pse_busy(struct mt7603_dev *dev)
15358c2ecf20Sopenharmony_ci{
15368c2ecf20Sopenharmony_ci	u32 addr, val;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (mt7603_rx_fifo_busy(dev))
15398c2ecf20Sopenharmony_ci		goto out;
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + MT_CLIENT_STATUS);
15428c2ecf20Sopenharmony_ci	mt76_wr(dev, addr, 3);
15438c2ecf20Sopenharmony_ci	val = mt76_rr(dev, addr) >> 16;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	if (!(val & BIT(0)))
15468c2ecf20Sopenharmony_ci		return false;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	if (is_mt7628(dev))
15498c2ecf20Sopenharmony_ci		val &= 0xa000;
15508c2ecf20Sopenharmony_ci	else
15518c2ecf20Sopenharmony_ci		val &= 0x8000;
15528c2ecf20Sopenharmony_ci	if (!val)
15538c2ecf20Sopenharmony_ci		return false;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ciout:
15568c2ecf20Sopenharmony_ci	if (mt76_rr(dev, MT_INT_SOURCE_CSR) &
15578c2ecf20Sopenharmony_ci	    (MT_INT_RX_DONE(0) | MT_INT_RX_DONE(1)))
15588c2ecf20Sopenharmony_ci		return false;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	return true;
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_cistatic bool
15648c2ecf20Sopenharmony_cimt7603_watchdog_check(struct mt7603_dev *dev, u8 *counter,
15658c2ecf20Sopenharmony_ci		      enum mt7603_reset_cause cause,
15668c2ecf20Sopenharmony_ci		      bool (*check)(struct mt7603_dev *dev))
15678c2ecf20Sopenharmony_ci{
15688c2ecf20Sopenharmony_ci	if (dev->reset_test == cause + 1) {
15698c2ecf20Sopenharmony_ci		dev->reset_test = 0;
15708c2ecf20Sopenharmony_ci		goto trigger;
15718c2ecf20Sopenharmony_ci	}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (check) {
15748c2ecf20Sopenharmony_ci		if (!check(dev) && *counter < MT7603_WATCHDOG_TIMEOUT) {
15758c2ecf20Sopenharmony_ci			*counter = 0;
15768c2ecf20Sopenharmony_ci			return false;
15778c2ecf20Sopenharmony_ci		}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		(*counter)++;
15808c2ecf20Sopenharmony_ci	}
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	if (*counter < MT7603_WATCHDOG_TIMEOUT)
15838c2ecf20Sopenharmony_ci		return false;
15848c2ecf20Sopenharmony_citrigger:
15858c2ecf20Sopenharmony_ci	dev->cur_reset_cause = cause;
15868c2ecf20Sopenharmony_ci	dev->reset_cause[cause]++;
15878c2ecf20Sopenharmony_ci	return true;
15888c2ecf20Sopenharmony_ci}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_civoid mt7603_update_channel(struct mt76_dev *mdev)
15918c2ecf20Sopenharmony_ci{
15928c2ecf20Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
15938c2ecf20Sopenharmony_ci	struct mt76_channel_state *state;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	state = mdev->phy.chan_state;
15968c2ecf20Sopenharmony_ci	state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA);
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_civoid
16008c2ecf20Sopenharmony_cimt7603_edcca_set_strict(struct mt7603_dev *dev, bool val)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	u32 rxtd_6 = 0xd7c80000;
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	if (val == dev->ed_strict_mode)
16058c2ecf20Sopenharmony_ci		return;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	dev->ed_strict_mode = val;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	/* Ensure that ED/CCA does not trigger if disabled */
16108c2ecf20Sopenharmony_ci	if (!dev->ed_monitor)
16118c2ecf20Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x34);
16128c2ecf20Sopenharmony_ci	else
16138c2ecf20Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x7d);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	if (dev->ed_monitor && !dev->ed_strict_mode)
16168c2ecf20Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x0f);
16178c2ecf20Sopenharmony_ci	else
16188c2ecf20Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x10);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_RXTD(6), rxtd_6);
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_RXTD(13), MT_RXTD_13_ACI_TH_EN,
16238c2ecf20Sopenharmony_ci		       dev->ed_monitor && !dev->ed_strict_mode);
16248c2ecf20Sopenharmony_ci}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_cistatic void
16278c2ecf20Sopenharmony_cimt7603_edcca_check(struct mt7603_dev *dev)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	u32 val = mt76_rr(dev, MT_AGC(41));
16308c2ecf20Sopenharmony_ci	ktime_t cur_time;
16318c2ecf20Sopenharmony_ci	int rssi0, rssi1;
16328c2ecf20Sopenharmony_ci	u32 active;
16338c2ecf20Sopenharmony_ci	u32 ed_busy;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if (!dev->ed_monitor)
16368c2ecf20Sopenharmony_ci		return;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	rssi0 = FIELD_GET(MT_AGC_41_RSSI_0, val);
16398c2ecf20Sopenharmony_ci	if (rssi0 > 128)
16408c2ecf20Sopenharmony_ci		rssi0 -= 256;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val);
16438c2ecf20Sopenharmony_ci	if (rssi1 > 128)
16448c2ecf20Sopenharmony_ci		rssi1 -= 256;
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	if (max(rssi0, rssi1) >= -40 &&
16478c2ecf20Sopenharmony_ci	    dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH)
16488c2ecf20Sopenharmony_ci		dev->ed_strong_signal++;
16498c2ecf20Sopenharmony_ci	else if (dev->ed_strong_signal > 0)
16508c2ecf20Sopenharmony_ci		dev->ed_strong_signal--;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	cur_time = ktime_get_boottime();
16538c2ecf20Sopenharmony_ci	ed_busy = mt76_rr(dev, MT_MIB_STAT_ED) & MT_MIB_STAT_ED_MASK;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	active = ktime_to_us(ktime_sub(cur_time, dev->ed_time));
16568c2ecf20Sopenharmony_ci	dev->ed_time = cur_time;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	if (!active)
16598c2ecf20Sopenharmony_ci		return;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (100 * ed_busy / active > 90) {
16628c2ecf20Sopenharmony_ci		if (dev->ed_trigger < 0)
16638c2ecf20Sopenharmony_ci			dev->ed_trigger = 0;
16648c2ecf20Sopenharmony_ci		dev->ed_trigger++;
16658c2ecf20Sopenharmony_ci	} else {
16668c2ecf20Sopenharmony_ci		if (dev->ed_trigger > 0)
16678c2ecf20Sopenharmony_ci			dev->ed_trigger = 0;
16688c2ecf20Sopenharmony_ci		dev->ed_trigger--;
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH ||
16728c2ecf20Sopenharmony_ci	    dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH / 2) {
16738c2ecf20Sopenharmony_ci		mt7603_edcca_set_strict(dev, true);
16748c2ecf20Sopenharmony_ci	} else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) {
16758c2ecf20Sopenharmony_ci		mt7603_edcca_set_strict(dev, false);
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH)
16798c2ecf20Sopenharmony_ci		dev->ed_trigger = MT7603_EDCCA_BLOCK_TH;
16808c2ecf20Sopenharmony_ci	else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH)
16818c2ecf20Sopenharmony_ci		dev->ed_trigger = -MT7603_EDCCA_BLOCK_TH;
16828c2ecf20Sopenharmony_ci}
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_civoid mt7603_cca_stats_reset(struct mt7603_dev *dev)
16858c2ecf20Sopenharmony_ci{
16868c2ecf20Sopenharmony_ci	mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET);
16878c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET);
16888c2ecf20Sopenharmony_ci	mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_EN);
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_cistatic void
16928c2ecf20Sopenharmony_cimt7603_adjust_sensitivity(struct mt7603_dev *dev)
16938c2ecf20Sopenharmony_ci{
16948c2ecf20Sopenharmony_ci	u32 agc0 = dev->agc0, agc3 = dev->agc3;
16958c2ecf20Sopenharmony_ci	u32 adj;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	if (!dev->sensitivity || dev->sensitivity < -100) {
16988c2ecf20Sopenharmony_ci		dev->sensitivity = 0;
16998c2ecf20Sopenharmony_ci	} else if (dev->sensitivity <= -84) {
17008c2ecf20Sopenharmony_ci		adj = 7 + (dev->sensitivity + 92) / 2;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci		agc0 = 0x56f0076f;
17038c2ecf20Sopenharmony_ci		agc0 |= adj << 12;
17048c2ecf20Sopenharmony_ci		agc0 |= adj << 16;
17058c2ecf20Sopenharmony_ci		agc3 = 0x81d0d5e3;
17068c2ecf20Sopenharmony_ci	} else if (dev->sensitivity <= -72) {
17078c2ecf20Sopenharmony_ci		adj = 7 + (dev->sensitivity + 80) / 2;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci		agc0 = 0x6af0006f;
17108c2ecf20Sopenharmony_ci		agc0 |= adj << 8;
17118c2ecf20Sopenharmony_ci		agc0 |= adj << 12;
17128c2ecf20Sopenharmony_ci		agc0 |= adj << 16;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci		agc3 = 0x8181d5e3;
17158c2ecf20Sopenharmony_ci	} else {
17168c2ecf20Sopenharmony_ci		if (dev->sensitivity > -54)
17178c2ecf20Sopenharmony_ci			dev->sensitivity = -54;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci		adj = 7 + (dev->sensitivity + 80) / 2;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci		agc0 = 0x7ff0000f;
17228c2ecf20Sopenharmony_ci		agc0 |= adj << 4;
17238c2ecf20Sopenharmony_ci		agc0 |= adj << 8;
17248c2ecf20Sopenharmony_ci		agc0 |= adj << 12;
17258c2ecf20Sopenharmony_ci		agc0 |= adj << 16;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci		agc3 = 0x818181e3;
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_AGC(0), agc0);
17318c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_AGC1(0), agc0);
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_AGC(3), agc3);
17348c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_AGC1(3), agc3);
17358c2ecf20Sopenharmony_ci}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_cistatic void
17388c2ecf20Sopenharmony_cimt7603_false_cca_check(struct mt7603_dev *dev)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	int pd_cck, pd_ofdm, mdrdy_cck, mdrdy_ofdm;
17418c2ecf20Sopenharmony_ci	int false_cca;
17428c2ecf20Sopenharmony_ci	int min_signal;
17438c2ecf20Sopenharmony_ci	u32 val;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	if (!dev->dynamic_sensitivity)
17468c2ecf20Sopenharmony_ci		return;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_PHYCTRL_STAT_PD);
17498c2ecf20Sopenharmony_ci	pd_cck = FIELD_GET(MT_PHYCTRL_STAT_PD_CCK, val);
17508c2ecf20Sopenharmony_ci	pd_ofdm = FIELD_GET(MT_PHYCTRL_STAT_PD_OFDM, val);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_PHYCTRL_STAT_MDRDY);
17538c2ecf20Sopenharmony_ci	mdrdy_cck = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_CCK, val);
17548c2ecf20Sopenharmony_ci	mdrdy_ofdm = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_OFDM, val);
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm;
17578c2ecf20Sopenharmony_ci	dev->false_cca_cck = pd_cck - mdrdy_cck;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	mt7603_cca_stats_reset(dev);
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	min_signal = mt76_get_min_avg_rssi(&dev->mt76, false);
17628c2ecf20Sopenharmony_ci	if (!min_signal) {
17638c2ecf20Sopenharmony_ci		dev->sensitivity = 0;
17648c2ecf20Sopenharmony_ci		dev->last_cca_adj = jiffies;
17658c2ecf20Sopenharmony_ci		goto out;
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	min_signal -= 15;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	false_cca = dev->false_cca_ofdm + dev->false_cca_cck;
17718c2ecf20Sopenharmony_ci	if (false_cca > 600 &&
17728c2ecf20Sopenharmony_ci	    dev->sensitivity < -100 + dev->sensitivity_limit) {
17738c2ecf20Sopenharmony_ci		if (!dev->sensitivity)
17748c2ecf20Sopenharmony_ci			dev->sensitivity = -92;
17758c2ecf20Sopenharmony_ci		else
17768c2ecf20Sopenharmony_ci			dev->sensitivity += 2;
17778c2ecf20Sopenharmony_ci		dev->last_cca_adj = jiffies;
17788c2ecf20Sopenharmony_ci	} else if (false_cca < 100 ||
17798c2ecf20Sopenharmony_ci		   time_after(jiffies, dev->last_cca_adj + 10 * HZ)) {
17808c2ecf20Sopenharmony_ci		dev->last_cca_adj = jiffies;
17818c2ecf20Sopenharmony_ci		if (!dev->sensitivity)
17828c2ecf20Sopenharmony_ci			goto out;
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci		dev->sensitivity -= 2;
17858c2ecf20Sopenharmony_ci	}
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (dev->sensitivity && dev->sensitivity > min_signal) {
17888c2ecf20Sopenharmony_ci		dev->sensitivity = min_signal;
17898c2ecf20Sopenharmony_ci		dev->last_cca_adj = jiffies;
17908c2ecf20Sopenharmony_ci	}
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ciout:
17938c2ecf20Sopenharmony_ci	mt7603_adjust_sensitivity(dev);
17948c2ecf20Sopenharmony_ci}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_civoid mt7603_mac_work(struct work_struct *work)
17978c2ecf20Sopenharmony_ci{
17988c2ecf20Sopenharmony_ci	struct mt7603_dev *dev = container_of(work, struct mt7603_dev,
17998c2ecf20Sopenharmony_ci					      mt76.mac_work.work);
18008c2ecf20Sopenharmony_ci	bool reset = false;
18018c2ecf20Sopenharmony_ci	int i, idx;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	mt76_tx_status_check(&dev->mt76, NULL, false);
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	dev->mac_work_count++;
18088c2ecf20Sopenharmony_ci	mt76_update_survey(&dev->mt76);
18098c2ecf20Sopenharmony_ci	mt7603_edcca_check(dev);
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_ci	for (i = 0, idx = 0; i < 2; i++) {
18128c2ecf20Sopenharmony_ci		u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci		dev->mt76.aggr_stats[idx++] += val & 0xffff;
18158c2ecf20Sopenharmony_ci		dev->mt76.aggr_stats[idx++] += val >> 16;
18168c2ecf20Sopenharmony_ci	}
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_ci	if (dev->mac_work_count == 10)
18198c2ecf20Sopenharmony_ci		mt7603_false_cca_check(dev);
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	if (mt7603_watchdog_check(dev, &dev->rx_pse_check,
18228c2ecf20Sopenharmony_ci				  RESET_CAUSE_RX_PSE_BUSY,
18238c2ecf20Sopenharmony_ci				  mt7603_rx_pse_busy) ||
18248c2ecf20Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->beacon_check,
18258c2ecf20Sopenharmony_ci				  RESET_CAUSE_BEACON_STUCK,
18268c2ecf20Sopenharmony_ci				  NULL) ||
18278c2ecf20Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->tx_hang_check,
18288c2ecf20Sopenharmony_ci				  RESET_CAUSE_TX_HANG,
18298c2ecf20Sopenharmony_ci				  mt7603_tx_hang) ||
18308c2ecf20Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->tx_dma_check,
18318c2ecf20Sopenharmony_ci				  RESET_CAUSE_TX_BUSY,
18328c2ecf20Sopenharmony_ci				  mt7603_tx_dma_busy) ||
18338c2ecf20Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->rx_dma_check,
18348c2ecf20Sopenharmony_ci				  RESET_CAUSE_RX_BUSY,
18358c2ecf20Sopenharmony_ci				  mt7603_rx_dma_busy) ||
18368c2ecf20Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->mcu_hang,
18378c2ecf20Sopenharmony_ci				  RESET_CAUSE_MCU_HANG,
18388c2ecf20Sopenharmony_ci				  NULL) ||
18398c2ecf20Sopenharmony_ci	    dev->reset_cause[RESET_CAUSE_RESET_FAILED]) {
18408c2ecf20Sopenharmony_ci		dev->beacon_check = 0;
18418c2ecf20Sopenharmony_ci		dev->tx_dma_check = 0;
18428c2ecf20Sopenharmony_ci		dev->tx_hang_check = 0;
18438c2ecf20Sopenharmony_ci		dev->rx_dma_check = 0;
18448c2ecf20Sopenharmony_ci		dev->rx_pse_check = 0;
18458c2ecf20Sopenharmony_ci		dev->mcu_hang = 0;
18468c2ecf20Sopenharmony_ci		dev->rx_dma_idx = ~0;
18478c2ecf20Sopenharmony_ci		memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx));
18488c2ecf20Sopenharmony_ci		reset = true;
18498c2ecf20Sopenharmony_ci		dev->mac_work_count = 0;
18508c2ecf20Sopenharmony_ci	}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	if (dev->mac_work_count >= 10)
18538c2ecf20Sopenharmony_ci		dev->mac_work_count = 0;
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	if (reset)
18588c2ecf20Sopenharmony_ci		mt7603_mac_watchdog_reset(dev);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
18618c2ecf20Sopenharmony_ci				     msecs_to_jiffies(MT7603_WATCHDOG_TIME));
18628c2ecf20Sopenharmony_ci}
1863