18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/* Copyright (C) 2019 MediaTek Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Author: Ryder Lee <ryder.lee@mediatek.com>
58c2ecf20Sopenharmony_ci *         Roy Luo <royluo@google.com>
68c2ecf20Sopenharmony_ci *         Felix Fietkau <nbd@nbd.name>
78c2ecf20Sopenharmony_ci *         Lorenzo Bianconi <lorenzo@kernel.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
118c2ecf20Sopenharmony_ci#include <linux/timekeeping.h>
128c2ecf20Sopenharmony_ci#include "mt7615.h"
138c2ecf20Sopenharmony_ci#include "../trace.h"
148c2ecf20Sopenharmony_ci#include "../dma.h"
158c2ecf20Sopenharmony_ci#include "mt7615_trace.h"
168c2ecf20Sopenharmony_ci#include "mac.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define to_rssi(field, rxv)		((FIELD_GET(field, rxv) - 220) / 2)
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic const struct mt7615_dfs_radar_spec etsi_radar_specs = {
218c2ecf20Sopenharmony_ci	.pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 },
228c2ecf20Sopenharmony_ci	.radar_pattern = {
238c2ecf20Sopenharmony_ci		[5] =  { 1, 0,  6, 32, 28, 0, 17,  990, 5010, 1, 1 },
248c2ecf20Sopenharmony_ci		[6] =  { 1, 0,  9, 32, 28, 0, 27,  615, 5010, 1, 1 },
258c2ecf20Sopenharmony_ci		[7] =  { 1, 0, 15, 32, 28, 0, 27,  240,  445, 1, 1 },
268c2ecf20Sopenharmony_ci		[8] =  { 1, 0, 12, 32, 28, 0, 42,  240,  510, 1, 1 },
278c2ecf20Sopenharmony_ci		[9] =  { 1, 1,  0,  0,  0, 0, 14, 2490, 3343, 0, 0, 12, 32, 28 },
288c2ecf20Sopenharmony_ci		[10] = { 1, 1,  0,  0,  0, 0, 14, 2490, 3343, 0, 0, 15, 32, 24 },
298c2ecf20Sopenharmony_ci		[11] = { 1, 1,  0,  0,  0, 0, 14,  823, 2510, 0, 0, 18, 32, 28 },
308c2ecf20Sopenharmony_ci		[12] = { 1, 1,  0,  0,  0, 0, 14,  823, 2510, 0, 0, 27, 32, 24 },
318c2ecf20Sopenharmony_ci	},
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic const struct mt7615_dfs_radar_spec fcc_radar_specs = {
358c2ecf20Sopenharmony_ci	.pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 },
368c2ecf20Sopenharmony_ci	.radar_pattern = {
378c2ecf20Sopenharmony_ci		[0] = { 1, 0,  9,  32, 28, 0, 13, 508, 3076, 1,  1 },
388c2ecf20Sopenharmony_ci		[1] = { 1, 0, 12,  32, 28, 0, 17, 140,  240, 1,  1 },
398c2ecf20Sopenharmony_ci		[2] = { 1, 0,  8,  32, 28, 0, 22, 190,  510, 1,  1 },
408c2ecf20Sopenharmony_ci		[3] = { 1, 0,  6,  32, 28, 0, 32, 190,  510, 1,  1 },
418c2ecf20Sopenharmony_ci		[4] = { 1, 0,  9, 255, 28, 0, 13, 323,  343, 1, 32 },
428c2ecf20Sopenharmony_ci	},
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const struct mt7615_dfs_radar_spec jp_radar_specs = {
468c2ecf20Sopenharmony_ci	.pulse_th = { 40, -10, -80, 800, 3360, 128, 5200 },
478c2ecf20Sopenharmony_ci	.radar_pattern = {
488c2ecf20Sopenharmony_ci		[0] =  { 1, 0,  8, 32, 28, 0, 13,  508, 3076, 1,  1 },
498c2ecf20Sopenharmony_ci		[1] =  { 1, 0, 12, 32, 28, 0, 17,  140,  240, 1,  1 },
508c2ecf20Sopenharmony_ci		[2] =  { 1, 0,  8, 32, 28, 0, 22,  190,  510, 1,  1 },
518c2ecf20Sopenharmony_ci		[3] =  { 1, 0,  6, 32, 28, 0, 32,  190,  510, 1,  1 },
528c2ecf20Sopenharmony_ci		[4] =  { 1, 0,  9, 32, 28, 0, 13,  323,  343, 1, 32 },
538c2ecf20Sopenharmony_ci		[13] = { 1, 0, 8,  32, 28, 0, 14, 3836, 3856, 1,  1 },
548c2ecf20Sopenharmony_ci		[14] = { 1, 0, 8,  32, 28, 0, 14, 3990, 4010, 1,  1 },
558c2ecf20Sopenharmony_ci	},
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
598c2ecf20Sopenharmony_ci					    u8 idx, bool unicast)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct mt7615_sta *sta;
628c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (idx >= MT7615_WTBL_SIZE)
658c2ecf20Sopenharmony_ci		return NULL;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[idx]);
688c2ecf20Sopenharmony_ci	if (unicast || !wcid)
698c2ecf20Sopenharmony_ci		return wcid;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (!wcid->sta)
728c2ecf20Sopenharmony_ci		return NULL;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	sta = container_of(wcid, struct mt7615_sta, wcid);
758c2ecf20Sopenharmony_ci	if (!sta->vif)
768c2ecf20Sopenharmony_ci		return NULL;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return &sta->vif->sta.wcid;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_civoid mt7615_mac_reset_counters(struct mt7615_dev *dev)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	int i;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
868c2ecf20Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(0, i));
878c2ecf20Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(1, i));
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
918c2ecf20Sopenharmony_ci	dev->mt76.phy.survey_time = ktime_get_boottime();
928c2ecf20Sopenharmony_ci	if (dev->mt76.phy2)
938c2ecf20Sopenharmony_ci		dev->mt76.phy2->survey_time = ktime_get_boottime();
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* reset airtime counters */
968c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR9(0));
978c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR9(1));
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR36(0));
1008c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR36(1));
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR37(0));
1038c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR37(1));
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
1068c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_civoid mt7615_mac_set_timing(struct mt7615_phy *phy)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	s16 coverage_class = phy->coverage_class;
1128c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
1138c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
1148c2ecf20Sopenharmony_ci	u32 val, reg_offset;
1158c2ecf20Sopenharmony_ci	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
1168c2ecf20Sopenharmony_ci		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
1178c2ecf20Sopenharmony_ci	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
1188c2ecf20Sopenharmony_ci		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
1198c2ecf20Sopenharmony_ci	int sifs, offset;
1208c2ecf20Sopenharmony_ci	bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
1238c2ecf20Sopenharmony_ci		return;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (is_5ghz)
1268c2ecf20Sopenharmony_ci		sifs = 16;
1278c2ecf20Sopenharmony_ci	else
1288c2ecf20Sopenharmony_ci		sifs = 10;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (ext_phy) {
1318c2ecf20Sopenharmony_ci		coverage_class = max_t(s16, dev->phy.coverage_class,
1328c2ecf20Sopenharmony_ci				       coverage_class);
1338c2ecf20Sopenharmony_ci		mt76_set(dev, MT_ARB_SCR,
1348c2ecf20Sopenharmony_ci			 MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE);
1358c2ecf20Sopenharmony_ci	} else {
1368c2ecf20Sopenharmony_ci		struct mt7615_phy *phy_ext = mt7615_ext_phy(dev);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci		if (phy_ext)
1398c2ecf20Sopenharmony_ci			coverage_class = max_t(s16, phy_ext->coverage_class,
1408c2ecf20Sopenharmony_ci					       coverage_class);
1418c2ecf20Sopenharmony_ci		mt76_set(dev, MT_ARB_SCR,
1428c2ecf20Sopenharmony_ci			 MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE);
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	udelay(1);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	offset = 3 * coverage_class;
1478c2ecf20Sopenharmony_ci	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
1488c2ecf20Sopenharmony_ci		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
1498c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TMAC_CDTR, cck + reg_offset);
1508c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TMAC_ODTR, ofdm + reg_offset);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_TMAC_ICR(ext_phy),
1538c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_EIFS, 360) |
1548c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_RIFS, 2) |
1558c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_SIFS, sifs) |
1568c2ecf20Sopenharmony_ci		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (phy->slottime < 20 || is_5ghz)
1598c2ecf20Sopenharmony_ci		val = MT7615_CFEND_RATE_DEFAULT;
1608c2ecf20Sopenharmony_ci	else
1618c2ecf20Sopenharmony_ci		val = MT7615_CFEND_RATE_11B;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_AGG_ACR(ext_phy), MT_AGG_ACR_CFEND_RATE, val);
1648c2ecf20Sopenharmony_ci	if (ext_phy)
1658c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_ARB_SCR,
1668c2ecf20Sopenharmony_ci			   MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE);
1678c2ecf20Sopenharmony_ci	else
1688c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_ARB_SCR,
1698c2ecf20Sopenharmony_ci			   MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic void
1748c2ecf20Sopenharmony_cimt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy,
1758c2ecf20Sopenharmony_ci			    struct mt76_rx_status *status, u8 chfreq)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
1788c2ecf20Sopenharmony_ci	    !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) &&
1798c2ecf20Sopenharmony_ci	    !test_bit(MT76_STATE_ROC, &mphy->state)) {
1808c2ecf20Sopenharmony_ci		status->freq = mphy->chandef.chan->center_freq;
1818c2ecf20Sopenharmony_ci		status->band = mphy->chandef.chan->band;
1828c2ecf20Sopenharmony_ci		return;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
1868c2ecf20Sopenharmony_ci	status->freq = ieee80211_channel_to_frequency(chfreq, status->band);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
1928c2ecf20Sopenharmony_ci	u32 rxv1 = le32_to_cpu(rxv[0]);
1938c2ecf20Sopenharmony_ci	u32 rxv3 = le32_to_cpu(rxv[2]);
1948c2ecf20Sopenharmony_ci	u32 rxv4 = le32_to_cpu(rxv[3]);
1958c2ecf20Sopenharmony_ci	u32 rxv5 = le32_to_cpu(rxv[4]);
1968c2ecf20Sopenharmony_ci	u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1);
1978c2ecf20Sopenharmony_ci	u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1);
1988c2ecf20Sopenharmony_ci	s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5);
1998c2ecf20Sopenharmony_ci	u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (!mode) {
2028c2ecf20Sopenharmony_ci		/* CCK */
2038c2ecf20Sopenharmony_ci		foe &= ~BIT(11);
2048c2ecf20Sopenharmony_ci		foe *= 1000;
2058c2ecf20Sopenharmony_ci		foe >>= 11;
2068c2ecf20Sopenharmony_ci	} else {
2078c2ecf20Sopenharmony_ci		if (foe > 2048)
2088c2ecf20Sopenharmony_ci			foe -= 4096;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		foe = (foe * foe_const) >> 15;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	dev->test.last_freq_offset = foe;
2148c2ecf20Sopenharmony_ci	dev->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4);
2158c2ecf20Sopenharmony_ci	dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4);
2168c2ecf20Sopenharmony_ci	dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4);
2178c2ecf20Sopenharmony_ci	dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4);
2188c2ecf20Sopenharmony_ci	dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
2198c2ecf20Sopenharmony_ci	dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
2208c2ecf20Sopenharmony_ci#endif
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
2268c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
2278c2ecf20Sopenharmony_ci	struct mt7615_phy *phy = &dev->phy;
2288c2ecf20Sopenharmony_ci	struct mt7615_phy *phy2 = dev->mt76.phy2 ? dev->mt76.phy2->priv : NULL;
2298c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
2308c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr;
2318c2ecf20Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
2328c2ecf20Sopenharmony_ci	u32 rxd0 = le32_to_cpu(rxd[0]);
2338c2ecf20Sopenharmony_ci	u32 rxd1 = le32_to_cpu(rxd[1]);
2348c2ecf20Sopenharmony_ci	u32 rxd2 = le32_to_cpu(rxd[2]);
2358c2ecf20Sopenharmony_ci	__le32 rxd12 = rxd[12];
2368c2ecf20Sopenharmony_ci	bool unicast, remove_pad, insert_ccmp_hdr = false;
2378c2ecf20Sopenharmony_ci	int phy_idx;
2388c2ecf20Sopenharmony_ci	int i, idx;
2398c2ecf20Sopenharmony_ci	u8 chfreq;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	memset(status, 0, sizeof(*status));
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	chfreq = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1);
2448c2ecf20Sopenharmony_ci	if (!phy2)
2458c2ecf20Sopenharmony_ci		phy_idx = 0;
2468c2ecf20Sopenharmony_ci	else if (phy2->chfreq == phy->chfreq)
2478c2ecf20Sopenharmony_ci		phy_idx = -1;
2488c2ecf20Sopenharmony_ci	else if (phy->chfreq == chfreq)
2498c2ecf20Sopenharmony_ci		phy_idx = 0;
2508c2ecf20Sopenharmony_ci	else if (phy2->chfreq == chfreq)
2518c2ecf20Sopenharmony_ci		phy_idx = 1;
2528c2ecf20Sopenharmony_ci	else
2538c2ecf20Sopenharmony_ci		phy_idx = -1;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
2568c2ecf20Sopenharmony_ci	idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
2578c2ecf20Sopenharmony_ci	status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (status->wcid) {
2608c2ecf20Sopenharmony_ci		struct mt7615_sta *msta;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		msta = container_of(status->wcid, struct mt7615_sta, wcid);
2638c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->sta_poll_lock);
2648c2ecf20Sopenharmony_ci		if (list_empty(&msta->poll_list))
2658c2ecf20Sopenharmony_ci			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
2668c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->sta_poll_lock);
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_FCS_ERR)
2708c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_FAILED_FCS_CRC;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR)
2738c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_ERROR;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
2768c2ecf20Sopenharmony_ci	    !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) {
2778c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
2788c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
2798c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
2858c2ecf20Sopenharmony_ci		return -EINVAL;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	rxd += 4;
2888c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
2898c2ecf20Sopenharmony_ci		rxd += 4;
2908c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
2918c2ecf20Sopenharmony_ci			return -EINVAL;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_1) {
2958c2ecf20Sopenharmony_ci		u8 *data = (u8 *)rxd;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (status->flag & RX_FLAG_DECRYPTED) {
2988c2ecf20Sopenharmony_ci			status->iv[0] = data[5];
2998c2ecf20Sopenharmony_ci			status->iv[1] = data[4];
3008c2ecf20Sopenharmony_ci			status->iv[2] = data[3];
3018c2ecf20Sopenharmony_ci			status->iv[3] = data[2];
3028c2ecf20Sopenharmony_ci			status->iv[4] = data[1];
3038c2ecf20Sopenharmony_ci			status->iv[5] = data[0];
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci			insert_ccmp_hdr = FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
3068c2ecf20Sopenharmony_ci		}
3078c2ecf20Sopenharmony_ci		rxd += 4;
3088c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
3098c2ecf20Sopenharmony_ci			return -EINVAL;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_2) {
3138c2ecf20Sopenharmony_ci		rxd += 2;
3148c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
3158c2ecf20Sopenharmony_ci			return -EINVAL;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
3198c2ecf20Sopenharmony_ci		u32 rxdg5 = le32_to_cpu(rxd[5]);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		/*
3228c2ecf20Sopenharmony_ci		 * If both PHYs are on the same channel and we don't have a WCID,
3238c2ecf20Sopenharmony_ci		 * we need to figure out which PHY this packet was received on.
3248c2ecf20Sopenharmony_ci		 * On the primary PHY, the noise value for the chains belonging to the
3258c2ecf20Sopenharmony_ci		 * second PHY will be set to the noise value of the last packet from
3268c2ecf20Sopenharmony_ci		 * that PHY.
3278c2ecf20Sopenharmony_ci		 */
3288c2ecf20Sopenharmony_ci		if (phy_idx < 0) {
3298c2ecf20Sopenharmony_ci			int first_chain = ffs(phy2->chainmask) - 1;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci			phy_idx = ((rxdg5 >> (first_chain * 8)) & 0xff) == 0;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (phy_idx == 1 && phy2) {
3368c2ecf20Sopenharmony_ci		mphy = dev->mt76.phy2;
3378c2ecf20Sopenharmony_ci		phy = phy2;
3388c2ecf20Sopenharmony_ci		status->ext_phy = true;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (!mt7615_firmware_offload(dev) && chfreq != phy->chfreq)
3428c2ecf20Sopenharmony_ci		return -EINVAL;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	mt7615_get_status_freq_info(dev, mphy, status, chfreq);
3458c2ecf20Sopenharmony_ci	if (status->band == NL80211_BAND_5GHZ)
3468c2ecf20Sopenharmony_ci		sband = &mphy->sband_5g.sband;
3478c2ecf20Sopenharmony_ci	else
3488c2ecf20Sopenharmony_ci		sband = &mphy->sband_2g.sband;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
3518c2ecf20Sopenharmony_ci		return -EINVAL;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if (!sband->channels)
3548c2ecf20Sopenharmony_ci		return -EINVAL;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
3578c2ecf20Sopenharmony_ci		      MT_RXD2_NORMAL_NON_AMPDU))) {
3588c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_AMPDU_DETAILS;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci		/* all subframes of an A-MPDU have the same timestamp */
3618c2ecf20Sopenharmony_ci		if (phy->rx_ampdu_ts != rxd12) {
3628c2ecf20Sopenharmony_ci			if (!++phy->ampdu_ref)
3638c2ecf20Sopenharmony_ci				phy->ampdu_ref++;
3648c2ecf20Sopenharmony_ci		}
3658c2ecf20Sopenharmony_ci		phy->rx_ampdu_ts = rxd12;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		status->ampdu_ref = phy->ampdu_ref;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
3718c2ecf20Sopenharmony_ci		u32 rxdg0 = le32_to_cpu(rxd[0]);
3728c2ecf20Sopenharmony_ci		u32 rxdg1 = le32_to_cpu(rxd[1]);
3738c2ecf20Sopenharmony_ci		u32 rxdg3 = le32_to_cpu(rxd[3]);
3748c2ecf20Sopenharmony_ci		u8 stbc = FIELD_GET(MT_RXV1_HT_STBC, rxdg0);
3758c2ecf20Sopenharmony_ci		bool cck = false;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0);
3788c2ecf20Sopenharmony_ci		switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
3798c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_CCK:
3808c2ecf20Sopenharmony_ci			cck = true;
3818c2ecf20Sopenharmony_ci			fallthrough;
3828c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_OFDM:
3838c2ecf20Sopenharmony_ci			i = mt76_get_rate(&dev->mt76, sband, i, cck);
3848c2ecf20Sopenharmony_ci			break;
3858c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_HT_GF:
3868c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_HT:
3878c2ecf20Sopenharmony_ci			status->encoding = RX_ENC_HT;
3888c2ecf20Sopenharmony_ci			if (i > 31)
3898c2ecf20Sopenharmony_ci				return -EINVAL;
3908c2ecf20Sopenharmony_ci			break;
3918c2ecf20Sopenharmony_ci		case MT_PHY_TYPE_VHT:
3928c2ecf20Sopenharmony_ci			status->nss = FIELD_GET(MT_RXV2_NSTS, rxdg1) + 1;
3938c2ecf20Sopenharmony_ci			status->encoding = RX_ENC_VHT;
3948c2ecf20Sopenharmony_ci			break;
3958c2ecf20Sopenharmony_ci		default:
3968c2ecf20Sopenharmony_ci			return -EINVAL;
3978c2ecf20Sopenharmony_ci		}
3988c2ecf20Sopenharmony_ci		status->rate_idx = i;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci		switch (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0)) {
4018c2ecf20Sopenharmony_ci		case MT_PHY_BW_20:
4028c2ecf20Sopenharmony_ci			break;
4038c2ecf20Sopenharmony_ci		case MT_PHY_BW_40:
4048c2ecf20Sopenharmony_ci			status->bw = RATE_INFO_BW_40;
4058c2ecf20Sopenharmony_ci			break;
4068c2ecf20Sopenharmony_ci		case MT_PHY_BW_80:
4078c2ecf20Sopenharmony_ci			status->bw = RATE_INFO_BW_80;
4088c2ecf20Sopenharmony_ci			break;
4098c2ecf20Sopenharmony_ci		case MT_PHY_BW_160:
4108c2ecf20Sopenharmony_ci			status->bw = RATE_INFO_BW_160;
4118c2ecf20Sopenharmony_ci			break;
4128c2ecf20Sopenharmony_ci		default:
4138c2ecf20Sopenharmony_ci			return -EINVAL;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_SHORT_GI)
4178c2ecf20Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
4188c2ecf20Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_AD_CODE)
4198c2ecf20Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_LDPC;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		status->chains = mphy->antenna_mask;
4248c2ecf20Sopenharmony_ci		status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3);
4258c2ecf20Sopenharmony_ci		status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3);
4268c2ecf20Sopenharmony_ci		status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3);
4278c2ecf20Sopenharmony_ci		status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3);
4288c2ecf20Sopenharmony_ci		status->signal = status->chain_signal[0];
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		for (i = 1; i < hweight8(mphy->antenna_mask); i++) {
4318c2ecf20Sopenharmony_ci			if (!(status->chains & BIT(i)))
4328c2ecf20Sopenharmony_ci				continue;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci			status->signal = max(status->signal,
4358c2ecf20Sopenharmony_ci					     status->chain_signal[i]);
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		mt7615_mac_fill_tm_rx(dev, rxd);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		rxd += 6;
4418c2ecf20Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
4428c2ecf20Sopenharmony_ci			return -EINVAL;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	skb_pull(skb, (u8 *)rxd - skb->data + 2 * remove_pad);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (insert_ccmp_hdr) {
4488c2ecf20Sopenharmony_ci		u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		mt76_insert_ccmp_hdr(skb, key_id);
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	hdr = (struct ieee80211_hdr *)skb->data;
4548c2ecf20Sopenharmony_ci	if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control))
4558c2ecf20Sopenharmony_ci		return 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	status->aggr = unicast &&
4588c2ecf20Sopenharmony_ci		       !ieee80211_is_qos_nullfunc(hdr->frame_control);
4598c2ecf20Sopenharmony_ci	status->tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
4608c2ecf20Sopenharmony_ci	status->seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return 0;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_civoid mt7615_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_sta_ps);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic u16
4718c2ecf20Sopenharmony_cimt7615_mac_tx_rate_val(struct mt7615_dev *dev,
4728c2ecf20Sopenharmony_ci		       struct mt76_phy *mphy,
4738c2ecf20Sopenharmony_ci		       const struct ieee80211_tx_rate *rate,
4748c2ecf20Sopenharmony_ci		       bool stbc, u8 *bw)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	u8 phy, nss, rate_idx;
4778c2ecf20Sopenharmony_ci	u16 rateval = 0;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	*bw = 0;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
4828c2ecf20Sopenharmony_ci		rate_idx = ieee80211_rate_get_vht_mcs(rate);
4838c2ecf20Sopenharmony_ci		nss = ieee80211_rate_get_vht_nss(rate);
4848c2ecf20Sopenharmony_ci		phy = MT_PHY_TYPE_VHT;
4858c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
4868c2ecf20Sopenharmony_ci			*bw = 1;
4878c2ecf20Sopenharmony_ci		else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
4888c2ecf20Sopenharmony_ci			*bw = 2;
4898c2ecf20Sopenharmony_ci		else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
4908c2ecf20Sopenharmony_ci			*bw = 3;
4918c2ecf20Sopenharmony_ci	} else if (rate->flags & IEEE80211_TX_RC_MCS) {
4928c2ecf20Sopenharmony_ci		rate_idx = rate->idx;
4938c2ecf20Sopenharmony_ci		nss = 1 + (rate->idx >> 3);
4948c2ecf20Sopenharmony_ci		phy = MT_PHY_TYPE_HT;
4958c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
4968c2ecf20Sopenharmony_ci			phy = MT_PHY_TYPE_HT_GF;
4978c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
4988c2ecf20Sopenharmony_ci			*bw = 1;
4998c2ecf20Sopenharmony_ci	} else {
5008c2ecf20Sopenharmony_ci		const struct ieee80211_rate *r;
5018c2ecf20Sopenharmony_ci		int band = mphy->chandef.chan->band;
5028c2ecf20Sopenharmony_ci		u16 val;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		nss = 1;
5058c2ecf20Sopenharmony_ci		r = &mphy->hw->wiphy->bands[band]->bitrates[rate->idx];
5068c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
5078c2ecf20Sopenharmony_ci			val = r->hw_value_short;
5088c2ecf20Sopenharmony_ci		else
5098c2ecf20Sopenharmony_ci			val = r->hw_value;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		phy = val >> 8;
5128c2ecf20Sopenharmony_ci		rate_idx = val & 0xff;
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (stbc && nss == 1) {
5168c2ecf20Sopenharmony_ci		nss++;
5178c2ecf20Sopenharmony_ci		rateval |= MT_TX_RATE_STBC;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	rateval |= (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
5218c2ecf20Sopenharmony_ci		    FIELD_PREP(MT_TX_RATE_MODE, phy) |
5228c2ecf20Sopenharmony_ci		    FIELD_PREP(MT_TX_RATE_NSS, nss - 1));
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return rateval;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ciint mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
5288c2ecf20Sopenharmony_ci			  struct sk_buff *skb, struct mt76_wcid *wcid,
5298c2ecf20Sopenharmony_ci			  struct ieee80211_sta *sta, int pid,
5308c2ecf20Sopenharmony_ci			  struct ieee80211_key_conf *key, bool beacon)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
5338c2ecf20Sopenharmony_ci	u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
5348c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
5358c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate *rate = &info->control.rates[0];
5368c2ecf20Sopenharmony_ci	bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
5378c2ecf20Sopenharmony_ci	bool multicast = is_multicast_ether_addr(hdr->addr1);
5388c2ecf20Sopenharmony_ci	struct ieee80211_vif *vif = info->control.vif;
5398c2ecf20Sopenharmony_ci	bool is_mmio = mt76_is_mmio(&dev->mt76);
5408c2ecf20Sopenharmony_ci	u32 val, sz_txd = is_mmio ? MT_TXD_SIZE : MT_USB_TXD_SIZE;
5418c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = &dev->mphy;
5428c2ecf20Sopenharmony_ci	__le16 fc = hdr->frame_control;
5438c2ecf20Sopenharmony_ci	int tx_count = 8;
5448c2ecf20Sopenharmony_ci	u16 seqno = 0;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (vif) {
5478c2ecf20Sopenharmony_ci		struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci		omac_idx = mvif->omac_idx;
5508c2ecf20Sopenharmony_ci		wmm_idx = mvif->wmm_idx;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (sta) {
5548c2ecf20Sopenharmony_ci		struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci		tx_count = msta->rate_count;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (ext_phy && dev->mt76.phy2)
5608c2ecf20Sopenharmony_ci		mphy = dev->mt76.phy2;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
5638c2ecf20Sopenharmony_ci	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (beacon) {
5668c2ecf20Sopenharmony_ci		p_fmt = MT_TX_TYPE_FW;
5678c2ecf20Sopenharmony_ci		q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0;
5688c2ecf20Sopenharmony_ci	} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
5698c2ecf20Sopenharmony_ci		p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
5708c2ecf20Sopenharmony_ci		q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0;
5718c2ecf20Sopenharmony_ci	} else {
5728c2ecf20Sopenharmony_ci		p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
5738c2ecf20Sopenharmony_ci		q_idx = wmm_idx * MT7615_MAX_WMM_SETS +
5748c2ecf20Sopenharmony_ci			mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb));
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
5788c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_LMAC) |
5798c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
5808c2ecf20Sopenharmony_ci	txwi[0] = cpu_to_le32(val);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	val = MT_TXD1_LONG_FORMAT |
5838c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
5848c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
5858c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_INFO,
5868c2ecf20Sopenharmony_ci			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
5878c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_TID,
5888c2ecf20Sopenharmony_ci			 skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
5898c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_PKT_FMT, p_fmt) |
5908c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
5918c2ecf20Sopenharmony_ci	txwi[1] = cpu_to_le32(val);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
5948c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
5958c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD2_MULTICAST, multicast);
5968c2ecf20Sopenharmony_ci	if (key) {
5978c2ecf20Sopenharmony_ci		if (multicast && ieee80211_is_robust_mgmt_frame(skb) &&
5988c2ecf20Sopenharmony_ci		    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
5998c2ecf20Sopenharmony_ci			val |= MT_TXD2_BIP;
6008c2ecf20Sopenharmony_ci			txwi[3] = 0;
6018c2ecf20Sopenharmony_ci		} else {
6028c2ecf20Sopenharmony_ci			txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME);
6038c2ecf20Sopenharmony_ci		}
6048c2ecf20Sopenharmony_ci	} else {
6058c2ecf20Sopenharmony_ci		txwi[3] = 0;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci	txwi[2] = cpu_to_le32(val);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
6108c2ecf20Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	txwi[4] = 0;
6138c2ecf20Sopenharmony_ci	txwi[6] = 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	if (rate->idx >= 0 && rate->count &&
6168c2ecf20Sopenharmony_ci	    !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
6178c2ecf20Sopenharmony_ci		bool stbc = info->flags & IEEE80211_TX_CTL_STBC;
6188c2ecf20Sopenharmony_ci		u8 bw;
6198c2ecf20Sopenharmony_ci		u16 rateval = mt7615_mac_tx_rate_val(dev, mphy, rate, stbc,
6208c2ecf20Sopenharmony_ci						     &bw);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		val = MT_TXD6_FIXED_BW |
6258c2ecf20Sopenharmony_ci		      FIELD_PREP(MT_TXD6_BW, bw) |
6268c2ecf20Sopenharmony_ci		      FIELD_PREP(MT_TXD6_TX_RATE, rateval);
6278c2ecf20Sopenharmony_ci		txwi[6] |= cpu_to_le32(val);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
6308c2ecf20Sopenharmony_ci			txwi[6] |= cpu_to_le32(MT_TXD6_SGI);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		if (info->flags & IEEE80211_TX_CTL_LDPC)
6338c2ecf20Sopenharmony_ci			txwi[6] |= cpu_to_le32(MT_TXD6_LDPC);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		if (!(rate->flags & (IEEE80211_TX_RC_MCS |
6368c2ecf20Sopenharmony_ci				     IEEE80211_TX_RC_VHT_MCS)))
6378c2ecf20Sopenharmony_ci			txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci		tx_count = rate->count;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if (!ieee80211_is_beacon(fc)) {
6438c2ecf20Sopenharmony_ci		struct ieee80211_hw *hw = mt76_hw(dev);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		val = MT_TXD5_TX_STATUS_HOST | FIELD_PREP(MT_TXD5_PID, pid);
6468c2ecf20Sopenharmony_ci		if (!ieee80211_hw_check(hw, SUPPORTS_PS))
6478c2ecf20Sopenharmony_ci			val |= MT_TXD5_SW_POWER_MGMT;
6488c2ecf20Sopenharmony_ci		txwi[5] = cpu_to_le32(val);
6498c2ecf20Sopenharmony_ci	} else {
6508c2ecf20Sopenharmony_ci		txwi[5] = 0;
6518c2ecf20Sopenharmony_ci		/* use maximum tx count for beacons */
6528c2ecf20Sopenharmony_ci		tx_count = 0x1f;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
6568c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
6578c2ecf20Sopenharmony_ci		seqno = le16_to_cpu(hdr->seq_ctrl);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		if (ieee80211_is_back_req(hdr->frame_control)) {
6608c2ecf20Sopenharmony_ci			struct ieee80211_bar *bar;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci			bar = (struct ieee80211_bar *)skb->data;
6638c2ecf20Sopenharmony_ci			seqno = le16_to_cpu(bar->start_seq_num);
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		val |= MT_TXD3_SN_VALID |
6678c2ecf20Sopenharmony_ci		       FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	txwi[3] |= cpu_to_le32(val);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
6738c2ecf20Sopenharmony_ci		txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
6768c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) |
6778c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_TXD7_SPE_IDX, 0x18);
6788c2ecf20Sopenharmony_ci	txwi[7] = cpu_to_le32(val);
6798c2ecf20Sopenharmony_ci	if (!is_mmio) {
6808c2ecf20Sopenharmony_ci		val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
6818c2ecf20Sopenharmony_ci		      FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
6828c2ecf20Sopenharmony_ci		txwi[8] = cpu_to_le32(val);
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	return 0;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_write_txwi);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_cistatic void
6908c2ecf20Sopenharmony_cimt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt7615_fw_txp *txp)
6918c2ecf20Sopenharmony_ci{
6928c2ecf20Sopenharmony_ci	int i;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	for (i = 0; i < txp->nbuf; i++)
6958c2ecf20Sopenharmony_ci		dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
6968c2ecf20Sopenharmony_ci				 le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic void
7008c2ecf20Sopenharmony_cimt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	u32 last_mask;
7038c2ecf20Sopenharmony_ci	int i;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	last_mask = is_mt7663(dev) ? MT_TXD_LEN_LAST : MT_TXD_LEN_MSDU_LAST;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(txp->ptr); i++) {
7088c2ecf20Sopenharmony_ci		struct mt7615_txp_ptr *ptr = &txp->ptr[i];
7098c2ecf20Sopenharmony_ci		bool last;
7108c2ecf20Sopenharmony_ci		u16 len;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci		len = le16_to_cpu(ptr->len0);
7138c2ecf20Sopenharmony_ci		last = len & last_mask;
7148c2ecf20Sopenharmony_ci		len &= MT_TXD_LEN_MASK;
7158c2ecf20Sopenharmony_ci		dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf0), len,
7168c2ecf20Sopenharmony_ci				 DMA_TO_DEVICE);
7178c2ecf20Sopenharmony_ci		if (last)
7188c2ecf20Sopenharmony_ci			break;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci		len = le16_to_cpu(ptr->len1);
7218c2ecf20Sopenharmony_ci		last = len & last_mask;
7228c2ecf20Sopenharmony_ci		len &= MT_TXD_LEN_MASK;
7238c2ecf20Sopenharmony_ci		dma_unmap_single(dev->dev, le32_to_cpu(ptr->buf1), len,
7248c2ecf20Sopenharmony_ci				 DMA_TO_DEVICE);
7258c2ecf20Sopenharmony_ci		if (last)
7268c2ecf20Sopenharmony_ci			break;
7278c2ecf20Sopenharmony_ci	}
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_civoid mt7615_txp_skb_unmap(struct mt76_dev *dev,
7318c2ecf20Sopenharmony_ci			  struct mt76_txwi_cache *t)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct mt7615_txp_common *txp;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	txp = mt7615_txwi_to_txp(dev, t);
7368c2ecf20Sopenharmony_ci	if (is_mt7615(dev))
7378c2ecf20Sopenharmony_ci		mt7615_txp_skb_unmap_fw(dev, &txp->fw);
7388c2ecf20Sopenharmony_ci	else
7398c2ecf20Sopenharmony_ci		mt7615_txp_skb_unmap_hw(dev, &txp->hw);
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_txp_skb_unmap);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cibool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
7468c2ecf20Sopenharmony_ci		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
7498c2ecf20Sopenharmony_ci			 0, 5000);
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_civoid mt7615_mac_sta_poll(struct mt7615_dev *dev)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	static const u8 ac_to_tid[4] = {
7558c2ecf20Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
7568c2ecf20Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
7578c2ecf20Sopenharmony_ci		[IEEE80211_AC_VI] = 4,
7588c2ecf20Sopenharmony_ci		[IEEE80211_AC_VO] = 6
7598c2ecf20Sopenharmony_ci	};
7608c2ecf20Sopenharmony_ci	static const u8 hw_queue_map[] = {
7618c2ecf20Sopenharmony_ci		[IEEE80211_AC_BK] = 0,
7628c2ecf20Sopenharmony_ci		[IEEE80211_AC_BE] = 1,
7638c2ecf20Sopenharmony_ci		[IEEE80211_AC_VI] = 2,
7648c2ecf20Sopenharmony_ci		[IEEE80211_AC_VO] = 3,
7658c2ecf20Sopenharmony_ci	};
7668c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta;
7678c2ecf20Sopenharmony_ci	struct mt7615_sta *msta;
7688c2ecf20Sopenharmony_ci	u32 addr, tx_time[4], rx_time[4];
7698c2ecf20Sopenharmony_ci	struct list_head sta_poll_list;
7708c2ecf20Sopenharmony_ci	int i;
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sta_poll_list);
7738c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->sta_poll_lock);
7748c2ecf20Sopenharmony_ci	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
7758c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->sta_poll_lock);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	while (!list_empty(&sta_poll_list)) {
7788c2ecf20Sopenharmony_ci		bool clear = false;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
7818c2ecf20Sopenharmony_ci					poll_list);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->sta_poll_lock);
7848c2ecf20Sopenharmony_ci		list_del_init(&msta->poll_list);
7858c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->sta_poll_lock);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci		addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++, addr += 8) {
7908c2ecf20Sopenharmony_ci			u32 tx_last = msta->airtime_ac[i];
7918c2ecf20Sopenharmony_ci			u32 rx_last = msta->airtime_ac[i + 4];
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci			msta->airtime_ac[i] = mt76_rr(dev, addr);
7948c2ecf20Sopenharmony_ci			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
7958c2ecf20Sopenharmony_ci			tx_time[i] = msta->airtime_ac[i] - tx_last;
7968c2ecf20Sopenharmony_ci			rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci			if ((tx_last | rx_last) & BIT(30))
7998c2ecf20Sopenharmony_ci				clear = true;
8008c2ecf20Sopenharmony_ci		}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci		if (clear) {
8038c2ecf20Sopenharmony_ci			mt7615_mac_wtbl_update(dev, msta->wcid.idx,
8048c2ecf20Sopenharmony_ci					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
8058c2ecf20Sopenharmony_ci			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
8068c2ecf20Sopenharmony_ci		}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci		if (!msta->wcid.sta)
8098c2ecf20Sopenharmony_ci			continue;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		sta = container_of((void *)msta, struct ieee80211_sta,
8128c2ecf20Sopenharmony_ci				   drv_priv);
8138c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++) {
8148c2ecf20Sopenharmony_ci			u32 tx_cur = tx_time[i];
8158c2ecf20Sopenharmony_ci			u32 rx_cur = rx_time[hw_queue_map[i]];
8168c2ecf20Sopenharmony_ci			u8 tid = ac_to_tid[i];
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci			if (!tx_cur && !rx_cur)
8198c2ecf20Sopenharmony_ci				continue;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci			ieee80211_sta_register_airtime(sta, tid, tx_cur,
8228c2ecf20Sopenharmony_ci						       rx_cur);
8238c2ecf20Sopenharmony_ci		}
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_sta_poll);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic void
8298c2ecf20Sopenharmony_cimt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta,
8308c2ecf20Sopenharmony_ci			    struct ieee80211_tx_rate *probe_rate,
8318c2ecf20Sopenharmony_ci			    struct ieee80211_tx_rate *rates,
8328c2ecf20Sopenharmony_ci			    struct mt7615_rate_desc *rd)
8338c2ecf20Sopenharmony_ci{
8348c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
8358c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
8368c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate *ref;
8378c2ecf20Sopenharmony_ci	bool rateset, stbc = false;
8388c2ecf20Sopenharmony_ci	int n_rates = sta->n_rates;
8398c2ecf20Sopenharmony_ci	u8 bw, bw_prev;
8408c2ecf20Sopenharmony_ci	int i, j;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	for (i = n_rates; i < 4; i++)
8438c2ecf20Sopenharmony_ci		rates[i] = rates[n_rates - 1];
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	rateset = !(sta->rate_set_tsf & BIT(0));
8468c2ecf20Sopenharmony_ci	memcpy(sta->rateset[rateset].rates, rates,
8478c2ecf20Sopenharmony_ci	       sizeof(sta->rateset[rateset].rates));
8488c2ecf20Sopenharmony_ci	if (probe_rate) {
8498c2ecf20Sopenharmony_ci		sta->rateset[rateset].probe_rate = *probe_rate;
8508c2ecf20Sopenharmony_ci		ref = &sta->rateset[rateset].probe_rate;
8518c2ecf20Sopenharmony_ci	} else {
8528c2ecf20Sopenharmony_ci		sta->rateset[rateset].probe_rate.idx = -1;
8538c2ecf20Sopenharmony_ci		ref = &sta->rateset[rateset].rates[0];
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	rates = sta->rateset[rateset].rates;
8578c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) {
8588c2ecf20Sopenharmony_ci		/*
8598c2ecf20Sopenharmony_ci		 * We don't support switching between short and long GI
8608c2ecf20Sopenharmony_ci		 * within the rate set. For accurate tx status reporting, we
8618c2ecf20Sopenharmony_ci		 * need to make sure that flags match.
8628c2ecf20Sopenharmony_ci		 * For improved performance, avoid duplicate entries by
8638c2ecf20Sopenharmony_ci		 * decrementing the MCS index if necessary
8648c2ecf20Sopenharmony_ci		 */
8658c2ecf20Sopenharmony_ci		if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI)
8668c2ecf20Sopenharmony_ci			rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci		for (j = 0; j < i; j++) {
8698c2ecf20Sopenharmony_ci			if (rates[i].idx != rates[j].idx)
8708c2ecf20Sopenharmony_ci				continue;
8718c2ecf20Sopenharmony_ci			if ((rates[i].flags ^ rates[j].flags) &
8728c2ecf20Sopenharmony_ci			    (IEEE80211_TX_RC_40_MHZ_WIDTH |
8738c2ecf20Sopenharmony_ci			     IEEE80211_TX_RC_80_MHZ_WIDTH |
8748c2ecf20Sopenharmony_ci			     IEEE80211_TX_RC_160_MHZ_WIDTH))
8758c2ecf20Sopenharmony_ci				continue;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci			if (!rates[i].idx)
8788c2ecf20Sopenharmony_ci				continue;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci			rates[i].idx--;
8818c2ecf20Sopenharmony_ci		}
8828c2ecf20Sopenharmony_ci	}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	rd->val[0] = mt7615_mac_tx_rate_val(dev, mphy, &rates[0], stbc, &bw);
8858c2ecf20Sopenharmony_ci	bw_prev = bw;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (probe_rate) {
8888c2ecf20Sopenharmony_ci		rd->probe_val = mt7615_mac_tx_rate_val(dev, mphy, probe_rate,
8898c2ecf20Sopenharmony_ci						       stbc, &bw);
8908c2ecf20Sopenharmony_ci		if (bw)
8918c2ecf20Sopenharmony_ci			rd->bw_idx = 1;
8928c2ecf20Sopenharmony_ci		else
8938c2ecf20Sopenharmony_ci			bw_prev = 0;
8948c2ecf20Sopenharmony_ci	} else {
8958c2ecf20Sopenharmony_ci		rd->probe_val = rd->val[0];
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	rd->val[1] = mt7615_mac_tx_rate_val(dev, mphy, &rates[1], stbc, &bw);
8998c2ecf20Sopenharmony_ci	if (bw_prev) {
9008c2ecf20Sopenharmony_ci		rd->bw_idx = 3;
9018c2ecf20Sopenharmony_ci		bw_prev = bw;
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	rd->val[2] = mt7615_mac_tx_rate_val(dev, mphy, &rates[2], stbc, &bw);
9058c2ecf20Sopenharmony_ci	if (bw_prev) {
9068c2ecf20Sopenharmony_ci		rd->bw_idx = 5;
9078c2ecf20Sopenharmony_ci		bw_prev = bw;
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	rd->val[3] = mt7615_mac_tx_rate_val(dev, mphy, &rates[3], stbc, &bw);
9118c2ecf20Sopenharmony_ci	if (bw_prev)
9128c2ecf20Sopenharmony_ci		rd->bw_idx = 7;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	rd->rateset = rateset;
9158c2ecf20Sopenharmony_ci	rd->bw = bw;
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_cistatic int
9198c2ecf20Sopenharmony_cimt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta,
9208c2ecf20Sopenharmony_ci			     struct ieee80211_tx_rate *probe_rate,
9218c2ecf20Sopenharmony_ci			     struct ieee80211_tx_rate *rates)
9228c2ecf20Sopenharmony_ci{
9238c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
9248c2ecf20Sopenharmony_ci	struct mt7615_wtbl_desc *wd;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (work_pending(&dev->wtbl_work))
9278c2ecf20Sopenharmony_ci		return -EBUSY;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	wd = kzalloc(sizeof(*wd), GFP_ATOMIC);
9308c2ecf20Sopenharmony_ci	if (!wd)
9318c2ecf20Sopenharmony_ci		return -ENOMEM;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	wd->type = MT7615_WTBL_RATE_DESC;
9348c2ecf20Sopenharmony_ci	wd->sta = sta;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates,
9378c2ecf20Sopenharmony_ci				    &wd->rate);
9388c2ecf20Sopenharmony_ci	list_add_tail(&wd->node, &dev->wd_head);
9398c2ecf20Sopenharmony_ci	queue_work(dev->mt76.wq, &dev->wtbl_work);
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	return 0;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ciu32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	u32 addr, val, val2;
9478c2ecf20Sopenharmony_ci	u8 offset;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	addr = mt7615_mac_wtbl_addr(dev, wcid) + 11 * 4;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	offset = tid * 12;
9528c2ecf20Sopenharmony_ci	addr += 4 * (offset / 32);
9538c2ecf20Sopenharmony_ci	offset %= 32;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	val = mt76_rr(dev, addr);
9568c2ecf20Sopenharmony_ci	val >>= offset;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	if (offset > 20) {
9598c2ecf20Sopenharmony_ci		addr += 4;
9608c2ecf20Sopenharmony_ci		val2 = mt76_rr(dev, addr);
9618c2ecf20Sopenharmony_ci		val |= val2 << (32 - offset);
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	return val & GENMASK(11, 0);
9658c2ecf20Sopenharmony_ci}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_civoid mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
9688c2ecf20Sopenharmony_ci			  struct ieee80211_tx_rate *probe_rate,
9698c2ecf20Sopenharmony_ci			  struct ieee80211_tx_rate *rates)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	int wcid = sta->wcid.idx, n_rates = sta->n_rates;
9728c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
9738c2ecf20Sopenharmony_ci	struct mt7615_rate_desc rd;
9748c2ecf20Sopenharmony_ci	u32 w5, w27, addr;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if (!mt76_is_mmio(&dev->mt76)) {
9778c2ecf20Sopenharmony_ci		mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates);
9788c2ecf20Sopenharmony_ci		return;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
9828c2ecf20Sopenharmony_ci		return;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	memset(&rd, 0, sizeof(struct mt7615_rate_desc));
9858c2ecf20Sopenharmony_ci	mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &rd);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	addr = mt7615_mac_wtbl_addr(dev, wcid);
9888c2ecf20Sopenharmony_ci	w27 = mt76_rr(dev, addr + 27 * 4);
9898c2ecf20Sopenharmony_ci	w27 &= ~MT_WTBL_W27_CC_BW_SEL;
9908c2ecf20Sopenharmony_ci	w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rd.bw);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	w5 = mt76_rr(dev, addr + 5 * 4);
9938c2ecf20Sopenharmony_ci	w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE |
9948c2ecf20Sopenharmony_ci		MT_WTBL_W5_MPDU_OK_COUNT |
9958c2ecf20Sopenharmony_ci		MT_WTBL_W5_MPDU_FAIL_COUNT |
9968c2ecf20Sopenharmony_ci		MT_WTBL_W5_RATE_IDX);
9978c2ecf20Sopenharmony_ci	w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rd.bw) |
9988c2ecf20Sopenharmony_ci	      FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE,
9998c2ecf20Sopenharmony_ci			 rd.bw_idx ? rd.bw_idx - 1 : 7);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR0, w5);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR1,
10048c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rd.probe_val) |
10058c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rd.val[0]) |
10068c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rd.val[1]));
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR2,
10098c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rd.val[1] >> 8) |
10108c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rd.val[1]) |
10118c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rd.val[2]) |
10128c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rd.val[2]));
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR3,
10158c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rd.val[2] >> 4) |
10168c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rd.val[3]) |
10178c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rd.val[3]));
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_UPDATE,
10208c2ecf20Sopenharmony_ci		FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
10218c2ecf20Sopenharmony_ci		MT_WTBL_UPDATE_RATE_UPDATE |
10228c2ecf20Sopenharmony_ci		MT_WTBL_UPDATE_TX_COUNT_CLEAR);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	mt76_wr(dev, addr + 27 * 4, w27);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */
10278c2ecf20Sopenharmony_ci	sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0);
10288c2ecf20Sopenharmony_ci	sta->rate_set_tsf |= rd.rateset;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
10318c2ecf20Sopenharmony_ci		mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates;
10348c2ecf20Sopenharmony_ci	sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
10358c2ecf20Sopenharmony_ci	sta->rate_probe = !!probe_rate;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ciint mt7615_mac_wtbl_update_key(struct mt7615_dev *dev,
10408c2ecf20Sopenharmony_ci			       struct mt76_wcid *wcid,
10418c2ecf20Sopenharmony_ci			       u8 *key, u8 keylen,
10428c2ecf20Sopenharmony_ci			       enum mt7615_cipher_type cipher,
10438c2ecf20Sopenharmony_ci			       enum set_key_cmd cmd)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4;
10468c2ecf20Sopenharmony_ci	u8 data[32] = {};
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (keylen > sizeof(data))
10498c2ecf20Sopenharmony_ci		return -EINVAL;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	mt76_rr_copy(dev, addr, data, sizeof(data));
10528c2ecf20Sopenharmony_ci	if (cmd == SET_KEY) {
10538c2ecf20Sopenharmony_ci		if (cipher == MT_CIPHER_TKIP) {
10548c2ecf20Sopenharmony_ci			/* Rx/Tx MIC keys are swapped */
10558c2ecf20Sopenharmony_ci			memcpy(data, key, 16);
10568c2ecf20Sopenharmony_ci			memcpy(data + 16, key + 24, 8);
10578c2ecf20Sopenharmony_ci			memcpy(data + 24, key + 16, 8);
10588c2ecf20Sopenharmony_ci		} else {
10598c2ecf20Sopenharmony_ci			if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher)
10608c2ecf20Sopenharmony_ci				memmove(data + 16, data, 16);
10618c2ecf20Sopenharmony_ci			if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
10628c2ecf20Sopenharmony_ci				memcpy(data, key, keylen);
10638c2ecf20Sopenharmony_ci			else if (cipher == MT_CIPHER_BIP_CMAC_128)
10648c2ecf20Sopenharmony_ci				memcpy(data + 16, key, 16);
10658c2ecf20Sopenharmony_ci		}
10668c2ecf20Sopenharmony_ci	} else {
10678c2ecf20Sopenharmony_ci		if (wcid->cipher & ~BIT(cipher)) {
10688c2ecf20Sopenharmony_ci			if (cipher != MT_CIPHER_BIP_CMAC_128)
10698c2ecf20Sopenharmony_ci				memmove(data, data + 16, 16);
10708c2ecf20Sopenharmony_ci			memset(data + 16, 0, 16);
10718c2ecf20Sopenharmony_ci		} else {
10728c2ecf20Sopenharmony_ci			memset(data, 0, sizeof(data));
10738c2ecf20Sopenharmony_ci		}
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci	mt76_wr_copy(dev, addr, data, sizeof(data));
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	return 0;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_key);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ciint mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev,
10828c2ecf20Sopenharmony_ci			      struct mt76_wcid *wcid,
10838c2ecf20Sopenharmony_ci			      enum mt7615_cipher_type cipher,
10848c2ecf20Sopenharmony_ci			      int keyidx, enum set_key_cmd cmd)
10858c2ecf20Sopenharmony_ci{
10868c2ecf20Sopenharmony_ci	u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
10898c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	w0 = mt76_rr(dev, addr);
10928c2ecf20Sopenharmony_ci	w1 = mt76_rr(dev, addr + 4);
10938c2ecf20Sopenharmony_ci	if (cmd == SET_KEY) {
10948c2ecf20Sopenharmony_ci		w0 |= MT_WTBL_W0_RX_KEY_VALID |
10958c2ecf20Sopenharmony_ci		      FIELD_PREP(MT_WTBL_W0_RX_IK_VALID,
10968c2ecf20Sopenharmony_ci				 cipher == MT_CIPHER_BIP_CMAC_128);
10978c2ecf20Sopenharmony_ci		if (cipher != MT_CIPHER_BIP_CMAC_128 ||
10988c2ecf20Sopenharmony_ci		    !wcid->cipher)
10998c2ecf20Sopenharmony_ci			w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx);
11008c2ecf20Sopenharmony_ci	}  else {
11018c2ecf20Sopenharmony_ci		if (!(wcid->cipher & ~BIT(cipher)))
11028c2ecf20Sopenharmony_ci			w0 &= ~(MT_WTBL_W0_RX_KEY_VALID |
11038c2ecf20Sopenharmony_ci				MT_WTBL_W0_KEY_IDX);
11048c2ecf20Sopenharmony_ci		if (cipher == MT_CIPHER_BIP_CMAC_128)
11058c2ecf20Sopenharmony_ci			w0 &= ~MT_WTBL_W0_RX_IK_VALID;
11068c2ecf20Sopenharmony_ci	}
11078c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RICR0, w0);
11088c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RICR1, w1);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	if (!mt7615_mac_wtbl_update(dev, wcid->idx,
11118c2ecf20Sopenharmony_ci				    MT_WTBL_UPDATE_RXINFO_UPDATE))
11128c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	return 0;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_pk);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_civoid mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
11198c2ecf20Sopenharmony_ci				   struct mt76_wcid *wcid,
11208c2ecf20Sopenharmony_ci				   enum mt7615_cipher_type cipher,
11218c2ecf20Sopenharmony_ci				   enum set_key_cmd cmd)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (cmd == SET_KEY) {
11268c2ecf20Sopenharmony_ci		if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
11278c2ecf20Sopenharmony_ci			mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE,
11288c2ecf20Sopenharmony_ci				 FIELD_PREP(MT_WTBL_W2_KEY_TYPE, cipher));
11298c2ecf20Sopenharmony_ci	} else {
11308c2ecf20Sopenharmony_ci		if (cipher != MT_CIPHER_BIP_CMAC_128 &&
11318c2ecf20Sopenharmony_ci		    wcid->cipher & BIT(MT_CIPHER_BIP_CMAC_128))
11328c2ecf20Sopenharmony_ci			mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE,
11338c2ecf20Sopenharmony_ci				 FIELD_PREP(MT_WTBL_W2_KEY_TYPE,
11348c2ecf20Sopenharmony_ci					    MT_CIPHER_BIP_CMAC_128));
11358c2ecf20Sopenharmony_ci		else if (!(wcid->cipher & ~BIT(cipher)))
11368c2ecf20Sopenharmony_ci			mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE);
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_cipher);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ciint mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
11428c2ecf20Sopenharmony_ci			    struct mt76_wcid *wcid,
11438c2ecf20Sopenharmony_ci			    struct ieee80211_key_conf *key,
11448c2ecf20Sopenharmony_ci			    enum set_key_cmd cmd)
11458c2ecf20Sopenharmony_ci{
11468c2ecf20Sopenharmony_ci	enum mt7615_cipher_type cipher;
11478c2ecf20Sopenharmony_ci	int err;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	cipher = mt7615_mac_get_cipher(key->cipher);
11508c2ecf20Sopenharmony_ci	if (cipher == MT_CIPHER_NONE)
11518c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->mt76.lock);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cmd);
11568c2ecf20Sopenharmony_ci	err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen,
11578c2ecf20Sopenharmony_ci					 cipher, cmd);
11588c2ecf20Sopenharmony_ci	if (err < 0)
11598c2ecf20Sopenharmony_ci		goto out;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
11628c2ecf20Sopenharmony_ci					cmd);
11638c2ecf20Sopenharmony_ci	if (err < 0)
11648c2ecf20Sopenharmony_ci		goto out;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	if (cmd == SET_KEY)
11678c2ecf20Sopenharmony_ci		wcid->cipher |= BIT(cipher);
11688c2ecf20Sopenharmony_ci	else
11698c2ecf20Sopenharmony_ci		wcid->cipher &= ~BIT(cipher);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ciout:
11728c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->mt76.lock);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	return err;
11758c2ecf20Sopenharmony_ci}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_cistatic bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
11788c2ecf20Sopenharmony_ci			    struct ieee80211_tx_info *info, __le32 *txs_data)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	struct ieee80211_supported_band *sband;
11818c2ecf20Sopenharmony_ci	struct mt7615_rate_set *rs;
11828c2ecf20Sopenharmony_ci	struct mt76_phy *mphy;
11838c2ecf20Sopenharmony_ci	int first_idx = 0, last_idx;
11848c2ecf20Sopenharmony_ci	int i, idx, count;
11858c2ecf20Sopenharmony_ci	bool fixed_rate, ack_timeout;
11868c2ecf20Sopenharmony_ci	bool ampdu, cck = false;
11878c2ecf20Sopenharmony_ci	bool rs_idx;
11888c2ecf20Sopenharmony_ci	u32 rate_set_tsf;
11898c2ecf20Sopenharmony_ci	u32 final_rate, final_rate_flags, final_nss, txs;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[1]);
11928c2ecf20Sopenharmony_ci	ampdu = txs & MT_TXS1_AMPDU;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[3]);
11958c2ecf20Sopenharmony_ci	count = FIELD_GET(MT_TXS3_TX_COUNT, txs);
11968c2ecf20Sopenharmony_ci	last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[0]);
11998c2ecf20Sopenharmony_ci	fixed_rate = txs & MT_TXS0_FIXED_RATE;
12008c2ecf20Sopenharmony_ci	final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
12018c2ecf20Sopenharmony_ci	ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT))
12048c2ecf20Sopenharmony_ci		return false;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	if (txs & MT_TXS0_QUEUE_TIMEOUT)
12078c2ecf20Sopenharmony_ci		return false;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	if (!ack_timeout)
12108c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	info->status.ampdu_len = 1;
12138c2ecf20Sopenharmony_ci	info->status.ampdu_ack_len = !!(info->flags &
12148c2ecf20Sopenharmony_ci					IEEE80211_TX_STAT_ACK);
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
12178c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (fixed_rate) {
12228c2ecf20Sopenharmony_ci		info->status.rates[0].count = count;
12238c2ecf20Sopenharmony_ci		i = 0;
12248c2ecf20Sopenharmony_ci		goto out;
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	rate_set_tsf = READ_ONCE(sta->rate_set_tsf);
12288c2ecf20Sopenharmony_ci	rs_idx = !((u32)(FIELD_GET(MT_TXS4_F0_TIMESTAMP, le32_to_cpu(txs_data[4])) -
12298c2ecf20Sopenharmony_ci			 rate_set_tsf) < 1000000);
12308c2ecf20Sopenharmony_ci	rs_idx ^= rate_set_tsf & BIT(0);
12318c2ecf20Sopenharmony_ci	rs = &sta->rateset[rs_idx];
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	if (!first_idx && rs->probe_rate.idx >= 0) {
12348c2ecf20Sopenharmony_ci		info->status.rates[0] = rs->probe_rate;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
12378c2ecf20Sopenharmony_ci		if (sta->rate_probe) {
12388c2ecf20Sopenharmony_ci			struct mt7615_phy *phy = &dev->phy;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci			if (sta->wcid.ext_phy && dev->mt76.phy2)
12418c2ecf20Sopenharmony_ci				phy = dev->mt76.phy2->priv;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci			mt7615_mac_set_rates(phy, sta, NULL, sta->rates);
12448c2ecf20Sopenharmony_ci		}
12458c2ecf20Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
12468c2ecf20Sopenharmony_ci	} else {
12478c2ecf20Sopenharmony_ci		info->status.rates[0] = rs->rates[first_idx / 2];
12488c2ecf20Sopenharmony_ci	}
12498c2ecf20Sopenharmony_ci	info->status.rates[0].count = 0;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) {
12528c2ecf20Sopenharmony_ci		struct ieee80211_tx_rate *cur_rate;
12538c2ecf20Sopenharmony_ci		int cur_count;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci		cur_rate = &rs->rates[idx / 2];
12568c2ecf20Sopenharmony_ci		cur_count = min_t(int, MT7615_RATE_RETRY, count);
12578c2ecf20Sopenharmony_ci		count -= cur_count;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci		if (idx && (cur_rate->idx != info->status.rates[i].idx ||
12608c2ecf20Sopenharmony_ci			    cur_rate->flags != info->status.rates[i].flags)) {
12618c2ecf20Sopenharmony_ci			i++;
12628c2ecf20Sopenharmony_ci			if (i == ARRAY_SIZE(info->status.rates)) {
12638c2ecf20Sopenharmony_ci				i--;
12648c2ecf20Sopenharmony_ci				break;
12658c2ecf20Sopenharmony_ci			}
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci			info->status.rates[i] = *cur_rate;
12688c2ecf20Sopenharmony_ci			info->status.rates[i].count = 0;
12698c2ecf20Sopenharmony_ci		}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci		info->status.rates[i].count += cur_count;
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ciout:
12758c2ecf20Sopenharmony_ci	final_rate_flags = info->status.rates[i].flags;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
12788c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_CCK:
12798c2ecf20Sopenharmony_ci		cck = true;
12808c2ecf20Sopenharmony_ci		fallthrough;
12818c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
12828c2ecf20Sopenharmony_ci		mphy = &dev->mphy;
12838c2ecf20Sopenharmony_ci		if (sta->wcid.ext_phy && dev->mt76.phy2)
12848c2ecf20Sopenharmony_ci			mphy = dev->mt76.phy2;
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
12878c2ecf20Sopenharmony_ci			sband = &mphy->sband_5g.sband;
12888c2ecf20Sopenharmony_ci		else
12898c2ecf20Sopenharmony_ci			sband = &mphy->sband_2g.sband;
12908c2ecf20Sopenharmony_ci		final_rate &= MT_TX_RATE_IDX;
12918c2ecf20Sopenharmony_ci		final_rate = mt76_get_rate(&dev->mt76, sband, final_rate,
12928c2ecf20Sopenharmony_ci					   cck);
12938c2ecf20Sopenharmony_ci		final_rate_flags = 0;
12948c2ecf20Sopenharmony_ci		break;
12958c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
12968c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT:
12978c2ecf20Sopenharmony_ci		final_rate_flags |= IEEE80211_TX_RC_MCS;
12988c2ecf20Sopenharmony_ci		final_rate &= MT_TX_RATE_IDX;
12998c2ecf20Sopenharmony_ci		if (final_rate > 31)
13008c2ecf20Sopenharmony_ci			return false;
13018c2ecf20Sopenharmony_ci		break;
13028c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_VHT:
13038c2ecf20Sopenharmony_ci		final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci		if ((final_rate & MT_TX_RATE_STBC) && final_nss)
13068c2ecf20Sopenharmony_ci			final_nss--;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci		final_rate_flags |= IEEE80211_TX_RC_VHT_MCS;
13098c2ecf20Sopenharmony_ci		final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4);
13108c2ecf20Sopenharmony_ci		break;
13118c2ecf20Sopenharmony_ci	default:
13128c2ecf20Sopenharmony_ci		return false;
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	info->status.rates[i].idx = final_rate;
13168c2ecf20Sopenharmony_ci	info->status.rates[i].flags = final_rate_flags;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	return true;
13198c2ecf20Sopenharmony_ci}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_cistatic bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev,
13228c2ecf20Sopenharmony_ci				   struct mt7615_sta *sta, int pid,
13238c2ecf20Sopenharmony_ci				   __le32 *txs_data)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
13268c2ecf20Sopenharmony_ci	struct sk_buff_head list;
13278c2ecf20Sopenharmony_ci	struct sk_buff *skb;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (pid < MT_PACKET_ID_FIRST)
13308c2ecf20Sopenharmony_ci		return false;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	trace_mac_txdone(mdev, sta->wcid.idx, pid);
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	mt76_tx_status_lock(mdev, &list);
13358c2ecf20Sopenharmony_ci	skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list);
13368c2ecf20Sopenharmony_ci	if (skb) {
13378c2ecf20Sopenharmony_ci		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci		if (!mt7615_fill_txs(dev, sta, info, txs_data)) {
13408c2ecf20Sopenharmony_ci			ieee80211_tx_info_clear_status(info);
13418c2ecf20Sopenharmony_ci			info->status.rates[0].idx = -1;
13428c2ecf20Sopenharmony_ci		}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci		mt76_tx_status_skb_done(mdev, skb, &list);
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci	mt76_tx_status_unlock(mdev, &list);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	return !!skb;
13498c2ecf20Sopenharmony_ci}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_cistatic void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
13528c2ecf20Sopenharmony_ci{
13538c2ecf20Sopenharmony_ci	struct ieee80211_tx_info info = {};
13548c2ecf20Sopenharmony_ci	struct ieee80211_sta *sta = NULL;
13558c2ecf20Sopenharmony_ci	struct mt7615_sta *msta = NULL;
13568c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid;
13578c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
13588c2ecf20Sopenharmony_ci	__le32 *txs_data = data;
13598c2ecf20Sopenharmony_ci	u32 txs;
13608c2ecf20Sopenharmony_ci	u8 wcidx;
13618c2ecf20Sopenharmony_ci	u8 pid;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[0]);
13648c2ecf20Sopenharmony_ci	pid = FIELD_GET(MT_TXS0_PID, txs);
13658c2ecf20Sopenharmony_ci	txs = le32_to_cpu(txs_data[2]);
13668c2ecf20Sopenharmony_ci	wcidx = FIELD_GET(MT_TXS2_WCID, txs);
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	if (pid == MT_PACKET_ID_NO_ACK)
13698c2ecf20Sopenharmony_ci		return;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	if (wcidx >= MT7615_WTBL_SIZE)
13728c2ecf20Sopenharmony_ci		return;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	rcu_read_lock();
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
13778c2ecf20Sopenharmony_ci	if (!wcid)
13788c2ecf20Sopenharmony_ci		goto out;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	msta = container_of(wcid, struct mt7615_sta, wcid);
13818c2ecf20Sopenharmony_ci	sta = wcid_to_sta(wcid);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->sta_poll_lock);
13848c2ecf20Sopenharmony_ci	if (list_empty(&msta->poll_list))
13858c2ecf20Sopenharmony_ci		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
13868c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->sta_poll_lock);
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
13898c2ecf20Sopenharmony_ci		goto out;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (wcidx >= MT7615_WTBL_STA || !sta)
13928c2ecf20Sopenharmony_ci		goto out;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (wcid->ext_phy && dev->mt76.phy2)
13958c2ecf20Sopenharmony_ci		mphy = dev->mt76.phy2;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	if (mt7615_fill_txs(dev, msta, &info, txs_data))
13988c2ecf20Sopenharmony_ci		ieee80211_tx_status_noskb(mphy->hw, sta, &info);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ciout:
14018c2ecf20Sopenharmony_ci	rcu_read_unlock();
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic void
14058c2ecf20Sopenharmony_cimt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
14088c2ecf20Sopenharmony_ci	struct mt76_txwi_cache *txwi;
14098c2ecf20Sopenharmony_ci	__le32 *txwi_data;
14108c2ecf20Sopenharmony_ci	u32 val;
14118c2ecf20Sopenharmony_ci	u8 wcid;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	trace_mac_tx_free(dev, token);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->token_lock);
14168c2ecf20Sopenharmony_ci	txwi = idr_remove(&dev->token, token);
14178c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->token_lock);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	if (!txwi)
14208c2ecf20Sopenharmony_ci		return;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
14238c2ecf20Sopenharmony_ci	val = le32_to_cpu(txwi_data[1]);
14248c2ecf20Sopenharmony_ci	wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	mt7615_txp_skb_unmap(mdev, txwi);
14278c2ecf20Sopenharmony_ci	if (txwi->skb) {
14288c2ecf20Sopenharmony_ci		mt76_tx_complete_skb(mdev, wcid, txwi->skb);
14298c2ecf20Sopenharmony_ci		txwi->skb = NULL;
14308c2ecf20Sopenharmony_ci	}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	mt76_put_txwi(mdev, txwi);
14338c2ecf20Sopenharmony_ci}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_cistatic void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
14388c2ecf20Sopenharmony_ci	u8 i, count;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
14418c2ecf20Sopenharmony_ci	if (is_mt7615(&dev->mt76)) {
14428c2ecf20Sopenharmony_ci		mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
14438c2ecf20Sopenharmony_ci	} else {
14448c2ecf20Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_ACS; i++)
14458c2ecf20Sopenharmony_ci			mt76_queue_tx_cleanup(dev, i, false);
14468c2ecf20Sopenharmony_ci	}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl));
14498c2ecf20Sopenharmony_ci	if (is_mt7615(&dev->mt76)) {
14508c2ecf20Sopenharmony_ci		__le16 *token = &free->token[0];
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++)
14538c2ecf20Sopenharmony_ci			mt7615_mac_tx_free_token(dev, le16_to_cpu(token[i]));
14548c2ecf20Sopenharmony_ci	} else {
14558c2ecf20Sopenharmony_ci		__le32 *token = (__le32 *)&free->token[0];
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++)
14588c2ecf20Sopenharmony_ci			mt7615_mac_tx_free_token(dev, le32_to_cpu(token[i]));
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	dev_kfree_skb(skb);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
14648c2ecf20Sopenharmony_ci		return;
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	rcu_read_lock();
14678c2ecf20Sopenharmony_ci	mt7615_mac_sta_poll(dev);
14688c2ecf20Sopenharmony_ci	rcu_read_unlock();
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	mt7615_pm_power_save_sched(dev);
14718c2ecf20Sopenharmony_ci	mt76_worker_schedule(&dev->mt76.tx_worker);
14728c2ecf20Sopenharmony_ci}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_civoid mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
14758c2ecf20Sopenharmony_ci			 struct sk_buff *skb)
14768c2ecf20Sopenharmony_ci{
14778c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
14788c2ecf20Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
14798c2ecf20Sopenharmony_ci	__le32 *end = (__le32 *)&skb->data[skb->len];
14808c2ecf20Sopenharmony_ci	enum rx_pkt_type type;
14818c2ecf20Sopenharmony_ci	u16 flag;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
14848c2ecf20Sopenharmony_ci	flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0]));
14858c2ecf20Sopenharmony_ci	if (type == PKT_TYPE_RX_EVENT && flag == 0x1)
14868c2ecf20Sopenharmony_ci		type = PKT_TYPE_NORMAL_MCU;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	switch (type) {
14898c2ecf20Sopenharmony_ci	case PKT_TYPE_TXS:
14908c2ecf20Sopenharmony_ci		for (rxd++; rxd + 7 <= end; rxd += 7)
14918c2ecf20Sopenharmony_ci			mt7615_mac_add_txs(dev, rxd);
14928c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
14938c2ecf20Sopenharmony_ci		break;
14948c2ecf20Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY:
14958c2ecf20Sopenharmony_ci		mt7615_mac_tx_free(dev, skb);
14968c2ecf20Sopenharmony_ci		break;
14978c2ecf20Sopenharmony_ci	case PKT_TYPE_RX_EVENT:
14988c2ecf20Sopenharmony_ci		mt7615_mcu_rx_event(dev, skb);
14998c2ecf20Sopenharmony_ci		break;
15008c2ecf20Sopenharmony_ci	case PKT_TYPE_NORMAL_MCU:
15018c2ecf20Sopenharmony_ci	case PKT_TYPE_NORMAL:
15028c2ecf20Sopenharmony_ci		if (!mt7615_mac_fill_rx(dev, skb)) {
15038c2ecf20Sopenharmony_ci			mt76_rx(&dev->mt76, q, skb);
15048c2ecf20Sopenharmony_ci			return;
15058c2ecf20Sopenharmony_ci		}
15068c2ecf20Sopenharmony_ci		fallthrough;
15078c2ecf20Sopenharmony_ci	default:
15088c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
15098c2ecf20Sopenharmony_ci		break;
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci}
15128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_queue_rx_skb);
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cistatic void
15158c2ecf20Sopenharmony_cimt7615_mac_set_sensitivity(struct mt7615_phy *phy, int val, bool ofdm)
15168c2ecf20Sopenharmony_ci{
15178c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
15188c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76)) {
15218c2ecf20Sopenharmony_ci		if (ofdm)
15228c2ecf20Sopenharmony_ci			mt76_rmw(dev, MT7663_WF_PHY_MIN_PRI_PWR(ext_phy),
15238c2ecf20Sopenharmony_ci				 MT_WF_PHY_PD_OFDM_MASK(0),
15248c2ecf20Sopenharmony_ci				 MT_WF_PHY_PD_OFDM(0, val));
15258c2ecf20Sopenharmony_ci		else
15268c2ecf20Sopenharmony_ci			mt76_rmw(dev, MT7663_WF_PHY_RXTD_CCK_PD(ext_phy),
15278c2ecf20Sopenharmony_ci				 MT_WF_PHY_PD_CCK_MASK(ext_phy),
15288c2ecf20Sopenharmony_ci				 MT_WF_PHY_PD_CCK(ext_phy, val));
15298c2ecf20Sopenharmony_ci		return;
15308c2ecf20Sopenharmony_ci	}
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	if (ofdm)
15338c2ecf20Sopenharmony_ci		mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy),
15348c2ecf20Sopenharmony_ci			 MT_WF_PHY_PD_OFDM_MASK(ext_phy),
15358c2ecf20Sopenharmony_ci			 MT_WF_PHY_PD_OFDM(ext_phy, val));
15368c2ecf20Sopenharmony_ci	else
15378c2ecf20Sopenharmony_ci		mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy),
15388c2ecf20Sopenharmony_ci			 MT_WF_PHY_PD_CCK_MASK(ext_phy),
15398c2ecf20Sopenharmony_ci			 MT_WF_PHY_PD_CCK(ext_phy, val));
15408c2ecf20Sopenharmony_ci}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_cistatic void
15438c2ecf20Sopenharmony_cimt7615_mac_set_default_sensitivity(struct mt7615_phy *phy)
15448c2ecf20Sopenharmony_ci{
15458c2ecf20Sopenharmony_ci	/* ofdm */
15468c2ecf20Sopenharmony_ci	mt7615_mac_set_sensitivity(phy, 0x13c, true);
15478c2ecf20Sopenharmony_ci	/* cck */
15488c2ecf20Sopenharmony_ci	mt7615_mac_set_sensitivity(phy, 0x92, false);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	phy->ofdm_sensitivity = -98;
15518c2ecf20Sopenharmony_ci	phy->cck_sensitivity = -110;
15528c2ecf20Sopenharmony_ci	phy->last_cca_adj = jiffies;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_civoid mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable)
15568c2ecf20Sopenharmony_ci{
15578c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
15588c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
15598c2ecf20Sopenharmony_ci	u32 reg, mask;
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	mt7615_mutex_acquire(dev);
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci	if (phy->scs_en == enable)
15648c2ecf20Sopenharmony_ci		goto out;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76)) {
15678c2ecf20Sopenharmony_ci		reg = MT7663_WF_PHY_MIN_PRI_PWR(ext_phy);
15688c2ecf20Sopenharmony_ci		mask = MT_WF_PHY_PD_BLK(0);
15698c2ecf20Sopenharmony_ci	} else {
15708c2ecf20Sopenharmony_ci		reg = MT_WF_PHY_MIN_PRI_PWR(ext_phy);
15718c2ecf20Sopenharmony_ci		mask = MT_WF_PHY_PD_BLK(ext_phy);
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	if (enable) {
15758c2ecf20Sopenharmony_ci		mt76_set(dev, reg, mask);
15768c2ecf20Sopenharmony_ci		if (is_mt7622(&dev->mt76)) {
15778c2ecf20Sopenharmony_ci			mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8);
15788c2ecf20Sopenharmony_ci			mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7);
15798c2ecf20Sopenharmony_ci		}
15808c2ecf20Sopenharmony_ci	} else {
15818c2ecf20Sopenharmony_ci		mt76_clear(dev, reg, mask);
15828c2ecf20Sopenharmony_ci	}
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	mt7615_mac_set_default_sensitivity(phy);
15858c2ecf20Sopenharmony_ci	phy->scs_en = enable;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ciout:
15888c2ecf20Sopenharmony_ci	mt7615_mutex_release(dev);
15898c2ecf20Sopenharmony_ci}
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_civoid mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy)
15928c2ecf20Sopenharmony_ci{
15938c2ecf20Sopenharmony_ci	u32 rxtd, reg;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76))
15968c2ecf20Sopenharmony_ci		reg = MT7663_WF_PHY_R0_PHYMUX_5;
15978c2ecf20Sopenharmony_ci	else
15988c2ecf20Sopenharmony_ci		reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	if (ext_phy)
16018c2ecf20Sopenharmony_ci		rxtd = MT_WF_PHY_RXTD2(10);
16028c2ecf20Sopenharmony_ci	else
16038c2ecf20Sopenharmony_ci		rxtd = MT_WF_PHY_RXTD(12);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	mt76_set(dev, rxtd, BIT(18) | BIT(29));
16068c2ecf20Sopenharmony_ci	mt76_set(dev, reg, 0x5 << 12);
16078c2ecf20Sopenharmony_ci}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_civoid mt7615_mac_cca_stats_reset(struct mt7615_phy *phy)
16108c2ecf20Sopenharmony_ci{
16118c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
16128c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
16138c2ecf20Sopenharmony_ci	u32 reg;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76))
16168c2ecf20Sopenharmony_ci		reg = MT7663_WF_PHY_R0_PHYMUX_5;
16178c2ecf20Sopenharmony_ci	else
16188c2ecf20Sopenharmony_ci		reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy);
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_ci	/* reset PD and MDRDY counters */
16218c2ecf20Sopenharmony_ci	mt76_clear(dev, reg, GENMASK(22, 20));
16228c2ecf20Sopenharmony_ci	mt76_set(dev, reg, BIT(22) | BIT(20));
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_cistatic void
16268c2ecf20Sopenharmony_cimt7615_mac_adjust_sensitivity(struct mt7615_phy *phy,
16278c2ecf20Sopenharmony_ci			      u32 rts_err_rate, bool ofdm)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
16308c2ecf20Sopenharmony_ci	int false_cca = ofdm ? phy->false_cca_ofdm : phy->false_cca_cck;
16318c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
16328c2ecf20Sopenharmony_ci	s16 def_th = ofdm ? -98 : -110;
16338c2ecf20Sopenharmony_ci	bool update = false;
16348c2ecf20Sopenharmony_ci	s8 *sensitivity;
16358c2ecf20Sopenharmony_ci	int signal;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	sensitivity = ofdm ? &phy->ofdm_sensitivity : &phy->cck_sensitivity;
16388c2ecf20Sopenharmony_ci	signal = mt76_get_min_avg_rssi(&dev->mt76, ext_phy);
16398c2ecf20Sopenharmony_ci	if (!signal) {
16408c2ecf20Sopenharmony_ci		mt7615_mac_set_default_sensitivity(phy);
16418c2ecf20Sopenharmony_ci		return;
16428c2ecf20Sopenharmony_ci	}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	signal = min(signal, -72);
16458c2ecf20Sopenharmony_ci	if (false_cca > 500) {
16468c2ecf20Sopenharmony_ci		if (rts_err_rate > MT_FRAC(40, 100))
16478c2ecf20Sopenharmony_ci			return;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		/* decrease coverage */
16508c2ecf20Sopenharmony_ci		if (*sensitivity == def_th && signal > -90) {
16518c2ecf20Sopenharmony_ci			*sensitivity = -90;
16528c2ecf20Sopenharmony_ci			update = true;
16538c2ecf20Sopenharmony_ci		} else if (*sensitivity + 2 < signal) {
16548c2ecf20Sopenharmony_ci			*sensitivity += 2;
16558c2ecf20Sopenharmony_ci			update = true;
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci	} else if ((false_cca > 0 && false_cca < 50) ||
16588c2ecf20Sopenharmony_ci		   rts_err_rate > MT_FRAC(60, 100)) {
16598c2ecf20Sopenharmony_ci		/* increase coverage */
16608c2ecf20Sopenharmony_ci		if (*sensitivity - 2 >= def_th) {
16618c2ecf20Sopenharmony_ci			*sensitivity -= 2;
16628c2ecf20Sopenharmony_ci			update = true;
16638c2ecf20Sopenharmony_ci		}
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	if (*sensitivity > signal) {
16678c2ecf20Sopenharmony_ci		*sensitivity = signal;
16688c2ecf20Sopenharmony_ci		update = true;
16698c2ecf20Sopenharmony_ci	}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	if (update) {
16728c2ecf20Sopenharmony_ci		u16 val = ofdm ? *sensitivity * 2 + 512 : *sensitivity + 256;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci		mt7615_mac_set_sensitivity(phy, val, ofdm);
16758c2ecf20Sopenharmony_ci		phy->last_cca_adj = jiffies;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci}
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_cistatic void
16808c2ecf20Sopenharmony_cimt7615_mac_scs_check(struct mt7615_phy *phy)
16818c2ecf20Sopenharmony_ci{
16828c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
16838c2ecf20Sopenharmony_ci	struct mib_stats *mib = &phy->mib;
16848c2ecf20Sopenharmony_ci	u32 val, rts_err_rate = 0;
16858c2ecf20Sopenharmony_ci	u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm;
16868c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	if (!phy->scs_en)
16898c2ecf20Sopenharmony_ci		return;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76))
16928c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS0(ext_phy));
16938c2ecf20Sopenharmony_ci	else
16948c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy));
16958c2ecf20Sopenharmony_ci	pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val);
16968c2ecf20Sopenharmony_ci	pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val);
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76))
16998c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS5(ext_phy));
17008c2ecf20Sopenharmony_ci	else
17018c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS5(ext_phy));
17028c2ecf20Sopenharmony_ci	mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val);
17038c2ecf20Sopenharmony_ci	mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val);
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	phy->false_cca_ofdm = pd_ofdm - mdrdy_ofdm;
17068c2ecf20Sopenharmony_ci	phy->false_cca_cck = pd_cck - mdrdy_cck;
17078c2ecf20Sopenharmony_ci	mt7615_mac_cca_stats_reset(phy);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	if (mib->rts_cnt + mib->rts_retries_cnt)
17108c2ecf20Sopenharmony_ci		rts_err_rate = MT_FRAC(mib->rts_retries_cnt,
17118c2ecf20Sopenharmony_ci				       mib->rts_cnt + mib->rts_retries_cnt);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	/* cck */
17148c2ecf20Sopenharmony_ci	mt7615_mac_adjust_sensitivity(phy, rts_err_rate, false);
17158c2ecf20Sopenharmony_ci	/* ofdm */
17168c2ecf20Sopenharmony_ci	mt7615_mac_adjust_sensitivity(phy, rts_err_rate, true);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	if (time_after(jiffies, phy->last_cca_adj + 10 * HZ))
17198c2ecf20Sopenharmony_ci		mt7615_mac_set_default_sensitivity(phy);
17208c2ecf20Sopenharmony_ci}
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_cistatic u8
17238c2ecf20Sopenharmony_cimt7615_phy_get_nf(struct mt7615_dev *dev, int idx)
17248c2ecf20Sopenharmony_ci{
17258c2ecf20Sopenharmony_ci	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
17268c2ecf20Sopenharmony_ci	u32 reg, val, sum = 0, n = 0;
17278c2ecf20Sopenharmony_ci	int i;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76))
17308c2ecf20Sopenharmony_ci		reg = MT7663_WF_PHY_RXTD(20);
17318c2ecf20Sopenharmony_ci	else
17328c2ecf20Sopenharmony_ci		reg = idx ? MT_WF_PHY_RXTD2(17) : MT_WF_PHY_RXTD(20);
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
17358c2ecf20Sopenharmony_ci		val = mt76_rr(dev, reg);
17368c2ecf20Sopenharmony_ci		sum += val * nf_power[i];
17378c2ecf20Sopenharmony_ci		n += val;
17388c2ecf20Sopenharmony_ci	}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	if (!n)
17418c2ecf20Sopenharmony_ci		return 0;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	return sum / n;
17448c2ecf20Sopenharmony_ci}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_cistatic void
17478c2ecf20Sopenharmony_cimt7615_phy_update_channel(struct mt76_phy *mphy, int idx)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76);
17508c2ecf20Sopenharmony_ci	struct mt7615_phy *phy = mphy->priv;
17518c2ecf20Sopenharmony_ci	struct mt76_channel_state *state;
17528c2ecf20Sopenharmony_ci	u64 busy_time, tx_time, rx_time, obss_time;
17538c2ecf20Sopenharmony_ci	u32 obss_reg = idx ? MT_WF_RMAC_MIB_TIME6 : MT_WF_RMAC_MIB_TIME5;
17548c2ecf20Sopenharmony_ci	int nf;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
17578c2ecf20Sopenharmony_ci				   MT_MIB_SDR9_BUSY_MASK);
17588c2ecf20Sopenharmony_ci	tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
17598c2ecf20Sopenharmony_ci				 MT_MIB_SDR36_TXTIME_MASK);
17608c2ecf20Sopenharmony_ci	rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
17618c2ecf20Sopenharmony_ci				 MT_MIB_SDR37_RXTIME_MASK);
17628c2ecf20Sopenharmony_ci	obss_time = mt76_get_field(dev, obss_reg, MT_MIB_OBSSTIME_MASK);
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	nf = mt7615_phy_get_nf(dev, idx);
17658c2ecf20Sopenharmony_ci	if (!phy->noise)
17668c2ecf20Sopenharmony_ci		phy->noise = nf << 4;
17678c2ecf20Sopenharmony_ci	else if (nf)
17688c2ecf20Sopenharmony_ci		phy->noise += nf - (phy->noise >> 4);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	state = mphy->chan_state;
17718c2ecf20Sopenharmony_ci	state->cc_busy += busy_time;
17728c2ecf20Sopenharmony_ci	state->cc_tx += tx_time;
17738c2ecf20Sopenharmony_ci	state->cc_rx += rx_time + obss_time;
17748c2ecf20Sopenharmony_ci	state->cc_bss_rx += rx_time;
17758c2ecf20Sopenharmony_ci	state->noise = -(phy->noise >> 4);
17768c2ecf20Sopenharmony_ci}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_cistatic void __mt7615_update_channel(struct mt7615_dev *dev)
17798c2ecf20Sopenharmony_ci{
17808c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	mt7615_phy_update_channel(&mdev->phy, 0);
17838c2ecf20Sopenharmony_ci	if (mdev->phy2)
17848c2ecf20Sopenharmony_ci		mt7615_phy_update_channel(mdev->phy2, 1);
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	/* reset obss airtime */
17878c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
17888c2ecf20Sopenharmony_ci}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_civoid mt7615_update_channel(struct mt76_dev *mdev)
17918c2ecf20Sopenharmony_ci{
17928c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_ci	if (mt7615_pm_wake(dev))
17958c2ecf20Sopenharmony_ci		return;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	__mt7615_update_channel(dev);
17988c2ecf20Sopenharmony_ci	mt7615_pm_power_save_sched(dev);
17998c2ecf20Sopenharmony_ci}
18008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_update_channel);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_cistatic void mt7615_update_survey(struct mt7615_dev *dev)
18038c2ecf20Sopenharmony_ci{
18048c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
18058c2ecf20Sopenharmony_ci	ktime_t cur_time;
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	__mt7615_update_channel(dev);
18088c2ecf20Sopenharmony_ci	cur_time = ktime_get_boottime();
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	mt76_update_survey_active_time(&mdev->phy, cur_time);
18118c2ecf20Sopenharmony_ci	if (mdev->phy2)
18128c2ecf20Sopenharmony_ci		mt76_update_survey_active_time(mdev->phy2, cur_time);
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_cistatic void
18168c2ecf20Sopenharmony_cimt7615_mac_update_mib_stats(struct mt7615_phy *phy)
18178c2ecf20Sopenharmony_ci{
18188c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
18198c2ecf20Sopenharmony_ci	struct mib_stats *mib = &phy->mib;
18208c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
18218c2ecf20Sopenharmony_ci	int i, aggr;
18228c2ecf20Sopenharmony_ci	u32 val, val2;
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci	mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(ext_phy),
18258c2ecf20Sopenharmony_ci					   MT_MIB_SDR3_FCS_ERR_MASK);
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	val = mt76_get_field(dev, MT_MIB_SDR14(ext_phy),
18288c2ecf20Sopenharmony_ci			     MT_MIB_AMPDU_MPDU_COUNT);
18298c2ecf20Sopenharmony_ci	if (val) {
18308c2ecf20Sopenharmony_ci		val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy),
18318c2ecf20Sopenharmony_ci				      MT_MIB_AMPDU_ACK_COUNT);
18328c2ecf20Sopenharmony_ci		mib->aggr_per = 1000 * (val - val2) / val;
18338c2ecf20Sopenharmony_ci	}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	aggr = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
18368c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
18378c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i));
18388c2ecf20Sopenharmony_ci		mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val);
18398c2ecf20Sopenharmony_ci		mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK,
18408c2ecf20Sopenharmony_ci					       val);
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i));
18438c2ecf20Sopenharmony_ci		mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val);
18448c2ecf20Sopenharmony_ci		mib->rts_retries_cnt += FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK,
18458c2ecf20Sopenharmony_ci						  val);
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci		val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i));
18488c2ecf20Sopenharmony_ci		dev->mt76.aggr_stats[aggr++] += val & 0xffff;
18498c2ecf20Sopenharmony_ci		dev->mt76.aggr_stats[aggr++] += val >> 16;
18508c2ecf20Sopenharmony_ci	}
18518c2ecf20Sopenharmony_ci}
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_civoid mt7615_pm_wake_work(struct work_struct *work)
18548c2ecf20Sopenharmony_ci{
18558c2ecf20Sopenharmony_ci	struct mt7615_dev *dev;
18568c2ecf20Sopenharmony_ci	struct mt76_phy *mphy;
18578c2ecf20Sopenharmony_ci	int i;
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_ci	dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
18608c2ecf20Sopenharmony_ci						pm.wake_work);
18618c2ecf20Sopenharmony_ci	mphy = dev->phy.mt76;
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	if (mt7615_mcu_set_drv_ctrl(dev)) {
18648c2ecf20Sopenharmony_ci		dev_err(mphy->dev->dev, "failed to wake device\n");
18658c2ecf20Sopenharmony_ci		goto out;
18668c2ecf20Sopenharmony_ci	}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->pm.txq_lock);
18698c2ecf20Sopenharmony_ci	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
18708c2ecf20Sopenharmony_ci		struct mt7615_sta *msta = dev->pm.tx_q[i].msta;
18718c2ecf20Sopenharmony_ci		struct ieee80211_sta *sta = NULL;
18728c2ecf20Sopenharmony_ci		struct mt76_wcid *wcid;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci		if (!dev->pm.tx_q[i].skb)
18758c2ecf20Sopenharmony_ci			continue;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci		wcid = msta ? &msta->wcid : &dev->mt76.global_wcid;
18788c2ecf20Sopenharmony_ci		if (msta && wcid->sta)
18798c2ecf20Sopenharmony_ci			sta = container_of((void *)msta, struct ieee80211_sta,
18808c2ecf20Sopenharmony_ci					   drv_priv);
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci		mt76_tx(mphy, sta, wcid, dev->pm.tx_q[i].skb);
18838c2ecf20Sopenharmony_ci		dev->pm.tx_q[i].skb = NULL;
18848c2ecf20Sopenharmony_ci	}
18858c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->pm.txq_lock);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	mt76_worker_schedule(&dev->mt76.tx_worker);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ciout:
18908c2ecf20Sopenharmony_ci	ieee80211_wake_queues(mphy->hw);
18918c2ecf20Sopenharmony_ci	complete_all(&dev->pm.wake_cmpl);
18928c2ecf20Sopenharmony_ci}
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ciint mt7615_pm_wake(struct mt7615_dev *dev)
18958c2ecf20Sopenharmony_ci{
18968c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = dev->phy.mt76;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (!mt7615_firmware_offload(dev))
18998c2ecf20Sopenharmony_ci		return 0;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	if (!mt76_is_mmio(mphy->dev))
19028c2ecf20Sopenharmony_ci		return 0;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_PM, &mphy->state))
19058c2ecf20Sopenharmony_ci		return 0;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
19088c2ecf20Sopenharmony_ci	    test_bit(MT76_HW_SCHED_SCANNING, &mphy->state))
19098c2ecf20Sopenharmony_ci		return 0;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	if (queue_work(dev->mt76.wq, &dev->pm.wake_work))
19128c2ecf20Sopenharmony_ci		reinit_completion(&dev->pm.wake_cmpl);
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) {
19158c2ecf20Sopenharmony_ci		ieee80211_wake_queues(mphy->hw);
19168c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
19178c2ecf20Sopenharmony_ci	}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	return 0;
19208c2ecf20Sopenharmony_ci}
19218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_pm_wake);
19228c2ecf20Sopenharmony_ci
19238c2ecf20Sopenharmony_civoid mt7615_pm_power_save_sched(struct mt7615_dev *dev)
19248c2ecf20Sopenharmony_ci{
19258c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = dev->phy.mt76;
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	if (!mt7615_firmware_offload(dev))
19288c2ecf20Sopenharmony_ci		return;
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	if (!mt76_is_mmio(mphy->dev))
19318c2ecf20Sopenharmony_ci		return;
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	if (!dev->pm.enable || !test_bit(MT76_STATE_RUNNING, &mphy->state))
19348c2ecf20Sopenharmony_ci		return;
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	dev->pm.last_activity = jiffies;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci	if (test_bit(MT76_HW_SCANNING, &mphy->state) ||
19398c2ecf20Sopenharmony_ci	    test_bit(MT76_HW_SCHED_SCANNING, &mphy->state))
19408c2ecf20Sopenharmony_ci		return;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_PM, &mphy->state))
19438c2ecf20Sopenharmony_ci		queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work,
19448c2ecf20Sopenharmony_ci				   dev->pm.idle_timeout);
19458c2ecf20Sopenharmony_ci}
19468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_civoid mt7615_pm_power_save_work(struct work_struct *work)
19498c2ecf20Sopenharmony_ci{
19508c2ecf20Sopenharmony_ci	struct mt7615_dev *dev;
19518c2ecf20Sopenharmony_ci	unsigned long delta;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
19548c2ecf20Sopenharmony_ci						pm.ps_work.work);
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	delta = dev->pm.idle_timeout;
19578c2ecf20Sopenharmony_ci	if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
19588c2ecf20Sopenharmony_ci		delta = dev->pm.last_activity + delta - jiffies;
19598c2ecf20Sopenharmony_ci		goto out;
19608c2ecf20Sopenharmony_ci	}
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	if (!mt7615_mcu_set_fw_ctrl(dev))
19638c2ecf20Sopenharmony_ci		return;
19648c2ecf20Sopenharmony_ciout:
19658c2ecf20Sopenharmony_ci	queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
19668c2ecf20Sopenharmony_ci}
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_cistatic void
19698c2ecf20Sopenharmony_cimt7615_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
19708c2ecf20Sopenharmony_ci{
19718c2ecf20Sopenharmony_ci	struct mt7615_phy *phy = priv;
19728c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
19738c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	if (mt7615_mcu_set_bss_pm(dev, vif, dev->pm.enable))
19768c2ecf20Sopenharmony_ci		return;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (dev->pm.enable) {
19798c2ecf20Sopenharmony_ci		vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
19808c2ecf20Sopenharmony_ci		mt76_set(dev, MT_WF_RFCR(ext_phy),
19818c2ecf20Sopenharmony_ci			 MT_WF_RFCR_DROP_OTHER_BEACON);
19828c2ecf20Sopenharmony_ci	} else {
19838c2ecf20Sopenharmony_ci		vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
19848c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_WF_RFCR(ext_phy),
19858c2ecf20Sopenharmony_ci			   MT_WF_RFCR_DROP_OTHER_BEACON);
19868c2ecf20Sopenharmony_ci	}
19878c2ecf20Sopenharmony_ci}
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ciint mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	struct mt76_phy *mphy = dev->phy.mt76;
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci	if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
19948c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	mt7615_mutex_acquire(dev);
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	if (dev->pm.enable == enable)
19998c2ecf20Sopenharmony_ci		goto out;
20008c2ecf20Sopenharmony_ci
20018c2ecf20Sopenharmony_ci	dev->pm.enable = enable;
20028c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces(mphy->hw,
20038c2ecf20Sopenharmony_ci					    IEEE80211_IFACE_ITER_RESUME_ALL,
20048c2ecf20Sopenharmony_ci					    mt7615_pm_interface_iter, mphy->priv);
20058c2ecf20Sopenharmony_ciout:
20068c2ecf20Sopenharmony_ci	mt7615_mutex_release(dev);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	return 0;
20098c2ecf20Sopenharmony_ci}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_civoid mt7615_mac_work(struct work_struct *work)
20128c2ecf20Sopenharmony_ci{
20138c2ecf20Sopenharmony_ci	struct mt7615_phy *phy;
20148c2ecf20Sopenharmony_ci	struct mt76_dev *mdev;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	phy = (struct mt7615_phy *)container_of(work, struct mt7615_phy,
20178c2ecf20Sopenharmony_ci						mac_work.work);
20188c2ecf20Sopenharmony_ci	mdev = &phy->dev->mt76;
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	mt7615_mutex_acquire(phy->dev);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	mt7615_update_survey(phy->dev);
20238c2ecf20Sopenharmony_ci	if (++phy->mac_work_count == 5) {
20248c2ecf20Sopenharmony_ci		phy->mac_work_count = 0;
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci		mt7615_mac_update_mib_stats(phy);
20278c2ecf20Sopenharmony_ci		mt7615_mac_scs_check(phy);
20288c2ecf20Sopenharmony_ci	}
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	mt7615_mutex_release(phy->dev);
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	mt76_tx_status_check(mdev, NULL, false);
20338c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
20348c2ecf20Sopenharmony_ci				     MT7615_WATCHDOG_TIME);
20358c2ecf20Sopenharmony_ci}
20368c2ecf20Sopenharmony_ci
20378c2ecf20Sopenharmony_cistatic bool
20388c2ecf20Sopenharmony_cimt7615_wait_reset_state(struct mt7615_dev *dev, u32 state)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	bool ret;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	ret = wait_event_timeout(dev->reset_wait,
20438c2ecf20Sopenharmony_ci				 (READ_ONCE(dev->reset_state) & state),
20448c2ecf20Sopenharmony_ci				 MT7615_RESET_TIMEOUT);
20458c2ecf20Sopenharmony_ci	WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
20468c2ecf20Sopenharmony_ci	return ret;
20478c2ecf20Sopenharmony_ci}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_cistatic void
20508c2ecf20Sopenharmony_cimt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
20518c2ecf20Sopenharmony_ci{
20528c2ecf20Sopenharmony_ci	struct ieee80211_hw *hw = priv;
20538c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = mt7615_hw_dev(hw);
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	mt7615_mcu_add_beacon(dev, hw, vif, vif->bss_conf.enable_beacon);
20568c2ecf20Sopenharmony_ci}
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_cistatic void
20598c2ecf20Sopenharmony_cimt7615_update_beacons(struct mt7615_dev *dev)
20608c2ecf20Sopenharmony_ci{
20618c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces(dev->mt76.hw,
20628c2ecf20Sopenharmony_ci		IEEE80211_IFACE_ITER_RESUME_ALL,
20638c2ecf20Sopenharmony_ci		mt7615_update_vif_beacon, dev->mt76.hw);
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	if (!dev->mt76.phy2)
20668c2ecf20Sopenharmony_ci		return;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	ieee80211_iterate_active_interfaces(dev->mt76.phy2->hw,
20698c2ecf20Sopenharmony_ci		IEEE80211_IFACE_ITER_RESUME_ALL,
20708c2ecf20Sopenharmony_ci		mt7615_update_vif_beacon, dev->mt76.phy2->hw);
20718c2ecf20Sopenharmony_ci}
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_civoid mt7615_dma_reset(struct mt7615_dev *dev)
20748c2ecf20Sopenharmony_ci{
20758c2ecf20Sopenharmony_ci	int i;
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	mt76_clear(dev, MT_WPDMA_GLO_CFG,
20788c2ecf20Sopenharmony_ci		   MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN |
20798c2ecf20Sopenharmony_ci		   MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
20808c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	for (i = 0; i < __MT_TXQ_MAX; i++)
20838c2ecf20Sopenharmony_ci		mt76_queue_tx_cleanup(dev, i, true);
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	mt76_for_each_q_rx(&dev->mt76, i) {
20868c2ecf20Sopenharmony_ci		mt76_queue_rx_reset(dev, i);
20878c2ecf20Sopenharmony_ci	}
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	mt76_set(dev, MT_WPDMA_GLO_CFG,
20908c2ecf20Sopenharmony_ci		 MT_WPDMA_GLO_CFG_RX_DMA_EN | MT_WPDMA_GLO_CFG_TX_DMA_EN |
20918c2ecf20Sopenharmony_ci		 MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
20928c2ecf20Sopenharmony_ci}
20938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_dma_reset);
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_civoid mt7615_tx_token_put(struct mt7615_dev *dev)
20968c2ecf20Sopenharmony_ci{
20978c2ecf20Sopenharmony_ci	struct mt76_txwi_cache *txwi;
20988c2ecf20Sopenharmony_ci	int id;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->token_lock);
21018c2ecf20Sopenharmony_ci	idr_for_each_entry(&dev->token, txwi, id) {
21028c2ecf20Sopenharmony_ci		mt7615_txp_skb_unmap(&dev->mt76, txwi);
21038c2ecf20Sopenharmony_ci		if (txwi->skb) {
21048c2ecf20Sopenharmony_ci			struct ieee80211_hw *hw;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci			hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
21078c2ecf20Sopenharmony_ci			ieee80211_free_txskb(hw, txwi->skb);
21088c2ecf20Sopenharmony_ci		}
21098c2ecf20Sopenharmony_ci		mt76_put_txwi(&dev->mt76, txwi);
21108c2ecf20Sopenharmony_ci	}
21118c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->token_lock);
21128c2ecf20Sopenharmony_ci	idr_destroy(&dev->token);
21138c2ecf20Sopenharmony_ci}
21148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_tx_token_put);
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_civoid mt7615_mac_reset_work(struct work_struct *work)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	struct mt7615_phy *phy2;
21198c2ecf20Sopenharmony_ci	struct mt76_phy *ext_phy;
21208c2ecf20Sopenharmony_ci	struct mt7615_dev *dev;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	dev = container_of(work, struct mt7615_dev, reset_work);
21238c2ecf20Sopenharmony_ci	ext_phy = dev->mt76.phy2;
21248c2ecf20Sopenharmony_ci	phy2 = ext_phy ? ext_phy->priv : NULL;
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_ci	if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_PDMA))
21278c2ecf20Sopenharmony_ci		return;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	ieee80211_stop_queues(mt76_hw(dev));
21308c2ecf20Sopenharmony_ci	if (ext_phy)
21318c2ecf20Sopenharmony_ci		ieee80211_stop_queues(ext_phy->hw);
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	set_bit(MT76_RESET, &dev->mphy.state);
21348c2ecf20Sopenharmony_ci	set_bit(MT76_MCU_RESET, &dev->mphy.state);
21358c2ecf20Sopenharmony_ci	wake_up(&dev->mt76.mcu.wait);
21368c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&dev->phy.mac_work);
21378c2ecf20Sopenharmony_ci	del_timer_sync(&dev->phy.roc_timer);
21388c2ecf20Sopenharmony_ci	cancel_work_sync(&dev->phy.roc_work);
21398c2ecf20Sopenharmony_ci	if (phy2) {
21408c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&phy2->mac_work);
21418c2ecf20Sopenharmony_ci		del_timer_sync(&phy2->roc_timer);
21428c2ecf20Sopenharmony_ci		cancel_work_sync(&phy2->roc_work);
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	/* lock/unlock all queues to ensure that no tx is pending */
21468c2ecf20Sopenharmony_ci	mt76_txq_schedule_all(&dev->mphy);
21478c2ecf20Sopenharmony_ci	if (ext_phy)
21488c2ecf20Sopenharmony_ci		mt76_txq_schedule_all(ext_phy);
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci	mt76_worker_disable(&dev->mt76.tx_worker);
21518c2ecf20Sopenharmony_ci	napi_disable(&dev->mt76.napi[0]);
21528c2ecf20Sopenharmony_ci	napi_disable(&dev->mt76.napi[1]);
21538c2ecf20Sopenharmony_ci	napi_disable(&dev->mt76.tx_napi);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci	mt7615_mutex_acquire(dev);
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_STOPPED);
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci	mt7615_tx_token_put(dev);
21608c2ecf20Sopenharmony_ci	idr_init(&dev->token);
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	if (mt7615_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
21638c2ecf20Sopenharmony_ci		mt7615_dma_reset(dev);
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_WPDMA_MEM_RNG_ERR, 0);
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_INIT);
21688c2ecf20Sopenharmony_ci		mt7615_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
21698c2ecf20Sopenharmony_ci	}
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
21728c2ecf20Sopenharmony_ci	clear_bit(MT76_RESET, &dev->mphy.state);
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	mt76_worker_enable(&dev->mt76.tx_worker);
21758c2ecf20Sopenharmony_ci	napi_enable(&dev->mt76.tx_napi);
21768c2ecf20Sopenharmony_ci	napi_schedule(&dev->mt76.tx_napi);
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	napi_enable(&dev->mt76.napi[0]);
21798c2ecf20Sopenharmony_ci	napi_schedule(&dev->mt76.napi[0]);
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	napi_enable(&dev->mt76.napi[1]);
21828c2ecf20Sopenharmony_ci	napi_schedule(&dev->mt76.napi[1]);
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	ieee80211_wake_queues(mt76_hw(dev));
21858c2ecf20Sopenharmony_ci	if (ext_phy)
21868c2ecf20Sopenharmony_ci		ieee80211_wake_queues(ext_phy->hw);
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
21898c2ecf20Sopenharmony_ci	mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci	mt7615_update_beacons(dev);
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	mt7615_mutex_release(dev);
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work,
21968c2ecf20Sopenharmony_ci				     MT7615_WATCHDOG_TIME);
21978c2ecf20Sopenharmony_ci	if (phy2)
21988c2ecf20Sopenharmony_ci		ieee80211_queue_delayed_work(ext_phy->hw, &phy2->mac_work,
21998c2ecf20Sopenharmony_ci					     MT7615_WATCHDOG_TIME);
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci}
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_cistatic void mt7615_dfs_stop_radar_detector(struct mt7615_phy *phy)
22048c2ecf20Sopenharmony_ci{
22058c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	if (phy->rdd_state & BIT(0))
22088c2ecf20Sopenharmony_ci		mt7615_mcu_rdd_cmd(dev, RDD_STOP, 0, MT_RX_SEL0, 0);
22098c2ecf20Sopenharmony_ci	if (phy->rdd_state & BIT(1))
22108c2ecf20Sopenharmony_ci		mt7615_mcu_rdd_cmd(dev, RDD_STOP, 1, MT_RX_SEL0, 0);
22118c2ecf20Sopenharmony_ci}
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_cistatic int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain)
22148c2ecf20Sopenharmony_ci{
22158c2ecf20Sopenharmony_ci	int err;
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_ci	err = mt7615_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0);
22188c2ecf20Sopenharmony_ci	if (err < 0)
22198c2ecf20Sopenharmony_ci		return err;
22208c2ecf20Sopenharmony_ci
22218c2ecf20Sopenharmony_ci	return mt7615_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
22228c2ecf20Sopenharmony_ci				  MT_RX_SEL0, 1);
22238c2ecf20Sopenharmony_ci}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_cistatic int mt7615_dfs_start_radar_detector(struct mt7615_phy *phy)
22268c2ecf20Sopenharmony_ci{
22278c2ecf20Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
22288c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
22298c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
22308c2ecf20Sopenharmony_ci	int err;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	/* start CAC */
22338c2ecf20Sopenharmony_ci	err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_START, ext_phy, MT_RX_SEL0, 0);
22348c2ecf20Sopenharmony_ci	if (err < 0)
22358c2ecf20Sopenharmony_ci		return err;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	err = mt7615_dfs_start_rdd(dev, ext_phy);
22388c2ecf20Sopenharmony_ci	if (err < 0)
22398c2ecf20Sopenharmony_ci		return err;
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	phy->rdd_state |= BIT(ext_phy);
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
22448c2ecf20Sopenharmony_ci	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
22458c2ecf20Sopenharmony_ci		err = mt7615_dfs_start_rdd(dev, 1);
22468c2ecf20Sopenharmony_ci		if (err < 0)
22478c2ecf20Sopenharmony_ci			return err;
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci		phy->rdd_state |= BIT(1);
22508c2ecf20Sopenharmony_ci	}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_ci	return 0;
22538c2ecf20Sopenharmony_ci}
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_cistatic int
22568c2ecf20Sopenharmony_cimt7615_dfs_init_radar_specs(struct mt7615_phy *phy)
22578c2ecf20Sopenharmony_ci{
22588c2ecf20Sopenharmony_ci	const struct mt7615_dfs_radar_spec *radar_specs;
22598c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
22608c2ecf20Sopenharmony_ci	int err, i;
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_ci	switch (dev->mt76.region) {
22638c2ecf20Sopenharmony_ci	case NL80211_DFS_FCC:
22648c2ecf20Sopenharmony_ci		radar_specs = &fcc_radar_specs;
22658c2ecf20Sopenharmony_ci		err = mt7615_mcu_set_fcc5_lpn(dev, 8);
22668c2ecf20Sopenharmony_ci		if (err < 0)
22678c2ecf20Sopenharmony_ci			return err;
22688c2ecf20Sopenharmony_ci		break;
22698c2ecf20Sopenharmony_ci	case NL80211_DFS_ETSI:
22708c2ecf20Sopenharmony_ci		radar_specs = &etsi_radar_specs;
22718c2ecf20Sopenharmony_ci		break;
22728c2ecf20Sopenharmony_ci	case NL80211_DFS_JP:
22738c2ecf20Sopenharmony_ci		radar_specs = &jp_radar_specs;
22748c2ecf20Sopenharmony_ci		break;
22758c2ecf20Sopenharmony_ci	default:
22768c2ecf20Sopenharmony_ci		return -EINVAL;
22778c2ecf20Sopenharmony_ci	}
22788c2ecf20Sopenharmony_ci
22798c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
22808c2ecf20Sopenharmony_ci		err = mt7615_mcu_set_radar_th(dev, i,
22818c2ecf20Sopenharmony_ci					      &radar_specs->radar_pattern[i]);
22828c2ecf20Sopenharmony_ci		if (err < 0)
22838c2ecf20Sopenharmony_ci			return err;
22848c2ecf20Sopenharmony_ci	}
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_ci	return mt7615_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
22878c2ecf20Sopenharmony_ci}
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ciint mt7615_dfs_init_radar_detector(struct mt7615_phy *phy)
22908c2ecf20Sopenharmony_ci{
22918c2ecf20Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
22928c2ecf20Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
22938c2ecf20Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
22948c2ecf20Sopenharmony_ci	int err;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	if (is_mt7663(&dev->mt76))
22978c2ecf20Sopenharmony_ci		return 0;
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	if (dev->mt76.region == NL80211_DFS_UNSET) {
23008c2ecf20Sopenharmony_ci		phy->dfs_state = -1;
23018c2ecf20Sopenharmony_ci		if (phy->rdd_state)
23028c2ecf20Sopenharmony_ci			goto stop;
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci		return 0;
23058c2ecf20Sopenharmony_ci	}
23068c2ecf20Sopenharmony_ci
23078c2ecf20Sopenharmony_ci	if (test_bit(MT76_SCANNING, &phy->mt76->state))
23088c2ecf20Sopenharmony_ci		return 0;
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	if (phy->dfs_state == chandef->chan->dfs_state)
23118c2ecf20Sopenharmony_ci		return 0;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	err = mt7615_dfs_init_radar_specs(phy);
23148c2ecf20Sopenharmony_ci	if (err < 0) {
23158c2ecf20Sopenharmony_ci		phy->dfs_state = -1;
23168c2ecf20Sopenharmony_ci		goto stop;
23178c2ecf20Sopenharmony_ci	}
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci	phy->dfs_state = chandef->chan->dfs_state;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
23228c2ecf20Sopenharmony_ci		if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
23238c2ecf20Sopenharmony_ci			return mt7615_dfs_start_radar_detector(phy);
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci		return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, ext_phy,
23268c2ecf20Sopenharmony_ci					  MT_RX_SEL0, 0);
23278c2ecf20Sopenharmony_ci	}
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_cistop:
23308c2ecf20Sopenharmony_ci	err = mt7615_mcu_rdd_cmd(dev, RDD_NORMAL_START, ext_phy, MT_RX_SEL0, 0);
23318c2ecf20Sopenharmony_ci	if (err < 0)
23328c2ecf20Sopenharmony_ci		return err;
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci	mt7615_dfs_stop_radar_detector(phy);
23358c2ecf20Sopenharmony_ci	return 0;
23368c2ecf20Sopenharmony_ci}
2337