linux/drivers/net/wireless/mediatek/mt7601u/mac.c
<<
>>
Prefs
   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->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}
 594