cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mac.c (15064B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
      4 * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
      5 */
      6
      7#include "mt7601u.h"
      8#include "trace.h"
      9#include <linux/etherdevice.h>
     10
     11void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr)
     12{
     13	ether_addr_copy(dev->macaddr, addr);
     14
     15	if (!is_valid_ether_addr(dev->macaddr)) {
     16		eth_random_addr(dev->macaddr);
     17		dev_info(dev->dev,
     18			 "Invalid MAC address, using random address %pM\n",
     19			 dev->macaddr);
     20	}
     21
     22	mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
     23	mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
     24		FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
     25}
     26
     27static void
     28mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate)
     29{
     30	u8 idx = FIELD_GET(MT_TXWI_RATE_MCS, rate);
     31
     32	txrate->idx = 0;
     33	txrate->flags = 0;
     34	txrate->count = 1;
     35
     36	switch (FIELD_GET(MT_TXWI_RATE_PHY_MODE, rate)) {
     37	case MT_PHY_TYPE_OFDM:
     38		txrate->idx = idx + 4;
     39		return;
     40	case MT_PHY_TYPE_CCK:
     41		if (idx >= 8)
     42			idx -= 8;
     43
     44		txrate->idx = idx;
     45		return;
     46	case MT_PHY_TYPE_HT_GF:
     47		txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
     48		fallthrough;
     49	case MT_PHY_TYPE_HT:
     50		txrate->flags |= IEEE80211_TX_RC_MCS;
     51		txrate->idx = idx;
     52		break;
     53	default:
     54		WARN_ON(1);
     55		return;
     56	}
     57
     58	if (FIELD_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40)
     59		txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
     60
     61	if (rate & MT_TXWI_RATE_SGI)
     62		txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
     63}
     64
     65static void
     66mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info,
     67			struct mt76_tx_status *st)
     68{
     69	struct ieee80211_tx_rate *rate = info->status.rates;
     70	int cur_idx, last_rate;
     71	int i;
     72
     73	last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
     74	mt76_mac_process_tx_rate(&rate[last_rate], st->rate);
     75	if (last_rate < IEEE80211_TX_MAX_RATES - 1)
     76		rate[last_rate + 1].idx = -1;
     77
     78	cur_idx = rate[last_rate].idx + st->retry;
     79	for (i = 0; i <= last_rate; i++) {
     80		rate[i].flags = rate[last_rate].flags;
     81		rate[i].idx = max_t(int, 0, cur_idx - i);
     82		rate[i].count = 1;
     83	}
     84
     85	if (last_rate > 0)
     86		rate[last_rate - 1].count = st->retry + 1 - last_rate;
     87
     88	info->status.ampdu_len = 1;
     89	info->status.ampdu_ack_len = st->success;
     90
     91	if (st->is_probe)
     92		info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
     93
     94	if (st->aggr)
     95		info->flags |= IEEE80211_TX_CTL_AMPDU |
     96			       IEEE80211_TX_STAT_AMPDU;
     97
     98	if (!st->ack_req)
     99		info->flags |= IEEE80211_TX_CTL_NO_ACK;
    100	else if (st->success)
    101		info->flags |= IEEE80211_TX_STAT_ACK;
    102}
    103
    104u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
    105			 const struct ieee80211_tx_rate *rate, u8 *nss_val)
    106{
    107	u16 rateval;
    108	u8 phy, rate_idx;
    109	u8 nss = 1;
    110	u8 bw = 0;
    111
    112	if (rate->flags & IEEE80211_TX_RC_MCS) {
    113		rate_idx = rate->idx;
    114		nss = 1 + (rate->idx >> 3);
    115		phy = MT_PHY_TYPE_HT;
    116		if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
    117			phy = MT_PHY_TYPE_HT_GF;
    118		if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
    119			bw = 1;
    120	} else {
    121		const struct ieee80211_rate *r;
    122		int band = dev->chandef.chan->band;
    123		u16 val;
    124
    125		r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx];
    126		if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
    127			val = r->hw_value_short;
    128		else
    129			val = r->hw_value;
    130
    131		phy = val >> 8;
    132		rate_idx = val & 0xff;
    133		bw = 0;
    134	}
    135
    136	rateval = FIELD_PREP(MT_RXWI_RATE_MCS, rate_idx);
    137	rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
    138	rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
    139	if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
    140		rateval |= MT_RXWI_RATE_SGI;
    141
    142	*nss_val = nss;
    143	return rateval;
    144}
    145
    146void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
    147			    const struct ieee80211_tx_rate *rate)
    148{
    149	unsigned long flags;
    150
    151	spin_lock_irqsave(&dev->lock, flags);
    152	wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
    153	wcid->tx_rate_set = true;
    154	spin_unlock_irqrestore(&dev->lock, flags);
    155}
    156
    157struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev)
    158{
    159	struct mt76_tx_status stat = {};
    160	u32 val;
    161
    162	val = mt7601u_rr(dev, MT_TX_STAT_FIFO);
    163	stat.valid = !!(val & MT_TX_STAT_FIFO_VALID);
    164	stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS);
    165	stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR);
    166	stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ);
    167	stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_PID_TYPE, val);
    168	stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, val);
    169	stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, val);
    170
    171	return stat;
    172}
    173
    174void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
    175{
    176	struct ieee80211_tx_info info = {};
    177	struct ieee80211_sta *sta = NULL;
    178	struct mt76_wcid *wcid = NULL;
    179	void *msta;
    180
    181	rcu_read_lock();
    182	if (stat->wcid < ARRAY_SIZE(dev->wcid))
    183		wcid = rcu_dereference(dev->wcid[stat->wcid]);
    184
    185	if (wcid) {
    186		msta = container_of(wcid, struct mt76_sta, wcid);
    187		sta = container_of(msta, struct ieee80211_sta,
    188				   drv_priv);
    189	}
    190
    191	mt76_mac_fill_tx_status(dev, &info, stat);
    192
    193	spin_lock_bh(&dev->mac_lock);
    194	ieee80211_tx_status_noskb(dev->hw, sta, &info);
    195	spin_unlock_bh(&dev->mac_lock);
    196
    197	rcu_read_unlock();
    198}
    199
    200void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
    201				int ht_mode)
    202{
    203	int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
    204	bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
    205	u32 prot[6];
    206	bool ht_rts[4] = {};
    207	int i;
    208
    209	prot[0] = MT_PROT_NAV_SHORT |
    210		  MT_PROT_TXOP_ALLOW_ALL |
    211		  MT_PROT_RTS_THR_EN;
    212	prot[1] = prot[0];
    213	if (legacy_prot)
    214		prot[1] |= MT_PROT_CTRL_CTS2SELF;
    215
    216	prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20;
    217	prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL;
    218
    219	if (legacy_prot) {
    220		prot[2] |= MT_PROT_RATE_CCK_11;
    221		prot[3] |= MT_PROT_RATE_CCK_11;
    222		prot[4] |= MT_PROT_RATE_CCK_11;
    223		prot[5] |= MT_PROT_RATE_CCK_11;
    224	} else {
    225		prot[2] |= MT_PROT_RATE_OFDM_24;
    226		prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
    227		prot[4] |= MT_PROT_RATE_OFDM_24;
    228		prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
    229	}
    230
    231	switch (mode) {
    232	case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
    233		break;
    234
    235	case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
    236		ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
    237		break;
    238
    239	case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
    240		ht_rts[1] = ht_rts[3] = true;
    241		break;
    242
    243	case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
    244		ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
    245		break;
    246	}
    247
    248	if (non_gf)
    249		ht_rts[2] = ht_rts[3] = true;
    250
    251	for (i = 0; i < 4; i++)
    252		if (ht_rts[i])
    253			prot[i + 2] |= MT_PROT_CTRL_RTS_CTS;
    254
    255	for (i = 0; i < 6; i++)
    256		mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
    257}
    258
    259void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb)
    260{
    261	if (short_preamb)
    262		mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
    263	else
    264		mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
    265}
    266
    267void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval)
    268{
    269	u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG);
    270
    271	val &= ~(MT_BEACON_TIME_CFG_TIMER_EN |
    272		 MT_BEACON_TIME_CFG_SYNC_MODE |
    273		 MT_BEACON_TIME_CFG_TBTT_EN);
    274
    275	if (!enable) {
    276		mt7601u_wr(dev, MT_BEACON_TIME_CFG, val);
    277		return;
    278	}
    279
    280	val &= ~MT_BEACON_TIME_CFG_INTVAL;
    281	val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) |
    282		MT_BEACON_TIME_CFG_TIMER_EN |
    283		MT_BEACON_TIME_CFG_SYNC_MODE |
    284		MT_BEACON_TIME_CFG_TBTT_EN;
    285}
    286
    287static void mt7601u_check_mac_err(struct mt7601u_dev *dev)
    288{
    289	u32 val = mt7601u_rr(dev, 0x10f4);
    290
    291	if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
    292		return;
    293
    294	dev_err(dev->dev, "Error: MAC specific condition occurred\n");
    295
    296	mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
    297	udelay(10);
    298	mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
    299}
    300
    301void mt7601u_mac_work(struct work_struct *work)
    302{
    303	struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
    304					       mac_work.work);
    305	struct {
    306		u32 addr_base;
    307		u32 span;
    308		u64 *stat_base;
    309	} spans[] = {
    310		{ MT_RX_STA_CNT0,	3,	dev->stats.rx_stat },
    311		{ MT_TX_STA_CNT0,	3,	dev->stats.tx_stat },
    312		{ MT_TX_AGG_STAT,	1,	dev->stats.aggr_stat },
    313		{ MT_MPDU_DENSITY_CNT,	1,	dev->stats.zero_len_del },
    314		{ MT_TX_AGG_CNT_BASE0,	8,	&dev->stats.aggr_n[0] },
    315		{ MT_TX_AGG_CNT_BASE1,	8,	&dev->stats.aggr_n[16] },
    316	};
    317	u32 sum, n;
    318	int i, j, k;
    319
    320	/* Note: using MCU_RANDOM_READ is actually slower then reading all the
    321	 *	 registers by hand.  MCU takes ca. 20ms to complete read of 24
    322	 *	 registers while reading them one by one will takes roughly
    323	 *	 24*200us =~ 5ms.
    324	 */
    325
    326	k = 0;
    327	n = 0;
    328	sum = 0;
    329	for (i = 0; i < ARRAY_SIZE(spans); i++)
    330		for (j = 0; j < spans[i].span; j++) {
    331			u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4);
    332
    333			spans[i].stat_base[j * 2] += val & 0xffff;
    334			spans[i].stat_base[j * 2 + 1] += val >> 16;
    335
    336			/* Calculate average AMPDU length */
    337			if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 &&
    338			    spans[i].addr_base != MT_TX_AGG_CNT_BASE1)
    339				continue;
    340
    341			n += (val >> 16) + (val & 0xffff);
    342			sum += (val & 0xffff) * (1 + k * 2) +
    343				(val >> 16) * (2 + k * 2);
    344			k++;
    345		}
    346
    347	atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1);
    348
    349	mt7601u_check_mac_err(dev);
    350
    351	ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ);
    352}
    353
    354void
    355mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
    356{
    357	u8 zmac[ETH_ALEN] = {};
    358	u32 attr;
    359
    360	attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
    361	       FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
    362
    363	mt76_wr(dev, MT_WCID_ATTR(idx), attr);
    364
    365	if (mac)
    366		memcpy(zmac, mac, sizeof(zmac));
    367
    368	mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac);
    369}
    370
    371void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev)
    372{
    373	struct ieee80211_sta *sta;
    374	struct mt76_wcid *wcid;
    375	void *msta;
    376	u8 min_factor = 3;
    377	int i;
    378
    379	rcu_read_lock();
    380	for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
    381		wcid = rcu_dereference(dev->wcid[i]);
    382		if (!wcid)
    383			continue;
    384
    385		msta = container_of(wcid, struct mt76_sta, wcid);
    386		sta = container_of(msta, struct ieee80211_sta, drv_priv);
    387
    388		min_factor = min(min_factor, sta->deflink.ht_cap.ampdu_factor);
    389	}
    390	rcu_read_unlock();
    391
    392	mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff |
    393		   FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor));
    394}
    395
    396static void
    397mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
    398{
    399	u8 idx = FIELD_GET(MT_RXWI_RATE_MCS, rate);
    400
    401	switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
    402	case MT_PHY_TYPE_OFDM:
    403		if (WARN_ON(idx >= 8))
    404			idx = 0;
    405		idx += 4;
    406
    407		status->rate_idx = idx;
    408		return;
    409	case MT_PHY_TYPE_CCK:
    410		if (idx >= 8) {
    411			idx -= 8;
    412			status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
    413		}
    414
    415		if (WARN_ON(idx >= 4))
    416			idx = 0;
    417
    418		status->rate_idx = idx;
    419		return;
    420	case MT_PHY_TYPE_HT_GF:
    421		status->enc_flags |= RX_ENC_FLAG_HT_GF;
    422		fallthrough;
    423	case MT_PHY_TYPE_HT:
    424		status->encoding = RX_ENC_HT;
    425		status->rate_idx = idx;
    426		break;
    427	default:
    428		WARN_ON(1);
    429		return;
    430	}
    431
    432	if (rate & MT_RXWI_RATE_SGI)
    433		status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
    434
    435	if (rate & MT_RXWI_RATE_STBC)
    436		status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
    437
    438	if (rate & MT_RXWI_RATE_BW)
    439		status->bw = RATE_INFO_BW_40;
    440}
    441
    442static void
    443mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
    444			  u16 rate, int rssi)
    445{
    446	dev->bcn_freq_off = rxwi->freq_off;
    447	dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate);
    448	ewma_rssi_add(&dev->avg_rssi, -rssi);
    449}
    450
    451static int
    452mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data)
    453{
    454	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
    455
    456	return ieee80211_is_beacon(hdr->frame_control) &&
    457		ether_addr_equal(hdr->addr2, dev->ap_bssid);
    458}
    459
    460u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
    461			u8 *data, void *rxi)
    462{
    463	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
    464	struct mt7601u_rxwi *rxwi = rxi;
    465	u32 len, ctl = le32_to_cpu(rxwi->ctl);
    466	u16 rate = le16_to_cpu(rxwi->rate);
    467	int rssi;
    468
    469	len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
    470	if (len < 10)
    471		return 0;
    472
    473	if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
    474		status->flag |= RX_FLAG_DECRYPTED;
    475		status->flag |= RX_FLAG_MMIC_STRIPPED;
    476		status->flag |= RX_FLAG_MIC_STRIPPED;
    477		status->flag |= RX_FLAG_ICV_STRIPPED;
    478		status->flag |= RX_FLAG_IV_STRIPPED;
    479	}
    480	/* let mac80211 take care of PN validation since apparently
    481	 * the hardware does not support it
    482	 */
    483	if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN))
    484		status->flag &= ~RX_FLAG_IV_STRIPPED;
    485
    486	status->chains = BIT(0);
    487	rssi = mt7601u_phy_get_rssi(dev, rxwi, rate);
    488	status->chain_signal[0] = status->signal = rssi;
    489	status->freq = dev->chandef.chan->center_freq;
    490	status->band = dev->chandef.chan->band;
    491
    492	mt76_mac_process_rate(status, rate);
    493
    494	spin_lock_bh(&dev->con_mon_lock);
    495	if (mt7601u_rx_is_our_beacon(dev, data))
    496		mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi);
    497	else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M))
    498		ewma_rssi_add(&dev->avg_rssi, -rssi);
    499	spin_unlock_bh(&dev->con_mon_lock);
    500
    501	return len;
    502}
    503
    504static enum mt76_cipher_type
    505mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
    506{
    507	memset(key_data, 0, 32);
    508	if (!key)
    509		return MT_CIPHER_NONE;
    510
    511	if (key->keylen > 32)
    512		return MT_CIPHER_NONE;
    513
    514	memcpy(key_data, key->key, key->keylen);
    515
    516	switch (key->cipher) {
    517	case WLAN_CIPHER_SUITE_WEP40:
    518		return MT_CIPHER_WEP40;
    519	case WLAN_CIPHER_SUITE_WEP104:
    520		return MT_CIPHER_WEP104;
    521	case WLAN_CIPHER_SUITE_TKIP:
    522		return MT_CIPHER_TKIP;
    523	case WLAN_CIPHER_SUITE_CCMP:
    524		return MT_CIPHER_AES_CCMP;
    525	default:
    526		return MT_CIPHER_NONE;
    527	}
    528}
    529
    530int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
    531			  struct ieee80211_key_conf *key)
    532{
    533	enum mt76_cipher_type cipher;
    534	u8 key_data[32];
    535	u8 iv_data[8];
    536	u32 val;
    537
    538	cipher = mt76_mac_get_key_info(key, key_data);
    539	if (cipher == MT_CIPHER_NONE && key)
    540		return -EINVAL;
    541
    542	trace_set_key(dev, idx);
    543
    544	mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
    545
    546	memset(iv_data, 0, sizeof(iv_data));
    547	if (key) {
    548		iv_data[3] = key->keyidx << 6;
    549		if (cipher >= MT_CIPHER_TKIP) {
    550			/* Note: start with 1 to comply with spec,
    551			 *	 (see comment on common/cmm_wpa.c:4291).
    552			 */
    553			iv_data[0] |= 1;
    554			iv_data[3] |= 0x20;
    555		}
    556	}
    557	mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
    558
    559	val = mt7601u_rr(dev, MT_WCID_ATTR(idx));
    560	val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT;
    561	val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) |
    562	       FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3);
    563	val &= ~MT_WCID_ATTR_PAIRWISE;
    564	val |= MT_WCID_ATTR_PAIRWISE *
    565		!!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
    566	mt7601u_wr(dev, MT_WCID_ATTR(idx), val);
    567
    568	return 0;
    569}
    570
    571int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
    572			      struct ieee80211_key_conf *key)
    573{
    574	enum mt76_cipher_type cipher;
    575	u8 key_data[32];
    576	u32 val;
    577
    578	cipher = mt76_mac_get_key_info(key, key_data);
    579	if (cipher == MT_CIPHER_NONE && key)
    580		return -EINVAL;
    581
    582	trace_set_shared_key(dev, vif_idx, key_idx);
    583
    584	mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx),
    585			key_data, sizeof(key_data));
    586
    587	val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
    588	val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
    589	val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
    590	mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
    591
    592	return 0;
    593}