162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/etherdevice.h>
462306a36Sopenharmony_ci#include <linux/timekeeping.h>
562306a36Sopenharmony_ci#include "mt7603.h"
662306a36Sopenharmony_ci#include "mac.h"
762306a36Sopenharmony_ci#include "../trace.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define MT_PSE_PAGE_SIZE	128
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic u32
1262306a36Sopenharmony_cimt7603_ac_queue_mask0(u32 mask)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	u32 ret = 0;
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci	ret |= GENMASK(3, 0) * !!(mask & BIT(0));
1762306a36Sopenharmony_ci	ret |= GENMASK(8, 5) * !!(mask & BIT(1));
1862306a36Sopenharmony_ci	ret |= GENMASK(13, 10) * !!(mask & BIT(2));
1962306a36Sopenharmony_ci	ret |= GENMASK(19, 16) * !!(mask & BIT(3));
2062306a36Sopenharmony_ci	return ret;
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic void
2462306a36Sopenharmony_cimt76_stop_tx_ac(struct mt7603_dev *dev, u32 mask)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	mt76_set(dev, MT_WF_ARB_TX_STOP_0, mt7603_ac_queue_mask0(mask));
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic void
3062306a36Sopenharmony_cimt76_start_tx_ac(struct mt7603_dev *dev, u32 mask)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask));
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_civoid mt7603_mac_reset_counters(struct mt7603_dev *dev)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	int i;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	for (i = 0; i < 2; i++)
4062306a36Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(i));
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	memset(dev->mphy.aggr_stats, 0, sizeof(dev->mphy.aggr_stats));
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid mt7603_mac_set_timing(struct mt7603_dev *dev)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
4862306a36Sopenharmony_ci		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
4962306a36Sopenharmony_ci	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
5062306a36Sopenharmony_ci		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 24);
5162306a36Sopenharmony_ci	int offset = 3 * dev->coverage_class;
5262306a36Sopenharmony_ci	u32 reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
5362306a36Sopenharmony_ci			 FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
5462306a36Sopenharmony_ci	bool is_5ghz = dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ;
5562306a36Sopenharmony_ci	int sifs;
5662306a36Sopenharmony_ci	u32 val;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (is_5ghz)
5962306a36Sopenharmony_ci		sifs = 16;
6062306a36Sopenharmony_ci	else
6162306a36Sopenharmony_ci		sifs = 10;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	mt76_set(dev, MT_ARB_SCR,
6462306a36Sopenharmony_ci		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
6562306a36Sopenharmony_ci	udelay(1);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	mt76_wr(dev, MT_TIMEOUT_CCK, cck + reg_offset);
6862306a36Sopenharmony_ci	mt76_wr(dev, MT_TIMEOUT_OFDM, ofdm + reg_offset);
6962306a36Sopenharmony_ci	mt76_wr(dev, MT_IFS,
7062306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_EIFS, 360) |
7162306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_RIFS, 2) |
7262306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_SIFS, sifs) |
7362306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_SLOT, dev->slottime));
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	if (dev->slottime < 20 || is_5ghz)
7662306a36Sopenharmony_ci		val = MT7603_CFEND_RATE_DEFAULT;
7762306a36Sopenharmony_ci	else
7862306a36Sopenharmony_ci		val = MT7603_CFEND_RATE_11B;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_AGG_CONTROL, MT_AGG_CONTROL_CFEND_RATE, val);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	mt76_clear(dev, MT_ARB_SCR,
8362306a36Sopenharmony_ci		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void
8762306a36Sopenharmony_cimt7603_wtbl_update(struct mt7603_dev *dev, int idx, u32 mask)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
9062306a36Sopenharmony_ci		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic u32
9662306a36Sopenharmony_cimt7603_wtbl1_addr(int idx)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	return MT_WTBL1_BASE + idx * MT_WTBL1_SIZE;
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic u32
10262306a36Sopenharmony_cimt7603_wtbl2_addr(int idx)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	/* Mapped to WTBL2 */
10562306a36Sopenharmony_ci	return MT_PCIE_REMAP_BASE_1 + idx * MT_WTBL2_SIZE;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic u32
10962306a36Sopenharmony_cimt7603_wtbl3_addr(int idx)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	u32 base = mt7603_wtbl2_addr(MT7603_WTBL_SIZE);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return base + idx * MT_WTBL3_SIZE;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic u32
11762306a36Sopenharmony_cimt7603_wtbl4_addr(int idx)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	u32 base = mt7603_wtbl3_addr(MT7603_WTBL_SIZE);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return base + idx * MT_WTBL4_SIZE;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_civoid mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif,
12562306a36Sopenharmony_ci		      const u8 *mac_addr)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	const void *_mac = mac_addr;
12862306a36Sopenharmony_ci	u32 addr = mt7603_wtbl1_addr(idx);
12962306a36Sopenharmony_ci	u32 w0 = 0, w1 = 0;
13062306a36Sopenharmony_ci	int i;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (_mac) {
13362306a36Sopenharmony_ci		w0 = FIELD_PREP(MT_WTBL1_W0_ADDR_HI,
13462306a36Sopenharmony_ci				get_unaligned_le16(_mac + 4));
13562306a36Sopenharmony_ci		w1 = FIELD_PREP(MT_WTBL1_W1_ADDR_LO,
13662306a36Sopenharmony_ci				get_unaligned_le32(_mac));
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (vif < 0)
14062306a36Sopenharmony_ci		vif = 0;
14162306a36Sopenharmony_ci	else
14262306a36Sopenharmony_ci		w0 |= MT_WTBL1_W0_RX_CHECK_A1;
14362306a36Sopenharmony_ci	w0 |= FIELD_PREP(MT_WTBL1_W0_MUAR_IDX, vif);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	mt76_set(dev, addr + 0 * 4, w0);
14862306a36Sopenharmony_ci	mt76_set(dev, addr + 1 * 4, w1);
14962306a36Sopenharmony_ci	mt76_set(dev, addr + 2 * 4, MT_WTBL1_W2_ADMISSION_CONTROL);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	mt76_stop_tx_ac(dev, GENMASK(3, 0));
15262306a36Sopenharmony_ci	addr = mt7603_wtbl2_addr(idx);
15362306a36Sopenharmony_ci	for (i = 0; i < MT_WTBL2_SIZE; i += 4)
15462306a36Sopenharmony_ci		mt76_wr(dev, addr + i, 0);
15562306a36Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2);
15662306a36Sopenharmony_ci	mt76_start_tx_ac(dev, GENMASK(3, 0));
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	addr = mt7603_wtbl3_addr(idx);
15962306a36Sopenharmony_ci	for (i = 0; i < MT_WTBL3_SIZE; i += 4)
16062306a36Sopenharmony_ci		mt76_wr(dev, addr + i, 0);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	addr = mt7603_wtbl4_addr(idx);
16362306a36Sopenharmony_ci	for (i = 0; i < MT_WTBL4_SIZE; i += 4)
16462306a36Sopenharmony_ci		mt76_wr(dev, addr + i, 0);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void
17062306a36Sopenharmony_cimt7603_wtbl_set_skip_tx(struct mt7603_dev *dev, int idx, bool enabled)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	u32 addr = mt7603_wtbl1_addr(idx);
17362306a36Sopenharmony_ci	u32 val = mt76_rr(dev, addr + 3 * 4);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	val &= ~MT_WTBL1_W3_SKIP_TX;
17662306a36Sopenharmony_ci	val |= enabled * MT_WTBL1_W3_SKIP_TX;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	mt76_wr(dev, addr + 3 * 4, val);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_civoid mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	u32 flush_mask;
18462306a36Sopenharmony_ci	int i, port, queue;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (abort) {
18762306a36Sopenharmony_ci		port = 3; /* PSE */
18862306a36Sopenharmony_ci		queue = 8; /* free queue */
18962306a36Sopenharmony_ci	} else {
19062306a36Sopenharmony_ci		port = 0; /* HIF */
19162306a36Sopenharmony_ci		queue = 1; /* MCU queue */
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	mt7603_wtbl_set_skip_tx(dev, idx, true);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	mt76_wr(dev, MT_TX_ABORT, MT_TX_ABORT_EN |
19762306a36Sopenharmony_ci			FIELD_PREP(MT_TX_ABORT_WCID, idx));
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	flush_mask = MT_WF_ARB_TX_FLUSH_AC0 |
20062306a36Sopenharmony_ci		     MT_WF_ARB_TX_FLUSH_AC1 |
20162306a36Sopenharmony_ci		     MT_WF_ARB_TX_FLUSH_AC2 |
20262306a36Sopenharmony_ci		     MT_WF_ARB_TX_FLUSH_AC3;
20362306a36Sopenharmony_ci	flush_mask <<= mac_idx;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	mt76_wr(dev, MT_WF_ARB_TX_FLUSH_0, flush_mask);
20662306a36Sopenharmony_ci	mt76_poll(dev, MT_WF_ARB_TX_FLUSH_0, flush_mask, 0, 20000);
20762306a36Sopenharmony_ci	mt76_wr(dev, MT_WF_ARB_TX_START_0, flush_mask);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	mt76_wr(dev, MT_TX_ABORT, 0);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
21262306a36Sopenharmony_ci		mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
21362306a36Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, idx) |
21462306a36Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, i) |
21562306a36Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, port) |
21662306a36Sopenharmony_ci			FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, queue));
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000);
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	WARN_ON_ONCE(mt76_rr(dev, MT_DMA_FQCR0) & MT_DMA_FQCR0_BUSY);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	mt7603_wtbl_set_skip_tx(dev, idx, false);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_civoid mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta,
22762306a36Sopenharmony_ci			  bool enabled)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	u32 addr = mt7603_wtbl1_addr(sta->wcid.idx);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (sta->smps == enabled)
23262306a36Sopenharmony_ci		return;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_SMPS, enabled);
23562306a36Sopenharmony_ci	sta->smps = enabled;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_civoid mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta,
23962306a36Sopenharmony_ci			bool enabled)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int idx = sta->wcid.idx;
24262306a36Sopenharmony_ci	u32 addr;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	spin_lock_bh(&dev->ps_lock);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (sta->ps == enabled)
24762306a36Sopenharmony_ci		goto out;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	mt76_wr(dev, MT_PSE_RTA,
25062306a36Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_TAG_ID, idx) |
25162306a36Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_PORT_ID, 0) |
25262306a36Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_QUEUE_ID, 1) |
25362306a36Sopenharmony_ci		FIELD_PREP(MT_PSE_RTA_REDIRECT_EN, enabled) |
25462306a36Sopenharmony_ci		MT_PSE_RTA_WRITE | MT_PSE_RTA_BUSY);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if (enabled)
25962306a36Sopenharmony_ci		mt7603_filter_tx(dev, sta->vif->idx, idx, false);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	addr = mt7603_wtbl1_addr(idx);
26262306a36Sopenharmony_ci	mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
26362306a36Sopenharmony_ci	mt76_rmw(dev, addr + 3 * 4, MT_WTBL1_W3_POWER_SAVE,
26462306a36Sopenharmony_ci		 enabled * MT_WTBL1_W3_POWER_SAVE);
26562306a36Sopenharmony_ci	mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
26662306a36Sopenharmony_ci	sta->ps = enabled;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ciout:
26962306a36Sopenharmony_ci	spin_unlock_bh(&dev->ps_lock);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_civoid mt7603_wtbl_clear(struct mt7603_dev *dev, int idx)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	int wtbl2_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL2_SIZE;
27562306a36Sopenharmony_ci	int wtbl2_frame = idx / wtbl2_frame_size;
27662306a36Sopenharmony_ci	int wtbl2_entry = idx % wtbl2_frame_size;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	int wtbl3_base_frame = MT_WTBL3_OFFSET / MT_PSE_PAGE_SIZE;
27962306a36Sopenharmony_ci	int wtbl3_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL3_SIZE;
28062306a36Sopenharmony_ci	int wtbl3_frame = wtbl3_base_frame + idx / wtbl3_frame_size;
28162306a36Sopenharmony_ci	int wtbl3_entry = (idx % wtbl3_frame_size) * 2;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	int wtbl4_base_frame = MT_WTBL4_OFFSET / MT_PSE_PAGE_SIZE;
28462306a36Sopenharmony_ci	int wtbl4_frame_size = MT_PSE_PAGE_SIZE / MT_WTBL4_SIZE;
28562306a36Sopenharmony_ci	int wtbl4_frame = wtbl4_base_frame + idx / wtbl4_frame_size;
28662306a36Sopenharmony_ci	int wtbl4_entry = idx % wtbl4_frame_size;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	u32 addr = MT_WTBL1_BASE + idx * MT_WTBL1_SIZE;
28962306a36Sopenharmony_ci	int i;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	mt76_wr(dev, addr + 0 * 4,
29462306a36Sopenharmony_ci		MT_WTBL1_W0_RX_CHECK_A1 |
29562306a36Sopenharmony_ci		MT_WTBL1_W0_RX_CHECK_A2 |
29662306a36Sopenharmony_ci		MT_WTBL1_W0_RX_VALID);
29762306a36Sopenharmony_ci	mt76_wr(dev, addr + 1 * 4, 0);
29862306a36Sopenharmony_ci	mt76_wr(dev, addr + 2 * 4, 0);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	mt76_set(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	mt76_wr(dev, addr + 3 * 4,
30362306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W3_WTBL2_FRAME_ID, wtbl2_frame) |
30462306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W3_WTBL2_ENTRY_ID, wtbl2_entry) |
30562306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W3_WTBL4_FRAME_ID, wtbl4_frame) |
30662306a36Sopenharmony_ci		MT_WTBL1_W3_I_PSM | MT_WTBL1_W3_KEEP_I_PSM);
30762306a36Sopenharmony_ci	mt76_wr(dev, addr + 4 * 4,
30862306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W4_WTBL3_FRAME_ID, wtbl3_frame) |
30962306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W4_WTBL3_ENTRY_ID, wtbl3_entry) |
31062306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL1_W4_WTBL4_ENTRY_ID, wtbl4_entry));
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	addr = mt7603_wtbl2_addr(idx);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* Clear BA information */
31762306a36Sopenharmony_ci	mt76_wr(dev, addr + (15 * 4), 0);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	mt76_stop_tx_ac(dev, GENMASK(3, 0));
32062306a36Sopenharmony_ci	for (i = 2; i <= 4; i++)
32162306a36Sopenharmony_ci		mt76_wr(dev, addr + (i * 4), 0);
32262306a36Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_WTBL2);
32362306a36Sopenharmony_ci	mt76_start_tx_ac(dev, GENMASK(3, 0));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_RX_COUNT_CLEAR);
32662306a36Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_TX_COUNT_CLEAR);
32762306a36Sopenharmony_ci	mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_civoid mt7603_wtbl_update_cap(struct mt7603_dev *dev, struct ieee80211_sta *sta)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
33362306a36Sopenharmony_ci	int idx = msta->wcid.idx;
33462306a36Sopenharmony_ci	u8 ampdu_density;
33562306a36Sopenharmony_ci	u32 addr;
33662306a36Sopenharmony_ci	u32 val;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	addr = mt7603_wtbl1_addr(idx);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	ampdu_density = sta->deflink.ht_cap.ampdu_density;
34162306a36Sopenharmony_ci	if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4)
34262306a36Sopenharmony_ci		ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	val = mt76_rr(dev, addr + 2 * 4);
34562306a36Sopenharmony_ci	val &= MT_WTBL1_W2_KEY_TYPE | MT_WTBL1_W2_ADMISSION_CONTROL;
34662306a36Sopenharmony_ci	val |= FIELD_PREP(MT_WTBL1_W2_AMPDU_FACTOR,
34762306a36Sopenharmony_ci			  sta->deflink.ht_cap.ampdu_factor) |
34862306a36Sopenharmony_ci	       FIELD_PREP(MT_WTBL1_W2_MPDU_DENSITY,
34962306a36Sopenharmony_ci			  sta->deflink.ht_cap.ampdu_density) |
35062306a36Sopenharmony_ci	       MT_WTBL1_W2_TXS_BAF_REPORT;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (sta->deflink.ht_cap.cap)
35362306a36Sopenharmony_ci		val |= MT_WTBL1_W2_HT;
35462306a36Sopenharmony_ci	if (sta->deflink.vht_cap.cap)
35562306a36Sopenharmony_ci		val |= MT_WTBL1_W2_VHT;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	mt76_wr(dev, addr + 2 * 4, val);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	addr = mt7603_wtbl2_addr(idx);
36062306a36Sopenharmony_ci	val = mt76_rr(dev, addr + 9 * 4);
36162306a36Sopenharmony_ci	val &= ~(MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 |
36262306a36Sopenharmony_ci		 MT_WTBL2_W9_SHORT_GI_80);
36362306a36Sopenharmony_ci	if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
36462306a36Sopenharmony_ci		val |= MT_WTBL2_W9_SHORT_GI_20;
36562306a36Sopenharmony_ci	if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
36662306a36Sopenharmony_ci		val |= MT_WTBL2_W9_SHORT_GI_40;
36762306a36Sopenharmony_ci	mt76_wr(dev, addr + 9 * 4, val);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	mt76_wr(dev, MT_BA_CONTROL_0, get_unaligned_le32(addr));
37362306a36Sopenharmony_ci	mt76_wr(dev, MT_BA_CONTROL_1,
37462306a36Sopenharmony_ci		(get_unaligned_le16(addr + 4) |
37562306a36Sopenharmony_ci		 FIELD_PREP(MT_BA_CONTROL_1_TID, tid) |
37662306a36Sopenharmony_ci		 MT_BA_CONTROL_1_RESET));
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_civoid mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
38062306a36Sopenharmony_ci			    int ba_size)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	u32 addr = mt7603_wtbl2_addr(wcid);
38362306a36Sopenharmony_ci	u32 tid_mask = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) |
38462306a36Sopenharmony_ci		       (MT_WTBL2_W15_BA_WIN_SIZE <<
38562306a36Sopenharmony_ci			(tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT));
38662306a36Sopenharmony_ci	u32 tid_val;
38762306a36Sopenharmony_ci	int i;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (ba_size < 0) {
39062306a36Sopenharmony_ci		/* disable */
39162306a36Sopenharmony_ci		mt76_clear(dev, addr + (15 * 4), tid_mask);
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	for (i = 7; i > 0; i--) {
39662306a36Sopenharmony_ci		if (ba_size >= MT_AGG_SIZE_LIMIT(i))
39762306a36Sopenharmony_ci			break;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	tid_val = FIELD_PREP(MT_WTBL2_W15_BA_EN_TIDS, BIT(tid)) |
40162306a36Sopenharmony_ci		  i << (tid * MT_WTBL2_W15_BA_WIN_SIZE_SHIFT);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val);
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_civoid mt7603_mac_sta_poll(struct mt7603_dev *dev)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	static const u8 ac_to_tid[4] = {
40962306a36Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
41062306a36Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
41162306a36Sopenharmony_ci		[IEEE80211_AC_VI] = 4,
41262306a36Sopenharmony_ci		[IEEE80211_AC_VO] = 6
41362306a36Sopenharmony_ci	};
41462306a36Sopenharmony_ci	struct ieee80211_sta *sta;
41562306a36Sopenharmony_ci	struct mt7603_sta *msta;
41662306a36Sopenharmony_ci	u32 total_airtime = 0;
41762306a36Sopenharmony_ci	u32 airtime[4];
41862306a36Sopenharmony_ci	u32 addr;
41962306a36Sopenharmony_ci	int i;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	rcu_read_lock();
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	while (1) {
42462306a36Sopenharmony_ci		bool clear = false;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
42762306a36Sopenharmony_ci		if (list_empty(&dev->mt76.sta_poll_list)) {
42862306a36Sopenharmony_ci			spin_unlock_bh(&dev->mt76.sta_poll_lock);
42962306a36Sopenharmony_ci			break;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		msta = list_first_entry(&dev->mt76.sta_poll_list,
43362306a36Sopenharmony_ci					struct mt7603_sta, wcid.poll_list);
43462306a36Sopenharmony_ci		list_del_init(&msta->wcid.poll_list);
43562306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		addr = mt7603_wtbl4_addr(msta->wcid.idx);
43862306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
43962306a36Sopenharmony_ci			u32 airtime_last = msta->tx_airtime_ac[i];
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci			msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8);
44262306a36Sopenharmony_ci			airtime[i] = msta->tx_airtime_ac[i] - airtime_last;
44362306a36Sopenharmony_ci			airtime[i] *= 32;
44462306a36Sopenharmony_ci			total_airtime += airtime[i];
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci			if (msta->tx_airtime_ac[i] & BIT(22))
44762306a36Sopenharmony_ci				clear = true;
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		if (clear) {
45162306a36Sopenharmony_ci			mt7603_wtbl_update(dev, msta->wcid.idx,
45262306a36Sopenharmony_ci					   MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
45362306a36Sopenharmony_ci			memset(msta->tx_airtime_ac, 0,
45462306a36Sopenharmony_ci			       sizeof(msta->tx_airtime_ac));
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		if (!msta->wcid.sta)
45862306a36Sopenharmony_ci			continue;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
46162306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
46262306a36Sopenharmony_ci			struct mt76_queue *q = dev->mphy.q_tx[i];
46362306a36Sopenharmony_ci			u8 qidx = q->hw_idx;
46462306a36Sopenharmony_ci			u8 tid = ac_to_tid[i];
46562306a36Sopenharmony_ci			u32 txtime = airtime[qidx];
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci			if (!txtime)
46862306a36Sopenharmony_ci				continue;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci			ieee80211_sta_register_airtime(sta, tid, txtime, 0);
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	rcu_read_unlock();
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	if (!total_airtime)
47762306a36Sopenharmony_ci		return;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.cc_lock);
48062306a36Sopenharmony_ci	dev->mphy.chan_state->cc_tx += total_airtime;
48162306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.cc_lock);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic struct mt76_wcid *
48562306a36Sopenharmony_cimt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct mt7603_sta *sta;
48862306a36Sopenharmony_ci	struct mt76_wcid *wcid;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (idx >= MT7603_WTBL_SIZE)
49162306a36Sopenharmony_ci		return NULL;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[idx]);
49462306a36Sopenharmony_ci	if (unicast || !wcid)
49562306a36Sopenharmony_ci		return wcid;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (!wcid->sta)
49862306a36Sopenharmony_ci		return NULL;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	sta = container_of(wcid, struct mt7603_sta, wcid);
50162306a36Sopenharmony_ci	if (!sta->vif)
50262306a36Sopenharmony_ci		return NULL;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return &sta->vif->sta.wcid;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ciint
50862306a36Sopenharmony_cimt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
51162306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
51262306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
51362306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
51462306a36Sopenharmony_ci	u32 rxd0 = le32_to_cpu(rxd[0]);
51562306a36Sopenharmony_ci	u32 rxd1 = le32_to_cpu(rxd[1]);
51662306a36Sopenharmony_ci	u32 rxd2 = le32_to_cpu(rxd[2]);
51762306a36Sopenharmony_ci	bool unicast = rxd1 & MT_RXD1_NORMAL_U2M;
51862306a36Sopenharmony_ci	bool insert_ccmp_hdr = false;
51962306a36Sopenharmony_ci	bool remove_pad;
52062306a36Sopenharmony_ci	int idx;
52162306a36Sopenharmony_ci	int i;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	memset(status, 0, sizeof(*status));
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	i = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1);
52662306a36Sopenharmony_ci	sband = (i & 1) ? &dev->mphy.sband_5g.sband : &dev->mphy.sband_2g.sband;
52762306a36Sopenharmony_ci	i >>= 1;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
53062306a36Sopenharmony_ci	status->wcid = mt7603_rx_get_wcid(dev, idx, unicast);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	status->band = sband->band;
53362306a36Sopenharmony_ci	if (i < sband->n_channels)
53462306a36Sopenharmony_ci		status->freq = sband->channels[i].center_freq;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_FCS_ERR)
53762306a36Sopenharmony_ci		status->flag |= RX_FLAG_FAILED_FCS_CRC;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR)
54062306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_ERROR;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* ICV error or CCMP/BIP/WPI MIC error */
54362306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_ICV_ERR)
54462306a36Sopenharmony_ci		status->flag |= RX_FLAG_ONLY_MONITOR;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
54762306a36Sopenharmony_ci	    !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) {
54862306a36Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
54962306a36Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
55062306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
55662306a36Sopenharmony_ci		return -EINVAL;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (!sband->channels)
55962306a36Sopenharmony_ci		return -EINVAL;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	rxd += 4;
56262306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
56362306a36Sopenharmony_ci		rxd += 4;
56462306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
56562306a36Sopenharmony_ci			return -EINVAL;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_1) {
56862306a36Sopenharmony_ci		u8 *data = (u8 *)rxd;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		if (status->flag & RX_FLAG_DECRYPTED) {
57162306a36Sopenharmony_ci			switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
57262306a36Sopenharmony_ci			case MT_CIPHER_AES_CCMP:
57362306a36Sopenharmony_ci			case MT_CIPHER_CCMP_CCX:
57462306a36Sopenharmony_ci			case MT_CIPHER_CCMP_256:
57562306a36Sopenharmony_ci				insert_ccmp_hdr =
57662306a36Sopenharmony_ci					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
57762306a36Sopenharmony_ci				fallthrough;
57862306a36Sopenharmony_ci			case MT_CIPHER_TKIP:
57962306a36Sopenharmony_ci			case MT_CIPHER_TKIP_NO_MIC:
58062306a36Sopenharmony_ci			case MT_CIPHER_GCMP:
58162306a36Sopenharmony_ci			case MT_CIPHER_GCMP_256:
58262306a36Sopenharmony_ci				status->iv[0] = data[5];
58362306a36Sopenharmony_ci				status->iv[1] = data[4];
58462306a36Sopenharmony_ci				status->iv[2] = data[3];
58562306a36Sopenharmony_ci				status->iv[3] = data[2];
58662306a36Sopenharmony_ci				status->iv[4] = data[1];
58762306a36Sopenharmony_ci				status->iv[5] = data[0];
58862306a36Sopenharmony_ci				break;
58962306a36Sopenharmony_ci			default:
59062306a36Sopenharmony_ci				break;
59162306a36Sopenharmony_ci			}
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		rxd += 4;
59562306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
59662306a36Sopenharmony_ci			return -EINVAL;
59762306a36Sopenharmony_ci	}
59862306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_2) {
59962306a36Sopenharmony_ci		status->timestamp = le32_to_cpu(rxd[0]);
60062306a36Sopenharmony_ci		status->flag |= RX_FLAG_MACTIME_START;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
60362306a36Sopenharmony_ci			      MT_RXD2_NORMAL_NON_AMPDU))) {
60462306a36Sopenharmony_ci			status->flag |= RX_FLAG_AMPDU_DETAILS;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci			/* all subframes of an A-MPDU have the same timestamp */
60762306a36Sopenharmony_ci			if (dev->rx_ampdu_ts != status->timestamp) {
60862306a36Sopenharmony_ci				if (!++dev->ampdu_ref)
60962306a36Sopenharmony_ci					dev->ampdu_ref++;
61062306a36Sopenharmony_ci			}
61162306a36Sopenharmony_ci			dev->rx_ampdu_ts = status->timestamp;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci			status->ampdu_ref = dev->ampdu_ref;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci		rxd += 2;
61762306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
61862306a36Sopenharmony_ci			return -EINVAL;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
62162306a36Sopenharmony_ci		u32 rxdg0 = le32_to_cpu(rxd[0]);
62262306a36Sopenharmony_ci		u32 rxdg3 = le32_to_cpu(rxd[3]);
62362306a36Sopenharmony_ci		bool cck = false;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0);
62662306a36Sopenharmony_ci		switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
62762306a36Sopenharmony_ci		case MT_PHY_TYPE_CCK:
62862306a36Sopenharmony_ci			cck = true;
62962306a36Sopenharmony_ci			fallthrough;
63062306a36Sopenharmony_ci		case MT_PHY_TYPE_OFDM:
63162306a36Sopenharmony_ci			i = mt76_get_rate(&dev->mt76, sband, i, cck);
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		case MT_PHY_TYPE_HT_GF:
63462306a36Sopenharmony_ci		case MT_PHY_TYPE_HT:
63562306a36Sopenharmony_ci			status->encoding = RX_ENC_HT;
63662306a36Sopenharmony_ci			if (i > 15)
63762306a36Sopenharmony_ci				return -EINVAL;
63862306a36Sopenharmony_ci			break;
63962306a36Sopenharmony_ci		default:
64062306a36Sopenharmony_ci			return -EINVAL;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_SHORT_GI)
64462306a36Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
64562306a36Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_AD_CODE)
64662306a36Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_LDPC;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_STBC_MASK *
64962306a36Sopenharmony_ci				    FIELD_GET(MT_RXV1_HT_STBC, rxdg0);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		status->rate_idx = i;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		status->chains = dev->mphy.antenna_mask;
65462306a36Sopenharmony_ci		status->chain_signal[0] = FIELD_GET(MT_RXV4_IB_RSSI0, rxdg3) +
65562306a36Sopenharmony_ci					  dev->rssi_offset[0];
65662306a36Sopenharmony_ci		status->chain_signal[1] = FIELD_GET(MT_RXV4_IB_RSSI1, rxdg3) +
65762306a36Sopenharmony_ci					  dev->rssi_offset[1];
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci		if (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0) == 1)
66062306a36Sopenharmony_ci			status->bw = RATE_INFO_BW_40;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		rxd += 6;
66362306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
66462306a36Sopenharmony_ci			return -EINVAL;
66562306a36Sopenharmony_ci	} else {
66662306a36Sopenharmony_ci		return -EINVAL;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (insert_ccmp_hdr) {
67262306a36Sopenharmony_ci		u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		mt76_insert_ccmp_hdr(skb, key_id);
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	hdr = (struct ieee80211_hdr *)skb->data;
67862306a36Sopenharmony_ci	if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
67962306a36Sopenharmony_ci		return 0;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	status->aggr = unicast &&
68262306a36Sopenharmony_ci		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
68362306a36Sopenharmony_ci	status->qos_ctl = *ieee80211_get_qos_ctl(hdr);
68462306a36Sopenharmony_ci	status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return 0;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic u16
69062306a36Sopenharmony_cimt7603_mac_tx_rate_val(struct mt7603_dev *dev,
69162306a36Sopenharmony_ci		       const struct ieee80211_tx_rate *rate, bool stbc, u8 *bw)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	u8 phy, nss, rate_idx;
69462306a36Sopenharmony_ci	u16 rateval;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	*bw = 0;
69762306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_MCS) {
69862306a36Sopenharmony_ci		rate_idx = rate->idx;
69962306a36Sopenharmony_ci		nss = 1 + (rate->idx >> 3);
70062306a36Sopenharmony_ci		phy = MT_PHY_TYPE_HT;
70162306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
70262306a36Sopenharmony_ci			phy = MT_PHY_TYPE_HT_GF;
70362306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
70462306a36Sopenharmony_ci			*bw = 1;
70562306a36Sopenharmony_ci	} else {
70662306a36Sopenharmony_ci		const struct ieee80211_rate *r;
70762306a36Sopenharmony_ci		int band = dev->mphy.chandef.chan->band;
70862306a36Sopenharmony_ci		u16 val;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		nss = 1;
71162306a36Sopenharmony_ci		r = &mt76_hw(dev)->wiphy->bands[band]->bitrates[rate->idx];
71262306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
71362306a36Sopenharmony_ci			val = r->hw_value_short;
71462306a36Sopenharmony_ci		else
71562306a36Sopenharmony_ci			val = r->hw_value;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		phy = val >> 8;
71862306a36Sopenharmony_ci		rate_idx = val & 0xff;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
72262306a36Sopenharmony_ci		   FIELD_PREP(MT_TX_RATE_MODE, phy));
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (stbc && nss == 1)
72562306a36Sopenharmony_ci		rateval |= MT_TX_RATE_STBC;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	return rateval;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_civoid mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta,
73162306a36Sopenharmony_ci			   struct ieee80211_tx_rate *probe_rate,
73262306a36Sopenharmony_ci			   struct ieee80211_tx_rate *rates)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct ieee80211_tx_rate *ref;
73562306a36Sopenharmony_ci	int wcid = sta->wcid.idx;
73662306a36Sopenharmony_ci	u32 addr = mt7603_wtbl2_addr(wcid);
73762306a36Sopenharmony_ci	bool stbc = false;
73862306a36Sopenharmony_ci	int n_rates = sta->n_rates;
73962306a36Sopenharmony_ci	u8 bw, bw_prev, bw_idx = 0;
74062306a36Sopenharmony_ci	u16 val[4];
74162306a36Sopenharmony_ci	u16 probe_val;
74262306a36Sopenharmony_ci	u32 w9 = mt76_rr(dev, addr + 9 * 4);
74362306a36Sopenharmony_ci	bool rateset;
74462306a36Sopenharmony_ci	int i, k;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
74762306a36Sopenharmony_ci		return;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	for (i = n_rates; i < 4; i++)
75062306a36Sopenharmony_ci		rates[i] = rates[n_rates - 1];
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	rateset = !(sta->rate_set_tsf & BIT(0));
75362306a36Sopenharmony_ci	memcpy(sta->rateset[rateset].rates, rates,
75462306a36Sopenharmony_ci	       sizeof(sta->rateset[rateset].rates));
75562306a36Sopenharmony_ci	if (probe_rate) {
75662306a36Sopenharmony_ci		sta->rateset[rateset].probe_rate = *probe_rate;
75762306a36Sopenharmony_ci		ref = &sta->rateset[rateset].probe_rate;
75862306a36Sopenharmony_ci	} else {
75962306a36Sopenharmony_ci		sta->rateset[rateset].probe_rate.idx = -1;
76062306a36Sopenharmony_ci		ref = &sta->rateset[rateset].rates[0];
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	rates = sta->rateset[rateset].rates;
76462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) {
76562306a36Sopenharmony_ci		/*
76662306a36Sopenharmony_ci		 * We don't support switching between short and long GI
76762306a36Sopenharmony_ci		 * within the rate set. For accurate tx status reporting, we
76862306a36Sopenharmony_ci		 * need to make sure that flags match.
76962306a36Sopenharmony_ci		 * For improved performance, avoid duplicate entries by
77062306a36Sopenharmony_ci		 * decrementing the MCS index if necessary
77162306a36Sopenharmony_ci		 */
77262306a36Sopenharmony_ci		if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI)
77362306a36Sopenharmony_ci			rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		for (k = 0; k < i; k++) {
77662306a36Sopenharmony_ci			if (rates[i].idx != rates[k].idx)
77762306a36Sopenharmony_ci				continue;
77862306a36Sopenharmony_ci			if ((rates[i].flags ^ rates[k].flags) &
77962306a36Sopenharmony_ci			    IEEE80211_TX_RC_40_MHZ_WIDTH)
78062306a36Sopenharmony_ci				continue;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci			if (!rates[i].idx)
78362306a36Sopenharmony_ci				continue;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci			rates[i].idx--;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 |
79062306a36Sopenharmony_ci	      MT_WTBL2_W9_SHORT_GI_80;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	val[0] = mt7603_mac_tx_rate_val(dev, &rates[0], stbc, &bw);
79362306a36Sopenharmony_ci	bw_prev = bw;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (probe_rate) {
79662306a36Sopenharmony_ci		probe_val = mt7603_mac_tx_rate_val(dev, probe_rate, stbc, &bw);
79762306a36Sopenharmony_ci		if (bw)
79862306a36Sopenharmony_ci			bw_idx = 1;
79962306a36Sopenharmony_ci		else
80062306a36Sopenharmony_ci			bw_prev = 0;
80162306a36Sopenharmony_ci	} else {
80262306a36Sopenharmony_ci		probe_val = val[0];
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	w9 |= FIELD_PREP(MT_WTBL2_W9_CC_BW_SEL, bw);
80662306a36Sopenharmony_ci	w9 |= FIELD_PREP(MT_WTBL2_W9_BW_CAP, bw);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	val[1] = mt7603_mac_tx_rate_val(dev, &rates[1], stbc, &bw);
80962306a36Sopenharmony_ci	if (bw_prev) {
81062306a36Sopenharmony_ci		bw_idx = 3;
81162306a36Sopenharmony_ci		bw_prev = bw;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	val[2] = mt7603_mac_tx_rate_val(dev, &rates[2], stbc, &bw);
81562306a36Sopenharmony_ci	if (bw_prev) {
81662306a36Sopenharmony_ci		bw_idx = 5;
81762306a36Sopenharmony_ci		bw_prev = bw;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	val[3] = mt7603_mac_tx_rate_val(dev, &rates[3], stbc, &bw);
82162306a36Sopenharmony_ci	if (bw_prev)
82262306a36Sopenharmony_ci		bw_idx = 7;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	w9 |= FIELD_PREP(MT_WTBL2_W9_CHANGE_BW_RATE,
82562306a36Sopenharmony_ci		       bw_idx ? bw_idx - 1 : 7);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR0, w9);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR1,
83062306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) |
83162306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) |
83262306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1]));
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR2,
83562306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) |
83662306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) |
83762306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) |
83862306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2]));
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR3,
84162306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) |
84262306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) |
84362306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3]));
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */
84662306a36Sopenharmony_ci	sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_UPDATE,
84962306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
85062306a36Sopenharmony_ci		MT_WTBL_UPDATE_RATE_UPDATE |
85162306a36Sopenharmony_ci		MT_WTBL_UPDATE_TX_COUNT_CLEAR);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
85462306a36Sopenharmony_ci		mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	sta->rate_count = 2 * MT7603_RATE_RETRY * n_rates;
85762306a36Sopenharmony_ci	sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_cistatic enum mt76_cipher_type
86162306a36Sopenharmony_cimt7603_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	memset(key_data, 0, 32);
86462306a36Sopenharmony_ci	if (!key)
86562306a36Sopenharmony_ci		return MT_CIPHER_NONE;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (key->keylen > 32)
86862306a36Sopenharmony_ci		return MT_CIPHER_NONE;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	memcpy(key_data, key->key, key->keylen);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	switch (key->cipher) {
87362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
87462306a36Sopenharmony_ci		return MT_CIPHER_WEP40;
87562306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
87662306a36Sopenharmony_ci		return MT_CIPHER_WEP104;
87762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
87862306a36Sopenharmony_ci		/* Rx/Tx MIC keys are swapped */
87962306a36Sopenharmony_ci		memcpy(key_data + 16, key->key + 24, 8);
88062306a36Sopenharmony_ci		memcpy(key_data + 24, key->key + 16, 8);
88162306a36Sopenharmony_ci		return MT_CIPHER_TKIP;
88262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
88362306a36Sopenharmony_ci		return MT_CIPHER_AES_CCMP;
88462306a36Sopenharmony_ci	default:
88562306a36Sopenharmony_ci		return MT_CIPHER_NONE;
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ciint mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid,
89062306a36Sopenharmony_ci			struct ieee80211_key_conf *key)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	enum mt76_cipher_type cipher;
89362306a36Sopenharmony_ci	u32 addr = mt7603_wtbl3_addr(wcid);
89462306a36Sopenharmony_ci	u8 key_data[32];
89562306a36Sopenharmony_ci	int key_len = sizeof(key_data);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	cipher = mt7603_mac_get_key_info(key, key_data);
89862306a36Sopenharmony_ci	if (cipher == MT_CIPHER_NONE && key)
89962306a36Sopenharmony_ci		return -EOPNOTSUPP;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (key && (cipher == MT_CIPHER_WEP40 || cipher == MT_CIPHER_WEP104)) {
90262306a36Sopenharmony_ci		addr += key->keyidx * 16;
90362306a36Sopenharmony_ci		key_len = 16;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	mt76_wr_copy(dev, addr, key_data, key_len);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	addr = mt7603_wtbl1_addr(wcid);
90962306a36Sopenharmony_ci	mt76_rmw_field(dev, addr + 2 * 4, MT_WTBL1_W2_KEY_TYPE, cipher);
91062306a36Sopenharmony_ci	if (key)
91162306a36Sopenharmony_ci		mt76_rmw_field(dev, addr, MT_WTBL1_W0_KEY_IDX, key->keyidx);
91262306a36Sopenharmony_ci	mt76_rmw_field(dev, addr, MT_WTBL1_W0_RX_KEY_VALID, !!key);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return 0;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistatic int
91862306a36Sopenharmony_cimt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
91962306a36Sopenharmony_ci		      struct sk_buff *skb, enum mt76_txq_id qid,
92062306a36Sopenharmony_ci		      struct mt76_wcid *wcid, struct ieee80211_sta *sta,
92162306a36Sopenharmony_ci		      int pid, struct ieee80211_key_conf *key)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
92462306a36Sopenharmony_ci	struct ieee80211_tx_rate *rate = &info->control.rates[0];
92562306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
92662306a36Sopenharmony_ci	struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
92762306a36Sopenharmony_ci	struct ieee80211_vif *vif = info->control.vif;
92862306a36Sopenharmony_ci	struct mt76_queue *q = dev->mphy.q_tx[qid];
92962306a36Sopenharmony_ci	struct mt7603_vif *mvif;
93062306a36Sopenharmony_ci	int wlan_idx;
93162306a36Sopenharmony_ci	int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
93262306a36Sopenharmony_ci	int tx_count = 8;
93362306a36Sopenharmony_ci	u8 frame_type, frame_subtype;
93462306a36Sopenharmony_ci	u16 fc = le16_to_cpu(hdr->frame_control);
93562306a36Sopenharmony_ci	u16 seqno = 0;
93662306a36Sopenharmony_ci	u8 vif_idx = 0;
93762306a36Sopenharmony_ci	u32 val;
93862306a36Sopenharmony_ci	u8 bw;
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	if (vif) {
94162306a36Sopenharmony_ci		mvif = (struct mt7603_vif *)vif->drv_priv;
94262306a36Sopenharmony_ci		vif_idx = mvif->idx;
94362306a36Sopenharmony_ci		if (vif_idx && qid >= MT_TXQ_BEACON)
94462306a36Sopenharmony_ci			vif_idx += 0x10;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	if (sta) {
94862306a36Sopenharmony_ci		struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		tx_count = msta->rate_count;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (wcid)
95462306a36Sopenharmony_ci		wlan_idx = wcid->idx;
95562306a36Sopenharmony_ci	else
95662306a36Sopenharmony_ci		wlan_idx = MT7603_WTBL_RESERVED;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	frame_type = (fc & IEEE80211_FCTL_FTYPE) >> 2;
95962306a36Sopenharmony_ci	frame_subtype = (fc & IEEE80211_FCTL_STYPE) >> 4;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
96262306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_Q_IDX, q->hw_idx);
96362306a36Sopenharmony_ci	txwi[0] = cpu_to_le32(val);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	val = MT_TXD1_LONG_FORMAT |
96662306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_OWN_MAC, vif_idx) |
96762306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_TID,
96862306a36Sopenharmony_ci			 skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
96962306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
97062306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_INFO, hdr_len / 2) |
97162306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_WLAN_IDX, wlan_idx) |
97262306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_PROTECTED, !!key);
97362306a36Sopenharmony_ci	txwi[1] = cpu_to_le32(val);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
97662306a36Sopenharmony_ci		txwi[1] |= cpu_to_le32(MT_TXD1_NO_ACK);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, frame_type) |
97962306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD2_SUB_TYPE, frame_subtype) |
98062306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD2_MULTICAST,
98162306a36Sopenharmony_ci			 is_multicast_ether_addr(hdr->addr1));
98262306a36Sopenharmony_ci	txwi[2] = cpu_to_le32(val);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
98562306a36Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	txwi[4] = 0;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	val = MT_TXD5_TX_STATUS_HOST | MT_TXD5_SW_POWER_MGMT |
99062306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD5_PID, pid);
99162306a36Sopenharmony_ci	txwi[5] = cpu_to_le32(val);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	txwi[6] = 0;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	if (rate->idx >= 0 && rate->count &&
99662306a36Sopenharmony_ci	    !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
99762306a36Sopenharmony_ci		bool stbc = info->flags & IEEE80211_TX_CTL_STBC;
99862306a36Sopenharmony_ci		u16 rateval = mt7603_mac_tx_rate_val(dev, rate, stbc, &bw);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci		val = MT_TXD6_FIXED_BW |
100362306a36Sopenharmony_ci		      FIELD_PREP(MT_TXD6_BW, bw) |
100462306a36Sopenharmony_ci		      FIELD_PREP(MT_TXD6_TX_RATE, rateval);
100562306a36Sopenharmony_ci		txwi[6] |= cpu_to_le32(val);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
100862306a36Sopenharmony_ci			txwi[6] |= cpu_to_le32(MT_TXD6_SGI);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci		if (!(rate->flags & IEEE80211_TX_RC_MCS))
101162306a36Sopenharmony_ci			txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		tx_count = rate->count;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	/* use maximum tx count for beacons and buffered multicast */
101762306a36Sopenharmony_ci	if (qid >= MT_TXQ_BEACON)
101862306a36Sopenharmony_ci		tx_count = 0x1f;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count) |
102162306a36Sopenharmony_ci		  MT_TXD3_SN_VALID;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (ieee80211_is_data_qos(hdr->frame_control))
102462306a36Sopenharmony_ci		seqno = le16_to_cpu(hdr->seq_ctrl);
102562306a36Sopenharmony_ci	else if (ieee80211_is_back_req(hdr->frame_control))
102662306a36Sopenharmony_ci		seqno = le16_to_cpu(bar->start_seq_num);
102762306a36Sopenharmony_ci	else
102862306a36Sopenharmony_ci		val &= ~MT_TXD3_SN_VALID;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	val |= FIELD_PREP(MT_TXD3_SEQ, seqno >> 4);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	txwi[3] = cpu_to_le32(val);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (key) {
103562306a36Sopenharmony_ci		u64 pn = atomic64_inc_return(&key->tx_pn);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci		txwi[3] |= cpu_to_le32(MT_TXD3_PN_VALID);
103862306a36Sopenharmony_ci		txwi[4] = cpu_to_le32(pn & GENMASK(31, 0));
103962306a36Sopenharmony_ci		txwi[5] |= cpu_to_le32(FIELD_PREP(MT_TXD5_PN_HIGH, pn >> 32));
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	txwi[7] = 0;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	return 0;
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ciint mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
104862306a36Sopenharmony_ci			  enum mt76_txq_id qid, struct mt76_wcid *wcid,
104962306a36Sopenharmony_ci			  struct ieee80211_sta *sta,
105062306a36Sopenharmony_ci			  struct mt76_tx_info *tx_info)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
105362306a36Sopenharmony_ci	struct mt7603_sta *msta = container_of(wcid, struct mt7603_sta, wcid);
105462306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
105562306a36Sopenharmony_ci	struct ieee80211_key_conf *key = info->control.hw_key;
105662306a36Sopenharmony_ci	int pid;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	if (!wcid)
105962306a36Sopenharmony_ci		wcid = &dev->global_sta.wcid;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	if (sta) {
106262306a36Sopenharmony_ci		msta = (struct mt7603_sta *)sta->drv_priv;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci		if ((info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
106562306a36Sopenharmony_ci				    IEEE80211_TX_CTL_CLEAR_PS_FILT)) ||
106662306a36Sopenharmony_ci		    (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
106762306a36Sopenharmony_ci			mt7603_wtbl_set_ps(dev, msta, false);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		mt76_tx_check_agg_ssn(sta, tx_info->skb);
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
107562306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
107662306a36Sopenharmony_ci		mt7603_wtbl_set_rates(dev, msta, &info->control.rates[0],
107762306a36Sopenharmony_ci				      msta->rates);
107862306a36Sopenharmony_ci		msta->rate_probe = true;
107962306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	mt7603_mac_write_txwi(dev, txwi_ptr, tx_info->skb, qid, wcid,
108362306a36Sopenharmony_ci			      sta, pid, key);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return 0;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic bool
108962306a36Sopenharmony_cimt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
109062306a36Sopenharmony_ci		struct ieee80211_tx_info *info, __le32 *txs_data)
109162306a36Sopenharmony_ci{
109262306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
109362306a36Sopenharmony_ci	struct mt7603_rate_set *rs;
109462306a36Sopenharmony_ci	int first_idx = 0, last_idx;
109562306a36Sopenharmony_ci	u32 rate_set_tsf;
109662306a36Sopenharmony_ci	u32 final_rate;
109762306a36Sopenharmony_ci	u32 final_rate_flags;
109862306a36Sopenharmony_ci	bool rs_idx;
109962306a36Sopenharmony_ci	bool ack_timeout;
110062306a36Sopenharmony_ci	bool fixed_rate;
110162306a36Sopenharmony_ci	bool probe;
110262306a36Sopenharmony_ci	bool ampdu;
110362306a36Sopenharmony_ci	bool cck = false;
110462306a36Sopenharmony_ci	int count;
110562306a36Sopenharmony_ci	u32 txs;
110662306a36Sopenharmony_ci	int idx;
110762306a36Sopenharmony_ci	int i;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	fixed_rate = info->status.rates[0].count;
111062306a36Sopenharmony_ci	probe = !!(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	txs = le32_to_cpu(txs_data[4]);
111362306a36Sopenharmony_ci	ampdu = !fixed_rate && (txs & MT_TXS4_AMPDU);
111462306a36Sopenharmony_ci	count = FIELD_GET(MT_TXS4_TX_COUNT, txs);
111562306a36Sopenharmony_ci	last_idx = FIELD_GET(MT_TXS4_LAST_TX_RATE, txs);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	txs = le32_to_cpu(txs_data[0]);
111862306a36Sopenharmony_ci	final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
111962306a36Sopenharmony_ci	ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT))
112262306a36Sopenharmony_ci		return false;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (txs & MT_TXS0_QUEUE_TIMEOUT)
112562306a36Sopenharmony_ci		return false;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	if (!ack_timeout)
112862306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	info->status.ampdu_len = 1;
113162306a36Sopenharmony_ci	info->status.ampdu_ack_len = !!(info->flags &
113262306a36Sopenharmony_ci					IEEE80211_TX_STAT_ACK);
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
113562306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	first_idx = max_t(int, 0, last_idx - (count - 1) / MT7603_RATE_RETRY);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	if (fixed_rate && !probe) {
114062306a36Sopenharmony_ci		info->status.rates[0].count = count;
114162306a36Sopenharmony_ci		i = 0;
114262306a36Sopenharmony_ci		goto out;
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	rate_set_tsf = READ_ONCE(sta->rate_set_tsf);
114662306a36Sopenharmony_ci	rs_idx = !((u32)(le32_get_bits(txs_data[1], MT_TXS1_F0_TIMESTAMP) -
114762306a36Sopenharmony_ci			 rate_set_tsf) < 1000000);
114862306a36Sopenharmony_ci	rs_idx ^= rate_set_tsf & BIT(0);
114962306a36Sopenharmony_ci	rs = &sta->rateset[rs_idx];
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	if (!first_idx && rs->probe_rate.idx >= 0) {
115262306a36Sopenharmony_ci		info->status.rates[0] = rs->probe_rate;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
115562306a36Sopenharmony_ci		if (sta->rate_probe) {
115662306a36Sopenharmony_ci			mt7603_wtbl_set_rates(dev, sta, NULL,
115762306a36Sopenharmony_ci					      sta->rates);
115862306a36Sopenharmony_ci			sta->rate_probe = false;
115962306a36Sopenharmony_ci		}
116062306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
116162306a36Sopenharmony_ci	} else {
116262306a36Sopenharmony_ci		info->status.rates[0] = rs->rates[first_idx / 2];
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci	info->status.rates[0].count = 0;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) {
116762306a36Sopenharmony_ci		struct ieee80211_tx_rate *cur_rate;
116862306a36Sopenharmony_ci		int cur_count;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		cur_rate = &rs->rates[idx / 2];
117162306a36Sopenharmony_ci		cur_count = min_t(int, MT7603_RATE_RETRY, count);
117262306a36Sopenharmony_ci		count -= cur_count;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci		if (idx && (cur_rate->idx != info->status.rates[i].idx ||
117562306a36Sopenharmony_ci			    cur_rate->flags != info->status.rates[i].flags)) {
117662306a36Sopenharmony_ci			i++;
117762306a36Sopenharmony_ci			if (i == ARRAY_SIZE(info->status.rates)) {
117862306a36Sopenharmony_ci				i--;
117962306a36Sopenharmony_ci				break;
118062306a36Sopenharmony_ci			}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci			info->status.rates[i] = *cur_rate;
118362306a36Sopenharmony_ci			info->status.rates[i].count = 0;
118462306a36Sopenharmony_ci		}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci		info->status.rates[i].count += cur_count;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ciout:
119062306a36Sopenharmony_ci	final_rate_flags = info->status.rates[i].flags;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
119362306a36Sopenharmony_ci	case MT_PHY_TYPE_CCK:
119462306a36Sopenharmony_ci		cck = true;
119562306a36Sopenharmony_ci		fallthrough;
119662306a36Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
119762306a36Sopenharmony_ci		if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ)
119862306a36Sopenharmony_ci			sband = &dev->mphy.sband_5g.sband;
119962306a36Sopenharmony_ci		else
120062306a36Sopenharmony_ci			sband = &dev->mphy.sband_2g.sband;
120162306a36Sopenharmony_ci		final_rate &= GENMASK(5, 0);
120262306a36Sopenharmony_ci		final_rate = mt76_get_rate(&dev->mt76, sband, final_rate,
120362306a36Sopenharmony_ci					   cck);
120462306a36Sopenharmony_ci		final_rate_flags = 0;
120562306a36Sopenharmony_ci		break;
120662306a36Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
120762306a36Sopenharmony_ci	case MT_PHY_TYPE_HT:
120862306a36Sopenharmony_ci		final_rate_flags |= IEEE80211_TX_RC_MCS;
120962306a36Sopenharmony_ci		final_rate &= GENMASK(5, 0);
121062306a36Sopenharmony_ci		if (final_rate > 15)
121162306a36Sopenharmony_ci			return false;
121262306a36Sopenharmony_ci		break;
121362306a36Sopenharmony_ci	default:
121462306a36Sopenharmony_ci		return false;
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	info->status.rates[i].idx = final_rate;
121862306a36Sopenharmony_ci	info->status.rates[i].flags = final_rate_flags;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	return true;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic bool
122462306a36Sopenharmony_cimt7603_mac_add_txs_skb(struct mt7603_dev *dev, struct mt7603_sta *sta, int pid,
122562306a36Sopenharmony_ci		       __le32 *txs_data)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
122862306a36Sopenharmony_ci	struct sk_buff_head list;
122962306a36Sopenharmony_ci	struct sk_buff *skb;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (pid < MT_PACKET_ID_FIRST)
123262306a36Sopenharmony_ci		return false;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	trace_mac_txdone(mdev, sta->wcid.idx, pid);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	mt76_tx_status_lock(mdev, &list);
123762306a36Sopenharmony_ci	skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list);
123862306a36Sopenharmony_ci	if (skb) {
123962306a36Sopenharmony_ci		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		if (!mt7603_fill_txs(dev, sta, info, txs_data)) {
124262306a36Sopenharmony_ci			info->status.rates[0].count = 0;
124362306a36Sopenharmony_ci			info->status.rates[0].idx = -1;
124462306a36Sopenharmony_ci		}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci		mt76_tx_status_skb_done(mdev, skb, &list);
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci	mt76_tx_status_unlock(mdev, &list);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	return !!skb;
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_civoid mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	struct ieee80211_tx_info info = {};
125662306a36Sopenharmony_ci	struct ieee80211_sta *sta = NULL;
125762306a36Sopenharmony_ci	struct mt7603_sta *msta = NULL;
125862306a36Sopenharmony_ci	struct mt76_wcid *wcid;
125962306a36Sopenharmony_ci	__le32 *txs_data = data;
126062306a36Sopenharmony_ci	u8 wcidx;
126162306a36Sopenharmony_ci	u8 pid;
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	pid = le32_get_bits(txs_data[4], MT_TXS4_PID);
126462306a36Sopenharmony_ci	wcidx = le32_get_bits(txs_data[3], MT_TXS3_WCID);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (pid == MT_PACKET_ID_NO_ACK)
126762306a36Sopenharmony_ci		return;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	if (wcidx >= MT7603_WTBL_SIZE)
127062306a36Sopenharmony_ci		return;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	rcu_read_lock();
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
127562306a36Sopenharmony_ci	if (!wcid)
127662306a36Sopenharmony_ci		goto out;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	msta = container_of(wcid, struct mt7603_sta, wcid);
127962306a36Sopenharmony_ci	sta = wcid_to_sta(wcid);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	if (list_empty(&msta->wcid.poll_list)) {
128262306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
128362306a36Sopenharmony_ci		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
128462306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
128862306a36Sopenharmony_ci		goto out;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	if (wcidx >= MT7603_WTBL_STA || !sta)
129162306a36Sopenharmony_ci		goto out;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (mt7603_fill_txs(dev, msta, &info, txs_data)) {
129462306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.rx_lock);
129562306a36Sopenharmony_ci		ieee80211_tx_status_noskb(mt76_hw(dev), sta, &info);
129662306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.rx_lock);
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ciout:
130062306a36Sopenharmony_ci	rcu_read_unlock();
130162306a36Sopenharmony_ci}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_civoid mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
130662306a36Sopenharmony_ci	struct sk_buff *skb = e->skb;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (!e->txwi) {
130962306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
131062306a36Sopenharmony_ci		return;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	dev->tx_hang_check = 0;
131462306a36Sopenharmony_ci	mt76_tx_complete_skb(mdev, e->wcid, skb);
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic bool
131862306a36Sopenharmony_ciwait_for_wpdma(struct mt7603_dev *dev)
131962306a36Sopenharmony_ci{
132062306a36Sopenharmony_ci	return mt76_poll(dev, MT_WPDMA_GLO_CFG,
132162306a36Sopenharmony_ci			 MT_WPDMA_GLO_CFG_TX_DMA_BUSY |
132262306a36Sopenharmony_ci			 MT_WPDMA_GLO_CFG_RX_DMA_BUSY,
132362306a36Sopenharmony_ci			 0, 1000);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic void mt7603_pse_reset(struct mt7603_dev *dev)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	/* Clear previous reset result */
132962306a36Sopenharmony_ci	if (!dev->reset_cause[RESET_CAUSE_RESET_FAILED])
133062306a36Sopenharmony_ci		mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE_S);
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	/* Reset PSE */
133362306a36Sopenharmony_ci	mt76_set(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (!mt76_poll_msec(dev, MT_MCU_DEBUG_RESET,
133662306a36Sopenharmony_ci			    MT_MCU_DEBUG_RESET_PSE_S,
133762306a36Sopenharmony_ci			    MT_MCU_DEBUG_RESET_PSE_S, 500)) {
133862306a36Sopenharmony_ci		dev->reset_cause[RESET_CAUSE_RESET_FAILED]++;
133962306a36Sopenharmony_ci		mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_PSE);
134062306a36Sopenharmony_ci	} else {
134162306a36Sopenharmony_ci		dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0;
134262306a36Sopenharmony_ci		mt76_clear(dev, MT_MCU_DEBUG_RESET, MT_MCU_DEBUG_RESET_QUEUES);
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] >= 3)
134662306a36Sopenharmony_ci		dev->reset_cause[RESET_CAUSE_RESET_FAILED] = 0;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_civoid mt7603_mac_dma_start(struct mt7603_dev *dev)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	mt7603_mac_start(dev);
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	wait_for_wpdma(dev);
135462306a36Sopenharmony_ci	usleep_range(50, 100);
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG,
135762306a36Sopenharmony_ci		 (MT_WPDMA_GLO_CFG_TX_DMA_EN |
135862306a36Sopenharmony_ci		  MT_WPDMA_GLO_CFG_RX_DMA_EN |
135962306a36Sopenharmony_ci		  FIELD_PREP(MT_WPDMA_GLO_CFG_DMA_BURST_SIZE, 3) |
136062306a36Sopenharmony_ci		  MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE));
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	mt7603_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL);
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_civoid mt7603_mac_start(struct mt7603_dev *dev)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	mt76_clear(dev, MT_ARB_SCR,
136862306a36Sopenharmony_ci		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
136962306a36Sopenharmony_ci	mt76_wr(dev, MT_WF_ARB_TX_START_0, ~0);
137062306a36Sopenharmony_ci	mt76_set(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START);
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_civoid mt7603_mac_stop(struct mt7603_dev *dev)
137462306a36Sopenharmony_ci{
137562306a36Sopenharmony_ci	mt76_set(dev, MT_ARB_SCR,
137662306a36Sopenharmony_ci		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
137762306a36Sopenharmony_ci	mt76_wr(dev, MT_WF_ARB_TX_START_0, 0);
137862306a36Sopenharmony_ci	mt76_clear(dev, MT_WF_ARB_RQCR, MT_WF_ARB_RQCR_RX_START);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_civoid mt7603_pse_client_reset(struct mt7603_dev *dev)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	u32 addr;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR +
138662306a36Sopenharmony_ci				   MT_CLIENT_RESET_TX);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	/* Clear previous reset state */
138962306a36Sopenharmony_ci	mt76_clear(dev, addr,
139062306a36Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_1 |
139162306a36Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_2 |
139262306a36Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_1_S |
139362306a36Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_2_S);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* Start PSE client TX abort */
139662306a36Sopenharmony_ci	mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_1);
139762306a36Sopenharmony_ci	mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_1_S,
139862306a36Sopenharmony_ci		       MT_CLIENT_RESET_TX_R_E_1_S, 500);
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	mt76_set(dev, addr, MT_CLIENT_RESET_TX_R_E_2);
140162306a36Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET);
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	/* Wait for PSE client to clear TX FIFO */
140462306a36Sopenharmony_ci	mt76_poll_msec(dev, addr, MT_CLIENT_RESET_TX_R_E_2_S,
140562306a36Sopenharmony_ci		       MT_CLIENT_RESET_TX_R_E_2_S, 500);
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	/* Clear PSE client TX abort state */
140862306a36Sopenharmony_ci	mt76_clear(dev, addr,
140962306a36Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_1 |
141062306a36Sopenharmony_ci		   MT_CLIENT_RESET_TX_R_E_2);
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic void mt7603_dma_sched_reset(struct mt7603_dev *dev)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	if (!is_mt7628(dev))
141662306a36Sopenharmony_ci		return;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	mt76_set(dev, MT_SCH_4, MT_SCH_4_RESET);
141962306a36Sopenharmony_ci	mt76_clear(dev, MT_SCH_4, MT_SCH_4_RESET);
142062306a36Sopenharmony_ci}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_cistatic void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
142362306a36Sopenharmony_ci{
142462306a36Sopenharmony_ci	int beacon_int = dev->mt76.beacon_int;
142562306a36Sopenharmony_ci	u32 mask = dev->mt76.mmio.irqmask;
142662306a36Sopenharmony_ci	int i;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	ieee80211_stop_queues(dev->mt76.hw);
142962306a36Sopenharmony_ci	set_bit(MT76_RESET, &dev->mphy.state);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	/* lock/unlock all queues to ensure that no tx is pending */
143262306a36Sopenharmony_ci	mt76_txq_schedule_all(&dev->mphy);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	mt76_worker_disable(&dev->mt76.tx_worker);
143562306a36Sopenharmony_ci	tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
143662306a36Sopenharmony_ci	napi_disable(&dev->mt76.napi[0]);
143762306a36Sopenharmony_ci	napi_disable(&dev->mt76.napi[1]);
143862306a36Sopenharmony_ci	napi_disable(&dev->mt76.tx_napi);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	mt7603_beacon_set_timer(dev, -1, 0);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	mt7603_mac_stop(dev);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	mt76_clear(dev, MT_WPDMA_GLO_CFG,
144762306a36Sopenharmony_ci		   MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN |
144862306a36Sopenharmony_ci		   MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
144962306a36Sopenharmony_ci	usleep_range(1000, 2000);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	mt7603_irq_disable(dev, mask);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	mt7603_pse_client_reset(dev);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
145662306a36Sopenharmony_ci	for (i = 0; i < __MT_TXQ_MAX; i++)
145762306a36Sopenharmony_ci		mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	mt7603_dma_sched_reset(dev);
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	mt76_tx_status_check(&dev->mt76, true);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	mt76_for_each_q_rx(&dev->mt76, i) {
146462306a36Sopenharmony_ci		mt76_queue_rx_reset(dev, i);
146562306a36Sopenharmony_ci	}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	if (dev->reset_cause[RESET_CAUSE_RESET_FAILED] ||
146862306a36Sopenharmony_ci	    dev->cur_reset_cause == RESET_CAUSE_RX_PSE_BUSY)
146962306a36Sopenharmony_ci		mt7603_pse_reset(dev);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	if (!dev->reset_cause[RESET_CAUSE_RESET_FAILED]) {
147262306a36Sopenharmony_ci		mt7603_mac_dma_start(dev);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		mt7603_irq_enable(dev, mask);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci		clear_bit(MT76_RESET, &dev->mphy.state);
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	mt76_worker_enable(&dev->mt76.tx_worker);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	tasklet_enable(&dev->mt76.pre_tbtt_tasklet);
148462306a36Sopenharmony_ci	mt7603_beacon_set_timer(dev, -1, beacon_int);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	local_bh_disable();
148762306a36Sopenharmony_ci	napi_enable(&dev->mt76.tx_napi);
148862306a36Sopenharmony_ci	napi_schedule(&dev->mt76.tx_napi);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	napi_enable(&dev->mt76.napi[0]);
149162306a36Sopenharmony_ci	napi_schedule(&dev->mt76.napi[0]);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	napi_enable(&dev->mt76.napi[1]);
149462306a36Sopenharmony_ci	napi_schedule(&dev->mt76.napi[1]);
149562306a36Sopenharmony_ci	local_bh_enable();
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	ieee80211_wake_queues(dev->mt76.hw);
149862306a36Sopenharmony_ci	mt76_txq_schedule_all(&dev->mphy);
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic u32 mt7603_dma_debug(struct mt7603_dev *dev, u8 index)
150262306a36Sopenharmony_ci{
150362306a36Sopenharmony_ci	u32 val;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	mt76_wr(dev, MT_WPDMA_DEBUG,
150662306a36Sopenharmony_ci		FIELD_PREP(MT_WPDMA_DEBUG_IDX, index) |
150762306a36Sopenharmony_ci		MT_WPDMA_DEBUG_SEL);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	val = mt76_rr(dev, MT_WPDMA_DEBUG);
151062306a36Sopenharmony_ci	return FIELD_GET(MT_WPDMA_DEBUG_VALUE, val);
151162306a36Sopenharmony_ci}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cistatic bool mt7603_rx_fifo_busy(struct mt7603_dev *dev)
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	if (is_mt7628(dev))
151662306a36Sopenharmony_ci		return mt7603_dma_debug(dev, 9) & BIT(9);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	return mt7603_dma_debug(dev, 2) & BIT(8);
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_cistatic bool mt7603_rx_dma_busy(struct mt7603_dev *dev)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_RX_DMA_BUSY))
152462306a36Sopenharmony_ci		return false;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	return mt7603_rx_fifo_busy(dev);
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic bool mt7603_tx_dma_busy(struct mt7603_dev *dev)
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	u32 val;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	if (!(mt76_rr(dev, MT_WPDMA_GLO_CFG) & MT_WPDMA_GLO_CFG_TX_DMA_BUSY))
153462306a36Sopenharmony_ci		return false;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	val = mt7603_dma_debug(dev, 9);
153762306a36Sopenharmony_ci	return (val & BIT(8)) && (val & 0xf) != 0xf;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_cistatic bool mt7603_tx_hang(struct mt7603_dev *dev)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	struct mt76_queue *q;
154362306a36Sopenharmony_ci	u32 dma_idx, prev_dma_idx;
154462306a36Sopenharmony_ci	int i;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
154762306a36Sopenharmony_ci		q = dev->mphy.q_tx[i];
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci		if (!q->queued)
155062306a36Sopenharmony_ci			continue;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci		prev_dma_idx = dev->tx_dma_idx[i];
155362306a36Sopenharmony_ci		dma_idx = readl(&q->regs->dma_idx);
155462306a36Sopenharmony_ci		dev->tx_dma_idx[i] = dma_idx;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci		if (dma_idx == prev_dma_idx &&
155762306a36Sopenharmony_ci		    dma_idx != readl(&q->regs->cpu_idx))
155862306a36Sopenharmony_ci			break;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	return i < 4;
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_cistatic bool mt7603_rx_pse_busy(struct mt7603_dev *dev)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	u32 addr, val;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (mt7603_rx_fifo_busy(dev))
156962306a36Sopenharmony_ci		goto out;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	addr = mt7603_reg_map(dev, MT_CLIENT_BASE_PHYS_ADDR + MT_CLIENT_STATUS);
157262306a36Sopenharmony_ci	mt76_wr(dev, addr, 3);
157362306a36Sopenharmony_ci	val = mt76_rr(dev, addr) >> 16;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (!(val & BIT(0)))
157662306a36Sopenharmony_ci		return false;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	if (is_mt7628(dev))
157962306a36Sopenharmony_ci		val &= 0xa000;
158062306a36Sopenharmony_ci	else
158162306a36Sopenharmony_ci		val &= 0x8000;
158262306a36Sopenharmony_ci	if (!val)
158362306a36Sopenharmony_ci		return false;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ciout:
158662306a36Sopenharmony_ci	if (mt76_rr(dev, MT_INT_SOURCE_CSR) &
158762306a36Sopenharmony_ci	    (MT_INT_RX_DONE(0) | MT_INT_RX_DONE(1)))
158862306a36Sopenharmony_ci		return false;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	return true;
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_cistatic bool
159462306a36Sopenharmony_cimt7603_watchdog_check(struct mt7603_dev *dev, u8 *counter,
159562306a36Sopenharmony_ci		      enum mt7603_reset_cause cause,
159662306a36Sopenharmony_ci		      bool (*check)(struct mt7603_dev *dev))
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci	if (dev->reset_test == cause + 1) {
159962306a36Sopenharmony_ci		dev->reset_test = 0;
160062306a36Sopenharmony_ci		goto trigger;
160162306a36Sopenharmony_ci	}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	if (check) {
160462306a36Sopenharmony_ci		if (!check(dev) && *counter < MT7603_WATCHDOG_TIMEOUT) {
160562306a36Sopenharmony_ci			*counter = 0;
160662306a36Sopenharmony_ci			return false;
160762306a36Sopenharmony_ci		}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci		(*counter)++;
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	if (*counter < MT7603_WATCHDOG_TIMEOUT)
161362306a36Sopenharmony_ci		return false;
161462306a36Sopenharmony_citrigger:
161562306a36Sopenharmony_ci	dev->cur_reset_cause = cause;
161662306a36Sopenharmony_ci	dev->reset_cause[cause]++;
161762306a36Sopenharmony_ci	return true;
161862306a36Sopenharmony_ci}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_civoid mt7603_update_channel(struct mt76_phy *mphy)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	struct mt7603_dev *dev = container_of(mphy->dev, struct mt7603_dev, mt76);
162362306a36Sopenharmony_ci	struct mt76_channel_state *state;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	state = mphy->chan_state;
162662306a36Sopenharmony_ci	state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA);
162762306a36Sopenharmony_ci}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_civoid
163062306a36Sopenharmony_cimt7603_edcca_set_strict(struct mt7603_dev *dev, bool val)
163162306a36Sopenharmony_ci{
163262306a36Sopenharmony_ci	u32 rxtd_6 = 0xd7c80000;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	if (val == dev->ed_strict_mode)
163562306a36Sopenharmony_ci		return;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	dev->ed_strict_mode = val;
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	/* Ensure that ED/CCA does not trigger if disabled */
164062306a36Sopenharmony_ci	if (!dev->ed_monitor)
164162306a36Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x34);
164262306a36Sopenharmony_ci	else
164362306a36Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_CCAED_TH, 0x7d);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	if (dev->ed_monitor && !dev->ed_strict_mode)
164662306a36Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x0f);
164762306a36Sopenharmony_ci	else
164862306a36Sopenharmony_ci		rxtd_6 |= FIELD_PREP(MT_RXTD_6_ACI_TH, 0x10);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	mt76_wr(dev, MT_RXTD(6), rxtd_6);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_RXTD(13), MT_RXTD_13_ACI_TH_EN,
165362306a36Sopenharmony_ci		       dev->ed_monitor && !dev->ed_strict_mode);
165462306a36Sopenharmony_ci}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_cistatic void
165762306a36Sopenharmony_cimt7603_edcca_check(struct mt7603_dev *dev)
165862306a36Sopenharmony_ci{
165962306a36Sopenharmony_ci	u32 val = mt76_rr(dev, MT_AGC(41));
166062306a36Sopenharmony_ci	ktime_t cur_time;
166162306a36Sopenharmony_ci	int rssi0, rssi1;
166262306a36Sopenharmony_ci	u32 active;
166362306a36Sopenharmony_ci	u32 ed_busy;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (!dev->ed_monitor)
166662306a36Sopenharmony_ci		return;
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci	rssi0 = FIELD_GET(MT_AGC_41_RSSI_0, val);
166962306a36Sopenharmony_ci	if (rssi0 > 128)
167062306a36Sopenharmony_ci		rssi0 -= 256;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	if (dev->mphy.antenna_mask & BIT(1)) {
167362306a36Sopenharmony_ci		rssi1 = FIELD_GET(MT_AGC_41_RSSI_1, val);
167462306a36Sopenharmony_ci		if (rssi1 > 128)
167562306a36Sopenharmony_ci			rssi1 -= 256;
167662306a36Sopenharmony_ci	} else {
167762306a36Sopenharmony_ci		rssi1 = rssi0;
167862306a36Sopenharmony_ci	}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (max(rssi0, rssi1) >= -40 &&
168162306a36Sopenharmony_ci	    dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH)
168262306a36Sopenharmony_ci		dev->ed_strong_signal++;
168362306a36Sopenharmony_ci	else if (dev->ed_strong_signal > 0)
168462306a36Sopenharmony_ci		dev->ed_strong_signal--;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	cur_time = ktime_get_boottime();
168762306a36Sopenharmony_ci	ed_busy = mt76_rr(dev, MT_MIB_STAT_ED) & MT_MIB_STAT_ED_MASK;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	active = ktime_to_us(ktime_sub(cur_time, dev->ed_time));
169062306a36Sopenharmony_ci	dev->ed_time = cur_time;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	if (!active)
169362306a36Sopenharmony_ci		return;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	if (100 * ed_busy / active > 90) {
169662306a36Sopenharmony_ci		if (dev->ed_trigger < 0)
169762306a36Sopenharmony_ci			dev->ed_trigger = 0;
169862306a36Sopenharmony_ci		dev->ed_trigger++;
169962306a36Sopenharmony_ci	} else {
170062306a36Sopenharmony_ci		if (dev->ed_trigger > 0)
170162306a36Sopenharmony_ci			dev->ed_trigger = 0;
170262306a36Sopenharmony_ci		dev->ed_trigger--;
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH ||
170662306a36Sopenharmony_ci	    dev->ed_strong_signal < MT7603_EDCCA_BLOCK_TH / 2) {
170762306a36Sopenharmony_ci		mt7603_edcca_set_strict(dev, true);
170862306a36Sopenharmony_ci	} else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH) {
170962306a36Sopenharmony_ci		mt7603_edcca_set_strict(dev, false);
171062306a36Sopenharmony_ci	}
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	if (dev->ed_trigger > MT7603_EDCCA_BLOCK_TH)
171362306a36Sopenharmony_ci		dev->ed_trigger = MT7603_EDCCA_BLOCK_TH;
171462306a36Sopenharmony_ci	else if (dev->ed_trigger < -MT7603_EDCCA_BLOCK_TH)
171562306a36Sopenharmony_ci		dev->ed_trigger = -MT7603_EDCCA_BLOCK_TH;
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_civoid mt7603_cca_stats_reset(struct mt7603_dev *dev)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET);
172162306a36Sopenharmony_ci	mt76_clear(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_RESET);
172262306a36Sopenharmony_ci	mt76_set(dev, MT_PHYCTRL(2), MT_PHYCTRL_2_STATUS_EN);
172362306a36Sopenharmony_ci}
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_cistatic void
172662306a36Sopenharmony_cimt7603_adjust_sensitivity(struct mt7603_dev *dev)
172762306a36Sopenharmony_ci{
172862306a36Sopenharmony_ci	u32 agc0 = dev->agc0, agc3 = dev->agc3;
172962306a36Sopenharmony_ci	u32 adj;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (!dev->sensitivity || dev->sensitivity < -100) {
173262306a36Sopenharmony_ci		dev->sensitivity = 0;
173362306a36Sopenharmony_ci	} else if (dev->sensitivity <= -84) {
173462306a36Sopenharmony_ci		adj = 7 + (dev->sensitivity + 92) / 2;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci		agc0 = 0x56f0076f;
173762306a36Sopenharmony_ci		agc0 |= adj << 12;
173862306a36Sopenharmony_ci		agc0 |= adj << 16;
173962306a36Sopenharmony_ci		agc3 = 0x81d0d5e3;
174062306a36Sopenharmony_ci	} else if (dev->sensitivity <= -72) {
174162306a36Sopenharmony_ci		adj = 7 + (dev->sensitivity + 80) / 2;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci		agc0 = 0x6af0006f;
174462306a36Sopenharmony_ci		agc0 |= adj << 8;
174562306a36Sopenharmony_ci		agc0 |= adj << 12;
174662306a36Sopenharmony_ci		agc0 |= adj << 16;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci		agc3 = 0x8181d5e3;
174962306a36Sopenharmony_ci	} else {
175062306a36Sopenharmony_ci		if (dev->sensitivity > -54)
175162306a36Sopenharmony_ci			dev->sensitivity = -54;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci		adj = 7 + (dev->sensitivity + 80) / 2;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		agc0 = 0x7ff0000f;
175662306a36Sopenharmony_ci		agc0 |= adj << 4;
175762306a36Sopenharmony_ci		agc0 |= adj << 8;
175862306a36Sopenharmony_ci		agc0 |= adj << 12;
175962306a36Sopenharmony_ci		agc0 |= adj << 16;
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci		agc3 = 0x818181e3;
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	mt76_wr(dev, MT_AGC(0), agc0);
176562306a36Sopenharmony_ci	mt76_wr(dev, MT_AGC1(0), agc0);
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	mt76_wr(dev, MT_AGC(3), agc3);
176862306a36Sopenharmony_ci	mt76_wr(dev, MT_AGC1(3), agc3);
176962306a36Sopenharmony_ci}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_cistatic void
177262306a36Sopenharmony_cimt7603_false_cca_check(struct mt7603_dev *dev)
177362306a36Sopenharmony_ci{
177462306a36Sopenharmony_ci	int pd_cck, pd_ofdm, mdrdy_cck, mdrdy_ofdm;
177562306a36Sopenharmony_ci	int false_cca;
177662306a36Sopenharmony_ci	int min_signal;
177762306a36Sopenharmony_ci	u32 val;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	if (!dev->dynamic_sensitivity)
178062306a36Sopenharmony_ci		return;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	val = mt76_rr(dev, MT_PHYCTRL_STAT_PD);
178362306a36Sopenharmony_ci	pd_cck = FIELD_GET(MT_PHYCTRL_STAT_PD_CCK, val);
178462306a36Sopenharmony_ci	pd_ofdm = FIELD_GET(MT_PHYCTRL_STAT_PD_OFDM, val);
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	val = mt76_rr(dev, MT_PHYCTRL_STAT_MDRDY);
178762306a36Sopenharmony_ci	mdrdy_cck = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_CCK, val);
178862306a36Sopenharmony_ci	mdrdy_ofdm = FIELD_GET(MT_PHYCTRL_STAT_MDRDY_OFDM, val);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm;
179162306a36Sopenharmony_ci	dev->false_cca_cck = pd_cck - mdrdy_cck;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	mt7603_cca_stats_reset(dev);
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	min_signal = mt76_get_min_avg_rssi(&dev->mt76, false);
179662306a36Sopenharmony_ci	if (!min_signal) {
179762306a36Sopenharmony_ci		dev->sensitivity = 0;
179862306a36Sopenharmony_ci		dev->last_cca_adj = jiffies;
179962306a36Sopenharmony_ci		goto out;
180062306a36Sopenharmony_ci	}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	min_signal -= 15;
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	false_cca = dev->false_cca_ofdm + dev->false_cca_cck;
180562306a36Sopenharmony_ci	if (false_cca > 600 &&
180662306a36Sopenharmony_ci	    dev->sensitivity < -100 + dev->sensitivity_limit) {
180762306a36Sopenharmony_ci		if (!dev->sensitivity)
180862306a36Sopenharmony_ci			dev->sensitivity = -92;
180962306a36Sopenharmony_ci		else
181062306a36Sopenharmony_ci			dev->sensitivity += 2;
181162306a36Sopenharmony_ci		dev->last_cca_adj = jiffies;
181262306a36Sopenharmony_ci	} else if (false_cca < 100 ||
181362306a36Sopenharmony_ci		   time_after(jiffies, dev->last_cca_adj + 10 * HZ)) {
181462306a36Sopenharmony_ci		dev->last_cca_adj = jiffies;
181562306a36Sopenharmony_ci		if (!dev->sensitivity)
181662306a36Sopenharmony_ci			goto out;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		dev->sensitivity -= 2;
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	if (dev->sensitivity && dev->sensitivity > min_signal) {
182262306a36Sopenharmony_ci		dev->sensitivity = min_signal;
182362306a36Sopenharmony_ci		dev->last_cca_adj = jiffies;
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ciout:
182762306a36Sopenharmony_ci	mt7603_adjust_sensitivity(dev);
182862306a36Sopenharmony_ci}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_civoid mt7603_mac_work(struct work_struct *work)
183162306a36Sopenharmony_ci{
183262306a36Sopenharmony_ci	struct mt7603_dev *dev = container_of(work, struct mt7603_dev,
183362306a36Sopenharmony_ci					      mphy.mac_work.work);
183462306a36Sopenharmony_ci	bool reset = false;
183562306a36Sopenharmony_ci	int i, idx;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	mt76_tx_status_check(&dev->mt76, false);
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	dev->mphy.mac_work_count++;
184262306a36Sopenharmony_ci	mt76_update_survey(&dev->mphy);
184362306a36Sopenharmony_ci	mt7603_edcca_check(dev);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	for (i = 0, idx = 0; i < 2; i++) {
184662306a36Sopenharmony_ci		u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci		dev->mphy.aggr_stats[idx++] += val & 0xffff;
184962306a36Sopenharmony_ci		dev->mphy.aggr_stats[idx++] += val >> 16;
185062306a36Sopenharmony_ci	}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	if (dev->mphy.mac_work_count == 10)
185362306a36Sopenharmony_ci		mt7603_false_cca_check(dev);
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if (mt7603_watchdog_check(dev, &dev->rx_pse_check,
185662306a36Sopenharmony_ci				  RESET_CAUSE_RX_PSE_BUSY,
185762306a36Sopenharmony_ci				  mt7603_rx_pse_busy) ||
185862306a36Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->beacon_check,
185962306a36Sopenharmony_ci				  RESET_CAUSE_BEACON_STUCK,
186062306a36Sopenharmony_ci				  NULL) ||
186162306a36Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->tx_hang_check,
186262306a36Sopenharmony_ci				  RESET_CAUSE_TX_HANG,
186362306a36Sopenharmony_ci				  mt7603_tx_hang) ||
186462306a36Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->tx_dma_check,
186562306a36Sopenharmony_ci				  RESET_CAUSE_TX_BUSY,
186662306a36Sopenharmony_ci				  mt7603_tx_dma_busy) ||
186762306a36Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->rx_dma_check,
186862306a36Sopenharmony_ci				  RESET_CAUSE_RX_BUSY,
186962306a36Sopenharmony_ci				  mt7603_rx_dma_busy) ||
187062306a36Sopenharmony_ci	    mt7603_watchdog_check(dev, &dev->mcu_hang,
187162306a36Sopenharmony_ci				  RESET_CAUSE_MCU_HANG,
187262306a36Sopenharmony_ci				  NULL) ||
187362306a36Sopenharmony_ci	    dev->reset_cause[RESET_CAUSE_RESET_FAILED]) {
187462306a36Sopenharmony_ci		dev->beacon_check = 0;
187562306a36Sopenharmony_ci		dev->tx_dma_check = 0;
187662306a36Sopenharmony_ci		dev->tx_hang_check = 0;
187762306a36Sopenharmony_ci		dev->rx_dma_check = 0;
187862306a36Sopenharmony_ci		dev->rx_pse_check = 0;
187962306a36Sopenharmony_ci		dev->mcu_hang = 0;
188062306a36Sopenharmony_ci		dev->rx_dma_idx = ~0;
188162306a36Sopenharmony_ci		memset(dev->tx_dma_idx, 0xff, sizeof(dev->tx_dma_idx));
188262306a36Sopenharmony_ci		reset = true;
188362306a36Sopenharmony_ci		dev->mphy.mac_work_count = 0;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	if (dev->mphy.mac_work_count >= 10)
188762306a36Sopenharmony_ci		dev->mphy.mac_work_count = 0;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	if (reset)
189262306a36Sopenharmony_ci		mt7603_mac_watchdog_reset(dev);
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
189562306a36Sopenharmony_ci				     msecs_to_jiffies(MT7603_WATCHDOG_TIME));
189662306a36Sopenharmony_ci}
1897