162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
462306a36Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "mt7601u.h"
862306a36Sopenharmony_ci#include "trace.h"
962306a36Sopenharmony_ci#include <linux/etherdevice.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_civoid mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr)
1262306a36Sopenharmony_ci{
1362306a36Sopenharmony_ci	ether_addr_copy(dev->macaddr, addr);
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	if (!is_valid_ether_addr(dev->macaddr)) {
1662306a36Sopenharmony_ci		eth_random_addr(dev->macaddr);
1762306a36Sopenharmony_ci		dev_info(dev->dev,
1862306a36Sopenharmony_ci			 "Invalid MAC address, using random address %pM\n",
1962306a36Sopenharmony_ci			 dev->macaddr);
2062306a36Sopenharmony_ci	}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
2362306a36Sopenharmony_ci	mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
2462306a36Sopenharmony_ci		FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void
2862306a36Sopenharmony_cimt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	u8 idx = FIELD_GET(MT_TXWI_RATE_MCS, rate);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	txrate->idx = 0;
3362306a36Sopenharmony_ci	txrate->flags = 0;
3462306a36Sopenharmony_ci	txrate->count = 1;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	switch (FIELD_GET(MT_TXWI_RATE_PHY_MODE, rate)) {
3762306a36Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
3862306a36Sopenharmony_ci		txrate->idx = idx + 4;
3962306a36Sopenharmony_ci		return;
4062306a36Sopenharmony_ci	case MT_PHY_TYPE_CCK:
4162306a36Sopenharmony_ci		if (idx >= 8)
4262306a36Sopenharmony_ci			idx -= 8;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci		txrate->idx = idx;
4562306a36Sopenharmony_ci		return;
4662306a36Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
4762306a36Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
4862306a36Sopenharmony_ci		fallthrough;
4962306a36Sopenharmony_ci	case MT_PHY_TYPE_HT:
5062306a36Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_MCS;
5162306a36Sopenharmony_ci		txrate->idx = idx;
5262306a36Sopenharmony_ci		break;
5362306a36Sopenharmony_ci	default:
5462306a36Sopenharmony_ci		WARN_ON(1);
5562306a36Sopenharmony_ci		return;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (FIELD_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40)
5962306a36Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (rate & MT_TXWI_RATE_SGI)
6262306a36Sopenharmony_ci		txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void
6662306a36Sopenharmony_cimt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info,
6762306a36Sopenharmony_ci			struct mt76_tx_status *st)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct ieee80211_tx_rate *rate = info->status.rates;
7062306a36Sopenharmony_ci	int cur_idx, last_rate;
7162306a36Sopenharmony_ci	int i;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
7462306a36Sopenharmony_ci	mt76_mac_process_tx_rate(&rate[last_rate], st->rate);
7562306a36Sopenharmony_ci	if (last_rate < IEEE80211_TX_MAX_RATES - 1)
7662306a36Sopenharmony_ci		rate[last_rate + 1].idx = -1;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	cur_idx = rate[last_rate].idx + st->retry;
7962306a36Sopenharmony_ci	for (i = 0; i <= last_rate; i++) {
8062306a36Sopenharmony_ci		rate[i].flags = rate[last_rate].flags;
8162306a36Sopenharmony_ci		rate[i].idx = max_t(int, 0, cur_idx - i);
8262306a36Sopenharmony_ci		rate[i].count = 1;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (last_rate > 0)
8662306a36Sopenharmony_ci		rate[last_rate - 1].count = st->retry + 1 - last_rate;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	info->status.ampdu_len = 1;
8962306a36Sopenharmony_ci	info->status.ampdu_ack_len = st->success;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (st->is_probe)
9262306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (st->aggr)
9562306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_CTL_AMPDU |
9662306a36Sopenharmony_ci			       IEEE80211_TX_STAT_AMPDU;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (!st->ack_req)
9962306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_CTL_NO_ACK;
10062306a36Sopenharmony_ci	else if (st->success)
10162306a36Sopenharmony_ci		info->flags |= IEEE80211_TX_STAT_ACK;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciu16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
10562306a36Sopenharmony_ci			 const struct ieee80211_tx_rate *rate, u8 *nss_val)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	u16 rateval;
10862306a36Sopenharmony_ci	u8 phy, rate_idx;
10962306a36Sopenharmony_ci	u8 nss = 1;
11062306a36Sopenharmony_ci	u8 bw = 0;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_MCS) {
11362306a36Sopenharmony_ci		rate_idx = rate->idx;
11462306a36Sopenharmony_ci		nss = 1 + (rate->idx >> 3);
11562306a36Sopenharmony_ci		phy = MT_PHY_TYPE_HT;
11662306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
11762306a36Sopenharmony_ci			phy = MT_PHY_TYPE_HT_GF;
11862306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
11962306a36Sopenharmony_ci			bw = 1;
12062306a36Sopenharmony_ci	} else {
12162306a36Sopenharmony_ci		const struct ieee80211_rate *r;
12262306a36Sopenharmony_ci		int band = dev->chandef.chan->band;
12362306a36Sopenharmony_ci		u16 val;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx];
12662306a36Sopenharmony_ci		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
12762306a36Sopenharmony_ci			val = r->hw_value_short;
12862306a36Sopenharmony_ci		else
12962306a36Sopenharmony_ci			val = r->hw_value;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		phy = val >> 8;
13262306a36Sopenharmony_ci		rate_idx = val & 0xff;
13362306a36Sopenharmony_ci		bw = 0;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	rateval = FIELD_PREP(MT_RXWI_RATE_MCS, rate_idx);
13762306a36Sopenharmony_ci	rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
13862306a36Sopenharmony_ci	rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
13962306a36Sopenharmony_ci	if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
14062306a36Sopenharmony_ci		rateval |= MT_RXWI_RATE_SGI;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	*nss_val = nss;
14362306a36Sopenharmony_ci	return rateval;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_civoid mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
14762306a36Sopenharmony_ci			    const struct ieee80211_tx_rate *rate)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	unsigned long flags;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	spin_lock_irqsave(&dev->lock, flags);
15262306a36Sopenharmony_ci	wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
15362306a36Sopenharmony_ci	wcid->tx_rate_set = true;
15462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dev->lock, flags);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistruct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct mt76_tx_status stat = {};
16062306a36Sopenharmony_ci	u32 val;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	val = mt7601u_rr(dev, MT_TX_STAT_FIFO);
16362306a36Sopenharmony_ci	stat.valid = !!(val & MT_TX_STAT_FIFO_VALID);
16462306a36Sopenharmony_ci	stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS);
16562306a36Sopenharmony_ci	stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR);
16662306a36Sopenharmony_ci	stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ);
16762306a36Sopenharmony_ci	stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_PID_TYPE, val);
16862306a36Sopenharmony_ci	stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, val);
16962306a36Sopenharmony_ci	stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, val);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return stat;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_civoid mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct ieee80211_tx_info info = {};
17762306a36Sopenharmony_ci	struct ieee80211_sta *sta = NULL;
17862306a36Sopenharmony_ci	struct mt76_wcid *wcid = NULL;
17962306a36Sopenharmony_ci	void *msta;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	rcu_read_lock();
18262306a36Sopenharmony_ci	if (stat->wcid < ARRAY_SIZE(dev->wcid))
18362306a36Sopenharmony_ci		wcid = rcu_dereference(dev->wcid[stat->wcid]);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (wcid) {
18662306a36Sopenharmony_ci		msta = container_of(wcid, struct mt76_sta, wcid);
18762306a36Sopenharmony_ci		sta = container_of(msta, struct ieee80211_sta,
18862306a36Sopenharmony_ci				   drv_priv);
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	mt76_mac_fill_tx_status(dev, &info, stat);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	spin_lock_bh(&dev->mac_lock);
19462306a36Sopenharmony_ci	ieee80211_tx_status_noskb(dev->hw, sta, &info);
19562306a36Sopenharmony_ci	spin_unlock_bh(&dev->mac_lock);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	rcu_read_unlock();
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_civoid mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
20162306a36Sopenharmony_ci				int ht_mode)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
20462306a36Sopenharmony_ci	bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
20562306a36Sopenharmony_ci	u32 prot[6];
20662306a36Sopenharmony_ci	bool ht_rts[4] = {};
20762306a36Sopenharmony_ci	int i;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	prot[0] = MT_PROT_NAV_SHORT |
21062306a36Sopenharmony_ci		  MT_PROT_TXOP_ALLOW_ALL |
21162306a36Sopenharmony_ci		  MT_PROT_RTS_THR_EN;
21262306a36Sopenharmony_ci	prot[1] = prot[0];
21362306a36Sopenharmony_ci	if (legacy_prot)
21462306a36Sopenharmony_ci		prot[1] |= MT_PROT_CTRL_CTS2SELF;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20;
21762306a36Sopenharmony_ci	prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (legacy_prot) {
22062306a36Sopenharmony_ci		prot[2] |= MT_PROT_RATE_CCK_11;
22162306a36Sopenharmony_ci		prot[3] |= MT_PROT_RATE_CCK_11;
22262306a36Sopenharmony_ci		prot[4] |= MT_PROT_RATE_CCK_11;
22362306a36Sopenharmony_ci		prot[5] |= MT_PROT_RATE_CCK_11;
22462306a36Sopenharmony_ci	} else {
22562306a36Sopenharmony_ci		prot[2] |= MT_PROT_RATE_OFDM_24;
22662306a36Sopenharmony_ci		prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
22762306a36Sopenharmony_ci		prot[4] |= MT_PROT_RATE_OFDM_24;
22862306a36Sopenharmony_ci		prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	switch (mode) {
23262306a36Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
23362306a36Sopenharmony_ci		break;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
23662306a36Sopenharmony_ci		ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
23762306a36Sopenharmony_ci		break;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
24062306a36Sopenharmony_ci		ht_rts[1] = ht_rts[3] = true;
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
24462306a36Sopenharmony_ci		ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (non_gf)
24962306a36Sopenharmony_ci		ht_rts[2] = ht_rts[3] = true;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
25262306a36Sopenharmony_ci		if (ht_rts[i])
25362306a36Sopenharmony_ci			prot[i + 2] |= MT_PROT_CTRL_RTS_CTS;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	for (i = 0; i < 6; i++)
25662306a36Sopenharmony_ci		mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_civoid mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	if (short_preamb)
26262306a36Sopenharmony_ci		mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
26362306a36Sopenharmony_ci	else
26462306a36Sopenharmony_ci		mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_civoid mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	val &= ~(MT_BEACON_TIME_CFG_TIMER_EN |
27262306a36Sopenharmony_ci		 MT_BEACON_TIME_CFG_SYNC_MODE |
27362306a36Sopenharmony_ci		 MT_BEACON_TIME_CFG_TBTT_EN);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (!enable) {
27662306a36Sopenharmony_ci		mt7601u_wr(dev, MT_BEACON_TIME_CFG, val);
27762306a36Sopenharmony_ci		return;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	val &= ~MT_BEACON_TIME_CFG_INTVAL;
28162306a36Sopenharmony_ci	val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) |
28262306a36Sopenharmony_ci		MT_BEACON_TIME_CFG_TIMER_EN |
28362306a36Sopenharmony_ci		MT_BEACON_TIME_CFG_SYNC_MODE |
28462306a36Sopenharmony_ci		MT_BEACON_TIME_CFG_TBTT_EN;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic void mt7601u_check_mac_err(struct mt7601u_dev *dev)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	u32 val = mt7601u_rr(dev, 0x10f4);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
29262306a36Sopenharmony_ci		return;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	dev_err(dev->dev, "Error: MAC specific condition occurred\n");
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
29762306a36Sopenharmony_ci	udelay(10);
29862306a36Sopenharmony_ci	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_civoid mt7601u_mac_work(struct work_struct *work)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
30462306a36Sopenharmony_ci					       mac_work.work);
30562306a36Sopenharmony_ci	struct {
30662306a36Sopenharmony_ci		u32 addr_base;
30762306a36Sopenharmony_ci		u32 span;
30862306a36Sopenharmony_ci		u64 *stat_base;
30962306a36Sopenharmony_ci	} spans[] = {
31062306a36Sopenharmony_ci		{ MT_RX_STA_CNT0,	3,	dev->stats.rx_stat },
31162306a36Sopenharmony_ci		{ MT_TX_STA_CNT0,	3,	dev->stats.tx_stat },
31262306a36Sopenharmony_ci		{ MT_TX_AGG_STAT,	1,	dev->stats.aggr_stat },
31362306a36Sopenharmony_ci		{ MT_MPDU_DENSITY_CNT,	1,	dev->stats.zero_len_del },
31462306a36Sopenharmony_ci		{ MT_TX_AGG_CNT_BASE0,	8,	&dev->stats.aggr_n[0] },
31562306a36Sopenharmony_ci		{ MT_TX_AGG_CNT_BASE1,	8,	&dev->stats.aggr_n[16] },
31662306a36Sopenharmony_ci	};
31762306a36Sopenharmony_ci	u32 sum, n;
31862306a36Sopenharmony_ci	int i, j, k;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Note: using MCU_RANDOM_READ is actually slower then reading all the
32162306a36Sopenharmony_ci	 *	 registers by hand.  MCU takes ca. 20ms to complete read of 24
32262306a36Sopenharmony_ci	 *	 registers while reading them one by one will takes roughly
32362306a36Sopenharmony_ci	 *	 24*200us =~ 5ms.
32462306a36Sopenharmony_ci	 */
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	k = 0;
32762306a36Sopenharmony_ci	n = 0;
32862306a36Sopenharmony_ci	sum = 0;
32962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(spans); i++)
33062306a36Sopenharmony_ci		for (j = 0; j < spans[i].span; j++) {
33162306a36Sopenharmony_ci			u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci			spans[i].stat_base[j * 2] += val & 0xffff;
33462306a36Sopenharmony_ci			spans[i].stat_base[j * 2 + 1] += val >> 16;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci			/* Calculate average AMPDU length */
33762306a36Sopenharmony_ci			if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 &&
33862306a36Sopenharmony_ci			    spans[i].addr_base != MT_TX_AGG_CNT_BASE1)
33962306a36Sopenharmony_ci				continue;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci			n += (val >> 16) + (val & 0xffff);
34262306a36Sopenharmony_ci			sum += (val & 0xffff) * (1 + k * 2) +
34362306a36Sopenharmony_ci				(val >> 16) * (2 + k * 2);
34462306a36Sopenharmony_ci			k++;
34562306a36Sopenharmony_ci		}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	mt7601u_check_mac_err(dev);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_civoid
35562306a36Sopenharmony_cimt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	u8 zmac[ETH_ALEN] = {};
35862306a36Sopenharmony_ci	u32 attr;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
36162306a36Sopenharmony_ci	       FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	mt76_wr(dev, MT_WCID_ATTR(idx), attr);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (mac)
36662306a36Sopenharmony_ci		memcpy(zmac, mac, sizeof(zmac));
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_civoid mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct ieee80211_sta *sta;
37462306a36Sopenharmony_ci	struct mt76_wcid *wcid;
37562306a36Sopenharmony_ci	void *msta;
37662306a36Sopenharmony_ci	u8 min_factor = 3;
37762306a36Sopenharmony_ci	int i;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	rcu_read_lock();
38062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
38162306a36Sopenharmony_ci		wcid = rcu_dereference(dev->wcid[i]);
38262306a36Sopenharmony_ci		if (!wcid)
38362306a36Sopenharmony_ci			continue;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		msta = container_of(wcid, struct mt76_sta, wcid);
38662306a36Sopenharmony_ci		sta = container_of(msta, struct ieee80211_sta, drv_priv);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		min_factor = min(min_factor, sta->deflink.ht_cap.ampdu_factor);
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	rcu_read_unlock();
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff |
39362306a36Sopenharmony_ci		   FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor));
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic void
39762306a36Sopenharmony_cimt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	u8 idx = FIELD_GET(MT_RXWI_RATE_MCS, rate);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
40262306a36Sopenharmony_ci	case MT_PHY_TYPE_OFDM:
40362306a36Sopenharmony_ci		if (WARN_ON(idx >= 8))
40462306a36Sopenharmony_ci			idx = 0;
40562306a36Sopenharmony_ci		idx += 4;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		status->rate_idx = idx;
40862306a36Sopenharmony_ci		return;
40962306a36Sopenharmony_ci	case MT_PHY_TYPE_CCK:
41062306a36Sopenharmony_ci		if (idx >= 8) {
41162306a36Sopenharmony_ci			idx -= 8;
41262306a36Sopenharmony_ci			status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		if (WARN_ON(idx >= 4))
41662306a36Sopenharmony_ci			idx = 0;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		status->rate_idx = idx;
41962306a36Sopenharmony_ci		return;
42062306a36Sopenharmony_ci	case MT_PHY_TYPE_HT_GF:
42162306a36Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_HT_GF;
42262306a36Sopenharmony_ci		fallthrough;
42362306a36Sopenharmony_ci	case MT_PHY_TYPE_HT:
42462306a36Sopenharmony_ci		status->encoding = RX_ENC_HT;
42562306a36Sopenharmony_ci		status->rate_idx = idx;
42662306a36Sopenharmony_ci		break;
42762306a36Sopenharmony_ci	default:
42862306a36Sopenharmony_ci		WARN_ON(1);
42962306a36Sopenharmony_ci		return;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (rate & MT_RXWI_RATE_SGI)
43362306a36Sopenharmony_ci		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (rate & MT_RXWI_RATE_STBC)
43662306a36Sopenharmony_ci		status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (rate & MT_RXWI_RATE_BW)
43962306a36Sopenharmony_ci		status->bw = RATE_INFO_BW_40;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic void
44362306a36Sopenharmony_cimt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
44462306a36Sopenharmony_ci			  u16 rate, int rssi)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	dev->bcn_freq_off = rxwi->freq_off;
44762306a36Sopenharmony_ci	dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate);
44862306a36Sopenharmony_ci	ewma_rssi_add(&dev->avg_rssi, -rssi);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int
45262306a36Sopenharmony_cimt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return ieee80211_is_beacon(hdr->frame_control) &&
45762306a36Sopenharmony_ci		ether_addr_equal(hdr->addr2, dev->ap_bssid);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ciu32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
46162306a36Sopenharmony_ci			u8 *data, void *rxi)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
46462306a36Sopenharmony_ci	struct mt7601u_rxwi *rxwi = rxi;
46562306a36Sopenharmony_ci	u32 len, ctl = le32_to_cpu(rxwi->ctl);
46662306a36Sopenharmony_ci	u16 rate = le16_to_cpu(rxwi->rate);
46762306a36Sopenharmony_ci	int rssi;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
47062306a36Sopenharmony_ci	if (len < 10)
47162306a36Sopenharmony_ci		return 0;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
47462306a36Sopenharmony_ci		status->flag |= RX_FLAG_DECRYPTED;
47562306a36Sopenharmony_ci		status->flag |= RX_FLAG_MMIC_STRIPPED;
47662306a36Sopenharmony_ci		status->flag |= RX_FLAG_MIC_STRIPPED;
47762306a36Sopenharmony_ci		status->flag |= RX_FLAG_ICV_STRIPPED;
47862306a36Sopenharmony_ci		status->flag |= RX_FLAG_IV_STRIPPED;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci	/* let mac80211 take care of PN validation since apparently
48162306a36Sopenharmony_ci	 * the hardware does not support it
48262306a36Sopenharmony_ci	 */
48362306a36Sopenharmony_ci	if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN))
48462306a36Sopenharmony_ci		status->flag &= ~RX_FLAG_IV_STRIPPED;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	status->chains = BIT(0);
48762306a36Sopenharmony_ci	rssi = mt7601u_phy_get_rssi(dev, rxwi, rate);
48862306a36Sopenharmony_ci	status->chain_signal[0] = status->signal = rssi;
48962306a36Sopenharmony_ci	status->freq = dev->chandef.chan->center_freq;
49062306a36Sopenharmony_ci	status->band = dev->chandef.chan->band;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	mt76_mac_process_rate(status, rate);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	spin_lock_bh(&dev->con_mon_lock);
49562306a36Sopenharmony_ci	if (mt7601u_rx_is_our_beacon(dev, data))
49662306a36Sopenharmony_ci		mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi);
49762306a36Sopenharmony_ci	else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M))
49862306a36Sopenharmony_ci		ewma_rssi_add(&dev->avg_rssi, -rssi);
49962306a36Sopenharmony_ci	spin_unlock_bh(&dev->con_mon_lock);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return len;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic enum mt76_cipher_type
50562306a36Sopenharmony_cimt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	memset(key_data, 0, 32);
50862306a36Sopenharmony_ci	if (!key)
50962306a36Sopenharmony_ci		return MT_CIPHER_NONE;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (key->keylen > 32)
51262306a36Sopenharmony_ci		return MT_CIPHER_NONE;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	memcpy(key_data, key->key, key->keylen);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	switch (key->cipher) {
51762306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP40:
51862306a36Sopenharmony_ci		return MT_CIPHER_WEP40;
51962306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_WEP104:
52062306a36Sopenharmony_ci		return MT_CIPHER_WEP104;
52162306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_TKIP:
52262306a36Sopenharmony_ci		return MT_CIPHER_TKIP;
52362306a36Sopenharmony_ci	case WLAN_CIPHER_SUITE_CCMP:
52462306a36Sopenharmony_ci		return MT_CIPHER_AES_CCMP;
52562306a36Sopenharmony_ci	default:
52662306a36Sopenharmony_ci		return MT_CIPHER_NONE;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciint mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
53162306a36Sopenharmony_ci			  struct ieee80211_key_conf *key)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	enum mt76_cipher_type cipher;
53462306a36Sopenharmony_ci	u8 key_data[32];
53562306a36Sopenharmony_ci	u8 iv_data[8];
53662306a36Sopenharmony_ci	u32 val;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	cipher = mt76_mac_get_key_info(key, key_data);
53962306a36Sopenharmony_ci	if (cipher == MT_CIPHER_NONE && key)
54062306a36Sopenharmony_ci		return -EINVAL;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	trace_set_key(dev, idx);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	memset(iv_data, 0, sizeof(iv_data));
54762306a36Sopenharmony_ci	if (key) {
54862306a36Sopenharmony_ci		iv_data[3] = key->keyidx << 6;
54962306a36Sopenharmony_ci		if (cipher >= MT_CIPHER_TKIP) {
55062306a36Sopenharmony_ci			/* Note: start with 1 to comply with spec,
55162306a36Sopenharmony_ci			 *	 (see comment on common/cmm_wpa.c:4291).
55262306a36Sopenharmony_ci			 */
55362306a36Sopenharmony_ci			iv_data[0] |= 1;
55462306a36Sopenharmony_ci			iv_data[3] |= 0x20;
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci	mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	val = mt7601u_rr(dev, MT_WCID_ATTR(idx));
56062306a36Sopenharmony_ci	val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT;
56162306a36Sopenharmony_ci	val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) |
56262306a36Sopenharmony_ci	       FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3);
56362306a36Sopenharmony_ci	val &= ~MT_WCID_ATTR_PAIRWISE;
56462306a36Sopenharmony_ci	val |= MT_WCID_ATTR_PAIRWISE *
56562306a36Sopenharmony_ci		!!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
56662306a36Sopenharmony_ci	mt7601u_wr(dev, MT_WCID_ATTR(idx), val);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	return 0;
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ciint mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
57262306a36Sopenharmony_ci			      struct ieee80211_key_conf *key)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	enum mt76_cipher_type cipher;
57562306a36Sopenharmony_ci	u8 key_data[32];
57662306a36Sopenharmony_ci	u32 val;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	cipher = mt76_mac_get_key_info(key, key_data);
57962306a36Sopenharmony_ci	if (cipher == MT_CIPHER_NONE && key)
58062306a36Sopenharmony_ci		return -EINVAL;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	trace_set_shared_key(dev, vif_idx, key_idx);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx),
58562306a36Sopenharmony_ci			key_data, sizeof(key_data));
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
58862306a36Sopenharmony_ci	val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
58962306a36Sopenharmony_ci	val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
59062306a36Sopenharmony_ci	mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return 0;
59362306a36Sopenharmony_ci}
594