18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
48c2ecf20Sopenharmony_ci * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "mt76x02.h"
88c2ecf20Sopenharmony_ci#include "mt76x02_trace.h"
98c2ecf20Sopenharmony_ci#include "trace.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_civoid mt76x02_mac_reset_counters(struct mt76x02_dev *dev)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	int i;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_RX_STAT_0);
168c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_RX_STAT_1);
178c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_RX_STAT_2);
188c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_TX_STA_0);
198c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_TX_STA_1);
208c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_TX_STA_2);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
238c2ecf20Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(i));
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
268c2ecf20Sopenharmony_ci		mt76_rr(dev, MT_TX_STAT_FIFO);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic enum mt76x02_cipher_type
338c2ecf20Sopenharmony_cimt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	memset(key_data, 0, 32);
368c2ecf20Sopenharmony_ci	if (!key)
378c2ecf20Sopenharmony_ci		return MT_CIPHER_NONE;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (key->keylen > 32)
408c2ecf20Sopenharmony_ci		return MT_CIPHER_NONE;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	memcpy(key_data, key->key, key->keylen);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	switch (key->cipher) {
458c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
468c2ecf20Sopenharmony_ci		return MT_CIPHER_WEP40;
478c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
488c2ecf20Sopenharmony_ci		return MT_CIPHER_WEP104;
498c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
508c2ecf20Sopenharmony_ci		return MT_CIPHER_TKIP;
518c2ecf20Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
528c2ecf20Sopenharmony_ci		return MT_CIPHER_AES_CCMP;
538c2ecf20Sopenharmony_ci	default:
548c2ecf20Sopenharmony_ci		return MT_CIPHER_NONE;
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ciint mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
598c2ecf20Sopenharmony_ci				 u8 key_idx, struct ieee80211_key_conf *key)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	enum mt76x02_cipher_type cipher;
628c2ecf20Sopenharmony_ci	u8 key_data[32];
638c2ecf20Sopenharmony_ci	u32 val;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	cipher = mt76x02_mac_get_key_info(key, key_data);
668c2ecf20Sopenharmony_ci	if (cipher == MT_CIPHER_NONE && key)
678c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
708c2ecf20Sopenharmony_ci	val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
718c2ecf20Sopenharmony_ci	val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
728c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data,
758c2ecf20Sopenharmony_ci		     sizeof(key_data));
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_civoid mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx,
828c2ecf20Sopenharmony_ci			      struct ieee80211_key_conf *key)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	enum mt76x02_cipher_type cipher;
858c2ecf20Sopenharmony_ci	u8 key_data[32];
868c2ecf20Sopenharmony_ci	u32 iv, eiv;
878c2ecf20Sopenharmony_ci	u64 pn;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	cipher = mt76x02_mac_get_key_info(key, key_data);
908c2ecf20Sopenharmony_ci	iv = mt76_rr(dev, MT_WCID_IV(idx));
918c2ecf20Sopenharmony_ci	eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	pn = (u64)eiv << 16;
948c2ecf20Sopenharmony_ci	if (cipher == MT_CIPHER_TKIP) {
958c2ecf20Sopenharmony_ci		pn |= (iv >> 16) & 0xff;
968c2ecf20Sopenharmony_ci		pn |= (iv & 0xff) << 8;
978c2ecf20Sopenharmony_ci	} else if (cipher >= MT_CIPHER_AES_CCMP) {
988c2ecf20Sopenharmony_ci		pn |= iv & 0xffff;
998c2ecf20Sopenharmony_ci	} else {
1008c2ecf20Sopenharmony_ci		return;
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	atomic64_set(&key->tx_pn, pn);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciint mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx,
1078c2ecf20Sopenharmony_ci			     struct ieee80211_key_conf *key)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	enum mt76x02_cipher_type cipher;
1108c2ecf20Sopenharmony_ci	u8 key_data[32];
1118c2ecf20Sopenharmony_ci	u8 iv_data[8];
1128c2ecf20Sopenharmony_ci	u64 pn;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	cipher = mt76x02_mac_get_key_info(key, key_data);
1158c2ecf20Sopenharmony_ci	if (cipher == MT_CIPHER_NONE && key)
1168c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
1198c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	memset(iv_data, 0, sizeof(iv_data));
1228c2ecf20Sopenharmony_ci	if (key) {
1238c2ecf20Sopenharmony_ci		mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE,
1248c2ecf20Sopenharmony_ci			       !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE));
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		pn = atomic64_read(&key->tx_pn);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		iv_data[3] = key->keyidx << 6;
1298c2ecf20Sopenharmony_ci		if (cipher >= MT_CIPHER_TKIP) {
1308c2ecf20Sopenharmony_ci			iv_data[3] |= 0x20;
1318c2ecf20Sopenharmony_ci			put_unaligned_le32(pn >> 16, &iv_data[4]);
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		if (cipher == MT_CIPHER_TKIP) {
1358c2ecf20Sopenharmony_ci			iv_data[0] = (pn >> 8) & 0xff;
1368c2ecf20Sopenharmony_ci			iv_data[1] = (iv_data[0] | 0x20) & 0x7f;
1378c2ecf20Sopenharmony_ci			iv_data[2] = pn & 0xff;
1388c2ecf20Sopenharmony_ci		} else if (cipher >= MT_CIPHER_AES_CCMP) {
1398c2ecf20Sopenharmony_ci			put_unaligned_le16((pn & 0xffff), &iv_data[0]);
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return 0;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_civoid mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx,
1498c2ecf20Sopenharmony_ci			    u8 vif_idx, u8 *mac)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct mt76_wcid_addr addr = {};
1528c2ecf20Sopenharmony_ci	u32 attr;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
1558c2ecf20Sopenharmony_ci	       FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_WCID_ATTR(idx), attr);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (idx >= 128)
1608c2ecf20Sopenharmony_ci		return;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (mac)
1638c2ecf20Sopenharmony_ci		memcpy(addr.macaddr, mac, ETH_ALEN);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr));
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_civoid mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	u32 val = mt76_rr(dev, MT_WCID_DROP(idx));
1728c2ecf20Sopenharmony_ci	u32 bit = MT_WCID_DROP_MASK(idx);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* prevent unnecessary writes */
1758c2ecf20Sopenharmony_ci	if ((val & bit) != (bit * drop))
1768c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop));
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic u16
1808c2ecf20Sopenharmony_cimt76x02_mac_tx_rate_val(struct mt76x02_dev *dev,
1818c2ecf20Sopenharmony_ci			const struct ieee80211_tx_rate *rate, u8 *nss_val)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u8 phy, rate_idx, nss, bw = 0;
1848c2ecf20Sopenharmony_ci	u16 rateval;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
1878c2ecf20Sopenharmony_ci		rate_idx = rate->idx;
1888c2ecf20Sopenharmony_ci		nss = 1 + (rate->idx >> 4);
1898c2ecf20Sopenharmony_ci		phy = MT_PHY_TYPE_VHT;
1908c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
1918c2ecf20Sopenharmony_ci			bw = 2;
1928c2ecf20Sopenharmony_ci		else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
1938c2ecf20Sopenharmony_ci			bw = 1;
1948c2ecf20Sopenharmony_ci	} else if (rate->flags & IEEE80211_TX_RC_MCS) {
1958c2ecf20Sopenharmony_ci		rate_idx = rate->idx;
1968c2ecf20Sopenharmony_ci		nss = 1 + (rate->idx >> 3);
1978c2ecf20Sopenharmony_ci		phy = MT_PHY_TYPE_HT;
1988c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
1998c2ecf20Sopenharmony_ci			phy = MT_PHY_TYPE_HT_GF;
2008c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
2018c2ecf20Sopenharmony_ci			bw = 1;
2028c2ecf20Sopenharmony_ci	} else {
2038c2ecf20Sopenharmony_ci		const struct ieee80211_rate *r;
2048c2ecf20Sopenharmony_ci		int band = dev->mphy.chandef.chan->band;
2058c2ecf20Sopenharmony_ci		u16 val;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx];
2088c2ecf20Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
2098c2ecf20Sopenharmony_ci			val = r->hw_value_short;
2108c2ecf20Sopenharmony_ci		else
2118c2ecf20Sopenharmony_ci			val = r->hw_value;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		phy = val >> 8;
2148c2ecf20Sopenharmony_ci		rate_idx = val & 0xff;
2158c2ecf20Sopenharmony_ci		nss = 1;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx);
2198c2ecf20Sopenharmony_ci	rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
2208c2ecf20Sopenharmony_ci	rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
2218c2ecf20Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
2228c2ecf20Sopenharmony_ci		rateval |= MT_RXWI_RATE_SGI;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	*nss_val = nss;
2258c2ecf20Sopenharmony_ci	return rateval;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_civoid mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid,
2298c2ecf20Sopenharmony_ci			       const struct ieee80211_tx_rate *rate)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
2328c2ecf20Sopenharmony_ci	u16 rateval;
2338c2ecf20Sopenharmony_ci	u32 tx_info;
2348c2ecf20Sopenharmony_ci	s8 nss;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss);
2378c2ecf20Sopenharmony_ci	tx_info = FIELD_PREP(MT_WCID_TX_INFO_RATE, rateval) |
2388c2ecf20Sopenharmony_ci		  FIELD_PREP(MT_WCID_TX_INFO_NSS, nss) |
2398c2ecf20Sopenharmony_ci		  FIELD_PREP(MT_WCID_TX_INFO_TXPWR_ADJ, max_txpwr_adj) |
2408c2ecf20Sopenharmony_ci		  MT_WCID_TX_INFO_SET;
2418c2ecf20Sopenharmony_ci	wcid->tx_info = tx_info;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_civoid mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	if (enable)
2478c2ecf20Sopenharmony_ci		mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
2488c2ecf20Sopenharmony_ci	else
2498c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cibool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev,
2538c2ecf20Sopenharmony_ci				struct mt76x02_tx_status *stat)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	u32 stat1, stat2;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT);
2588c2ecf20Sopenharmony_ci	stat1 = mt76_rr(dev, MT_TX_STAT_FIFO);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID);
2618c2ecf20Sopenharmony_ci	if (!stat->valid)
2628c2ecf20Sopenharmony_ci		return false;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS);
2658c2ecf20Sopenharmony_ci	stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR);
2668c2ecf20Sopenharmony_ci	stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ);
2678c2ecf20Sopenharmony_ci	stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1);
2688c2ecf20Sopenharmony_ci	stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2);
2718c2ecf20Sopenharmony_ci	stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	trace_mac_txstat_fetch(dev, stat);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	return true;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic int
2798c2ecf20Sopenharmony_cimt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
2808c2ecf20Sopenharmony_ci			    enum nl80211_band band)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	txrate->idx = 0;
2858c2ecf20Sopenharmony_ci	txrate->flags = 0;
2868c2ecf20Sopenharmony_ci	txrate->count = 1;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
2898c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
2908c2ecf20Sopenharmony_ci		if (band == NL80211_BAND_2GHZ)
2918c2ecf20Sopenharmony_ci			idx += 4;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci		txrate->idx = idx;
2948c2ecf20Sopenharmony_ci		return 0;
2958c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_CCK:
2968c2ecf20Sopenharmony_ci		if (idx >= 8)
2978c2ecf20Sopenharmony_ci			idx -= 8;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		txrate->idx = idx;
3008c2ecf20Sopenharmony_ci		return 0;
3018c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
3028c2ecf20Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
3038c2ecf20Sopenharmony_ci		fallthrough;
3048c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT:
3058c2ecf20Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_MCS;
3068c2ecf20Sopenharmony_ci		txrate->idx = idx;
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_VHT:
3098c2ecf20Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
3108c2ecf20Sopenharmony_ci		txrate->idx = idx;
3118c2ecf20Sopenharmony_ci		break;
3128c2ecf20Sopenharmony_ci	default:
3138c2ecf20Sopenharmony_ci		return -EINVAL;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
3178c2ecf20Sopenharmony_ci	case MT_PHY_BW_20:
3188c2ecf20Sopenharmony_ci		break;
3198c2ecf20Sopenharmony_ci	case MT_PHY_BW_40:
3208c2ecf20Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
3218c2ecf20Sopenharmony_ci		break;
3228c2ecf20Sopenharmony_ci	case MT_PHY_BW_80:
3238c2ecf20Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
3248c2ecf20Sopenharmony_ci		break;
3258c2ecf20Sopenharmony_ci	default:
3268c2ecf20Sopenharmony_ci		return -EINVAL;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (rate & MT_RXWI_RATE_SGI)
3308c2ecf20Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return 0;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_civoid mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
3368c2ecf20Sopenharmony_ci			    struct sk_buff *skb, struct mt76_wcid *wcid,
3378c2ecf20Sopenharmony_ci			    struct ieee80211_sta *sta, int len)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
3408c2ecf20Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
3418c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate *rate = &info->control.rates[0];
3428c2ecf20Sopenharmony_ci	struct ieee80211_key_conf *key = info->control.hw_key;
3438c2ecf20Sopenharmony_ci	u32 wcid_tx_info;
3448c2ecf20Sopenharmony_ci	u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2));
3458c2ecf20Sopenharmony_ci	u16 txwi_flags = 0, rateval;
3468c2ecf20Sopenharmony_ci	u8 nss;
3478c2ecf20Sopenharmony_ci	s8 txpwr_adj, max_txpwr_adj;
3488c2ecf20Sopenharmony_ci	u8 ccmp_pn[8], nstreams = dev->chainmask & 0xf;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	memset(txwi, 0, sizeof(*txwi));
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	mt76_tx_check_agg_ssn(sta, skb);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff &&
3558c2ecf20Sopenharmony_ci	    ieee80211_has_protected(hdr->frame_control)) {
3568c2ecf20Sopenharmony_ci		wcid = NULL;
3578c2ecf20Sopenharmony_ci		ieee80211_get_tx_rates(info->control.vif, sta, skb,
3588c2ecf20Sopenharmony_ci				       info->control.rates, 1);
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (wcid)
3628c2ecf20Sopenharmony_ci		txwi->wcid = wcid->idx;
3638c2ecf20Sopenharmony_ci	else
3648c2ecf20Sopenharmony_ci		txwi->wcid = 0xff;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (wcid && wcid->sw_iv && key) {
3678c2ecf20Sopenharmony_ci		u64 pn = atomic64_inc_return(&key->tx_pn);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		ccmp_pn[0] = pn;
3708c2ecf20Sopenharmony_ci		ccmp_pn[1] = pn >> 8;
3718c2ecf20Sopenharmony_ci		ccmp_pn[2] = 0;
3728c2ecf20Sopenharmony_ci		ccmp_pn[3] = 0x20 | (key->keyidx << 6);
3738c2ecf20Sopenharmony_ci		ccmp_pn[4] = pn >> 16;
3748c2ecf20Sopenharmony_ci		ccmp_pn[5] = pn >> 24;
3758c2ecf20Sopenharmony_ci		ccmp_pn[6] = pn >> 32;
3768c2ecf20Sopenharmony_ci		ccmp_pn[7] = pn >> 40;
3778c2ecf20Sopenharmony_ci		txwi->iv = *((__le32 *)&ccmp_pn[0]);
3788c2ecf20Sopenharmony_ci		txwi->eiv = *((__le32 *)&ccmp_pn[4]);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	if (wcid && (rate->idx < 0 || !rate->count)) {
3828c2ecf20Sopenharmony_ci		wcid_tx_info = wcid->tx_info;
3838c2ecf20Sopenharmony_ci		rateval = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info);
3848c2ecf20Sopenharmony_ci		max_txpwr_adj = FIELD_GET(MT_WCID_TX_INFO_TXPWR_ADJ,
3858c2ecf20Sopenharmony_ci					  wcid_tx_info);
3868c2ecf20Sopenharmony_ci		nss = FIELD_GET(MT_WCID_TX_INFO_NSS, wcid_tx_info);
3878c2ecf20Sopenharmony_ci	} else {
3888c2ecf20Sopenharmony_ci		rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss);
3898c2ecf20Sopenharmony_ci		max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate);
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci	txwi->rate = cpu_to_le16(rateval);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->txpower_conf,
3948c2ecf20Sopenharmony_ci					     max_txpwr_adj);
3958c2ecf20Sopenharmony_ci	txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4)
3988c2ecf20Sopenharmony_ci		txwi->txstream = 0x13;
3998c2ecf20Sopenharmony_ci	else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 &&
4008c2ecf20Sopenharmony_ci		 !(txwi->rate & cpu_to_le16(rate_ht_mask)))
4018c2ecf20Sopenharmony_ci		txwi->txstream = 0x93;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (is_mt76x2(dev) && (info->flags & IEEE80211_TX_CTL_LDPC))
4048c2ecf20Sopenharmony_ci		txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC);
4058c2ecf20Sopenharmony_ci	if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1)
4068c2ecf20Sopenharmony_ci		txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC);
4078c2ecf20Sopenharmony_ci	if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC)
4088c2ecf20Sopenharmony_ci		txwi_flags |= MT_TXWI_FLAGS_MMPS;
4098c2ecf20Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
4108c2ecf20Sopenharmony_ci		txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ;
4118c2ecf20Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
4128c2ecf20Sopenharmony_ci		txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ;
4138c2ecf20Sopenharmony_ci	if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) {
4148c2ecf20Sopenharmony_ci		u8 ba_size = IEEE80211_MIN_AMPDU_BUF;
4158c2ecf20Sopenharmony_ci		u8 ampdu_density = sta->ht_cap.ampdu_density;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		ba_size <<= sta->ht_cap.ampdu_factor;
4188c2ecf20Sopenharmony_ci		ba_size = min_t(int, 63, ba_size - 1);
4198c2ecf20Sopenharmony_ci		if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)
4208c2ecf20Sopenharmony_ci			ba_size = 0;
4218c2ecf20Sopenharmony_ci		txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci		if (ampdu_density < IEEE80211_HT_MPDU_DENSITY_4)
4248c2ecf20Sopenharmony_ci			ampdu_density = IEEE80211_HT_MPDU_DENSITY_4;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		txwi_flags |= MT_TXWI_FLAGS_AMPDU |
4278c2ecf20Sopenharmony_ci			 FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, ampdu_density);
4288c2ecf20Sopenharmony_ci	}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (ieee80211_is_probe_resp(hdr->frame_control) ||
4318c2ecf20Sopenharmony_ci	    ieee80211_is_beacon(hdr->frame_control))
4328c2ecf20Sopenharmony_ci		txwi_flags |= MT_TXWI_FLAGS_TS;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	txwi->flags |= cpu_to_le16(txwi_flags);
4358c2ecf20Sopenharmony_ci	txwi->len_ctl = cpu_to_le16(len);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic void
4408c2ecf20Sopenharmony_cimt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	u8 mcs, nss;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (!idx)
4458c2ecf20Sopenharmony_ci		return;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	rates += idx - 1;
4488c2ecf20Sopenharmony_ci	rates[1] = rates[0];
4498c2ecf20Sopenharmony_ci	switch (phy) {
4508c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_VHT:
4518c2ecf20Sopenharmony_ci		mcs = ieee80211_rate_get_vht_mcs(rates);
4528c2ecf20Sopenharmony_ci		nss = ieee80211_rate_get_vht_nss(rates);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		if (mcs == 0)
4558c2ecf20Sopenharmony_ci			nss = max_t(int, nss - 1, 1);
4568c2ecf20Sopenharmony_ci		else
4578c2ecf20Sopenharmony_ci			mcs--;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci		ieee80211_rate_set_vht(rates + 1, mcs, nss);
4608c2ecf20Sopenharmony_ci		break;
4618c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
4628c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT:
4638c2ecf20Sopenharmony_ci		/* MCS 8 falls back to MCS 0 */
4648c2ecf20Sopenharmony_ci		if (rates[0].idx == 8) {
4658c2ecf20Sopenharmony_ci			rates[1].idx = 0;
4668c2ecf20Sopenharmony_ci			break;
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci		fallthrough;
4698c2ecf20Sopenharmony_ci	default:
4708c2ecf20Sopenharmony_ci		rates[1].idx = max_t(int, rates[0].idx - 1, 0);
4718c2ecf20Sopenharmony_ci		break;
4728c2ecf20Sopenharmony_ci	}
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic void
4768c2ecf20Sopenharmony_cimt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
4778c2ecf20Sopenharmony_ci			   struct ieee80211_tx_info *info,
4788c2ecf20Sopenharmony_ci			   struct mt76x02_tx_status *st, int n_frames)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate *rate = info->status.rates;
4818c2ecf20Sopenharmony_ci	struct ieee80211_tx_rate last_rate;
4828c2ecf20Sopenharmony_ci	u16 first_rate;
4838c2ecf20Sopenharmony_ci	int retry = st->retry;
4848c2ecf20Sopenharmony_ci	int phy;
4858c2ecf20Sopenharmony_ci	int i;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (!n_frames)
4888c2ecf20Sopenharmony_ci		return;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (st->pktid & MT_PACKET_ID_HAS_RATE) {
4938c2ecf20Sopenharmony_ci		first_rate = st->rate & ~MT_PKTID_RATE;
4948c2ecf20Sopenharmony_ci		first_rate |= st->pktid & MT_PKTID_RATE;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		mt76x02_mac_process_tx_rate(&rate[0], first_rate,
4978c2ecf20Sopenharmony_ci					    dev->mphy.chandef.chan->band);
4988c2ecf20Sopenharmony_ci	} else if (rate[0].idx < 0) {
4998c2ecf20Sopenharmony_ci		if (!msta)
5008c2ecf20Sopenharmony_ci			return;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci		mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
5038c2ecf20Sopenharmony_ci					    dev->mphy.chandef.chan->band);
5048c2ecf20Sopenharmony_ci	}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	mt76x02_mac_process_tx_rate(&last_rate, st->rate,
5078c2ecf20Sopenharmony_ci				    dev->mphy.chandef.chan->band);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
5108c2ecf20Sopenharmony_ci		retry--;
5118c2ecf20Sopenharmony_ci		if (i + 1 == ARRAY_SIZE(info->status.rates)) {
5128c2ecf20Sopenharmony_ci			info->status.rates[i] = last_rate;
5138c2ecf20Sopenharmony_ci			info->status.rates[i].count = max_t(int, retry, 1);
5148c2ecf20Sopenharmony_ci			break;
5158c2ecf20Sopenharmony_ci		}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		mt76x02_tx_rate_fallback(info->status.rates, i, phy);
5188c2ecf20Sopenharmony_ci		if (info->status.rates[i].idx == last_rate.idx)
5198c2ecf20Sopenharmony_ci			break;
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (i + 1 < ARRAY_SIZE(info->status.rates)) {
5238c2ecf20Sopenharmony_ci		info->status.rates[i + 1].idx = -1;
5248c2ecf20Sopenharmony_ci		info->status.rates[i + 1].count = 0;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	info->status.ampdu_len = n_frames;
5288c2ecf20Sopenharmony_ci	info->status.ampdu_ack_len = st->success ? n_frames : 0;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (st->aggr)
5318c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_CTL_AMPDU |
5328c2ecf20Sopenharmony_ci			       IEEE80211_TX_STAT_AMPDU;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (!st->ack_req)
5358c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_CTL_NO_ACK;
5368c2ecf20Sopenharmony_ci	else if (st->success)
5378c2ecf20Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_civoid mt76x02_send_tx_status(struct mt76x02_dev *dev,
5418c2ecf20Sopenharmony_ci			    struct mt76x02_tx_status *stat, u8 *update)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	struct ieee80211_tx_info info = {};
5448c2ecf20Sopenharmony_ci	struct ieee80211_tx_status status = {
5458c2ecf20Sopenharmony_ci		.info = &info
5468c2ecf20Sopenharmony_ci	};
5478c2ecf20Sopenharmony_ci	static const u8 ac_to_tid[4] = {
5488c2ecf20Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
5498c2ecf20Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
5508c2ecf20Sopenharmony_ci		[IEEE80211_AC_VI] = 4,
5518c2ecf20Sopenharmony_ci		[IEEE80211_AC_VO] = 6
5528c2ecf20Sopenharmony_ci	};
5538c2ecf20Sopenharmony_ci	struct mt76_wcid *wcid = NULL;
5548c2ecf20Sopenharmony_ci	struct mt76x02_sta *msta = NULL;
5558c2ecf20Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
5568c2ecf20Sopenharmony_ci	struct sk_buff_head list;
5578c2ecf20Sopenharmony_ci	u32 duration = 0;
5588c2ecf20Sopenharmony_ci	u8 cur_pktid;
5598c2ecf20Sopenharmony_ci	u32 ac = 0;
5608c2ecf20Sopenharmony_ci	int len = 0;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (stat->pktid == MT_PACKET_ID_NO_ACK)
5638c2ecf20Sopenharmony_ci		return;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	rcu_read_lock();
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (stat->wcid < MT76x02_N_WCIDS)
5688c2ecf20Sopenharmony_ci		wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (wcid && wcid->sta) {
5718c2ecf20Sopenharmony_ci		void *priv;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		priv = msta = container_of(wcid, struct mt76x02_sta, wcid);
5748c2ecf20Sopenharmony_ci		status.sta = container_of(priv, struct ieee80211_sta,
5758c2ecf20Sopenharmony_ci					  drv_priv);
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	mt76_tx_status_lock(mdev, &list);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (wcid) {
5818c2ecf20Sopenharmony_ci		if (mt76_is_skb_pktid(stat->pktid))
5828c2ecf20Sopenharmony_ci			status.skb = mt76_tx_status_skb_get(mdev, wcid,
5838c2ecf20Sopenharmony_ci							    stat->pktid, &list);
5848c2ecf20Sopenharmony_ci		if (status.skb)
5858c2ecf20Sopenharmony_ci			status.info = IEEE80211_SKB_CB(status.skb);
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
5898c2ecf20Sopenharmony_ci		mt76_tx_status_unlock(mdev, &list);
5908c2ecf20Sopenharmony_ci		goto out;
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	if (msta && stat->aggr && !status.skb) {
5958c2ecf20Sopenharmony_ci		u32 stat_val, stat_cache;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci		stat_val = stat->rate;
5988c2ecf20Sopenharmony_ci		stat_val |= ((u32)stat->retry) << 16;
5998c2ecf20Sopenharmony_ci		stat_cache = msta->status.rate;
6008c2ecf20Sopenharmony_ci		stat_cache |= ((u32)msta->status.retry) << 16;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		if (*update == 0 && stat_val == stat_cache &&
6038c2ecf20Sopenharmony_ci		    stat->wcid == msta->status.wcid && msta->n_frames < 32) {
6048c2ecf20Sopenharmony_ci			msta->n_frames++;
6058c2ecf20Sopenharmony_ci			mt76_tx_status_unlock(mdev, &list);
6068c2ecf20Sopenharmony_ci			goto out;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		cur_pktid = msta->status.pktid;
6108c2ecf20Sopenharmony_ci		mt76x02_mac_fill_tx_status(dev, msta, status.info,
6118c2ecf20Sopenharmony_ci					   &msta->status, msta->n_frames);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci		msta->status = *stat;
6148c2ecf20Sopenharmony_ci		msta->n_frames = 1;
6158c2ecf20Sopenharmony_ci		*update = 0;
6168c2ecf20Sopenharmony_ci	} else {
6178c2ecf20Sopenharmony_ci		cur_pktid = stat->pktid;
6188c2ecf20Sopenharmony_ci		mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
6198c2ecf20Sopenharmony_ci		*update = 1;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (status.skb) {
6238c2ecf20Sopenharmony_ci		info = *status.info;
6248c2ecf20Sopenharmony_ci		len = status.skb->len;
6258c2ecf20Sopenharmony_ci		ac = skb_get_queue_mapping(status.skb);
6268c2ecf20Sopenharmony_ci		mt76_tx_status_skb_done(mdev, status.skb, &list);
6278c2ecf20Sopenharmony_ci	} else if (msta) {
6288c2ecf20Sopenharmony_ci		len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen);
6298c2ecf20Sopenharmony_ci		ac = FIELD_GET(MT_PKTID_AC, cur_pktid);
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	mt76_tx_status_unlock(mdev, &list);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (!status.skb)
6358c2ecf20Sopenharmony_ci		ieee80211_tx_status_ext(mt76_hw(dev), &status);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (!len)
6388c2ecf20Sopenharmony_ci		goto out;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	duration = ieee80211_calc_tx_airtime(mt76_hw(dev), &info, len);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->mt76.cc_lock);
6438c2ecf20Sopenharmony_ci	dev->tx_airtime += duration;
6448c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->mt76.cc_lock);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (msta)
6478c2ecf20Sopenharmony_ci		ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ciout:
6508c2ecf20Sopenharmony_ci	rcu_read_unlock();
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic int
6548c2ecf20Sopenharmony_cimt76x02_mac_process_rate(struct mt76x02_dev *dev,
6558c2ecf20Sopenharmony_ci			 struct mt76_rx_status *status,
6568c2ecf20Sopenharmony_ci			 u16 rate)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
6618c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
6628c2ecf20Sopenharmony_ci		if (idx >= 8)
6638c2ecf20Sopenharmony_ci			idx = 0;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		if (status->band == NL80211_BAND_2GHZ)
6668c2ecf20Sopenharmony_ci			idx += 4;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		status->rate_idx = idx;
6698c2ecf20Sopenharmony_ci		return 0;
6708c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_CCK:
6718c2ecf20Sopenharmony_ci		if (idx >= 8) {
6728c2ecf20Sopenharmony_ci			idx -= 8;
6738c2ecf20Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci		if (idx >= 4)
6778c2ecf20Sopenharmony_ci			idx = 0;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		status->rate_idx = idx;
6808c2ecf20Sopenharmony_ci		return 0;
6818c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
6828c2ecf20Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_HT_GF;
6838c2ecf20Sopenharmony_ci		fallthrough;
6848c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_HT:
6858c2ecf20Sopenharmony_ci		status->encoding = RX_ENC_HT;
6868c2ecf20Sopenharmony_ci		status->rate_idx = idx;
6878c2ecf20Sopenharmony_ci		break;
6888c2ecf20Sopenharmony_ci	case MT_PHY_TYPE_VHT: {
6898c2ecf20Sopenharmony_ci		u8 n_rxstream = dev->chainmask & 0xf;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		status->encoding = RX_ENC_VHT;
6928c2ecf20Sopenharmony_ci		status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx);
6938c2ecf20Sopenharmony_ci		status->nss = min_t(u8, n_rxstream,
6948c2ecf20Sopenharmony_ci				    FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1);
6958c2ecf20Sopenharmony_ci		break;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci	default:
6988c2ecf20Sopenharmony_ci		return -EINVAL;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if (rate & MT_RXWI_RATE_LDPC)
7028c2ecf20Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_LDPC;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	if (rate & MT_RXWI_RATE_SGI)
7058c2ecf20Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (rate & MT_RXWI_RATE_STBC)
7088c2ecf20Sopenharmony_ci		status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) {
7118c2ecf20Sopenharmony_ci	case MT_PHY_BW_20:
7128c2ecf20Sopenharmony_ci		break;
7138c2ecf20Sopenharmony_ci	case MT_PHY_BW_40:
7148c2ecf20Sopenharmony_ci		status->bw = RATE_INFO_BW_40;
7158c2ecf20Sopenharmony_ci		break;
7168c2ecf20Sopenharmony_ci	case MT_PHY_BW_80:
7178c2ecf20Sopenharmony_ci		status->bw = RATE_INFO_BW_80;
7188c2ecf20Sopenharmony_ci		break;
7198c2ecf20Sopenharmony_ci	default:
7208c2ecf20Sopenharmony_ci		break;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	return 0;
7248c2ecf20Sopenharmony_ci}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_civoid mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	static const u8 null_addr[ETH_ALEN] = {};
7298c2ecf20Sopenharmony_ci	int i;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	ether_addr_copy(dev->mt76.macaddr, addr);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(dev->mt76.macaddr)) {
7348c2ecf20Sopenharmony_ci		eth_random_addr(dev->mt76.macaddr);
7358c2ecf20Sopenharmony_ci		dev_info(dev->mt76.dev,
7368c2ecf20Sopenharmony_ci			 "Invalid MAC address, using random address %pM\n",
7378c2ecf20Sopenharmony_ci			 dev->mt76.macaddr);
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
7418c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MAC_ADDR_DW1,
7428c2ecf20Sopenharmony_ci		get_unaligned_le16(dev->mt76.macaddr + 4) |
7438c2ecf20Sopenharmony_ci		FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MAC_BSSID_DW0,
7468c2ecf20Sopenharmony_ci		get_unaligned_le32(dev->mt76.macaddr));
7478c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MAC_BSSID_DW1,
7488c2ecf20Sopenharmony_ci		get_unaligned_le16(dev->mt76.macaddr + 4) |
7498c2ecf20Sopenharmony_ci		FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */
7508c2ecf20Sopenharmony_ci		MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT);
7518c2ecf20Sopenharmony_ci	/* enable 7 additional beacon slots and control them with bypass mask */
7528c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, 7);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	for (i = 0; i < 16; i++)
7558c2ecf20Sopenharmony_ci		mt76x02_mac_set_bssid(dev, i, null_addr);
7568c2ecf20Sopenharmony_ci}
7578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_setaddr);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic int
7608c2ecf20Sopenharmony_cimt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci	struct mt76x02_rx_freq_cal *cal = &dev->cal.rx;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	rssi += cal->rssi_offset[chain];
7658c2ecf20Sopenharmony_ci	rssi -= cal->lna_gain;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return rssi;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ciint mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
7718c2ecf20Sopenharmony_ci			   void *rxi)
7728c2ecf20Sopenharmony_ci{
7738c2ecf20Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
7748c2ecf20Sopenharmony_ci	struct mt76x02_rxwi *rxwi = rxi;
7758c2ecf20Sopenharmony_ci	struct mt76x02_sta *sta;
7768c2ecf20Sopenharmony_ci	u32 rxinfo = le32_to_cpu(rxwi->rxinfo);
7778c2ecf20Sopenharmony_ci	u32 ctl = le32_to_cpu(rxwi->ctl);
7788c2ecf20Sopenharmony_ci	u16 rate = le16_to_cpu(rxwi->rate);
7798c2ecf20Sopenharmony_ci	u16 tid_sn = le16_to_cpu(rxwi->tid_sn);
7808c2ecf20Sopenharmony_ci	bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST);
7818c2ecf20Sopenharmony_ci	int pad_len = 0, nstreams = dev->chainmask & 0xf;
7828c2ecf20Sopenharmony_ci	s8 signal;
7838c2ecf20Sopenharmony_ci	u8 pn_len;
7848c2ecf20Sopenharmony_ci	u8 wcid;
7858c2ecf20Sopenharmony_ci	int len;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
7888c2ecf20Sopenharmony_ci		return -EINVAL;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	if (rxinfo & MT_RXINFO_L2PAD)
7918c2ecf20Sopenharmony_ci		pad_len += 2;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (rxinfo & MT_RXINFO_DECRYPT) {
7948c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
7958c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED;
7968c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_MIC_STRIPPED;
7978c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
7988c2ecf20Sopenharmony_ci	}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl);
8018c2ecf20Sopenharmony_ci	sta = mt76x02_rx_get_sta(&dev->mt76, wcid);
8028c2ecf20Sopenharmony_ci	status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
8058c2ecf20Sopenharmony_ci	pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
8068c2ecf20Sopenharmony_ci	if (pn_len) {
8078c2ecf20Sopenharmony_ci		int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
8088c2ecf20Sopenharmony_ci		u8 *data = skb->data + offset;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci		status->iv[0] = data[7];
8118c2ecf20Sopenharmony_ci		status->iv[1] = data[6];
8128c2ecf20Sopenharmony_ci		status->iv[2] = data[5];
8138c2ecf20Sopenharmony_ci		status->iv[3] = data[4];
8148c2ecf20Sopenharmony_ci		status->iv[4] = data[1];
8158c2ecf20Sopenharmony_ci		status->iv[5] = data[0];
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci		/*
8188c2ecf20Sopenharmony_ci		 * Driver CCMP validation can't deal with fragments.
8198c2ecf20Sopenharmony_ci		 * Let mac80211 take care of it.
8208c2ecf20Sopenharmony_ci		 */
8218c2ecf20Sopenharmony_ci		if (rxinfo & MT_RXINFO_FRAG) {
8228c2ecf20Sopenharmony_ci			status->flag &= ~RX_FLAG_IV_STRIPPED;
8238c2ecf20Sopenharmony_ci		} else {
8248c2ecf20Sopenharmony_ci			pad_len += pn_len << 2;
8258c2ecf20Sopenharmony_ci			len -= pn_len << 2;
8268c2ecf20Sopenharmony_ci		}
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	mt76x02_remove_hdr_pad(skb, pad_len);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
8328c2ecf20Sopenharmony_ci		status->aggr = true;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	if (rxinfo & MT_RXINFO_AMPDU) {
8358c2ecf20Sopenharmony_ci		status->flag |= RX_FLAG_AMPDU_DETAILS;
8368c2ecf20Sopenharmony_ci		status->ampdu_ref = dev->ampdu_ref;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		/*
8398c2ecf20Sopenharmony_ci		 * When receiving an A-MPDU subframe and RSSI info is not valid,
8408c2ecf20Sopenharmony_ci		 * we can assume that more subframes belonging to the same A-MPDU
8418c2ecf20Sopenharmony_ci		 * are coming. The last one will have valid RSSI info
8428c2ecf20Sopenharmony_ci		 */
8438c2ecf20Sopenharmony_ci		if (rxinfo & MT_RXINFO_RSSI) {
8448c2ecf20Sopenharmony_ci			if (!++dev->ampdu_ref)
8458c2ecf20Sopenharmony_ci				dev->ampdu_ref++;
8468c2ecf20Sopenharmony_ci		}
8478c2ecf20Sopenharmony_ci	}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(len > skb->len))
8508c2ecf20Sopenharmony_ci		return -EINVAL;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	pskb_trim(skb, len);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	status->chains = BIT(0);
8558c2ecf20Sopenharmony_ci	signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0);
8568c2ecf20Sopenharmony_ci	status->chain_signal[0] = signal;
8578c2ecf20Sopenharmony_ci	if (nstreams > 1) {
8588c2ecf20Sopenharmony_ci		status->chains |= BIT(1);
8598c2ecf20Sopenharmony_ci		status->chain_signal[1] = mt76x02_mac_get_rssi(dev,
8608c2ecf20Sopenharmony_ci							       rxwi->rssi[1],
8618c2ecf20Sopenharmony_ci							       1);
8628c2ecf20Sopenharmony_ci		signal = max_t(s8, signal, status->chain_signal[1]);
8638c2ecf20Sopenharmony_ci	}
8648c2ecf20Sopenharmony_ci	status->signal = signal;
8658c2ecf20Sopenharmony_ci	status->freq = dev->mphy.chandef.chan->center_freq;
8668c2ecf20Sopenharmony_ci	status->band = dev->mphy.chandef.chan->band;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	status->tid = FIELD_GET(MT_RXWI_TID, tid_sn);
8698c2ecf20Sopenharmony_ci	status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	return mt76x02_mac_process_rate(dev, status, rate);
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_civoid mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	struct mt76x02_tx_status stat = {};
8778c2ecf20Sopenharmony_ci	u8 update = 1;
8788c2ecf20Sopenharmony_ci	bool ret;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
8818c2ecf20Sopenharmony_ci		return;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	trace_mac_txstat_poll(dev);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) {
8868c2ecf20Sopenharmony_ci		if (!spin_trylock(&dev->txstatus_fifo_lock))
8878c2ecf20Sopenharmony_ci			break;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci		ret = mt76x02_mac_load_tx_status(dev, &stat);
8908c2ecf20Sopenharmony_ci		spin_unlock(&dev->txstatus_fifo_lock);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci		if (!ret)
8938c2ecf20Sopenharmony_ci			break;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci		if (!irq) {
8968c2ecf20Sopenharmony_ci			mt76x02_send_tx_status(dev, &stat, &update);
8978c2ecf20Sopenharmony_ci			continue;
8988c2ecf20Sopenharmony_ci		}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci		kfifo_put(&dev->txstatus_fifo, stat);
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_civoid mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
9058c2ecf20Sopenharmony_ci{
9068c2ecf20Sopenharmony_ci	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
9078c2ecf20Sopenharmony_ci	struct mt76x02_txwi *txwi;
9088c2ecf20Sopenharmony_ci	u8 *txwi_ptr;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (!e->txwi) {
9118c2ecf20Sopenharmony_ci		dev_kfree_skb_any(e->skb);
9128c2ecf20Sopenharmony_ci		return;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	mt76x02_mac_poll_tx_status(dev, false);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi);
9188c2ecf20Sopenharmony_ci	txwi = (struct mt76x02_txwi *)txwi_ptr;
9198c2ecf20Sopenharmony_ci	trace_mac_txdone(mdev, txwi->wcid, txwi->pktid);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	mt76_tx_complete_skb(mdev, e->wcid, e->skb);
9228c2ecf20Sopenharmony_ci}
9238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_civoid mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	u32 data = 0;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	if (val != ~0)
9308c2ecf20Sopenharmony_ci		data = FIELD_PREP(MT_PROT_CFG_CTRL, 1) |
9318c2ecf20Sopenharmony_ci		       MT_PROT_CFG_RTS_THRESH;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, val);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	mt76_rmw(dev, MT_CCK_PROT_CFG,
9368c2ecf20Sopenharmony_ci		 MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data);
9378c2ecf20Sopenharmony_ci	mt76_rmw(dev, MT_OFDM_PROT_CFG,
9388c2ecf20Sopenharmony_ci		 MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data);
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_civoid mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot,
9428c2ecf20Sopenharmony_ci				   int ht_mode)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
9458c2ecf20Sopenharmony_ci	bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
9468c2ecf20Sopenharmony_ci	u32 prot[6];
9478c2ecf20Sopenharmony_ci	u32 vht_prot[3];
9488c2ecf20Sopenharmony_ci	int i;
9498c2ecf20Sopenharmony_ci	u16 rts_thr;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(prot); i++) {
9528c2ecf20Sopenharmony_ci		prot[i] = mt76_rr(dev, MT_CCK_PROT_CFG + i * 4);
9538c2ecf20Sopenharmony_ci		prot[i] &= ~MT_PROT_CFG_CTRL;
9548c2ecf20Sopenharmony_ci		if (i >= 2)
9558c2ecf20Sopenharmony_ci			prot[i] &= ~MT_PROT_CFG_RATE;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vht_prot); i++) {
9598c2ecf20Sopenharmony_ci		vht_prot[i] = mt76_rr(dev, MT_TX_PROT_CFG6 + i * 4);
9608c2ecf20Sopenharmony_ci		vht_prot[i] &= ~(MT_PROT_CFG_CTRL | MT_PROT_CFG_RATE);
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	rts_thr = mt76_get_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (rts_thr != 0xffff)
9668c2ecf20Sopenharmony_ci		prot[0] |= MT_PROT_CTRL_RTS_CTS;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (legacy_prot) {
9698c2ecf20Sopenharmony_ci		prot[1] |= MT_PROT_CTRL_CTS2SELF;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		prot[2] |= MT_PROT_RATE_CCK_11;
9728c2ecf20Sopenharmony_ci		prot[3] |= MT_PROT_RATE_CCK_11;
9738c2ecf20Sopenharmony_ci		prot[4] |= MT_PROT_RATE_CCK_11;
9748c2ecf20Sopenharmony_ci		prot[5] |= MT_PROT_RATE_CCK_11;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		vht_prot[0] |= MT_PROT_RATE_CCK_11;
9778c2ecf20Sopenharmony_ci		vht_prot[1] |= MT_PROT_RATE_CCK_11;
9788c2ecf20Sopenharmony_ci		vht_prot[2] |= MT_PROT_RATE_CCK_11;
9798c2ecf20Sopenharmony_ci	} else {
9808c2ecf20Sopenharmony_ci		if (rts_thr != 0xffff)
9818c2ecf20Sopenharmony_ci			prot[1] |= MT_PROT_CTRL_RTS_CTS;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		prot[2] |= MT_PROT_RATE_OFDM_24;
9848c2ecf20Sopenharmony_ci		prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
9858c2ecf20Sopenharmony_ci		prot[4] |= MT_PROT_RATE_OFDM_24;
9868c2ecf20Sopenharmony_ci		prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci		vht_prot[0] |= MT_PROT_RATE_OFDM_24;
9898c2ecf20Sopenharmony_ci		vht_prot[1] |= MT_PROT_RATE_DUP_OFDM_24;
9908c2ecf20Sopenharmony_ci		vht_prot[2] |= MT_PROT_RATE_SGI_OFDM_24;
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	switch (mode) {
9948c2ecf20Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
9958c2ecf20Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
9968c2ecf20Sopenharmony_ci		prot[2] |= MT_PROT_CTRL_RTS_CTS;
9978c2ecf20Sopenharmony_ci		prot[3] |= MT_PROT_CTRL_RTS_CTS;
9988c2ecf20Sopenharmony_ci		prot[4] |= MT_PROT_CTRL_RTS_CTS;
9998c2ecf20Sopenharmony_ci		prot[5] |= MT_PROT_CTRL_RTS_CTS;
10008c2ecf20Sopenharmony_ci		vht_prot[0] |= MT_PROT_CTRL_RTS_CTS;
10018c2ecf20Sopenharmony_ci		vht_prot[1] |= MT_PROT_CTRL_RTS_CTS;
10028c2ecf20Sopenharmony_ci		vht_prot[2] |= MT_PROT_CTRL_RTS_CTS;
10038c2ecf20Sopenharmony_ci		break;
10048c2ecf20Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
10058c2ecf20Sopenharmony_ci		prot[3] |= MT_PROT_CTRL_RTS_CTS;
10068c2ecf20Sopenharmony_ci		prot[5] |= MT_PROT_CTRL_RTS_CTS;
10078c2ecf20Sopenharmony_ci		vht_prot[1] |= MT_PROT_CTRL_RTS_CTS;
10088c2ecf20Sopenharmony_ci		vht_prot[2] |= MT_PROT_CTRL_RTS_CTS;
10098c2ecf20Sopenharmony_ci		break;
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	if (non_gf) {
10138c2ecf20Sopenharmony_ci		prot[4] |= MT_PROT_CTRL_RTS_CTS;
10148c2ecf20Sopenharmony_ci		prot[5] |= MT_PROT_CTRL_RTS_CTS;
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(prot); i++)
10188c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(vht_prot); i++)
10218c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]);
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_civoid mt76x02_update_channel(struct mt76_dev *mdev)
10258c2ecf20Sopenharmony_ci{
10268c2ecf20Sopenharmony_ci	struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
10278c2ecf20Sopenharmony_ci	struct mt76_channel_state *state;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	state = mdev->phy.chan_state;
10308c2ecf20Sopenharmony_ci	state->cc_busy += mt76_rr(dev, MT_CH_BUSY);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	spin_lock_bh(&dev->mt76.cc_lock);
10338c2ecf20Sopenharmony_ci	state->cc_tx += dev->tx_airtime;
10348c2ecf20Sopenharmony_ci	dev->tx_airtime = 0;
10358c2ecf20Sopenharmony_ci	spin_unlock_bh(&dev->mt76.cc_lock);
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_update_channel);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_cistatic void mt76x02_check_mac_err(struct mt76x02_dev *dev)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	u32 val = mt76_rr(dev, 0x10f4);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
10448c2ecf20Sopenharmony_ci		return;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	dev_err(dev->mt76.dev, "mac specific condition occurred\n");
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
10498c2ecf20Sopenharmony_ci	udelay(10);
10508c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MAC_SYS_CTRL,
10518c2ecf20Sopenharmony_ci		MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic void
10558c2ecf20Sopenharmony_cimt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	if (enable) {
10588c2ecf20Sopenharmony_ci		u32 data;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci		mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
10618c2ecf20Sopenharmony_ci		mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN);
10628c2ecf20Sopenharmony_ci		/* enable pa-lna */
10638c2ecf20Sopenharmony_ci		data = mt76_rr(dev, MT_TX_PIN_CFG);
10648c2ecf20Sopenharmony_ci		data |= MT_TX_PIN_CFG_TXANT |
10658c2ecf20Sopenharmony_ci			MT_TX_PIN_CFG_RXANT |
10668c2ecf20Sopenharmony_ci			MT_TX_PIN_RFTR_EN |
10678c2ecf20Sopenharmony_ci			MT_TX_PIN_TRSW_EN;
10688c2ecf20Sopenharmony_ci		mt76_wr(dev, MT_TX_PIN_CFG, data);
10698c2ecf20Sopenharmony_ci	} else {
10708c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
10718c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN);
10728c2ecf20Sopenharmony_ci		/* disable pa-lna */
10738c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT);
10748c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_RXANT);
10758c2ecf20Sopenharmony_ci	}
10768c2ecf20Sopenharmony_ci	dev->ed_tx_blocked = !enable;
10778c2ecf20Sopenharmony_ci}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_civoid mt76x02_edcca_init(struct mt76x02_dev *dev)
10808c2ecf20Sopenharmony_ci{
10818c2ecf20Sopenharmony_ci	dev->ed_trigger = 0;
10828c2ecf20Sopenharmony_ci	dev->ed_silent = 0;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	if (dev->ed_monitor) {
10858c2ecf20Sopenharmony_ci		struct ieee80211_channel *chan = dev->mphy.chandef.chan;
10868c2ecf20Sopenharmony_ci		u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN);
10898c2ecf20Sopenharmony_ci		mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
10908c2ecf20Sopenharmony_ci		mt76_rmw(dev, MT_BBP(AGC, 2), GENMASK(15, 0),
10918c2ecf20Sopenharmony_ci			 ed_th << 8 | ed_th);
10928c2ecf20Sopenharmony_ci		mt76_set(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN);
10938c2ecf20Sopenharmony_ci	} else {
10948c2ecf20Sopenharmony_ci		mt76_set(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN);
10958c2ecf20Sopenharmony_ci		mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN);
10968c2ecf20Sopenharmony_ci		if (is_mt76x2(dev)) {
10978c2ecf20Sopenharmony_ci			mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070);
10988c2ecf20Sopenharmony_ci			mt76_set(dev, MT_TXOP_HLDR_ET,
10998c2ecf20Sopenharmony_ci				 MT_TXOP_HLDR_TX40M_BLK_EN);
11008c2ecf20Sopenharmony_ci		} else {
11018c2ecf20Sopenharmony_ci			mt76_wr(dev, MT_BBP(AGC, 2), 0x003a6464);
11028c2ecf20Sopenharmony_ci			mt76_clear(dev, MT_TXOP_HLDR_ET,
11038c2ecf20Sopenharmony_ci				   MT_TXOP_HLDR_TX40M_BLK_EN);
11048c2ecf20Sopenharmony_ci		}
11058c2ecf20Sopenharmony_ci	}
11068c2ecf20Sopenharmony_ci	mt76x02_edcca_tx_enable(dev, true);
11078c2ecf20Sopenharmony_ci	dev->ed_monitor_learning = true;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/* clear previous CCA timer value */
11108c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_ED_CCA_TIMER);
11118c2ecf20Sopenharmony_ci	dev->ed_time = ktime_get_boottime();
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_edcca_init);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci#define MT_EDCCA_TH		92
11168c2ecf20Sopenharmony_ci#define MT_EDCCA_BLOCK_TH	2
11178c2ecf20Sopenharmony_ci#define MT_EDCCA_LEARN_TH	50
11188c2ecf20Sopenharmony_ci#define MT_EDCCA_LEARN_CCA	180
11198c2ecf20Sopenharmony_ci#define MT_EDCCA_LEARN_TIMEOUT	(20 * HZ)
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic void mt76x02_edcca_check(struct mt76x02_dev *dev)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	ktime_t cur_time;
11248c2ecf20Sopenharmony_ci	u32 active, val, busy;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	cur_time = ktime_get_boottime();
11278c2ecf20Sopenharmony_ci	val = mt76_rr(dev, MT_ED_CCA_TIMER);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	active = ktime_to_us(ktime_sub(cur_time, dev->ed_time));
11308c2ecf20Sopenharmony_ci	dev->ed_time = cur_time;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	busy = (val * 100) / active;
11338c2ecf20Sopenharmony_ci	busy = min_t(u32, busy, 100);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	if (busy > MT_EDCCA_TH) {
11368c2ecf20Sopenharmony_ci		dev->ed_trigger++;
11378c2ecf20Sopenharmony_ci		dev->ed_silent = 0;
11388c2ecf20Sopenharmony_ci	} else {
11398c2ecf20Sopenharmony_ci		dev->ed_silent++;
11408c2ecf20Sopenharmony_ci		dev->ed_trigger = 0;
11418c2ecf20Sopenharmony_ci	}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	if (dev->cal.agc_lowest_gain &&
11448c2ecf20Sopenharmony_ci	    dev->cal.false_cca > MT_EDCCA_LEARN_CCA &&
11458c2ecf20Sopenharmony_ci	    dev->ed_trigger > MT_EDCCA_LEARN_TH) {
11468c2ecf20Sopenharmony_ci		dev->ed_monitor_learning = false;
11478c2ecf20Sopenharmony_ci		dev->ed_trigger_timeout = jiffies + 20 * HZ;
11488c2ecf20Sopenharmony_ci	} else if (!dev->ed_monitor_learning &&
11498c2ecf20Sopenharmony_ci		   time_is_after_jiffies(dev->ed_trigger_timeout)) {
11508c2ecf20Sopenharmony_ci		dev->ed_monitor_learning = true;
11518c2ecf20Sopenharmony_ci		mt76x02_edcca_tx_enable(dev, true);
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (dev->ed_monitor_learning)
11558c2ecf20Sopenharmony_ci		return;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	if (dev->ed_trigger > MT_EDCCA_BLOCK_TH && !dev->ed_tx_blocked)
11588c2ecf20Sopenharmony_ci		mt76x02_edcca_tx_enable(dev, false);
11598c2ecf20Sopenharmony_ci	else if (dev->ed_silent > MT_EDCCA_BLOCK_TH && dev->ed_tx_blocked)
11608c2ecf20Sopenharmony_ci		mt76x02_edcca_tx_enable(dev, true);
11618c2ecf20Sopenharmony_ci}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_civoid mt76x02_mac_work(struct work_struct *work)
11648c2ecf20Sopenharmony_ci{
11658c2ecf20Sopenharmony_ci	struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev,
11668c2ecf20Sopenharmony_ci					       mt76.mac_work.work);
11678c2ecf20Sopenharmony_ci	int i, idx;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	mutex_lock(&dev->mt76.mutex);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	mt76_update_survey(&dev->mt76);
11728c2ecf20Sopenharmony_ci	for (i = 0, idx = 0; i < 16; i++) {
11738c2ecf20Sopenharmony_ci		u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci		dev->mt76.aggr_stats[idx++] += val & 0xffff;
11768c2ecf20Sopenharmony_ci		dev->mt76.aggr_stats[idx++] += val >> 16;
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	if (!dev->mt76.beacon_mask)
11808c2ecf20Sopenharmony_ci		mt76x02_check_mac_err(dev);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (dev->ed_monitor)
11838c2ecf20Sopenharmony_ci		mt76x02_edcca_check(dev);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	mutex_unlock(&dev->mt76.mutex);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	mt76_tx_status_check(&dev->mt76, NULL, false);
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
11908c2ecf20Sopenharmony_ci				     MT_MAC_WORK_INTERVAL);
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_civoid mt76x02_mac_cc_reset(struct mt76x02_dev *dev)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	dev->mphy.survey_time = ktime_get_boottime();
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_CH_TIME_CFG,
11988c2ecf20Sopenharmony_ci		MT_CH_TIME_CFG_TIMER_EN |
11998c2ecf20Sopenharmony_ci		MT_CH_TIME_CFG_TX_AS_BUSY |
12008c2ecf20Sopenharmony_ci		MT_CH_TIME_CFG_RX_AS_BUSY |
12018c2ecf20Sopenharmony_ci		MT_CH_TIME_CFG_NAV_AS_BUSY |
12028c2ecf20Sopenharmony_ci		MT_CH_TIME_CFG_EIFS_AS_BUSY |
12038c2ecf20Sopenharmony_ci		MT_CH_CCA_RC_EN |
12048c2ecf20Sopenharmony_ci		FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	/* channel cycle counters read-and-clear */
12078c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_CH_BUSY);
12088c2ecf20Sopenharmony_ci	mt76_rr(dev, MT_CH_IDLE);
12098c2ecf20Sopenharmony_ci}
12108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mt76x02_mac_cc_reset);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_civoid mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
12138c2ecf20Sopenharmony_ci{
12148c2ecf20Sopenharmony_ci	idx &= 7;
12158c2ecf20Sopenharmony_ci	mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr));
12168c2ecf20Sopenharmony_ci	mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR,
12178c2ecf20Sopenharmony_ci		       get_unaligned_le16(addr + 4));
12188c2ecf20Sopenharmony_ci}
1219