0001
0002
0003
0004
0005
0006
0007 #include "mt7601u.h"
0008 #include "trace.h"
0009 #include <linux/etherdevice.h>
0010
0011 void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr)
0012 {
0013 ether_addr_copy(dev->macaddr, addr);
0014
0015 if (!is_valid_ether_addr(dev->macaddr)) {
0016 eth_random_addr(dev->macaddr);
0017 dev_info(dev->dev,
0018 "Invalid MAC address, using random address %pM\n",
0019 dev->macaddr);
0020 }
0021
0022 mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->macaddr));
0023 mt76_wr(dev, MT_MAC_ADDR_DW1, get_unaligned_le16(dev->macaddr + 4) |
0024 FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
0025 }
0026
0027 static void
0028 mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate)
0029 {
0030 u8 idx = FIELD_GET(MT_TXWI_RATE_MCS, rate);
0031
0032 txrate->idx = 0;
0033 txrate->flags = 0;
0034 txrate->count = 1;
0035
0036 switch (FIELD_GET(MT_TXWI_RATE_PHY_MODE, rate)) {
0037 case MT_PHY_TYPE_OFDM:
0038 txrate->idx = idx + 4;
0039 return;
0040 case MT_PHY_TYPE_CCK:
0041 if (idx >= 8)
0042 idx -= 8;
0043
0044 txrate->idx = idx;
0045 return;
0046 case MT_PHY_TYPE_HT_GF:
0047 txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
0048 fallthrough;
0049 case MT_PHY_TYPE_HT:
0050 txrate->flags |= IEEE80211_TX_RC_MCS;
0051 txrate->idx = idx;
0052 break;
0053 default:
0054 WARN_ON(1);
0055 return;
0056 }
0057
0058 if (FIELD_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40)
0059 txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
0060
0061 if (rate & MT_TXWI_RATE_SGI)
0062 txrate->flags |= IEEE80211_TX_RC_SHORT_GI;
0063 }
0064
0065 static void
0066 mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info,
0067 struct mt76_tx_status *st)
0068 {
0069 struct ieee80211_tx_rate *rate = info->status.rates;
0070 int cur_idx, last_rate;
0071 int i;
0072
0073 last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1);
0074 mt76_mac_process_tx_rate(&rate[last_rate], st->rate);
0075 if (last_rate < IEEE80211_TX_MAX_RATES - 1)
0076 rate[last_rate + 1].idx = -1;
0077
0078 cur_idx = rate[last_rate].idx + st->retry;
0079 for (i = 0; i <= last_rate; i++) {
0080 rate[i].flags = rate[last_rate].flags;
0081 rate[i].idx = max_t(int, 0, cur_idx - i);
0082 rate[i].count = 1;
0083 }
0084
0085 if (last_rate > 0)
0086 rate[last_rate - 1].count = st->retry + 1 - last_rate;
0087
0088 info->status.ampdu_len = 1;
0089 info->status.ampdu_ack_len = st->success;
0090
0091 if (st->is_probe)
0092 info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
0093
0094 if (st->aggr)
0095 info->flags |= IEEE80211_TX_CTL_AMPDU |
0096 IEEE80211_TX_STAT_AMPDU;
0097
0098 if (!st->ack_req)
0099 info->flags |= IEEE80211_TX_CTL_NO_ACK;
0100 else if (st->success)
0101 info->flags |= IEEE80211_TX_STAT_ACK;
0102 }
0103
0104 u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev,
0105 const struct ieee80211_tx_rate *rate, u8 *nss_val)
0106 {
0107 u16 rateval;
0108 u8 phy, rate_idx;
0109 u8 nss = 1;
0110 u8 bw = 0;
0111
0112 if (rate->flags & IEEE80211_TX_RC_MCS) {
0113 rate_idx = rate->idx;
0114 nss = 1 + (rate->idx >> 3);
0115 phy = MT_PHY_TYPE_HT;
0116 if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD)
0117 phy = MT_PHY_TYPE_HT_GF;
0118 if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
0119 bw = 1;
0120 } else {
0121 const struct ieee80211_rate *r;
0122 int band = dev->chandef.chan->band;
0123 u16 val;
0124
0125 r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx];
0126 if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
0127 val = r->hw_value_short;
0128 else
0129 val = r->hw_value;
0130
0131 phy = val >> 8;
0132 rate_idx = val & 0xff;
0133 bw = 0;
0134 }
0135
0136 rateval = FIELD_PREP(MT_RXWI_RATE_MCS, rate_idx);
0137 rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy);
0138 rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw);
0139 if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
0140 rateval |= MT_RXWI_RATE_SGI;
0141
0142 *nss_val = nss;
0143 return rateval;
0144 }
0145
0146 void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid,
0147 const struct ieee80211_tx_rate *rate)
0148 {
0149 unsigned long flags;
0150
0151 spin_lock_irqsave(&dev->lock, flags);
0152 wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss);
0153 wcid->tx_rate_set = true;
0154 spin_unlock_irqrestore(&dev->lock, flags);
0155 }
0156
0157 struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev)
0158 {
0159 struct mt76_tx_status stat = {};
0160 u32 val;
0161
0162 val = mt7601u_rr(dev, MT_TX_STAT_FIFO);
0163 stat.valid = !!(val & MT_TX_STAT_FIFO_VALID);
0164 stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS);
0165 stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR);
0166 stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ);
0167 stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_PID_TYPE, val);
0168 stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, val);
0169 stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, val);
0170
0171 return stat;
0172 }
0173
0174 void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat)
0175 {
0176 struct ieee80211_tx_info info = {};
0177 struct ieee80211_sta *sta = NULL;
0178 struct mt76_wcid *wcid = NULL;
0179 void *msta;
0180
0181 rcu_read_lock();
0182 if (stat->wcid < ARRAY_SIZE(dev->wcid))
0183 wcid = rcu_dereference(dev->wcid[stat->wcid]);
0184
0185 if (wcid) {
0186 msta = container_of(wcid, struct mt76_sta, wcid);
0187 sta = container_of(msta, struct ieee80211_sta,
0188 drv_priv);
0189 }
0190
0191 mt76_mac_fill_tx_status(dev, &info, stat);
0192
0193 spin_lock_bh(&dev->mac_lock);
0194 ieee80211_tx_status_noskb(dev->hw, sta, &info);
0195 spin_unlock_bh(&dev->mac_lock);
0196
0197 rcu_read_unlock();
0198 }
0199
0200 void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot,
0201 int ht_mode)
0202 {
0203 int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION;
0204 bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
0205 u32 prot[6];
0206 bool ht_rts[4] = {};
0207 int i;
0208
0209 prot[0] = MT_PROT_NAV_SHORT |
0210 MT_PROT_TXOP_ALLOW_ALL |
0211 MT_PROT_RTS_THR_EN;
0212 prot[1] = prot[0];
0213 if (legacy_prot)
0214 prot[1] |= MT_PROT_CTRL_CTS2SELF;
0215
0216 prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20;
0217 prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL;
0218
0219 if (legacy_prot) {
0220 prot[2] |= MT_PROT_RATE_CCK_11;
0221 prot[3] |= MT_PROT_RATE_CCK_11;
0222 prot[4] |= MT_PROT_RATE_CCK_11;
0223 prot[5] |= MT_PROT_RATE_CCK_11;
0224 } else {
0225 prot[2] |= MT_PROT_RATE_OFDM_24;
0226 prot[3] |= MT_PROT_RATE_DUP_OFDM_24;
0227 prot[4] |= MT_PROT_RATE_OFDM_24;
0228 prot[5] |= MT_PROT_RATE_DUP_OFDM_24;
0229 }
0230
0231 switch (mode) {
0232 case IEEE80211_HT_OP_MODE_PROTECTION_NONE:
0233 break;
0234
0235 case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
0236 ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
0237 break;
0238
0239 case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
0240 ht_rts[1] = ht_rts[3] = true;
0241 break;
0242
0243 case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
0244 ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true;
0245 break;
0246 }
0247
0248 if (non_gf)
0249 ht_rts[2] = ht_rts[3] = true;
0250
0251 for (i = 0; i < 4; i++)
0252 if (ht_rts[i])
0253 prot[i + 2] |= MT_PROT_CTRL_RTS_CTS;
0254
0255 for (i = 0; i < 6; i++)
0256 mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]);
0257 }
0258
0259 void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb)
0260 {
0261 if (short_preamb)
0262 mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
0263 else
0264 mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT);
0265 }
0266
0267 void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval)
0268 {
0269 u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG);
0270
0271 val &= ~(MT_BEACON_TIME_CFG_TIMER_EN |
0272 MT_BEACON_TIME_CFG_SYNC_MODE |
0273 MT_BEACON_TIME_CFG_TBTT_EN);
0274
0275 if (!enable) {
0276 mt7601u_wr(dev, MT_BEACON_TIME_CFG, val);
0277 return;
0278 }
0279
0280 val &= ~MT_BEACON_TIME_CFG_INTVAL;
0281 val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) |
0282 MT_BEACON_TIME_CFG_TIMER_EN |
0283 MT_BEACON_TIME_CFG_SYNC_MODE |
0284 MT_BEACON_TIME_CFG_TBTT_EN;
0285 }
0286
0287 static void mt7601u_check_mac_err(struct mt7601u_dev *dev)
0288 {
0289 u32 val = mt7601u_rr(dev, 0x10f4);
0290
0291 if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
0292 return;
0293
0294 dev_err(dev->dev, "Error: MAC specific condition occurred\n");
0295
0296 mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
0297 udelay(10);
0298 mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
0299 }
0300
0301 void mt7601u_mac_work(struct work_struct *work)
0302 {
0303 struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev,
0304 mac_work.work);
0305 struct {
0306 u32 addr_base;
0307 u32 span;
0308 u64 *stat_base;
0309 } spans[] = {
0310 { MT_RX_STA_CNT0, 3, dev->stats.rx_stat },
0311 { MT_TX_STA_CNT0, 3, dev->stats.tx_stat },
0312 { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat },
0313 { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del },
0314 { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] },
0315 { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] },
0316 };
0317 u32 sum, n;
0318 int i, j, k;
0319
0320
0321
0322
0323
0324
0325
0326 k = 0;
0327 n = 0;
0328 sum = 0;
0329 for (i = 0; i < ARRAY_SIZE(spans); i++)
0330 for (j = 0; j < spans[i].span; j++) {
0331 u32 val = mt7601u_rr(dev, spans[i].addr_base + j * 4);
0332
0333 spans[i].stat_base[j * 2] += val & 0xffff;
0334 spans[i].stat_base[j * 2 + 1] += val >> 16;
0335
0336
0337 if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 &&
0338 spans[i].addr_base != MT_TX_AGG_CNT_BASE1)
0339 continue;
0340
0341 n += (val >> 16) + (val & 0xffff);
0342 sum += (val & 0xffff) * (1 + k * 2) +
0343 (val >> 16) * (2 + k * 2);
0344 k++;
0345 }
0346
0347 atomic_set(&dev->avg_ampdu_len, n ? DIV_ROUND_CLOSEST(sum, n) : 1);
0348
0349 mt7601u_check_mac_err(dev);
0350
0351 ieee80211_queue_delayed_work(dev->hw, &dev->mac_work, 10 * HZ);
0352 }
0353
0354 void
0355 mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac)
0356 {
0357 u8 zmac[ETH_ALEN] = {};
0358 u32 attr;
0359
0360 attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) |
0361 FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8));
0362
0363 mt76_wr(dev, MT_WCID_ATTR(idx), attr);
0364
0365 if (mac)
0366 memcpy(zmac, mac, sizeof(zmac));
0367
0368 mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), zmac);
0369 }
0370
0371 void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev)
0372 {
0373 struct ieee80211_sta *sta;
0374 struct mt76_wcid *wcid;
0375 void *msta;
0376 u8 min_factor = 3;
0377 int i;
0378
0379 rcu_read_lock();
0380 for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
0381 wcid = rcu_dereference(dev->wcid[i]);
0382 if (!wcid)
0383 continue;
0384
0385 msta = container_of(wcid, struct mt76_sta, wcid);
0386 sta = container_of(msta, struct ieee80211_sta, drv_priv);
0387
0388 min_factor = min(min_factor, sta->deflink.ht_cap.ampdu_factor);
0389 }
0390 rcu_read_unlock();
0391
0392 mt7601u_wr(dev, MT_MAX_LEN_CFG, 0xa0fff |
0393 FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor));
0394 }
0395
0396 static void
0397 mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate)
0398 {
0399 u8 idx = FIELD_GET(MT_RXWI_RATE_MCS, rate);
0400
0401 switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) {
0402 case MT_PHY_TYPE_OFDM:
0403 if (WARN_ON(idx >= 8))
0404 idx = 0;
0405 idx += 4;
0406
0407 status->rate_idx = idx;
0408 return;
0409 case MT_PHY_TYPE_CCK:
0410 if (idx >= 8) {
0411 idx -= 8;
0412 status->enc_flags |= RX_ENC_FLAG_SHORTPRE;
0413 }
0414
0415 if (WARN_ON(idx >= 4))
0416 idx = 0;
0417
0418 status->rate_idx = idx;
0419 return;
0420 case MT_PHY_TYPE_HT_GF:
0421 status->enc_flags |= RX_ENC_FLAG_HT_GF;
0422 fallthrough;
0423 case MT_PHY_TYPE_HT:
0424 status->encoding = RX_ENC_HT;
0425 status->rate_idx = idx;
0426 break;
0427 default:
0428 WARN_ON(1);
0429 return;
0430 }
0431
0432 if (rate & MT_RXWI_RATE_SGI)
0433 status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
0434
0435 if (rate & MT_RXWI_RATE_STBC)
0436 status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT;
0437
0438 if (rate & MT_RXWI_RATE_BW)
0439 status->bw = RATE_INFO_BW_40;
0440 }
0441
0442 static void
0443 mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi,
0444 u16 rate, int rssi)
0445 {
0446 dev->bcn_freq_off = rxwi->freq_off;
0447 dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate);
0448 ewma_rssi_add(&dev->avg_rssi, -rssi);
0449 }
0450
0451 static int
0452 mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data)
0453 {
0454 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data;
0455
0456 return ieee80211_is_beacon(hdr->frame_control) &&
0457 ether_addr_equal(hdr->addr2, dev->ap_bssid);
0458 }
0459
0460 u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb,
0461 u8 *data, void *rxi)
0462 {
0463 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
0464 struct mt7601u_rxwi *rxwi = rxi;
0465 u32 len, ctl = le32_to_cpu(rxwi->ctl);
0466 u16 rate = le16_to_cpu(rxwi->rate);
0467 int rssi;
0468
0469 len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
0470 if (len < 10)
0471 return 0;
0472
0473 if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) {
0474 status->flag |= RX_FLAG_DECRYPTED;
0475 status->flag |= RX_FLAG_MMIC_STRIPPED;
0476 status->flag |= RX_FLAG_MIC_STRIPPED;
0477 status->flag |= RX_FLAG_ICV_STRIPPED;
0478 status->flag |= RX_FLAG_IV_STRIPPED;
0479 }
0480
0481
0482
0483 if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN))
0484 status->flag &= ~RX_FLAG_IV_STRIPPED;
0485
0486 status->chains = BIT(0);
0487 rssi = mt7601u_phy_get_rssi(dev, rxwi, rate);
0488 status->chain_signal[0] = status->signal = rssi;
0489 status->freq = dev->chandef.chan->center_freq;
0490 status->band = dev->chandef.chan->band;
0491
0492 mt76_mac_process_rate(status, rate);
0493
0494 spin_lock_bh(&dev->con_mon_lock);
0495 if (mt7601u_rx_is_our_beacon(dev, data))
0496 mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi);
0497 else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M))
0498 ewma_rssi_add(&dev->avg_rssi, -rssi);
0499 spin_unlock_bh(&dev->con_mon_lock);
0500
0501 return len;
0502 }
0503
0504 static enum mt76_cipher_type
0505 mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
0506 {
0507 memset(key_data, 0, 32);
0508 if (!key)
0509 return MT_CIPHER_NONE;
0510
0511 if (key->keylen > 32)
0512 return MT_CIPHER_NONE;
0513
0514 memcpy(key_data, key->key, key->keylen);
0515
0516 switch (key->cipher) {
0517 case WLAN_CIPHER_SUITE_WEP40:
0518 return MT_CIPHER_WEP40;
0519 case WLAN_CIPHER_SUITE_WEP104:
0520 return MT_CIPHER_WEP104;
0521 case WLAN_CIPHER_SUITE_TKIP:
0522 return MT_CIPHER_TKIP;
0523 case WLAN_CIPHER_SUITE_CCMP:
0524 return MT_CIPHER_AES_CCMP;
0525 default:
0526 return MT_CIPHER_NONE;
0527 }
0528 }
0529
0530 int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx,
0531 struct ieee80211_key_conf *key)
0532 {
0533 enum mt76_cipher_type cipher;
0534 u8 key_data[32];
0535 u8 iv_data[8];
0536 u32 val;
0537
0538 cipher = mt76_mac_get_key_info(key, key_data);
0539 if (cipher == MT_CIPHER_NONE && key)
0540 return -EINVAL;
0541
0542 trace_set_key(dev, idx);
0543
0544 mt7601u_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data));
0545
0546 memset(iv_data, 0, sizeof(iv_data));
0547 if (key) {
0548 iv_data[3] = key->keyidx << 6;
0549 if (cipher >= MT_CIPHER_TKIP) {
0550
0551
0552
0553 iv_data[0] |= 1;
0554 iv_data[3] |= 0x20;
0555 }
0556 }
0557 mt7601u_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data));
0558
0559 val = mt7601u_rr(dev, MT_WCID_ATTR(idx));
0560 val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT;
0561 val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) |
0562 FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3);
0563 val &= ~MT_WCID_ATTR_PAIRWISE;
0564 val |= MT_WCID_ATTR_PAIRWISE *
0565 !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
0566 mt7601u_wr(dev, MT_WCID_ATTR(idx), val);
0567
0568 return 0;
0569 }
0570
0571 int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx,
0572 struct ieee80211_key_conf *key)
0573 {
0574 enum mt76_cipher_type cipher;
0575 u8 key_data[32];
0576 u32 val;
0577
0578 cipher = mt76_mac_get_key_info(key, key_data);
0579 if (cipher == MT_CIPHER_NONE && key)
0580 return -EINVAL;
0581
0582 trace_set_shared_key(dev, vif_idx, key_idx);
0583
0584 mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx),
0585 key_data, sizeof(key_data));
0586
0587 val = mt76_rr(dev, MT_SKEY_MODE(vif_idx));
0588 val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx));
0589 val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx);
0590 mt76_wr(dev, MT_SKEY_MODE(vif_idx), val);
0591
0592 return 0;
0593 }