162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC
262306a36Sopenharmony_ci/* Copyright (C) 2019 MediaTek Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Author: Ryder Lee <ryder.lee@mediatek.com>
562306a36Sopenharmony_ci *         Roy Luo <royluo@google.com>
662306a36Sopenharmony_ci *         Felix Fietkau <nbd@nbd.name>
762306a36Sopenharmony_ci *         Lorenzo Bianconi <lorenzo@kernel.org>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/devcoredump.h>
1162306a36Sopenharmony_ci#include <linux/etherdevice.h>
1262306a36Sopenharmony_ci#include <linux/timekeeping.h>
1362306a36Sopenharmony_ci#include "mt7615.h"
1462306a36Sopenharmony_ci#include "../trace.h"
1562306a36Sopenharmony_ci#include "../dma.h"
1662306a36Sopenharmony_ci#include "mt7615_trace.h"
1762306a36Sopenharmony_ci#include "mac.h"
1862306a36Sopenharmony_ci#include "mcu.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define to_rssi(field, rxv)		((FIELD_GET(field, rxv) - 220) / 2)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic const struct mt7615_dfs_radar_spec etsi_radar_specs = {
2362306a36Sopenharmony_ci	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
2462306a36Sopenharmony_ci	.radar_pattern = {
2562306a36Sopenharmony_ci		[5] =  { 1, 0,  6, 32, 28, 0, 17,  990, 5010, 1, 1 },
2662306a36Sopenharmony_ci		[6] =  { 1, 0,  9, 32, 28, 0, 27,  615, 5010, 1, 1 },
2762306a36Sopenharmony_ci		[7] =  { 1, 0, 15, 32, 28, 0, 27,  240,  445, 1, 1 },
2862306a36Sopenharmony_ci		[8] =  { 1, 0, 12, 32, 28, 0, 42,  240,  510, 1, 1 },
2962306a36Sopenharmony_ci		[9] =  { 1, 1,  0,  0,  0, 0, 14, 2490, 3343, 0, 0, 12, 32, 28 },
3062306a36Sopenharmony_ci		[10] = { 1, 1,  0,  0,  0, 0, 14, 2490, 3343, 0, 0, 15, 32, 24 },
3162306a36Sopenharmony_ci		[11] = { 1, 1,  0,  0,  0, 0, 14,  823, 2510, 0, 0, 18, 32, 28 },
3262306a36Sopenharmony_ci		[12] = { 1, 1,  0,  0,  0, 0, 14,  823, 2510, 0, 0, 27, 32, 24 },
3362306a36Sopenharmony_ci	},
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic const struct mt7615_dfs_radar_spec fcc_radar_specs = {
3762306a36Sopenharmony_ci	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
3862306a36Sopenharmony_ci	.radar_pattern = {
3962306a36Sopenharmony_ci		[0] = { 1, 0,  9,  32, 28, 0, 13, 508, 3076, 1,  1 },
4062306a36Sopenharmony_ci		[1] = { 1, 0, 12,  32, 28, 0, 17, 140,  240, 1,  1 },
4162306a36Sopenharmony_ci		[2] = { 1, 0,  8,  32, 28, 0, 22, 190,  510, 1,  1 },
4262306a36Sopenharmony_ci		[3] = { 1, 0,  6,  32, 28, 0, 32, 190,  510, 1,  1 },
4362306a36Sopenharmony_ci		[4] = { 1, 0,  9, 255, 28, 0, 13, 323,  343, 1, 32 },
4462306a36Sopenharmony_ci	},
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const struct mt7615_dfs_radar_spec jp_radar_specs = {
4862306a36Sopenharmony_ci	.pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
4962306a36Sopenharmony_ci	.radar_pattern = {
5062306a36Sopenharmony_ci		[0] =  { 1, 0,  8, 32, 28, 0, 13,  508, 3076, 1,  1 },
5162306a36Sopenharmony_ci		[1] =  { 1, 0, 12, 32, 28, 0, 17,  140,  240, 1,  1 },
5262306a36Sopenharmony_ci		[2] =  { 1, 0,  8, 32, 28, 0, 22,  190,  510, 1,  1 },
5362306a36Sopenharmony_ci		[3] =  { 1, 0,  6, 32, 28, 0, 32,  190,  510, 1,  1 },
5462306a36Sopenharmony_ci		[4] =  { 1, 0,  9, 32, 28, 0, 13,  323,  343, 1, 32 },
5562306a36Sopenharmony_ci		[13] = { 1, 0, 8,  32, 28, 0, 14, 3836, 3856, 1,  1 },
5662306a36Sopenharmony_ci		[14] = { 1, 0, 8,  32, 28, 0, 14, 3990, 4010, 1,  1 },
5762306a36Sopenharmony_ci	},
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic enum mt76_cipher_type
6162306a36Sopenharmony_cimt7615_mac_get_cipher(int cipher)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	switch (cipher) {
6462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
6562306a36Sopenharmony_ci		return MT_CIPHER_WEP40;
6662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
6762306a36Sopenharmony_ci		return MT_CIPHER_WEP104;
6862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
6962306a36Sopenharmony_ci		return MT_CIPHER_TKIP;
7062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_AES_CMAC:
7162306a36Sopenharmony_ci		return MT_CIPHER_BIP_CMAC_128;
7262306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
7362306a36Sopenharmony_ci		return MT_CIPHER_AES_CCMP;
7462306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP_256:
7562306a36Sopenharmony_ci		return MT_CIPHER_CCMP_256;
7662306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP:
7762306a36Sopenharmony_ci		return MT_CIPHER_GCMP;
7862306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_GCMP_256:
7962306a36Sopenharmony_ci		return MT_CIPHER_GCMP_256;
8062306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_SMS4:
8162306a36Sopenharmony_ci		return MT_CIPHER_WAPI;
8262306a36Sopenharmony_ci	default:
8362306a36Sopenharmony_ci		return MT_CIPHER_NONE;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
8862306a36Sopenharmony_ci					    u8 idx, bool unicast)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct mt7615_sta *sta;
9162306a36Sopenharmony_ci	struct mt76_wcid *wcid;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (idx >= MT7615_WTBL_SIZE)
9462306a36Sopenharmony_ci		return NULL;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[idx]);
9762306a36Sopenharmony_ci	if (unicast || !wcid)
9862306a36Sopenharmony_ci		return wcid;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (!wcid->sta)
10162306a36Sopenharmony_ci		return NULL;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	sta = container_of(wcid, struct mt7615_sta, wcid);
10462306a36Sopenharmony_ci	if (!sta->vif)
10562306a36Sopenharmony_ci		return NULL;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return &sta->vif->sta.wcid;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_civoid mt7615_mac_reset_counters(struct mt7615_phy *phy)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
11362306a36Sopenharmony_ci	int i;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
11662306a36Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(0, i));
11762306a36Sopenharmony_ci		mt76_rr(dev, MT_TX_AGG_CNT(1, i));
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	memset(phy->mt76->aggr_stats, 0, sizeof(phy->mt76->aggr_stats));
12162306a36Sopenharmony_ci	phy->mt76->survey_time = ktime_get_boottime();
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	/* reset airtime counters */
12462306a36Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR9(0));
12562306a36Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR9(1));
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR36(0));
12862306a36Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR36(1));
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR37(0));
13162306a36Sopenharmony_ci	mt76_rr(dev, MT_MIB_SDR37(1));
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
13462306a36Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_civoid mt7615_mac_set_timing(struct mt7615_phy *phy)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	s16 coverage_class = phy->coverage_class;
14062306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
14162306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
14262306a36Sopenharmony_ci	u32 val, reg_offset;
14362306a36Sopenharmony_ci	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
14462306a36Sopenharmony_ci		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
14562306a36Sopenharmony_ci	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
14662306a36Sopenharmony_ci		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
14762306a36Sopenharmony_ci	int sifs, offset;
14862306a36Sopenharmony_ci	bool is_5ghz = phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
15162306a36Sopenharmony_ci		return;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	if (is_5ghz)
15462306a36Sopenharmony_ci		sifs = 16;
15562306a36Sopenharmony_ci	else
15662306a36Sopenharmony_ci		sifs = 10;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (ext_phy) {
15962306a36Sopenharmony_ci		coverage_class = max_t(s16, dev->phy.coverage_class,
16062306a36Sopenharmony_ci				       coverage_class);
16162306a36Sopenharmony_ci		mt76_set(dev, MT_ARB_SCR,
16262306a36Sopenharmony_ci			 MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE);
16362306a36Sopenharmony_ci	} else {
16462306a36Sopenharmony_ci		struct mt7615_phy *phy_ext = mt7615_ext_phy(dev);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		if (phy_ext)
16762306a36Sopenharmony_ci			coverage_class = max_t(s16, phy_ext->coverage_class,
16862306a36Sopenharmony_ci					       coverage_class);
16962306a36Sopenharmony_ci		mt76_set(dev, MT_ARB_SCR,
17062306a36Sopenharmony_ci			 MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	udelay(1);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	offset = 3 * coverage_class;
17562306a36Sopenharmony_ci	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
17662306a36Sopenharmony_ci		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
17762306a36Sopenharmony_ci	mt76_wr(dev, MT_TMAC_CDTR, cck + reg_offset);
17862306a36Sopenharmony_ci	mt76_wr(dev, MT_TMAC_ODTR, ofdm + reg_offset);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	mt76_wr(dev, MT_TMAC_ICR(ext_phy),
18162306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_EIFS, 360) |
18262306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_RIFS, 2) |
18362306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_SIFS, sifs) |
18462306a36Sopenharmony_ci		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (phy->slottime < 20 || is_5ghz)
18762306a36Sopenharmony_ci		val = MT7615_CFEND_RATE_DEFAULT;
18862306a36Sopenharmony_ci	else
18962306a36Sopenharmony_ci		val = MT7615_CFEND_RATE_11B;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mt76_rmw_field(dev, MT_AGG_ACR(ext_phy), MT_AGG_ACR_CFEND_RATE, val);
19262306a36Sopenharmony_ci	if (ext_phy)
19362306a36Sopenharmony_ci		mt76_clear(dev, MT_ARB_SCR,
19462306a36Sopenharmony_ci			   MT_ARB_SCR_TX1_DISABLE | MT_ARB_SCR_RX1_DISABLE);
19562306a36Sopenharmony_ci	else
19662306a36Sopenharmony_ci		mt76_clear(dev, MT_ARB_SCR,
19762306a36Sopenharmony_ci			   MT_ARB_SCR_TX0_DISABLE | MT_ARB_SCR_RX0_DISABLE);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void
20262306a36Sopenharmony_cimt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy,
20362306a36Sopenharmony_ci			    struct mt76_rx_status *status, u8 chfreq)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	if (!test_bit(MT76_HW_SCANNING, &mphy->state) &&
20662306a36Sopenharmony_ci	    !test_bit(MT76_HW_SCHED_SCANNING, &mphy->state) &&
20762306a36Sopenharmony_ci	    !test_bit(MT76_STATE_ROC, &mphy->state)) {
20862306a36Sopenharmony_ci		status->freq = mphy->chandef.chan->center_freq;
20962306a36Sopenharmony_ci		status->band = mphy->chandef.chan->band;
21062306a36Sopenharmony_ci		return;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	status->band = chfreq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
21462306a36Sopenharmony_ci	status->freq = ieee80211_channel_to_frequency(chfreq, status->band);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void mt7615_mac_fill_tm_rx(struct mt7615_phy *phy, __le32 *rxv)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci#ifdef CONFIG_NL80211_TESTMODE
22062306a36Sopenharmony_ci	u32 rxv1 = le32_to_cpu(rxv[0]);
22162306a36Sopenharmony_ci	u32 rxv3 = le32_to_cpu(rxv[2]);
22262306a36Sopenharmony_ci	u32 rxv4 = le32_to_cpu(rxv[3]);
22362306a36Sopenharmony_ci	u32 rxv5 = le32_to_cpu(rxv[4]);
22462306a36Sopenharmony_ci	u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1);
22562306a36Sopenharmony_ci	u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1);
22662306a36Sopenharmony_ci	s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5);
22762306a36Sopenharmony_ci	u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (!mode) {
23062306a36Sopenharmony_ci		/* CCK */
23162306a36Sopenharmony_ci		foe &= ~BIT(11);
23262306a36Sopenharmony_ci		foe *= 1000;
23362306a36Sopenharmony_ci		foe >>= 11;
23462306a36Sopenharmony_ci	} else {
23562306a36Sopenharmony_ci		if (foe > 2048)
23662306a36Sopenharmony_ci			foe -= 4096;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		foe = (foe * foe_const) >> 15;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	phy->test.last_freq_offset = foe;
24262306a36Sopenharmony_ci	phy->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4);
24362306a36Sopenharmony_ci	phy->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4);
24462306a36Sopenharmony_ci	phy->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4);
24562306a36Sopenharmony_ci	phy->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4);
24662306a36Sopenharmony_ci	phy->test.last_ib_rssi[0] = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
24762306a36Sopenharmony_ci	phy->test.last_wb_rssi[0] = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
24862306a36Sopenharmony_ci#endif
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/* The HW does not translate the mac header to 802.3 for mesh point */
25262306a36Sopenharmony_cistatic int mt7615_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
25562306a36Sopenharmony_ci	struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
25662306a36Sopenharmony_ci	struct mt7615_sta *msta = (struct mt7615_sta *)status->wcid;
25762306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
25862306a36Sopenharmony_ci	struct ieee80211_sta *sta;
25962306a36Sopenharmony_ci	struct ieee80211_vif *vif;
26062306a36Sopenharmony_ci	struct ieee80211_hdr hdr;
26162306a36Sopenharmony_ci	u16 frame_control;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (le32_get_bits(rxd[1], MT_RXD1_NORMAL_ADDR_TYPE) !=
26462306a36Sopenharmony_ci	    MT_RXD1_NORMAL_U2M)
26562306a36Sopenharmony_ci		return -EINVAL;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (!(le32_to_cpu(rxd[0]) & MT_RXD0_NORMAL_GROUP_4))
26862306a36Sopenharmony_ci		return -EINVAL;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (!msta || !msta->vif)
27162306a36Sopenharmony_ci		return -EINVAL;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
27462306a36Sopenharmony_ci	vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* store the info from RXD and ethhdr to avoid being overridden */
27762306a36Sopenharmony_ci	frame_control = le32_get_bits(rxd[4], MT_RXD4_FRAME_CONTROL);
27862306a36Sopenharmony_ci	hdr.frame_control = cpu_to_le16(frame_control);
27962306a36Sopenharmony_ci	hdr.seq_ctrl = cpu_to_le16(le32_get_bits(rxd[6], MT_RXD6_SEQ_CTRL));
28062306a36Sopenharmony_ci	hdr.duration_id = 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	ether_addr_copy(hdr.addr1, vif->addr);
28362306a36Sopenharmony_ci	ether_addr_copy(hdr.addr2, sta->addr);
28462306a36Sopenharmony_ci	switch (frame_control & (IEEE80211_FCTL_TODS |
28562306a36Sopenharmony_ci				 IEEE80211_FCTL_FROMDS)) {
28662306a36Sopenharmony_ci	case 0:
28762306a36Sopenharmony_ci		ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
28862306a36Sopenharmony_ci		break;
28962306a36Sopenharmony_ci	case IEEE80211_FCTL_FROMDS:
29062306a36Sopenharmony_ci		ether_addr_copy(hdr.addr3, eth_hdr->h_source);
29162306a36Sopenharmony_ci		break;
29262306a36Sopenharmony_ci	case IEEE80211_FCTL_TODS:
29362306a36Sopenharmony_ci		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci	case IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS:
29662306a36Sopenharmony_ci		ether_addr_copy(hdr.addr3, eth_hdr->h_dest);
29762306a36Sopenharmony_ci		ether_addr_copy(hdr.addr4, eth_hdr->h_source);
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	default:
30062306a36Sopenharmony_ci		break;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
30462306a36Sopenharmony_ci	if (eth_hdr->h_proto == cpu_to_be16(ETH_P_AARP) ||
30562306a36Sopenharmony_ci	    eth_hdr->h_proto == cpu_to_be16(ETH_P_IPX))
30662306a36Sopenharmony_ci		ether_addr_copy(skb_push(skb, ETH_ALEN), bridge_tunnel_header);
30762306a36Sopenharmony_ci	else if (be16_to_cpu(eth_hdr->h_proto) >= ETH_P_802_3_MIN)
30862306a36Sopenharmony_ci		ether_addr_copy(skb_push(skb, ETH_ALEN), rfc1042_header);
30962306a36Sopenharmony_ci	else
31062306a36Sopenharmony_ci		skb_pull(skb, 2);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (ieee80211_has_order(hdr.frame_control))
31362306a36Sopenharmony_ci		memcpy(skb_push(skb, IEEE80211_HT_CTL_LEN), &rxd[7],
31462306a36Sopenharmony_ci		       IEEE80211_HT_CTL_LEN);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (ieee80211_is_data_qos(hdr.frame_control)) {
31762306a36Sopenharmony_ci		__le16 qos_ctrl;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		qos_ctrl = cpu_to_le16(le32_get_bits(rxd[6], MT_RXD6_QOS_CTL));
32062306a36Sopenharmony_ci		memcpy(skb_push(skb, IEEE80211_QOS_CTL_LEN), &qos_ctrl,
32162306a36Sopenharmony_ci		       IEEE80211_QOS_CTL_LEN);
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (ieee80211_has_a4(hdr.frame_control))
32562306a36Sopenharmony_ci		memcpy(skb_push(skb, sizeof(hdr)), &hdr, sizeof(hdr));
32662306a36Sopenharmony_ci	else
32762306a36Sopenharmony_ci		memcpy(skb_push(skb, sizeof(hdr) - 6), &hdr, sizeof(hdr) - 6);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	status->flag &= ~(RX_FLAG_RADIOTAP_HE | RX_FLAG_RADIOTAP_HE_MU);
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
33662306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
33762306a36Sopenharmony_ci	struct mt7615_phy *phy = &dev->phy;
33862306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
33962306a36Sopenharmony_ci	struct ieee80211_hdr *hdr;
34062306a36Sopenharmony_ci	struct mt7615_phy *phy2;
34162306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
34262306a36Sopenharmony_ci	u32 rxd0 = le32_to_cpu(rxd[0]);
34362306a36Sopenharmony_ci	u32 rxd1 = le32_to_cpu(rxd[1]);
34462306a36Sopenharmony_ci	u32 rxd2 = le32_to_cpu(rxd[2]);
34562306a36Sopenharmony_ci	u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
34662306a36Sopenharmony_ci	u32 csum_status = *(u32 *)skb->cb;
34762306a36Sopenharmony_ci	bool unicast, hdr_trans, remove_pad, insert_ccmp_hdr = false;
34862306a36Sopenharmony_ci	u16 hdr_gap;
34962306a36Sopenharmony_ci	int phy_idx;
35062306a36Sopenharmony_ci	int i, idx;
35162306a36Sopenharmony_ci	u8 chfreq, amsdu_info, qos_ctl = 0;
35262306a36Sopenharmony_ci	u16 seq_ctrl = 0;
35362306a36Sopenharmony_ci	__le16 fc = 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	memset(status, 0, sizeof(*status));
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	chfreq = FIELD_GET(MT_RXD1_NORMAL_CH_FREQ, rxd1);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	phy2 = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
36062306a36Sopenharmony_ci	if (!phy2)
36162306a36Sopenharmony_ci		phy_idx = 0;
36262306a36Sopenharmony_ci	else if (phy2->chfreq == phy->chfreq)
36362306a36Sopenharmony_ci		phy_idx = -1;
36462306a36Sopenharmony_ci	else if (phy->chfreq == chfreq)
36562306a36Sopenharmony_ci		phy_idx = 0;
36662306a36Sopenharmony_ci	else if (phy2->chfreq == chfreq)
36762306a36Sopenharmony_ci		phy_idx = 1;
36862306a36Sopenharmony_ci	else
36962306a36Sopenharmony_ci		phy_idx = -1;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_AMSDU_ERR)
37262306a36Sopenharmony_ci		return -EINVAL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	hdr_trans = rxd1 & MT_RXD1_NORMAL_HDR_TRANS;
37562306a36Sopenharmony_ci	if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_CM))
37662306a36Sopenharmony_ci		return -EINVAL;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/* ICV error or CCMP/BIP/WPI MIC error */
37962306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_ICV_ERR)
38062306a36Sopenharmony_ci		status->flag |= RX_FLAG_ONLY_MONITOR;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	unicast = (rxd1 & MT_RXD1_NORMAL_ADDR_TYPE) == MT_RXD1_NORMAL_U2M;
38362306a36Sopenharmony_ci	idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
38462306a36Sopenharmony_ci	status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (status->wcid) {
38762306a36Sopenharmony_ci		struct mt7615_sta *msta;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		msta = container_of(status->wcid, struct mt7615_sta, wcid);
39062306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
39162306a36Sopenharmony_ci		if (list_empty(&msta->wcid.poll_list))
39262306a36Sopenharmony_ci			list_add_tail(&msta->wcid.poll_list,
39362306a36Sopenharmony_ci				      &dev->mt76.sta_poll_list);
39462306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (mt76_is_mmio(&dev->mt76) && (rxd0 & csum_mask) == csum_mask &&
39862306a36Sopenharmony_ci	    !(csum_status & (BIT(0) | BIT(2) | BIT(3))))
39962306a36Sopenharmony_ci		skb->ip_summed = CHECKSUM_UNNECESSARY;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_FCS_ERR)
40262306a36Sopenharmony_ci		status->flag |= RX_FLAG_FAILED_FCS_CRC;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_TKIP_MIC_ERR)
40562306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_ERROR;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2) != 0 &&
40862306a36Sopenharmony_ci	    !(rxd2 & (MT_RXD2_NORMAL_CLM | MT_RXD2_NORMAL_CM))) {
40962306a36Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
41062306a36Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
41162306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
41762306a36Sopenharmony_ci		return -EINVAL;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	rxd += 4;
42062306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_4) {
42162306a36Sopenharmony_ci		u32 v0 = le32_to_cpu(rxd[0]);
42262306a36Sopenharmony_ci		u32 v2 = le32_to_cpu(rxd[2]);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci		fc = cpu_to_le16(FIELD_GET(MT_RXD4_FRAME_CONTROL, v0));
42562306a36Sopenharmony_ci		qos_ctl = FIELD_GET(MT_RXD6_QOS_CTL, v2);
42662306a36Sopenharmony_ci		seq_ctrl = FIELD_GET(MT_RXD6_SEQ_CTRL, v2);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		rxd += 4;
42962306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
43062306a36Sopenharmony_ci			return -EINVAL;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_1) {
43462306a36Sopenharmony_ci		u8 *data = (u8 *)rxd;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		if (status->flag & RX_FLAG_DECRYPTED) {
43762306a36Sopenharmony_ci			switch (FIELD_GET(MT_RXD2_NORMAL_SEC_MODE, rxd2)) {
43862306a36Sopenharmony_ci			case MT_CIPHER_AES_CCMP:
43962306a36Sopenharmony_ci			case MT_CIPHER_CCMP_CCX:
44062306a36Sopenharmony_ci			case MT_CIPHER_CCMP_256:
44162306a36Sopenharmony_ci				insert_ccmp_hdr =
44262306a36Sopenharmony_ci					FIELD_GET(MT_RXD2_NORMAL_FRAG, rxd2);
44362306a36Sopenharmony_ci				fallthrough;
44462306a36Sopenharmony_ci			case MT_CIPHER_TKIP:
44562306a36Sopenharmony_ci			case MT_CIPHER_TKIP_NO_MIC:
44662306a36Sopenharmony_ci			case MT_CIPHER_GCMP:
44762306a36Sopenharmony_ci			case MT_CIPHER_GCMP_256:
44862306a36Sopenharmony_ci				status->iv[0] = data[5];
44962306a36Sopenharmony_ci				status->iv[1] = data[4];
45062306a36Sopenharmony_ci				status->iv[2] = data[3];
45162306a36Sopenharmony_ci				status->iv[3] = data[2];
45262306a36Sopenharmony_ci				status->iv[4] = data[1];
45362306a36Sopenharmony_ci				status->iv[5] = data[0];
45462306a36Sopenharmony_ci				break;
45562306a36Sopenharmony_ci			default:
45662306a36Sopenharmony_ci				break;
45762306a36Sopenharmony_ci			}
45862306a36Sopenharmony_ci		}
45962306a36Sopenharmony_ci		rxd += 4;
46062306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
46162306a36Sopenharmony_ci			return -EINVAL;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_2) {
46562306a36Sopenharmony_ci		status->timestamp = le32_to_cpu(rxd[0]);
46662306a36Sopenharmony_ci		status->flag |= RX_FLAG_MACTIME_START;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci		if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
46962306a36Sopenharmony_ci			      MT_RXD2_NORMAL_NON_AMPDU))) {
47062306a36Sopenharmony_ci			status->flag |= RX_FLAG_AMPDU_DETAILS;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci			/* all subframes of an A-MPDU have the same timestamp */
47362306a36Sopenharmony_ci			if (phy->rx_ampdu_ts != status->timestamp) {
47462306a36Sopenharmony_ci				if (!++phy->ampdu_ref)
47562306a36Sopenharmony_ci					phy->ampdu_ref++;
47662306a36Sopenharmony_ci			}
47762306a36Sopenharmony_ci			phy->rx_ampdu_ts = status->timestamp;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci			status->ampdu_ref = phy->ampdu_ref;
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci		rxd += 2;
48362306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
48462306a36Sopenharmony_ci			return -EINVAL;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
48862306a36Sopenharmony_ci		u32 rxdg5 = le32_to_cpu(rxd[5]);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		/*
49162306a36Sopenharmony_ci		 * If both PHYs are on the same channel and we don't have a WCID,
49262306a36Sopenharmony_ci		 * we need to figure out which PHY this packet was received on.
49362306a36Sopenharmony_ci		 * On the primary PHY, the noise value for the chains belonging to the
49462306a36Sopenharmony_ci		 * second PHY will be set to the noise value of the last packet from
49562306a36Sopenharmony_ci		 * that PHY.
49662306a36Sopenharmony_ci		 */
49762306a36Sopenharmony_ci		if (phy_idx < 0) {
49862306a36Sopenharmony_ci			int first_chain = ffs(phy2->mt76->chainmask) - 1;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci			phy_idx = ((rxdg5 >> (first_chain * 8)) & 0xff) == 0;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (phy_idx == 1 && phy2) {
50562306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
50662306a36Sopenharmony_ci		phy = phy2;
50762306a36Sopenharmony_ci		status->phy_idx = phy_idx;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (!mt7615_firmware_offload(dev) && chfreq != phy->chfreq)
51162306a36Sopenharmony_ci		return -EINVAL;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	mt7615_get_status_freq_info(dev, mphy, status, chfreq);
51462306a36Sopenharmony_ci	if (status->band == NL80211_BAND_5GHZ)
51562306a36Sopenharmony_ci		sband = &mphy->sband_5g.sband;
51662306a36Sopenharmony_ci	else
51762306a36Sopenharmony_ci		sband = &mphy->sband_2g.sband;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
52062306a36Sopenharmony_ci		return -EINVAL;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (!sband->channels)
52362306a36Sopenharmony_ci		return -EINVAL;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	if (rxd0 & MT_RXD0_NORMAL_GROUP_3) {
52662306a36Sopenharmony_ci		u32 rxdg0 = le32_to_cpu(rxd[0]);
52762306a36Sopenharmony_ci		u32 rxdg1 = le32_to_cpu(rxd[1]);
52862306a36Sopenharmony_ci		u32 rxdg3 = le32_to_cpu(rxd[3]);
52962306a36Sopenharmony_ci		u8 stbc = FIELD_GET(MT_RXV1_HT_STBC, rxdg0);
53062306a36Sopenharmony_ci		bool cck = false;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		i = FIELD_GET(MT_RXV1_TX_RATE, rxdg0);
53362306a36Sopenharmony_ci		switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
53462306a36Sopenharmony_ci		case MT_PHY_TYPE_CCK:
53562306a36Sopenharmony_ci			cck = true;
53662306a36Sopenharmony_ci			fallthrough;
53762306a36Sopenharmony_ci		case MT_PHY_TYPE_OFDM:
53862306a36Sopenharmony_ci			i = mt76_get_rate(&dev->mt76, sband, i, cck);
53962306a36Sopenharmony_ci			break;
54062306a36Sopenharmony_ci		case MT_PHY_TYPE_HT_GF:
54162306a36Sopenharmony_ci		case MT_PHY_TYPE_HT:
54262306a36Sopenharmony_ci			status->encoding = RX_ENC_HT;
54362306a36Sopenharmony_ci			if (i > 31)
54462306a36Sopenharmony_ci				return -EINVAL;
54562306a36Sopenharmony_ci			break;
54662306a36Sopenharmony_ci		case MT_PHY_TYPE_VHT:
54762306a36Sopenharmony_ci			status->nss = FIELD_GET(MT_RXV2_NSTS, rxdg1) + 1;
54862306a36Sopenharmony_ci			status->encoding = RX_ENC_VHT;
54962306a36Sopenharmony_ci			break;
55062306a36Sopenharmony_ci		default:
55162306a36Sopenharmony_ci			return -EINVAL;
55262306a36Sopenharmony_ci		}
55362306a36Sopenharmony_ci		status->rate_idx = i;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		switch (FIELD_GET(MT_RXV1_FRAME_MODE, rxdg0)) {
55662306a36Sopenharmony_ci		case MT_PHY_BW_20:
55762306a36Sopenharmony_ci			break;
55862306a36Sopenharmony_ci		case MT_PHY_BW_40:
55962306a36Sopenharmony_ci			status->bw = RATE_INFO_BW_40;
56062306a36Sopenharmony_ci			break;
56162306a36Sopenharmony_ci		case MT_PHY_BW_80:
56262306a36Sopenharmony_ci			status->bw = RATE_INFO_BW_80;
56362306a36Sopenharmony_ci			break;
56462306a36Sopenharmony_ci		case MT_PHY_BW_160:
56562306a36Sopenharmony_ci			status->bw = RATE_INFO_BW_160;
56662306a36Sopenharmony_ci			break;
56762306a36Sopenharmony_ci		default:
56862306a36Sopenharmony_ci			return -EINVAL;
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_SHORT_GI)
57262306a36Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
57362306a36Sopenharmony_ci		if (rxdg0 & MT_RXV1_HT_AD_CODE)
57462306a36Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_LDPC;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci		status->chains = mphy->antenna_mask;
57962306a36Sopenharmony_ci		status->chain_signal[0] = to_rssi(MT_RXV4_RCPI0, rxdg3);
58062306a36Sopenharmony_ci		status->chain_signal[1] = to_rssi(MT_RXV4_RCPI1, rxdg3);
58162306a36Sopenharmony_ci		status->chain_signal[2] = to_rssi(MT_RXV4_RCPI2, rxdg3);
58262306a36Sopenharmony_ci		status->chain_signal[3] = to_rssi(MT_RXV4_RCPI3, rxdg3);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		mt7615_mac_fill_tm_rx(mphy->priv, rxd);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci		rxd += 6;
58762306a36Sopenharmony_ci		if ((u8 *)rxd - skb->data >= skb->len)
58862306a36Sopenharmony_ci			return -EINVAL;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	amsdu_info = FIELD_GET(MT_RXD1_NORMAL_PAYLOAD_FORMAT, rxd1);
59262306a36Sopenharmony_ci	status->amsdu = !!amsdu_info;
59362306a36Sopenharmony_ci	if (status->amsdu) {
59462306a36Sopenharmony_ci		status->first_amsdu = amsdu_info == MT_RXD1_FIRST_AMSDU_FRAME;
59562306a36Sopenharmony_ci		status->last_amsdu = amsdu_info == MT_RXD1_LAST_AMSDU_FRAME;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
59962306a36Sopenharmony_ci	if (hdr_trans && ieee80211_has_morefrags(fc)) {
60062306a36Sopenharmony_ci		if (mt7615_reverse_frag0_hdr_trans(skb, hdr_gap))
60162306a36Sopenharmony_ci			return -EINVAL;
60262306a36Sopenharmony_ci		hdr_trans = false;
60362306a36Sopenharmony_ci	} else {
60462306a36Sopenharmony_ci		int pad_start = 0;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci		skb_pull(skb, hdr_gap);
60762306a36Sopenharmony_ci		if (!hdr_trans && status->amsdu) {
60862306a36Sopenharmony_ci			pad_start = ieee80211_get_hdrlen_from_skb(skb);
60962306a36Sopenharmony_ci		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
61062306a36Sopenharmony_ci			/*
61162306a36Sopenharmony_ci			 * When header translation failure is indicated,
61262306a36Sopenharmony_ci			 * the hardware will insert an extra 2-byte field
61362306a36Sopenharmony_ci			 * containing the data length after the protocol
61462306a36Sopenharmony_ci			 * type field. This happens either when the LLC-SNAP
61562306a36Sopenharmony_ci			 * pattern did not match, or if a VLAN header was
61662306a36Sopenharmony_ci			 * detected.
61762306a36Sopenharmony_ci			 */
61862306a36Sopenharmony_ci			pad_start = 12;
61962306a36Sopenharmony_ci			if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
62062306a36Sopenharmony_ci				pad_start += 4;
62162306a36Sopenharmony_ci			else
62262306a36Sopenharmony_ci				pad_start = 0;
62362306a36Sopenharmony_ci		}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci		if (pad_start) {
62662306a36Sopenharmony_ci			memmove(skb->data + 2, skb->data, pad_start);
62762306a36Sopenharmony_ci			skb_pull(skb, 2);
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (insert_ccmp_hdr && !hdr_trans) {
63262306a36Sopenharmony_ci		u8 key_id = FIELD_GET(MT_RXD1_NORMAL_KEY_ID, rxd1);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci		mt76_insert_ccmp_hdr(skb, key_id);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (!hdr_trans) {
63862306a36Sopenharmony_ci		hdr = (struct ieee80211_hdr *)skb->data;
63962306a36Sopenharmony_ci		fc = hdr->frame_control;
64062306a36Sopenharmony_ci		if (ieee80211_is_data_qos(fc)) {
64162306a36Sopenharmony_ci			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
64262306a36Sopenharmony_ci			qos_ctl = *ieee80211_get_qos_ctl(hdr);
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci	} else {
64562306a36Sopenharmony_ci		status->flag |= RX_FLAG_8023;
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	if (!status->wcid || !ieee80211_is_data_qos(fc))
64962306a36Sopenharmony_ci		return 0;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	status->aggr = unicast &&
65262306a36Sopenharmony_ci		       !ieee80211_is_qos_nullfunc(fc);
65362306a36Sopenharmony_ci	status->qos_ctl = qos_ctl;
65462306a36Sopenharmony_ci	status->seqno = IEEE80211_SEQ_TO_SN(seq_ctrl);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic u16
66062306a36Sopenharmony_cimt7615_mac_tx_rate_val(struct mt7615_dev *dev,
66162306a36Sopenharmony_ci		       struct mt76_phy *mphy,
66262306a36Sopenharmony_ci		       const struct ieee80211_tx_rate *rate,
66362306a36Sopenharmony_ci		       bool stbc, u8 *bw)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	u8 phy, nss, rate_idx;
66662306a36Sopenharmony_ci	u16 rateval = 0;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	*bw = 0;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
67162306a36Sopenharmony_ci		rate_idx = ieee80211_rate_get_vht_mcs(rate);
67262306a36Sopenharmony_ci		nss = ieee80211_rate_get_vht_nss(rate);
67362306a36Sopenharmony_ci		phy = MT_PHY_TYPE_VHT;
67462306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
67562306a36Sopenharmony_ci			*bw = 1;
67662306a36Sopenharmony_ci		else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
67762306a36Sopenharmony_ci			*bw = 2;
67862306a36Sopenharmony_ci		else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
67962306a36Sopenharmony_ci			*bw = 3;
68062306a36Sopenharmony_ci	} else if (rate->flags & IEEE80211_TX_RC_MCS) {
68162306a36Sopenharmony_ci		rate_idx = rate->idx;
68262306a36Sopenharmony_ci		nss = 1 + (rate->idx >> 3);
68362306a36Sopenharmony_ci		phy = MT_PHY_TYPE_HT;
68462306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
68562306a36Sopenharmony_ci			phy = MT_PHY_TYPE_HT_GF;
68662306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
68762306a36Sopenharmony_ci			*bw = 1;
68862306a36Sopenharmony_ci	} else {
68962306a36Sopenharmony_ci		const struct ieee80211_rate *r;
69062306a36Sopenharmony_ci		int band = mphy->chandef.chan->band;
69162306a36Sopenharmony_ci		u16 val;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		nss = 1;
69462306a36Sopenharmony_ci		r = &mphy->hw->wiphy->bands[band]->bitrates[rate->idx];
69562306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
69662306a36Sopenharmony_ci			val = r->hw_value_short;
69762306a36Sopenharmony_ci		else
69862306a36Sopenharmony_ci			val = r->hw_value;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		phy = val >> 8;
70162306a36Sopenharmony_ci		rate_idx = val & 0xff;
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (stbc && nss == 1) {
70562306a36Sopenharmony_ci		nss++;
70662306a36Sopenharmony_ci		rateval |= MT_TX_RATE_STBC;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	rateval |= (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
71062306a36Sopenharmony_ci		    FIELD_PREP(MT_TX_RATE_MODE, phy) |
71162306a36Sopenharmony_ci		    FIELD_PREP(MT_TX_RATE_NSS, nss - 1));
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	return rateval;
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ciint mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
71762306a36Sopenharmony_ci			  struct sk_buff *skb, struct mt76_wcid *wcid,
71862306a36Sopenharmony_ci			  struct ieee80211_sta *sta, int pid,
71962306a36Sopenharmony_ci			  struct ieee80211_key_conf *key,
72062306a36Sopenharmony_ci			  enum mt76_txq_id qid, bool beacon)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
72362306a36Sopenharmony_ci	u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
72462306a36Sopenharmony_ci	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
72562306a36Sopenharmony_ci	struct ieee80211_tx_rate *rate = &info->control.rates[0];
72662306a36Sopenharmony_ci	u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
72762306a36Sopenharmony_ci	bool multicast = is_multicast_ether_addr(hdr->addr1);
72862306a36Sopenharmony_ci	struct ieee80211_vif *vif = info->control.vif;
72962306a36Sopenharmony_ci	bool is_mmio = mt76_is_mmio(&dev->mt76);
73062306a36Sopenharmony_ci	u32 val, sz_txd = is_mmio ? MT_TXD_SIZE : MT_USB_TXD_SIZE;
73162306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mphy;
73262306a36Sopenharmony_ci	__le16 fc = hdr->frame_control;
73362306a36Sopenharmony_ci	int tx_count = 8;
73462306a36Sopenharmony_ci	u16 seqno = 0;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (vif) {
73762306a36Sopenharmony_ci		struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		omac_idx = mvif->omac_idx;
74062306a36Sopenharmony_ci		wmm_idx = mvif->wmm_idx;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (sta) {
74462306a36Sopenharmony_ci		struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		tx_count = msta->rate_count;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (phy_idx && dev->mt76.phys[MT_BAND1])
75062306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
75362306a36Sopenharmony_ci	fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (beacon) {
75662306a36Sopenharmony_ci		p_fmt = MT_TX_TYPE_FW;
75762306a36Sopenharmony_ci		q_idx = phy_idx ? MT_LMAC_BCN1 : MT_LMAC_BCN0;
75862306a36Sopenharmony_ci	} else if (qid >= MT_TXQ_PSD) {
75962306a36Sopenharmony_ci		p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
76062306a36Sopenharmony_ci		q_idx = phy_idx ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0;
76162306a36Sopenharmony_ci	} else {
76262306a36Sopenharmony_ci		p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF;
76362306a36Sopenharmony_ci		q_idx = wmm_idx * MT7615_MAX_WMM_SETS +
76462306a36Sopenharmony_ci			mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb));
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
76862306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_LMAC) |
76962306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
77062306a36Sopenharmony_ci	txwi[0] = cpu_to_le32(val);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	val = MT_TXD1_LONG_FORMAT |
77362306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
77462306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
77562306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_HDR_INFO,
77662306a36Sopenharmony_ci			 ieee80211_get_hdrlen_from_skb(skb) / 2) |
77762306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_TID,
77862306a36Sopenharmony_ci			 skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
77962306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_PKT_FMT, p_fmt) |
78062306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
78162306a36Sopenharmony_ci	txwi[1] = cpu_to_le32(val);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
78462306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
78562306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD2_MULTICAST, multicast);
78662306a36Sopenharmony_ci	if (key) {
78762306a36Sopenharmony_ci		if (multicast && ieee80211_is_robust_mgmt_frame(skb) &&
78862306a36Sopenharmony_ci		    key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
78962306a36Sopenharmony_ci			val |= MT_TXD2_BIP;
79062306a36Sopenharmony_ci			txwi[3] = 0;
79162306a36Sopenharmony_ci		} else {
79262306a36Sopenharmony_ci			txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME);
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci	} else {
79562306a36Sopenharmony_ci		txwi[3] = 0;
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci	txwi[2] = cpu_to_le32(val);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
80062306a36Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	txwi[4] = 0;
80362306a36Sopenharmony_ci	txwi[6] = 0;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (rate->idx >= 0 && rate->count &&
80662306a36Sopenharmony_ci	    !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
80762306a36Sopenharmony_ci		bool stbc = info->flags & IEEE80211_TX_CTL_STBC;
80862306a36Sopenharmony_ci		u8 bw;
80962306a36Sopenharmony_ci		u16 rateval = mt7615_mac_tx_rate_val(dev, mphy, rate, stbc,
81062306a36Sopenharmony_ci						     &bw);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci		txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		val = MT_TXD6_FIXED_BW |
81562306a36Sopenharmony_ci		      FIELD_PREP(MT_TXD6_BW, bw) |
81662306a36Sopenharmony_ci		      FIELD_PREP(MT_TXD6_TX_RATE, rateval);
81762306a36Sopenharmony_ci		txwi[6] |= cpu_to_le32(val);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
82062306a36Sopenharmony_ci			txwi[6] |= cpu_to_le32(MT_TXD6_SGI);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		if (info->flags & IEEE80211_TX_CTL_LDPC)
82362306a36Sopenharmony_ci			txwi[6] |= cpu_to_le32(MT_TXD6_LDPC);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		if (!(rate->flags & (IEEE80211_TX_RC_MCS |
82662306a36Sopenharmony_ci				     IEEE80211_TX_RC_VHT_MCS)))
82762306a36Sopenharmony_ci			txwi[2] |= cpu_to_le32(MT_TXD2_BA_DISABLE);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		tx_count = rate->count;
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (!ieee80211_is_beacon(fc)) {
83362306a36Sopenharmony_ci		struct ieee80211_hw *hw = mt76_hw(dev);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		val = MT_TXD5_TX_STATUS_HOST | FIELD_PREP(MT_TXD5_PID, pid);
83662306a36Sopenharmony_ci		if (!ieee80211_hw_check(hw, SUPPORTS_PS))
83762306a36Sopenharmony_ci			val |= MT_TXD5_SW_POWER_MGMT;
83862306a36Sopenharmony_ci		txwi[5] = cpu_to_le32(val);
83962306a36Sopenharmony_ci	} else {
84062306a36Sopenharmony_ci		txwi[5] = 0;
84162306a36Sopenharmony_ci		/* use maximum tx count for beacons */
84262306a36Sopenharmony_ci		tx_count = 0x1f;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
84662306a36Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_INJECTED) {
84762306a36Sopenharmony_ci		seqno = le16_to_cpu(hdr->seq_ctrl);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci		if (ieee80211_is_back_req(hdr->frame_control)) {
85062306a36Sopenharmony_ci			struct ieee80211_bar *bar;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci			bar = (struct ieee80211_bar *)skb->data;
85362306a36Sopenharmony_ci			seqno = le16_to_cpu(bar->start_seq_num);
85462306a36Sopenharmony_ci		}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		val |= MT_TXD3_SN_VALID |
85762306a36Sopenharmony_ci		       FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	txwi[3] |= cpu_to_le32(val);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (info->flags & IEEE80211_TX_CTL_NO_ACK)
86362306a36Sopenharmony_ci		txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
86662306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) |
86762306a36Sopenharmony_ci	      FIELD_PREP(MT_TXD7_SPE_IDX, 0x18);
86862306a36Sopenharmony_ci	txwi[7] = cpu_to_le32(val);
86962306a36Sopenharmony_ci	if (!is_mmio) {
87062306a36Sopenharmony_ci		val = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) |
87162306a36Sopenharmony_ci		      FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype);
87262306a36Sopenharmony_ci		txwi[8] = cpu_to_le32(val);
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	return 0;
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_write_txwi);
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cibool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
88262306a36Sopenharmony_ci		 FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
88562306a36Sopenharmony_ci			 0, 5000);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_civoid mt7615_mac_sta_poll(struct mt7615_dev *dev)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	static const u8 ac_to_tid[4] = {
89162306a36Sopenharmony_ci		[IEEE80211_AC_BE] = 0,
89262306a36Sopenharmony_ci		[IEEE80211_AC_BK] = 1,
89362306a36Sopenharmony_ci		[IEEE80211_AC_VI] = 4,
89462306a36Sopenharmony_ci		[IEEE80211_AC_VO] = 6
89562306a36Sopenharmony_ci	};
89662306a36Sopenharmony_ci	static const u8 hw_queue_map[] = {
89762306a36Sopenharmony_ci		[IEEE80211_AC_BK] = 0,
89862306a36Sopenharmony_ci		[IEEE80211_AC_BE] = 1,
89962306a36Sopenharmony_ci		[IEEE80211_AC_VI] = 2,
90062306a36Sopenharmony_ci		[IEEE80211_AC_VO] = 3,
90162306a36Sopenharmony_ci	};
90262306a36Sopenharmony_ci	struct ieee80211_sta *sta;
90362306a36Sopenharmony_ci	struct mt7615_sta *msta;
90462306a36Sopenharmony_ci	u32 addr, tx_time[4], rx_time[4];
90562306a36Sopenharmony_ci	struct list_head sta_poll_list;
90662306a36Sopenharmony_ci	int i;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	INIT_LIST_HEAD(&sta_poll_list);
90962306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.sta_poll_lock);
91062306a36Sopenharmony_ci	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
91162306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.sta_poll_lock);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	while (!list_empty(&sta_poll_list)) {
91462306a36Sopenharmony_ci		bool clear = false;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci		msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
91762306a36Sopenharmony_ci					wcid.poll_list);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.sta_poll_lock);
92062306a36Sopenharmony_ci		list_del_init(&msta->wcid.poll_list);
92162306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.sta_poll_lock);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		for (i = 0; i < 4; i++, addr += 8) {
92662306a36Sopenharmony_ci			u32 tx_last = msta->airtime_ac[i];
92762306a36Sopenharmony_ci			u32 rx_last = msta->airtime_ac[i + 4];
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci			msta->airtime_ac[i] = mt76_rr(dev, addr);
93062306a36Sopenharmony_ci			msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
93162306a36Sopenharmony_ci			tx_time[i] = msta->airtime_ac[i] - tx_last;
93262306a36Sopenharmony_ci			rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci			if ((tx_last | rx_last) & BIT(30))
93562306a36Sopenharmony_ci				clear = true;
93662306a36Sopenharmony_ci		}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		if (clear) {
93962306a36Sopenharmony_ci			mt7615_mac_wtbl_update(dev, msta->wcid.idx,
94062306a36Sopenharmony_ci					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
94162306a36Sopenharmony_ci			memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		if (!msta->wcid.sta)
94562306a36Sopenharmony_ci			continue;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci		sta = container_of((void *)msta, struct ieee80211_sta,
94862306a36Sopenharmony_ci				   drv_priv);
94962306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
95062306a36Sopenharmony_ci			u32 tx_cur = tx_time[i];
95162306a36Sopenharmony_ci			u32 rx_cur = rx_time[hw_queue_map[i]];
95262306a36Sopenharmony_ci			u8 tid = ac_to_tid[i];
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci			if (!tx_cur && !rx_cur)
95562306a36Sopenharmony_ci				continue;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci			ieee80211_sta_register_airtime(sta, tid, tx_cur,
95862306a36Sopenharmony_ci						       rx_cur);
95962306a36Sopenharmony_ci		}
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_sta_poll);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic void
96562306a36Sopenharmony_cimt7615_mac_update_rate_desc(struct mt7615_phy *phy, struct mt7615_sta *sta,
96662306a36Sopenharmony_ci			    struct ieee80211_tx_rate *probe_rate,
96762306a36Sopenharmony_ci			    struct ieee80211_tx_rate *rates,
96862306a36Sopenharmony_ci			    struct mt7615_rate_desc *rd)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
97162306a36Sopenharmony_ci	struct mt76_phy *mphy = phy->mt76;
97262306a36Sopenharmony_ci	struct ieee80211_tx_rate *ref;
97362306a36Sopenharmony_ci	bool rateset, stbc = false;
97462306a36Sopenharmony_ci	int n_rates = sta->n_rates;
97562306a36Sopenharmony_ci	u8 bw, bw_prev;
97662306a36Sopenharmony_ci	int i, j;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	for (i = n_rates; i < 4; i++)
97962306a36Sopenharmony_ci		rates[i] = rates[n_rates - 1];
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	rateset = !(sta->rate_set_tsf & BIT(0));
98262306a36Sopenharmony_ci	memcpy(sta->rateset[rateset].rates, rates,
98362306a36Sopenharmony_ci	       sizeof(sta->rateset[rateset].rates));
98462306a36Sopenharmony_ci	if (probe_rate) {
98562306a36Sopenharmony_ci		sta->rateset[rateset].probe_rate = *probe_rate;
98662306a36Sopenharmony_ci		ref = &sta->rateset[rateset].probe_rate;
98762306a36Sopenharmony_ci	} else {
98862306a36Sopenharmony_ci		sta->rateset[rateset].probe_rate.idx = -1;
98962306a36Sopenharmony_ci		ref = &sta->rateset[rateset].rates[0];
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	rates = sta->rateset[rateset].rates;
99362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) {
99462306a36Sopenharmony_ci		/*
99562306a36Sopenharmony_ci		 * We don't support switching between short and long GI
99662306a36Sopenharmony_ci		 * within the rate set. For accurate tx status reporting, we
99762306a36Sopenharmony_ci		 * need to make sure that flags match.
99862306a36Sopenharmony_ci		 * For improved performance, avoid duplicate entries by
99962306a36Sopenharmony_ci		 * decrementing the MCS index if necessary
100062306a36Sopenharmony_ci		 */
100162306a36Sopenharmony_ci		if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI)
100262306a36Sopenharmony_ci			rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		for (j = 0; j < i; j++) {
100562306a36Sopenharmony_ci			if (rates[i].idx != rates[j].idx)
100662306a36Sopenharmony_ci				continue;
100762306a36Sopenharmony_ci			if ((rates[i].flags ^ rates[j].flags) &
100862306a36Sopenharmony_ci			    (IEEE80211_TX_RC_40_MHZ_WIDTH |
100962306a36Sopenharmony_ci			     IEEE80211_TX_RC_80_MHZ_WIDTH |
101062306a36Sopenharmony_ci			     IEEE80211_TX_RC_160_MHZ_WIDTH))
101162306a36Sopenharmony_ci				continue;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci			if (!rates[i].idx)
101462306a36Sopenharmony_ci				continue;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci			rates[i].idx--;
101762306a36Sopenharmony_ci		}
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	rd->val[0] = mt7615_mac_tx_rate_val(dev, mphy, &rates[0], stbc, &bw);
102162306a36Sopenharmony_ci	bw_prev = bw;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (probe_rate) {
102462306a36Sopenharmony_ci		rd->probe_val = mt7615_mac_tx_rate_val(dev, mphy, probe_rate,
102562306a36Sopenharmony_ci						       stbc, &bw);
102662306a36Sopenharmony_ci		if (bw)
102762306a36Sopenharmony_ci			rd->bw_idx = 1;
102862306a36Sopenharmony_ci		else
102962306a36Sopenharmony_ci			bw_prev = 0;
103062306a36Sopenharmony_ci	} else {
103162306a36Sopenharmony_ci		rd->probe_val = rd->val[0];
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	rd->val[1] = mt7615_mac_tx_rate_val(dev, mphy, &rates[1], stbc, &bw);
103562306a36Sopenharmony_ci	if (bw_prev) {
103662306a36Sopenharmony_ci		rd->bw_idx = 3;
103762306a36Sopenharmony_ci		bw_prev = bw;
103862306a36Sopenharmony_ci	}
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	rd->val[2] = mt7615_mac_tx_rate_val(dev, mphy, &rates[2], stbc, &bw);
104162306a36Sopenharmony_ci	if (bw_prev) {
104262306a36Sopenharmony_ci		rd->bw_idx = 5;
104362306a36Sopenharmony_ci		bw_prev = bw;
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	rd->val[3] = mt7615_mac_tx_rate_val(dev, mphy, &rates[3], stbc, &bw);
104762306a36Sopenharmony_ci	if (bw_prev)
104862306a36Sopenharmony_ci		rd->bw_idx = 7;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	rd->rateset = rateset;
105162306a36Sopenharmony_ci	rd->bw = bw;
105262306a36Sopenharmony_ci}
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic int
105562306a36Sopenharmony_cimt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta,
105662306a36Sopenharmony_ci			     struct ieee80211_tx_rate *probe_rate,
105762306a36Sopenharmony_ci			     struct ieee80211_tx_rate *rates)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
106062306a36Sopenharmony_ci	struct mt7615_wtbl_rate_desc *wrd;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (work_pending(&dev->rate_work))
106362306a36Sopenharmony_ci		return -EBUSY;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	wrd = kzalloc(sizeof(*wrd), GFP_ATOMIC);
106662306a36Sopenharmony_ci	if (!wrd)
106762306a36Sopenharmony_ci		return -ENOMEM;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	wrd->sta = sta;
107062306a36Sopenharmony_ci	mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates,
107162306a36Sopenharmony_ci				    &wrd->rate);
107262306a36Sopenharmony_ci	list_add_tail(&wrd->node, &dev->wrd_head);
107362306a36Sopenharmony_ci	queue_work(dev->mt76.wq, &dev->rate_work);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	return 0;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ciu32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	u32 addr, val, val2;
108162306a36Sopenharmony_ci	u8 offset;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	addr = mt7615_mac_wtbl_addr(dev, wcid) + 11 * 4;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	offset = tid * 12;
108662306a36Sopenharmony_ci	addr += 4 * (offset / 32);
108762306a36Sopenharmony_ci	offset %= 32;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	val = mt76_rr(dev, addr);
109062306a36Sopenharmony_ci	val >>= offset;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (offset > 20) {
109362306a36Sopenharmony_ci		addr += 4;
109462306a36Sopenharmony_ci		val2 = mt76_rr(dev, addr);
109562306a36Sopenharmony_ci		val |= val2 << (32 - offset);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	return val & GENMASK(11, 0);
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_civoid mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
110262306a36Sopenharmony_ci			  struct ieee80211_tx_rate *probe_rate,
110362306a36Sopenharmony_ci			  struct ieee80211_tx_rate *rates)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	int wcid = sta->wcid.idx, n_rates = sta->n_rates;
110662306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
110762306a36Sopenharmony_ci	struct mt7615_rate_desc rd;
110862306a36Sopenharmony_ci	u32 w5, w27, addr;
110962306a36Sopenharmony_ci	u16 idx = sta->vif->mt76.omac_idx;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (!mt76_is_mmio(&dev->mt76)) {
111262306a36Sopenharmony_ci		mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates);
111362306a36Sopenharmony_ci		return;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
111762306a36Sopenharmony_ci		return;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	memset(&rd, 0, sizeof(struct mt7615_rate_desc));
112062306a36Sopenharmony_ci	mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &rd);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	addr = mt7615_mac_wtbl_addr(dev, wcid);
112362306a36Sopenharmony_ci	w27 = mt76_rr(dev, addr + 27 * 4);
112462306a36Sopenharmony_ci	w27 &= ~MT_WTBL_W27_CC_BW_SEL;
112562306a36Sopenharmony_ci	w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rd.bw);
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	w5 = mt76_rr(dev, addr + 5 * 4);
112862306a36Sopenharmony_ci	w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE |
112962306a36Sopenharmony_ci		MT_WTBL_W5_MPDU_OK_COUNT |
113062306a36Sopenharmony_ci		MT_WTBL_W5_MPDU_FAIL_COUNT |
113162306a36Sopenharmony_ci		MT_WTBL_W5_RATE_IDX);
113262306a36Sopenharmony_ci	w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rd.bw) |
113362306a36Sopenharmony_ci	      FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE,
113462306a36Sopenharmony_ci			 rd.bw_idx ? rd.bw_idx - 1 : 7);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR0, w5);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR1,
113962306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rd.probe_val) |
114062306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rd.val[0]) |
114162306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rd.val[1]));
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR2,
114462306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rd.val[1] >> 8) |
114562306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rd.val[1]) |
114662306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rd.val[2]) |
114762306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rd.val[2]));
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RIUCR3,
115062306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rd.val[2] >> 4) |
115162306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rd.val[3]) |
115262306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rd.val[3]));
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_UPDATE,
115562306a36Sopenharmony_ci		FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
115662306a36Sopenharmony_ci		MT_WTBL_UPDATE_RATE_UPDATE |
115762306a36Sopenharmony_ci		MT_WTBL_UPDATE_TX_COUNT_CLEAR);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	mt76_wr(dev, addr + 27 * 4, w27);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
116262306a36Sopenharmony_ci	addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	mt76_rmw(dev, addr, MT_LPON_TCR_MODE, MT_LPON_TCR_READ); /* TSF read */
116562306a36Sopenharmony_ci	sta->rate_set_tsf = mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0);
116662306a36Sopenharmony_ci	sta->rate_set_tsf |= rd.rateset;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
116962306a36Sopenharmony_ci		mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates;
117262306a36Sopenharmony_ci	sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
117362306a36Sopenharmony_ci	sta->rate_probe = !!probe_rate;
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_civoid mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
117862306a36Sopenharmony_ci			      struct ieee80211_vif *vif, bool enable)
117962306a36Sopenharmony_ci{
118062306a36Sopenharmony_ci	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
118162306a36Sopenharmony_ci	u32 addr;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (enable)
118662306a36Sopenharmony_ci		mt76_set(dev, addr, MT_WTBL_W3_RTS);
118762306a36Sopenharmony_ci	else
118862306a36Sopenharmony_ci		mt76_clear(dev, addr, MT_WTBL_W3_RTS);
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_cistatic int
119362306a36Sopenharmony_cimt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
119462306a36Sopenharmony_ci			   struct ieee80211_key_conf *key,
119562306a36Sopenharmony_ci			   enum mt76_cipher_type cipher, u16 cipher_mask)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4;
119862306a36Sopenharmony_ci	u8 data[32] = {};
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (key->keylen > sizeof(data))
120162306a36Sopenharmony_ci		return -EINVAL;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	mt76_rr_copy(dev, addr, data, sizeof(data));
120462306a36Sopenharmony_ci	if (cipher == MT_CIPHER_TKIP) {
120562306a36Sopenharmony_ci		/* Rx/Tx MIC keys are swapped */
120662306a36Sopenharmony_ci		memcpy(data, key->key, 16);
120762306a36Sopenharmony_ci		memcpy(data + 16, key->key + 24, 8);
120862306a36Sopenharmony_ci		memcpy(data + 24, key->key + 16, 8);
120962306a36Sopenharmony_ci	} else {
121062306a36Sopenharmony_ci		if (cipher_mask == BIT(cipher))
121162306a36Sopenharmony_ci			memcpy(data, key->key, key->keylen);
121262306a36Sopenharmony_ci		else if (cipher != MT_CIPHER_BIP_CMAC_128)
121362306a36Sopenharmony_ci			memcpy(data, key->key, 16);
121462306a36Sopenharmony_ci		if (cipher == MT_CIPHER_BIP_CMAC_128)
121562306a36Sopenharmony_ci			memcpy(data + 16, key->key, 16);
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	mt76_wr_copy(dev, addr, data, sizeof(data));
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	return 0;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic int
122462306a36Sopenharmony_cimt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
122562306a36Sopenharmony_ci			  enum mt76_cipher_type cipher, u16 cipher_mask,
122662306a36Sopenharmony_ci			  int keyidx)
122762306a36Sopenharmony_ci{
122862306a36Sopenharmony_ci	u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
123162306a36Sopenharmony_ci		return -ETIMEDOUT;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	w0 = mt76_rr(dev, addr);
123462306a36Sopenharmony_ci	w1 = mt76_rr(dev, addr + 4);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	if (cipher_mask)
123762306a36Sopenharmony_ci		w0 |= MT_WTBL_W0_RX_KEY_VALID;
123862306a36Sopenharmony_ci	else
123962306a36Sopenharmony_ci		w0 &= ~(MT_WTBL_W0_RX_KEY_VALID | MT_WTBL_W0_KEY_IDX);
124062306a36Sopenharmony_ci	if (cipher_mask & BIT(MT_CIPHER_BIP_CMAC_128))
124162306a36Sopenharmony_ci		w0 |= MT_WTBL_W0_RX_IK_VALID;
124262306a36Sopenharmony_ci	else
124362306a36Sopenharmony_ci		w0 &= ~MT_WTBL_W0_RX_IK_VALID;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (cipher != MT_CIPHER_BIP_CMAC_128 || cipher_mask == BIT(cipher)) {
124662306a36Sopenharmony_ci		w0 &= ~MT_WTBL_W0_KEY_IDX;
124762306a36Sopenharmony_ci		w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx);
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RICR0, w0);
125162306a36Sopenharmony_ci	mt76_wr(dev, MT_WTBL_RICR1, w1);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (!mt7615_mac_wtbl_update(dev, wcid->idx,
125462306a36Sopenharmony_ci				    MT_WTBL_UPDATE_RXINFO_UPDATE))
125562306a36Sopenharmony_ci		return -ETIMEDOUT;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	return 0;
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic void
126162306a36Sopenharmony_cimt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid,
126262306a36Sopenharmony_ci			      enum mt76_cipher_type cipher, u16 cipher_mask)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (cipher == MT_CIPHER_BIP_CMAC_128 &&
126762306a36Sopenharmony_ci	    cipher_mask & ~BIT(MT_CIPHER_BIP_CMAC_128))
126862306a36Sopenharmony_ci		return;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE,
127162306a36Sopenharmony_ci		 FIELD_PREP(MT_WTBL_W2_KEY_TYPE, cipher));
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ciint __mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
127562306a36Sopenharmony_ci			      struct mt76_wcid *wcid,
127662306a36Sopenharmony_ci			      struct ieee80211_key_conf *key)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	enum mt76_cipher_type cipher;
127962306a36Sopenharmony_ci	u16 cipher_mask = wcid->cipher;
128062306a36Sopenharmony_ci	int err;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	cipher = mt7615_mac_get_cipher(key->cipher);
128362306a36Sopenharmony_ci	if (cipher == MT_CIPHER_NONE)
128462306a36Sopenharmony_ci		return -EOPNOTSUPP;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	cipher_mask |= BIT(cipher);
128762306a36Sopenharmony_ci	mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cipher_mask);
128862306a36Sopenharmony_ci	err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cipher_mask);
128962306a36Sopenharmony_ci	if (err < 0)
129062306a36Sopenharmony_ci		return err;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, cipher_mask,
129362306a36Sopenharmony_ci					key->keyidx);
129462306a36Sopenharmony_ci	if (err < 0)
129562306a36Sopenharmony_ci		return err;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	wcid->cipher = cipher_mask;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	return 0;
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ciint mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
130362306a36Sopenharmony_ci			    struct mt76_wcid *wcid,
130462306a36Sopenharmony_ci			    struct ieee80211_key_conf *key)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	int err;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.lock);
130962306a36Sopenharmony_ci	err = __mt7615_mac_wtbl_set_key(dev, wcid, key);
131062306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.lock);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return err;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
131662306a36Sopenharmony_ci			    struct ieee80211_tx_info *info, __le32 *txs_data)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	struct ieee80211_supported_band *sband;
131962306a36Sopenharmony_ci	struct mt7615_rate_set *rs;
132062306a36Sopenharmony_ci	struct mt76_phy *mphy;
132162306a36Sopenharmony_ci	int first_idx = 0, last_idx;
132262306a36Sopenharmony_ci	int i, idx, count;
132362306a36Sopenharmony_ci	bool fixed_rate, ack_timeout;
132462306a36Sopenharmony_ci	bool ampdu, cck = false;
132562306a36Sopenharmony_ci	bool rs_idx;
132662306a36Sopenharmony_ci	u32 rate_set_tsf;
132762306a36Sopenharmony_ci	u32 final_rate, final_rate_flags, final_nss, txs;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	txs = le32_to_cpu(txs_data[1]);
133062306a36Sopenharmony_ci	ampdu = txs & MT_TXS1_AMPDU;
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	txs = le32_to_cpu(txs_data[3]);
133362306a36Sopenharmony_ci	count = FIELD_GET(MT_TXS3_TX_COUNT, txs);
133462306a36Sopenharmony_ci	last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	txs = le32_to_cpu(txs_data[0]);
133762306a36Sopenharmony_ci	fixed_rate = txs & MT_TXS0_FIXED_RATE;
133862306a36Sopenharmony_ci	final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
133962306a36Sopenharmony_ci	ack_timeout = txs & MT_TXS0_ACK_TIMEOUT;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	if (!ampdu && (txs & MT_TXS0_RTS_TIMEOUT))
134262306a36Sopenharmony_ci		return false;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (txs & MT_TXS0_QUEUE_TIMEOUT)
134562306a36Sopenharmony_ci		return false;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	if (!ack_timeout)
134862306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	info->status.ampdu_len = 1;
135162306a36Sopenharmony_ci	info->status.ampdu_ack_len = !!(info->flags &
135262306a36Sopenharmony_ci					IEEE80211_TX_STAT_ACK);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
135562306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	first_idx = max_t(int, 0, last_idx - (count - 1) / MT7615_RATE_RETRY);
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if (fixed_rate) {
136062306a36Sopenharmony_ci		info->status.rates[0].count = count;
136162306a36Sopenharmony_ci		i = 0;
136262306a36Sopenharmony_ci		goto out;
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	rate_set_tsf = READ_ONCE(sta->rate_set_tsf);
136662306a36Sopenharmony_ci	rs_idx = !((u32)(le32_get_bits(txs_data[4], MT_TXS4_F0_TIMESTAMP) -
136762306a36Sopenharmony_ci			 rate_set_tsf) < 1000000);
136862306a36Sopenharmony_ci	rs_idx ^= rate_set_tsf & BIT(0);
136962306a36Sopenharmony_ci	rs = &sta->rateset[rs_idx];
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	if (!first_idx && rs->probe_rate.idx >= 0) {
137262306a36Sopenharmony_ci		info->status.rates[0] = rs->probe_rate;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
137562306a36Sopenharmony_ci		if (sta->rate_probe) {
137662306a36Sopenharmony_ci			struct mt7615_phy *phy = &dev->phy;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci			if (sta->wcid.phy_idx && dev->mt76.phys[MT_BAND1])
137962306a36Sopenharmony_ci				phy = dev->mt76.phys[MT_BAND1]->priv;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci			mt7615_mac_set_rates(phy, sta, NULL, sta->rates);
138262306a36Sopenharmony_ci		}
138362306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
138462306a36Sopenharmony_ci	} else {
138562306a36Sopenharmony_ci		info->status.rates[0] = rs->rates[first_idx / 2];
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci	info->status.rates[0].count = 0;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) {
139062306a36Sopenharmony_ci		struct ieee80211_tx_rate *cur_rate;
139162306a36Sopenharmony_ci		int cur_count;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		cur_rate = &rs->rates[idx / 2];
139462306a36Sopenharmony_ci		cur_count = min_t(int, MT7615_RATE_RETRY, count);
139562306a36Sopenharmony_ci		count -= cur_count;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci		if (idx && (cur_rate->idx != info->status.rates[i].idx ||
139862306a36Sopenharmony_ci			    cur_rate->flags != info->status.rates[i].flags)) {
139962306a36Sopenharmony_ci			i++;
140062306a36Sopenharmony_ci			if (i == ARRAY_SIZE(info->status.rates)) {
140162306a36Sopenharmony_ci				i--;
140262306a36Sopenharmony_ci				break;
140362306a36Sopenharmony_ci			}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci			info->status.rates[i] = *cur_rate;
140662306a36Sopenharmony_ci			info->status.rates[i].count = 0;
140762306a36Sopenharmony_ci		}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		info->status.rates[i].count += cur_count;
141062306a36Sopenharmony_ci	}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ciout:
141362306a36Sopenharmony_ci	final_rate_flags = info->status.rates[i].flags;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
141662306a36Sopenharmony_ci	case MT_PHY_TYPE_CCK:
141762306a36Sopenharmony_ci		cck = true;
141862306a36Sopenharmony_ci		fallthrough;
141962306a36Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
142062306a36Sopenharmony_ci		mphy = &dev->mphy;
142162306a36Sopenharmony_ci		if (sta->wcid.phy_idx && dev->mt76.phys[MT_BAND1])
142262306a36Sopenharmony_ci			mphy = dev->mt76.phys[MT_BAND1];
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci		if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
142562306a36Sopenharmony_ci			sband = &mphy->sband_5g.sband;
142662306a36Sopenharmony_ci		else
142762306a36Sopenharmony_ci			sband = &mphy->sband_2g.sband;
142862306a36Sopenharmony_ci		final_rate &= MT_TX_RATE_IDX;
142962306a36Sopenharmony_ci		final_rate = mt76_get_rate(&dev->mt76, sband, final_rate,
143062306a36Sopenharmony_ci					   cck);
143162306a36Sopenharmony_ci		final_rate_flags = 0;
143262306a36Sopenharmony_ci		break;
143362306a36Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
143462306a36Sopenharmony_ci	case MT_PHY_TYPE_HT:
143562306a36Sopenharmony_ci		final_rate_flags |= IEEE80211_TX_RC_MCS;
143662306a36Sopenharmony_ci		final_rate &= MT_TX_RATE_IDX;
143762306a36Sopenharmony_ci		if (final_rate > 31)
143862306a36Sopenharmony_ci			return false;
143962306a36Sopenharmony_ci		break;
144062306a36Sopenharmony_ci	case MT_PHY_TYPE_VHT:
144162306a36Sopenharmony_ci		final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci		if ((final_rate & MT_TX_RATE_STBC) && final_nss)
144462306a36Sopenharmony_ci			final_nss--;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		final_rate_flags |= IEEE80211_TX_RC_VHT_MCS;
144762306a36Sopenharmony_ci		final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4);
144862306a36Sopenharmony_ci		break;
144962306a36Sopenharmony_ci	default:
145062306a36Sopenharmony_ci		return false;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	info->status.rates[i].idx = final_rate;
145462306a36Sopenharmony_ci	info->status.rates[i].flags = final_rate_flags;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	return true;
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_cistatic bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev,
146062306a36Sopenharmony_ci				   struct mt7615_sta *sta, int pid,
146162306a36Sopenharmony_ci				   __le32 *txs_data)
146262306a36Sopenharmony_ci{
146362306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
146462306a36Sopenharmony_ci	struct sk_buff_head list;
146562306a36Sopenharmony_ci	struct sk_buff *skb;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	if (pid < MT_PACKET_ID_FIRST)
146862306a36Sopenharmony_ci		return false;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	trace_mac_txdone(mdev, sta->wcid.idx, pid);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	mt76_tx_status_lock(mdev, &list);
147362306a36Sopenharmony_ci	skb = mt76_tx_status_skb_get(mdev, &sta->wcid, pid, &list);
147462306a36Sopenharmony_ci	if (skb) {
147562306a36Sopenharmony_ci		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci		if (!mt7615_fill_txs(dev, sta, info, txs_data)) {
147862306a36Sopenharmony_ci			info->status.rates[0].count = 0;
147962306a36Sopenharmony_ci			info->status.rates[0].idx = -1;
148062306a36Sopenharmony_ci		}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci		mt76_tx_status_skb_done(mdev, skb, &list);
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci	mt76_tx_status_unlock(mdev, &list);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	return !!skb;
148762306a36Sopenharmony_ci}
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_cistatic void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	struct ieee80211_tx_info info = {};
149262306a36Sopenharmony_ci	struct ieee80211_sta *sta = NULL;
149362306a36Sopenharmony_ci	struct mt7615_sta *msta = NULL;
149462306a36Sopenharmony_ci	struct mt76_wcid *wcid;
149562306a36Sopenharmony_ci	struct mt76_phy *mphy = &dev->mt76.phy;
149662306a36Sopenharmony_ci	__le32 *txs_data = data;
149762306a36Sopenharmony_ci	u8 wcidx;
149862306a36Sopenharmony_ci	u8 pid;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	pid = le32_get_bits(txs_data[0], MT_TXS0_PID);
150162306a36Sopenharmony_ci	wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	if (pid == MT_PACKET_ID_NO_ACK)
150462306a36Sopenharmony_ci		return;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	if (wcidx >= MT7615_WTBL_SIZE)
150762306a36Sopenharmony_ci		return;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	rcu_read_lock();
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
151262306a36Sopenharmony_ci	if (!wcid)
151362306a36Sopenharmony_ci		goto out;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	msta = container_of(wcid, struct mt7615_sta, wcid);
151662306a36Sopenharmony_ci	sta = wcid_to_sta(wcid);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.sta_poll_lock);
151962306a36Sopenharmony_ci	if (list_empty(&msta->wcid.poll_list))
152062306a36Sopenharmony_ci		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
152162306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.sta_poll_lock);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
152462306a36Sopenharmony_ci		goto out;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	if (wcidx >= MT7615_WTBL_STA || !sta)
152762306a36Sopenharmony_ci		goto out;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (wcid->phy_idx && dev->mt76.phys[MT_BAND1])
153062306a36Sopenharmony_ci		mphy = dev->mt76.phys[MT_BAND1];
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	if (mt7615_fill_txs(dev, msta, &info, txs_data)) {
153362306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.rx_lock);
153462306a36Sopenharmony_ci		ieee80211_tx_status_noskb(mphy->hw, sta, &info);
153562306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.rx_lock);
153662306a36Sopenharmony_ci	}
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ciout:
153962306a36Sopenharmony_ci	rcu_read_unlock();
154062306a36Sopenharmony_ci}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_cistatic void
154362306a36Sopenharmony_cimt7615_txwi_free(struct mt7615_dev *dev, struct mt76_txwi_cache *txwi)
154462306a36Sopenharmony_ci{
154562306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
154662306a36Sopenharmony_ci	__le32 *txwi_data;
154762306a36Sopenharmony_ci	u32 val;
154862306a36Sopenharmony_ci	u8 wcid;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	mt76_connac_txp_skb_unmap(mdev, txwi);
155162306a36Sopenharmony_ci	if (!txwi->skb)
155262306a36Sopenharmony_ci		goto out;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
155562306a36Sopenharmony_ci	val = le32_to_cpu(txwi_data[1]);
155662306a36Sopenharmony_ci	wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
155762306a36Sopenharmony_ci	mt76_tx_complete_skb(mdev, wcid, txwi->skb);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ciout:
156062306a36Sopenharmony_ci	txwi->skb = NULL;
156162306a36Sopenharmony_ci	mt76_put_txwi(mdev, txwi);
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_cistatic void
156562306a36Sopenharmony_cimt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
156862306a36Sopenharmony_ci	struct mt76_txwi_cache *txwi;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	trace_mac_tx_free(dev, token);
157162306a36Sopenharmony_ci	txwi = mt76_token_put(mdev, token);
157262306a36Sopenharmony_ci	if (!txwi)
157362306a36Sopenharmony_ci		return;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	mt7615_txwi_free(dev, txwi);
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_cistatic void mt7615_mac_tx_free(struct mt7615_dev *dev, void *data, int len)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	struct mt76_connac_tx_free *free = data;
158162306a36Sopenharmony_ci	void *tx_token = data + sizeof(*free);
158262306a36Sopenharmony_ci	void *end = data + len;
158362306a36Sopenharmony_ci	u8 i, count;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
158662306a36Sopenharmony_ci	if (is_mt7615(&dev->mt76)) {
158762306a36Sopenharmony_ci		mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
158862306a36Sopenharmony_ci	} else {
158962306a36Sopenharmony_ci		for (i = 0; i < IEEE80211_NUM_ACS; i++)
159062306a36Sopenharmony_ci			mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
159162306a36Sopenharmony_ci	}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	count = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_ID_CNT);
159462306a36Sopenharmony_ci	if (is_mt7615(&dev->mt76)) {
159562306a36Sopenharmony_ci		__le16 *token = tx_token;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci		if (WARN_ON_ONCE((void *)&token[count] > end))
159862306a36Sopenharmony_ci			return;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci		for (i = 0; i < count; i++)
160162306a36Sopenharmony_ci			mt7615_mac_tx_free_token(dev, le16_to_cpu(token[i]));
160262306a36Sopenharmony_ci	} else {
160362306a36Sopenharmony_ci		__le32 *token = tx_token;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci		if (WARN_ON_ONCE((void *)&token[count] > end))
160662306a36Sopenharmony_ci			return;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci		for (i = 0; i < count; i++)
160962306a36Sopenharmony_ci			mt7615_mac_tx_free_token(dev, le32_to_cpu(token[i]));
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	rcu_read_lock();
161362306a36Sopenharmony_ci	mt7615_mac_sta_poll(dev);
161462306a36Sopenharmony_ci	rcu_read_unlock();
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	mt76_worker_schedule(&dev->mt76.tx_worker);
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_cibool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
162262306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)data;
162362306a36Sopenharmony_ci	__le32 *end = (__le32 *)&rxd[len / 4];
162462306a36Sopenharmony_ci	enum rx_pkt_type type;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	switch (type) {
162962306a36Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY:
163062306a36Sopenharmony_ci		mt7615_mac_tx_free(dev, data, len);
163162306a36Sopenharmony_ci		return false;
163262306a36Sopenharmony_ci	case PKT_TYPE_TXS:
163362306a36Sopenharmony_ci		for (rxd++; rxd + 7 <= end; rxd += 7)
163462306a36Sopenharmony_ci			mt7615_mac_add_txs(dev, rxd);
163562306a36Sopenharmony_ci		return false;
163662306a36Sopenharmony_ci	default:
163762306a36Sopenharmony_ci		return true;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci}
164062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_rx_check);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_civoid mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
164362306a36Sopenharmony_ci			 struct sk_buff *skb, u32 *info)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
164662306a36Sopenharmony_ci	__le32 *rxd = (__le32 *)skb->data;
164762306a36Sopenharmony_ci	__le32 *end = (__le32 *)&skb->data[skb->len];
164862306a36Sopenharmony_ci	enum rx_pkt_type type;
164962306a36Sopenharmony_ci	u16 flag;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	type = le32_get_bits(rxd[0], MT_RXD0_PKT_TYPE);
165262306a36Sopenharmony_ci	flag = le32_get_bits(rxd[0], MT_RXD0_PKT_FLAG);
165362306a36Sopenharmony_ci	if (type == PKT_TYPE_RX_EVENT && flag == 0x1)
165462306a36Sopenharmony_ci		type = PKT_TYPE_NORMAL_MCU;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	switch (type) {
165762306a36Sopenharmony_ci	case PKT_TYPE_TXS:
165862306a36Sopenharmony_ci		for (rxd++; rxd + 7 <= end; rxd += 7)
165962306a36Sopenharmony_ci			mt7615_mac_add_txs(dev, rxd);
166062306a36Sopenharmony_ci		dev_kfree_skb(skb);
166162306a36Sopenharmony_ci		break;
166262306a36Sopenharmony_ci	case PKT_TYPE_TXRX_NOTIFY:
166362306a36Sopenharmony_ci		mt7615_mac_tx_free(dev, skb->data, skb->len);
166462306a36Sopenharmony_ci		dev_kfree_skb(skb);
166562306a36Sopenharmony_ci		break;
166662306a36Sopenharmony_ci	case PKT_TYPE_RX_EVENT:
166762306a36Sopenharmony_ci		mt7615_mcu_rx_event(dev, skb);
166862306a36Sopenharmony_ci		break;
166962306a36Sopenharmony_ci	case PKT_TYPE_NORMAL_MCU:
167062306a36Sopenharmony_ci	case PKT_TYPE_NORMAL:
167162306a36Sopenharmony_ci		if (!mt7615_mac_fill_rx(dev, skb)) {
167262306a36Sopenharmony_ci			mt76_rx(&dev->mt76, q, skb);
167362306a36Sopenharmony_ci			return;
167462306a36Sopenharmony_ci		}
167562306a36Sopenharmony_ci		fallthrough;
167662306a36Sopenharmony_ci	default:
167762306a36Sopenharmony_ci		dev_kfree_skb(skb);
167862306a36Sopenharmony_ci		break;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_queue_rx_skb);
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cistatic void
168462306a36Sopenharmony_cimt7615_mac_set_sensitivity(struct mt7615_phy *phy, int val, bool ofdm)
168562306a36Sopenharmony_ci{
168662306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
168762306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76)) {
169062306a36Sopenharmony_ci		if (ofdm)
169162306a36Sopenharmony_ci			mt76_rmw(dev, MT7663_WF_PHY_MIN_PRI_PWR(ext_phy),
169262306a36Sopenharmony_ci				 MT_WF_PHY_PD_OFDM_MASK(0),
169362306a36Sopenharmony_ci				 MT_WF_PHY_PD_OFDM(0, val));
169462306a36Sopenharmony_ci		else
169562306a36Sopenharmony_ci			mt76_rmw(dev, MT7663_WF_PHY_RXTD_CCK_PD(ext_phy),
169662306a36Sopenharmony_ci				 MT_WF_PHY_PD_CCK_MASK(ext_phy),
169762306a36Sopenharmony_ci				 MT_WF_PHY_PD_CCK(ext_phy, val));
169862306a36Sopenharmony_ci		return;
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	if (ofdm)
170262306a36Sopenharmony_ci		mt76_rmw(dev, MT_WF_PHY_MIN_PRI_PWR(ext_phy),
170362306a36Sopenharmony_ci			 MT_WF_PHY_PD_OFDM_MASK(ext_phy),
170462306a36Sopenharmony_ci			 MT_WF_PHY_PD_OFDM(ext_phy, val));
170562306a36Sopenharmony_ci	else
170662306a36Sopenharmony_ci		mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy),
170762306a36Sopenharmony_ci			 MT_WF_PHY_PD_CCK_MASK(ext_phy),
170862306a36Sopenharmony_ci			 MT_WF_PHY_PD_CCK(ext_phy, val));
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic void
171262306a36Sopenharmony_cimt7615_mac_set_default_sensitivity(struct mt7615_phy *phy)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	/* ofdm */
171562306a36Sopenharmony_ci	mt7615_mac_set_sensitivity(phy, 0x13c, true);
171662306a36Sopenharmony_ci	/* cck */
171762306a36Sopenharmony_ci	mt7615_mac_set_sensitivity(phy, 0x92, false);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	phy->ofdm_sensitivity = -98;
172062306a36Sopenharmony_ci	phy->cck_sensitivity = -110;
172162306a36Sopenharmony_ci	phy->last_cca_adj = jiffies;
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_civoid mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
172762306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
172862306a36Sopenharmony_ci	u32 reg, mask;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	mt7615_mutex_acquire(dev);
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	if (phy->scs_en == enable)
173362306a36Sopenharmony_ci		goto out;
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76)) {
173662306a36Sopenharmony_ci		reg = MT7663_WF_PHY_MIN_PRI_PWR(ext_phy);
173762306a36Sopenharmony_ci		mask = MT_WF_PHY_PD_BLK(0);
173862306a36Sopenharmony_ci	} else {
173962306a36Sopenharmony_ci		reg = MT_WF_PHY_MIN_PRI_PWR(ext_phy);
174062306a36Sopenharmony_ci		mask = MT_WF_PHY_PD_BLK(ext_phy);
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	if (enable) {
174462306a36Sopenharmony_ci		mt76_set(dev, reg, mask);
174562306a36Sopenharmony_ci		if (is_mt7622(&dev->mt76)) {
174662306a36Sopenharmony_ci			mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7 << 8);
174762306a36Sopenharmony_ci			mt76_set(dev, MT_MIB_M0_MISC_CR(0), 0x7);
174862306a36Sopenharmony_ci		}
174962306a36Sopenharmony_ci	} else {
175062306a36Sopenharmony_ci		mt76_clear(dev, reg, mask);
175162306a36Sopenharmony_ci	}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	mt7615_mac_set_default_sensitivity(phy);
175462306a36Sopenharmony_ci	phy->scs_en = enable;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ciout:
175762306a36Sopenharmony_ci	mt7615_mutex_release(dev);
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_civoid mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	u32 rxtd, reg;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76))
176562306a36Sopenharmony_ci		reg = MT7663_WF_PHY_R0_PHYMUX_5;
176662306a36Sopenharmony_ci	else
176762306a36Sopenharmony_ci		reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy);
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	if (ext_phy)
177062306a36Sopenharmony_ci		rxtd = MT_WF_PHY_RXTD2(10);
177162306a36Sopenharmony_ci	else
177262306a36Sopenharmony_ci		rxtd = MT_WF_PHY_RXTD(12);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	mt76_set(dev, rxtd, BIT(18) | BIT(29));
177562306a36Sopenharmony_ci	mt76_set(dev, reg, 0x5 << 12);
177662306a36Sopenharmony_ci}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_civoid mt7615_mac_cca_stats_reset(struct mt7615_phy *phy)
177962306a36Sopenharmony_ci{
178062306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
178162306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
178262306a36Sopenharmony_ci	u32 reg;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76))
178562306a36Sopenharmony_ci		reg = MT7663_WF_PHY_R0_PHYMUX_5;
178662306a36Sopenharmony_ci	else
178762306a36Sopenharmony_ci		reg = MT_WF_PHY_R0_PHYMUX_5(ext_phy);
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	/* reset PD and MDRDY counters */
179062306a36Sopenharmony_ci	mt76_clear(dev, reg, GENMASK(22, 20));
179162306a36Sopenharmony_ci	mt76_set(dev, reg, BIT(22) | BIT(20));
179262306a36Sopenharmony_ci}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_cistatic void
179562306a36Sopenharmony_cimt7615_mac_adjust_sensitivity(struct mt7615_phy *phy,
179662306a36Sopenharmony_ci			      u32 rts_err_rate, bool ofdm)
179762306a36Sopenharmony_ci{
179862306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
179962306a36Sopenharmony_ci	int false_cca = ofdm ? phy->false_cca_ofdm : phy->false_cca_cck;
180062306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
180162306a36Sopenharmony_ci	s16 def_th = ofdm ? -98 : -110;
180262306a36Sopenharmony_ci	bool update = false;
180362306a36Sopenharmony_ci	s8 *sensitivity;
180462306a36Sopenharmony_ci	int signal;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	sensitivity = ofdm ? &phy->ofdm_sensitivity : &phy->cck_sensitivity;
180762306a36Sopenharmony_ci	signal = mt76_get_min_avg_rssi(&dev->mt76, ext_phy);
180862306a36Sopenharmony_ci	if (!signal) {
180962306a36Sopenharmony_ci		mt7615_mac_set_default_sensitivity(phy);
181062306a36Sopenharmony_ci		return;
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	signal = min(signal, -72);
181462306a36Sopenharmony_ci	if (false_cca > 500) {
181562306a36Sopenharmony_ci		if (rts_err_rate > MT_FRAC(40, 100))
181662306a36Sopenharmony_ci			return;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		/* decrease coverage */
181962306a36Sopenharmony_ci		if (*sensitivity == def_th && signal > -90) {
182062306a36Sopenharmony_ci			*sensitivity = -90;
182162306a36Sopenharmony_ci			update = true;
182262306a36Sopenharmony_ci		} else if (*sensitivity + 2 < signal) {
182362306a36Sopenharmony_ci			*sensitivity += 2;
182462306a36Sopenharmony_ci			update = true;
182562306a36Sopenharmony_ci		}
182662306a36Sopenharmony_ci	} else if ((false_cca > 0 && false_cca < 50) ||
182762306a36Sopenharmony_ci		   rts_err_rate > MT_FRAC(60, 100)) {
182862306a36Sopenharmony_ci		/* increase coverage */
182962306a36Sopenharmony_ci		if (*sensitivity - 2 >= def_th) {
183062306a36Sopenharmony_ci			*sensitivity -= 2;
183162306a36Sopenharmony_ci			update = true;
183262306a36Sopenharmony_ci		}
183362306a36Sopenharmony_ci	}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	if (*sensitivity > signal) {
183662306a36Sopenharmony_ci		*sensitivity = signal;
183762306a36Sopenharmony_ci		update = true;
183862306a36Sopenharmony_ci	}
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (update) {
184162306a36Sopenharmony_ci		u16 val = ofdm ? *sensitivity * 2 + 512 : *sensitivity + 256;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci		mt7615_mac_set_sensitivity(phy, val, ofdm);
184462306a36Sopenharmony_ci		phy->last_cca_adj = jiffies;
184562306a36Sopenharmony_ci	}
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic void
184962306a36Sopenharmony_cimt7615_mac_scs_check(struct mt7615_phy *phy)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
185262306a36Sopenharmony_ci	struct mib_stats *mib = &phy->mib;
185362306a36Sopenharmony_ci	u32 val, rts_err_rate = 0;
185462306a36Sopenharmony_ci	u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm;
185562306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	if (!phy->scs_en)
185862306a36Sopenharmony_ci		return;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76))
186162306a36Sopenharmony_ci		val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS0(ext_phy));
186262306a36Sopenharmony_ci	else
186362306a36Sopenharmony_ci		val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS0(ext_phy));
186462306a36Sopenharmony_ci	pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val);
186562306a36Sopenharmony_ci	pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76))
186862306a36Sopenharmony_ci		val = mt76_rr(dev, MT7663_WF_PHY_R0_PHYCTRL_STS5(ext_phy));
186962306a36Sopenharmony_ci	else
187062306a36Sopenharmony_ci		val = mt76_rr(dev, MT_WF_PHY_R0_PHYCTRL_STS5(ext_phy));
187162306a36Sopenharmony_ci	mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val);
187262306a36Sopenharmony_ci	mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val);
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	phy->false_cca_ofdm = pd_ofdm - mdrdy_ofdm;
187562306a36Sopenharmony_ci	phy->false_cca_cck = pd_cck - mdrdy_cck;
187662306a36Sopenharmony_ci	mt7615_mac_cca_stats_reset(phy);
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	if (mib->rts_cnt + mib->rts_retries_cnt)
187962306a36Sopenharmony_ci		rts_err_rate = MT_FRAC(mib->rts_retries_cnt,
188062306a36Sopenharmony_ci				       mib->rts_cnt + mib->rts_retries_cnt);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	/* cck */
188362306a36Sopenharmony_ci	mt7615_mac_adjust_sensitivity(phy, rts_err_rate, false);
188462306a36Sopenharmony_ci	/* ofdm */
188562306a36Sopenharmony_ci	mt7615_mac_adjust_sensitivity(phy, rts_err_rate, true);
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	if (time_after(jiffies, phy->last_cca_adj + 10 * HZ))
188862306a36Sopenharmony_ci		mt7615_mac_set_default_sensitivity(phy);
188962306a36Sopenharmony_ci}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_cistatic u8
189262306a36Sopenharmony_cimt7615_phy_get_nf(struct mt7615_dev *dev, int idx)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
189562306a36Sopenharmony_ci	u32 reg, val, sum = 0, n = 0;
189662306a36Sopenharmony_ci	int i;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76))
189962306a36Sopenharmony_ci		reg = MT7663_WF_PHY_RXTD(20);
190062306a36Sopenharmony_ci	else
190162306a36Sopenharmony_ci		reg = idx ? MT_WF_PHY_RXTD2(17) : MT_WF_PHY_RXTD(20);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
190462306a36Sopenharmony_ci		val = mt76_rr(dev, reg);
190562306a36Sopenharmony_ci		sum += val * nf_power[i];
190662306a36Sopenharmony_ci		n += val;
190762306a36Sopenharmony_ci	}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	if (!n)
191062306a36Sopenharmony_ci		return 0;
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	return sum / n;
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_cistatic void
191662306a36Sopenharmony_cimt7615_phy_update_channel(struct mt76_phy *mphy, int idx)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76);
191962306a36Sopenharmony_ci	struct mt7615_phy *phy = mphy->priv;
192062306a36Sopenharmony_ci	struct mt76_channel_state *state;
192162306a36Sopenharmony_ci	u64 busy_time, tx_time, rx_time, obss_time;
192262306a36Sopenharmony_ci	u32 obss_reg = idx ? MT_WF_RMAC_MIB_TIME6 : MT_WF_RMAC_MIB_TIME5;
192362306a36Sopenharmony_ci	int nf;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
192662306a36Sopenharmony_ci				   MT_MIB_SDR9_BUSY_MASK);
192762306a36Sopenharmony_ci	tx_time = mt76_get_field(dev, MT_MIB_SDR36(idx),
192862306a36Sopenharmony_ci				 MT_MIB_SDR36_TXTIME_MASK);
192962306a36Sopenharmony_ci	rx_time = mt76_get_field(dev, MT_MIB_SDR37(idx),
193062306a36Sopenharmony_ci				 MT_MIB_SDR37_RXTIME_MASK);
193162306a36Sopenharmony_ci	obss_time = mt76_get_field(dev, obss_reg, MT_MIB_OBSSTIME_MASK);
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	nf = mt7615_phy_get_nf(dev, idx);
193462306a36Sopenharmony_ci	if (!phy->noise)
193562306a36Sopenharmony_ci		phy->noise = nf << 4;
193662306a36Sopenharmony_ci	else if (nf)
193762306a36Sopenharmony_ci		phy->noise += nf - (phy->noise >> 4);
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	state = mphy->chan_state;
194062306a36Sopenharmony_ci	state->cc_busy += busy_time;
194162306a36Sopenharmony_ci	state->cc_tx += tx_time;
194262306a36Sopenharmony_ci	state->cc_rx += rx_time + obss_time;
194362306a36Sopenharmony_ci	state->cc_bss_rx += rx_time;
194462306a36Sopenharmony_ci	state->noise = -(phy->noise >> 4);
194562306a36Sopenharmony_ci}
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_cistatic void mt7615_update_survey(struct mt7615_dev *dev)
194862306a36Sopenharmony_ci{
194962306a36Sopenharmony_ci	struct mt76_dev *mdev = &dev->mt76;
195062306a36Sopenharmony_ci	struct mt76_phy *mphy_ext = mdev->phys[MT_BAND1];
195162306a36Sopenharmony_ci	ktime_t cur_time;
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_ci	/* MT7615 can only update both phys simultaneously
195462306a36Sopenharmony_ci	 * since some reisters are shared across bands.
195562306a36Sopenharmony_ci	 */
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	mt7615_phy_update_channel(&mdev->phy, 0);
195862306a36Sopenharmony_ci	if (mphy_ext)
195962306a36Sopenharmony_ci		mt7615_phy_update_channel(mphy_ext, 1);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	cur_time = ktime_get_boottime();
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	mt76_update_survey_active_time(&mdev->phy, cur_time);
196462306a36Sopenharmony_ci	if (mphy_ext)
196562306a36Sopenharmony_ci		mt76_update_survey_active_time(mphy_ext, cur_time);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	/* reset obss airtime */
196862306a36Sopenharmony_ci	mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
196962306a36Sopenharmony_ci}
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_civoid mt7615_update_channel(struct mt76_phy *mphy)
197262306a36Sopenharmony_ci{
197362306a36Sopenharmony_ci	struct mt7615_dev *dev = container_of(mphy->dev, struct mt7615_dev, mt76);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	if (mt76_connac_pm_wake(&dev->mphy, &dev->pm))
197662306a36Sopenharmony_ci		return;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	mt7615_update_survey(dev);
197962306a36Sopenharmony_ci	mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
198062306a36Sopenharmony_ci}
198162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_update_channel);
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_cistatic void
198462306a36Sopenharmony_cimt7615_mac_update_mib_stats(struct mt7615_phy *phy)
198562306a36Sopenharmony_ci{
198662306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
198762306a36Sopenharmony_ci	struct mib_stats *mib = &phy->mib;
198862306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
198962306a36Sopenharmony_ci	int i, aggr = 0;
199062306a36Sopenharmony_ci	u32 val, val2;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	mib->fcs_err_cnt += mt76_get_field(dev, MT_MIB_SDR3(ext_phy),
199362306a36Sopenharmony_ci					   MT_MIB_SDR3_FCS_ERR_MASK);
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci	val = mt76_get_field(dev, MT_MIB_SDR14(ext_phy),
199662306a36Sopenharmony_ci			     MT_MIB_AMPDU_MPDU_COUNT);
199762306a36Sopenharmony_ci	if (val) {
199862306a36Sopenharmony_ci		val2 = mt76_get_field(dev, MT_MIB_SDR15(ext_phy),
199962306a36Sopenharmony_ci				      MT_MIB_AMPDU_ACK_COUNT);
200062306a36Sopenharmony_ci		mib->aggr_per = 1000 * (val - val2) / val;
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
200462306a36Sopenharmony_ci		val = mt76_rr(dev, MT_MIB_MB_SDR1(ext_phy, i));
200562306a36Sopenharmony_ci		mib->ba_miss_cnt += FIELD_GET(MT_MIB_BA_MISS_COUNT_MASK, val);
200662306a36Sopenharmony_ci		mib->ack_fail_cnt += FIELD_GET(MT_MIB_ACK_FAIL_COUNT_MASK,
200762306a36Sopenharmony_ci					       val);
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci		val = mt76_rr(dev, MT_MIB_MB_SDR0(ext_phy, i));
201062306a36Sopenharmony_ci		mib->rts_cnt += FIELD_GET(MT_MIB_RTS_COUNT_MASK, val);
201162306a36Sopenharmony_ci		mib->rts_retries_cnt += FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK,
201262306a36Sopenharmony_ci						  val);
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci		val = mt76_rr(dev, MT_TX_AGG_CNT(ext_phy, i));
201562306a36Sopenharmony_ci		phy->mt76->aggr_stats[aggr++] += val & 0xffff;
201662306a36Sopenharmony_ci		phy->mt76->aggr_stats[aggr++] += val >> 16;
201762306a36Sopenharmony_ci	}
201862306a36Sopenharmony_ci}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_civoid mt7615_pm_wake_work(struct work_struct *work)
202162306a36Sopenharmony_ci{
202262306a36Sopenharmony_ci	struct mt7615_dev *dev;
202362306a36Sopenharmony_ci	struct mt76_phy *mphy;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
202662306a36Sopenharmony_ci						pm.wake_work);
202762306a36Sopenharmony_ci	mphy = dev->phy.mt76;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	if (!mt7615_mcu_set_drv_ctrl(dev)) {
203062306a36Sopenharmony_ci		struct mt76_dev *mdev = &dev->mt76;
203162306a36Sopenharmony_ci		int i;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci		if (mt76_is_sdio(mdev)) {
203462306a36Sopenharmony_ci			mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
203562306a36Sopenharmony_ci			mt76_worker_schedule(&mdev->sdio.txrx_worker);
203662306a36Sopenharmony_ci		} else {
203762306a36Sopenharmony_ci			local_bh_disable();
203862306a36Sopenharmony_ci			mt76_for_each_q_rx(mdev, i)
203962306a36Sopenharmony_ci				napi_schedule(&mdev->napi[i]);
204062306a36Sopenharmony_ci			local_bh_enable();
204162306a36Sopenharmony_ci			mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
204262306a36Sopenharmony_ci			mt76_queue_tx_cleanup(dev, mdev->q_mcu[MT_MCUQ_WM],
204362306a36Sopenharmony_ci					      false);
204462306a36Sopenharmony_ci		}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci		if (test_bit(MT76_STATE_RUNNING, &mphy->state)) {
204762306a36Sopenharmony_ci			unsigned long timeout;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci			timeout = mt7615_get_macwork_timeout(dev);
205062306a36Sopenharmony_ci			ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
205162306a36Sopenharmony_ci						     timeout);
205262306a36Sopenharmony_ci		}
205362306a36Sopenharmony_ci	}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci	ieee80211_wake_queues(mphy->hw);
205662306a36Sopenharmony_ci	wake_up(&dev->pm.wait);
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_civoid mt7615_pm_power_save_work(struct work_struct *work)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	struct mt7615_dev *dev;
206262306a36Sopenharmony_ci	unsigned long delta;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
206562306a36Sopenharmony_ci						pm.ps_work.work);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	delta = dev->pm.idle_timeout;
206862306a36Sopenharmony_ci	if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) ||
206962306a36Sopenharmony_ci	    test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state))
207062306a36Sopenharmony_ci		goto out;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	if (mutex_is_locked(&dev->mt76.mutex))
207362306a36Sopenharmony_ci		/* if mt76 mutex is held we should not put the device
207462306a36Sopenharmony_ci		 * to sleep since we are currently accessing device
207562306a36Sopenharmony_ci		 * register map. We need to wait for the next power_save
207662306a36Sopenharmony_ci		 * trigger.
207762306a36Sopenharmony_ci		 */
207862306a36Sopenharmony_ci		goto out;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
208162306a36Sopenharmony_ci		delta = dev->pm.last_activity + delta - jiffies;
208262306a36Sopenharmony_ci		goto out;
208362306a36Sopenharmony_ci	}
208462306a36Sopenharmony_ci
208562306a36Sopenharmony_ci	if (!mt7615_mcu_set_fw_ctrl(dev))
208662306a36Sopenharmony_ci		return;
208762306a36Sopenharmony_ciout:
208862306a36Sopenharmony_ci	queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
208962306a36Sopenharmony_ci}
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_civoid mt7615_mac_work(struct work_struct *work)
209262306a36Sopenharmony_ci{
209362306a36Sopenharmony_ci	struct mt7615_phy *phy;
209462306a36Sopenharmony_ci	struct mt76_phy *mphy;
209562306a36Sopenharmony_ci	unsigned long timeout;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	mphy = (struct mt76_phy *)container_of(work, struct mt76_phy,
209862306a36Sopenharmony_ci					       mac_work.work);
209962306a36Sopenharmony_ci	phy = mphy->priv;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	mt7615_mutex_acquire(phy->dev);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	mt7615_update_survey(phy->dev);
210462306a36Sopenharmony_ci	if (++mphy->mac_work_count == 5) {
210562306a36Sopenharmony_ci		mphy->mac_work_count = 0;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci		mt7615_mac_update_mib_stats(phy);
210862306a36Sopenharmony_ci		mt7615_mac_scs_check(phy);
210962306a36Sopenharmony_ci	}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	mt7615_mutex_release(phy->dev);
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	mt76_tx_status_check(mphy->dev, false);
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	timeout = mt7615_get_macwork_timeout(phy->dev);
211662306a36Sopenharmony_ci	ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, timeout);
211762306a36Sopenharmony_ci}
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_civoid mt7615_tx_token_put(struct mt7615_dev *dev)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	struct mt76_txwi_cache *txwi;
212262306a36Sopenharmony_ci	int id;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	spin_lock_bh(&dev->mt76.token_lock);
212562306a36Sopenharmony_ci	idr_for_each_entry(&dev->mt76.token, txwi, id)
212662306a36Sopenharmony_ci		mt7615_txwi_free(dev, txwi);
212762306a36Sopenharmony_ci	spin_unlock_bh(&dev->mt76.token_lock);
212862306a36Sopenharmony_ci	idr_destroy(&dev->mt76.token);
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mt7615_tx_token_put);
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_cistatic void mt7615_dfs_stop_radar_detector(struct mt7615_phy *phy)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	if (phy->rdd_state & BIT(0))
213762306a36Sopenharmony_ci		mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 0,
213862306a36Sopenharmony_ci					MT_RX_SEL0, 0);
213962306a36Sopenharmony_ci	if (phy->rdd_state & BIT(1))
214062306a36Sopenharmony_ci		mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_STOP, 1,
214162306a36Sopenharmony_ci					MT_RX_SEL0, 0);
214262306a36Sopenharmony_ci}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_cistatic int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain)
214562306a36Sopenharmony_ci{
214662306a36Sopenharmony_ci	int err;
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_START, chain,
214962306a36Sopenharmony_ci				      MT_RX_SEL0, 0);
215062306a36Sopenharmony_ci	if (err < 0)
215162306a36Sopenharmony_ci		return err;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_DET_MODE, chain,
215462306a36Sopenharmony_ci				       MT_RX_SEL0, 1);
215562306a36Sopenharmony_ci}
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_cistatic int mt7615_dfs_start_radar_detector(struct mt7615_phy *phy)
215862306a36Sopenharmony_ci{
215962306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
216062306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
216162306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
216262306a36Sopenharmony_ci	int err;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/* start CAC */
216562306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_START, ext_phy,
216662306a36Sopenharmony_ci				      MT_RX_SEL0, 0);
216762306a36Sopenharmony_ci	if (err < 0)
216862306a36Sopenharmony_ci		return err;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	err = mt7615_dfs_start_rdd(dev, ext_phy);
217162306a36Sopenharmony_ci	if (err < 0)
217262306a36Sopenharmony_ci		return err;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	phy->rdd_state |= BIT(ext_phy);
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	if (chandef->width == NL80211_CHAN_WIDTH_160 ||
217762306a36Sopenharmony_ci	    chandef->width == NL80211_CHAN_WIDTH_80P80) {
217862306a36Sopenharmony_ci		err = mt7615_dfs_start_rdd(dev, 1);
217962306a36Sopenharmony_ci		if (err < 0)
218062306a36Sopenharmony_ci			return err;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci		phy->rdd_state |= BIT(1);
218362306a36Sopenharmony_ci	}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	return 0;
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_cistatic int
218962306a36Sopenharmony_cimt7615_dfs_init_radar_specs(struct mt7615_phy *phy)
219062306a36Sopenharmony_ci{
219162306a36Sopenharmony_ci	const struct mt7615_dfs_radar_spec *radar_specs;
219262306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
219362306a36Sopenharmony_ci	int err, i, lpn = 500;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci	switch (dev->mt76.region) {
219662306a36Sopenharmony_ci	case NL80211_DFS_FCC:
219762306a36Sopenharmony_ci		radar_specs = &fcc_radar_specs;
219862306a36Sopenharmony_ci		lpn = 8;
219962306a36Sopenharmony_ci		break;
220062306a36Sopenharmony_ci	case NL80211_DFS_ETSI:
220162306a36Sopenharmony_ci		radar_specs = &etsi_radar_specs;
220262306a36Sopenharmony_ci		break;
220362306a36Sopenharmony_ci	case NL80211_DFS_JP:
220462306a36Sopenharmony_ci		radar_specs = &jp_radar_specs;
220562306a36Sopenharmony_ci		break;
220662306a36Sopenharmony_ci	default:
220762306a36Sopenharmony_ci		return -EINVAL;
220862306a36Sopenharmony_ci	}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	/* avoid FCC radar detection in non-FCC region */
221162306a36Sopenharmony_ci	err = mt7615_mcu_set_fcc5_lpn(dev, lpn);
221262306a36Sopenharmony_ci	if (err < 0)
221362306a36Sopenharmony_ci		return err;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) {
221662306a36Sopenharmony_ci		err = mt7615_mcu_set_radar_th(dev, i,
221762306a36Sopenharmony_ci					      &radar_specs->radar_pattern[i]);
221862306a36Sopenharmony_ci		if (err < 0)
221962306a36Sopenharmony_ci			return err;
222062306a36Sopenharmony_ci	}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	return mt7615_mcu_set_pulse_th(dev, &radar_specs->pulse_th);
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ciint mt7615_dfs_init_radar_detector(struct mt7615_phy *phy)
222662306a36Sopenharmony_ci{
222762306a36Sopenharmony_ci	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
222862306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
222962306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
223062306a36Sopenharmony_ci	enum mt76_dfs_state dfs_state, prev_state;
223162306a36Sopenharmony_ci	int err;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci	if (is_mt7663(&dev->mt76))
223462306a36Sopenharmony_ci		return 0;
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	prev_state = phy->mt76->dfs_state;
223762306a36Sopenharmony_ci	dfs_state = mt76_phy_dfs_state(phy->mt76);
223862306a36Sopenharmony_ci	if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
223962306a36Sopenharmony_ci	    dfs_state < MT_DFS_STATE_CAC)
224062306a36Sopenharmony_ci		dfs_state = MT_DFS_STATE_ACTIVE;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	if (prev_state == dfs_state)
224362306a36Sopenharmony_ci		return 0;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci	if (dfs_state == MT_DFS_STATE_DISABLED)
224662306a36Sopenharmony_ci		goto stop;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	if (prev_state <= MT_DFS_STATE_DISABLED) {
224962306a36Sopenharmony_ci		err = mt7615_dfs_init_radar_specs(phy);
225062306a36Sopenharmony_ci		if (err < 0)
225162306a36Sopenharmony_ci			return err;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci		err = mt7615_dfs_start_radar_detector(phy);
225462306a36Sopenharmony_ci		if (err < 0)
225562306a36Sopenharmony_ci			return err;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci		phy->mt76->dfs_state = MT_DFS_STATE_CAC;
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	if (dfs_state == MT_DFS_STATE_CAC)
226162306a36Sopenharmony_ci		return 0;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_CAC_END,
226462306a36Sopenharmony_ci				      ext_phy, MT_RX_SEL0, 0);
226562306a36Sopenharmony_ci	if (err < 0) {
226662306a36Sopenharmony_ci		phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
226762306a36Sopenharmony_ci		return err;
226862306a36Sopenharmony_ci	}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci	phy->mt76->dfs_state = MT_DFS_STATE_ACTIVE;
227162306a36Sopenharmony_ci	return 0;
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_cistop:
227462306a36Sopenharmony_ci	err = mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_NORMAL_START, ext_phy,
227562306a36Sopenharmony_ci				      MT_RX_SEL0, 0);
227662306a36Sopenharmony_ci	if (err < 0)
227762306a36Sopenharmony_ci		return err;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	mt7615_dfs_stop_radar_detector(phy);
228062306a36Sopenharmony_ci	phy->mt76->dfs_state = MT_DFS_STATE_DISABLED;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	return 0;
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ciint mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
228662306a36Sopenharmony_ci				 struct ieee80211_vif *vif,
228762306a36Sopenharmony_ci				 bool enable)
228862306a36Sopenharmony_ci{
228962306a36Sopenharmony_ci	struct mt7615_dev *dev = phy->dev;
229062306a36Sopenharmony_ci	bool ext_phy = phy != &dev->phy;
229162306a36Sopenharmony_ci	int err;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	if (!mt7615_firmware_offload(dev))
229462306a36Sopenharmony_ci		return -EOPNOTSUPP;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	switch (vif->type) {
229762306a36Sopenharmony_ci	case NL80211_IFTYPE_MONITOR:
229862306a36Sopenharmony_ci		return 0;
229962306a36Sopenharmony_ci	case NL80211_IFTYPE_MESH_POINT:
230062306a36Sopenharmony_ci	case NL80211_IFTYPE_ADHOC:
230162306a36Sopenharmony_ci	case NL80211_IFTYPE_AP:
230262306a36Sopenharmony_ci		if (enable)
230362306a36Sopenharmony_ci			phy->n_beacon_vif++;
230462306a36Sopenharmony_ci		else
230562306a36Sopenharmony_ci			phy->n_beacon_vif--;
230662306a36Sopenharmony_ci		fallthrough;
230762306a36Sopenharmony_ci	default:
230862306a36Sopenharmony_ci		break;
230962306a36Sopenharmony_ci	}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	err = mt7615_mcu_set_bss_pm(dev, vif, !phy->n_beacon_vif);
231262306a36Sopenharmony_ci	if (err)
231362306a36Sopenharmony_ci		return err;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	if (phy->n_beacon_vif) {
231662306a36Sopenharmony_ci		vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
231762306a36Sopenharmony_ci		mt76_clear(dev, MT_WF_RFCR(ext_phy),
231862306a36Sopenharmony_ci			   MT_WF_RFCR_DROP_OTHER_BEACON);
231962306a36Sopenharmony_ci	} else {
232062306a36Sopenharmony_ci		vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
232162306a36Sopenharmony_ci		mt76_set(dev, MT_WF_RFCR(ext_phy),
232262306a36Sopenharmony_ci			 MT_WF_RFCR_DROP_OTHER_BEACON);
232362306a36Sopenharmony_ci	}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	return 0;
232662306a36Sopenharmony_ci}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_civoid mt7615_coredump_work(struct work_struct *work)
232962306a36Sopenharmony_ci{
233062306a36Sopenharmony_ci	struct mt7615_dev *dev;
233162306a36Sopenharmony_ci	char *dump, *data;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
233462306a36Sopenharmony_ci						coredump.work.work);
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_ci	if (time_is_after_jiffies(dev->coredump.last_activity +
233762306a36Sopenharmony_ci				  4 * MT76_CONNAC_COREDUMP_TIMEOUT)) {
233862306a36Sopenharmony_ci		queue_delayed_work(dev->mt76.wq, &dev->coredump.work,
233962306a36Sopenharmony_ci				   MT76_CONNAC_COREDUMP_TIMEOUT);
234062306a36Sopenharmony_ci		return;
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	dump = vzalloc(MT76_CONNAC_COREDUMP_SZ);
234462306a36Sopenharmony_ci	data = dump;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	while (true) {
234762306a36Sopenharmony_ci		struct sk_buff *skb;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci		spin_lock_bh(&dev->mt76.lock);
235062306a36Sopenharmony_ci		skb = __skb_dequeue(&dev->coredump.msg_list);
235162306a36Sopenharmony_ci		spin_unlock_bh(&dev->mt76.lock);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci		if (!skb)
235462306a36Sopenharmony_ci			break;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci		skb_pull(skb, sizeof(struct mt7615_mcu_rxd));
235762306a36Sopenharmony_ci		if (!dump || data + skb->len - dump > MT76_CONNAC_COREDUMP_SZ) {
235862306a36Sopenharmony_ci			dev_kfree_skb(skb);
235962306a36Sopenharmony_ci			continue;
236062306a36Sopenharmony_ci		}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci		memcpy(data, skb->data, skb->len);
236362306a36Sopenharmony_ci		data += skb->len;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci		dev_kfree_skb(skb);
236662306a36Sopenharmony_ci	}
236762306a36Sopenharmony_ci
236862306a36Sopenharmony_ci	if (dump)
236962306a36Sopenharmony_ci		dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ,
237062306a36Sopenharmony_ci			      GFP_KERNEL);
237162306a36Sopenharmony_ci}
2372