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