linux/drivers/net/wireless/mediatek/mt7601u/main.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 "mac.h"
   9#include <linux/etherdevice.h>
  10
  11static int mt7601u_start(struct ieee80211_hw *hw)
  12{
  13        struct mt7601u_dev *dev = hw->priv;
  14        int ret;
  15
  16        mutex_lock(&dev->mutex);
  17
  18        ret = mt7601u_mac_start(dev);
  19        if (ret)
  20                goto out;
  21
  22        ieee80211_queue_delayed_work(dev->hw, &dev->mac_work,
  23                                     MT_CALIBRATE_INTERVAL);
  24        ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
  25                                     MT_CALIBRATE_INTERVAL);
  26out:
  27        mutex_unlock(&dev->mutex);
  28        return ret;
  29}
  30
  31static void mt7601u_stop(struct ieee80211_hw *hw)
  32{
  33        struct mt7601u_dev *dev = hw->priv;
  34
  35        mutex_lock(&dev->mutex);
  36
  37        cancel_delayed_work_sync(&dev->cal_work);
  38        cancel_delayed_work_sync(&dev->mac_work);
  39        mt7601u_mac_stop(dev);
  40
  41        mutex_unlock(&dev->mutex);
  42}
  43
  44static int mt7601u_add_interface(struct ieee80211_hw *hw,
  45                                 struct ieee80211_vif *vif)
  46{
  47        struct mt7601u_dev *dev = hw->priv;
  48        struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
  49        unsigned int idx = 0;
  50        unsigned int wcid = GROUP_WCID(idx);
  51
  52        /* Note: for AP do the AP-STA things mt76 does:
  53         *      - beacon offsets
  54         *      - do mac address tricks
  55         *      - shift vif idx
  56         */
  57        mvif->idx = idx;
  58
  59        if (!ether_addr_equal(dev->macaddr, vif->addr))
  60                mt7601u_set_macaddr(dev, vif->addr);
  61
  62        if (dev->wcid_mask[wcid / BITS_PER_LONG] & BIT(wcid % BITS_PER_LONG))
  63                return -ENOSPC;
  64        dev->wcid_mask[wcid / BITS_PER_LONG] |= BIT(wcid % BITS_PER_LONG);
  65        mvif->group_wcid.idx = wcid;
  66        mvif->group_wcid.hw_key_idx = -1;
  67
  68        return 0;
  69}
  70
  71static void mt7601u_remove_interface(struct ieee80211_hw *hw,
  72                                     struct ieee80211_vif *vif)
  73{
  74        struct mt7601u_dev *dev = hw->priv;
  75        struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
  76        unsigned int wcid = mvif->group_wcid.idx;
  77
  78        dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG);
  79}
  80
  81static int mt7601u_config(struct ieee80211_hw *hw, u32 changed)
  82{
  83        struct mt7601u_dev *dev = hw->priv;
  84        int ret = 0;
  85
  86        mutex_lock(&dev->mutex);
  87
  88        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
  89                ieee80211_stop_queues(hw);
  90                ret = mt7601u_phy_set_channel(dev, &hw->conf.chandef);
  91                ieee80211_wake_queues(hw);
  92        }
  93
  94        mutex_unlock(&dev->mutex);
  95
  96        return ret;
  97}
  98
  99static void
 100mt76_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
 101                      unsigned int *total_flags, u64 multicast)
 102{
 103        struct mt7601u_dev *dev = hw->priv;
 104        u32 flags = 0;
 105
 106#define MT76_FILTER(_flag, _hw) do { \
 107                flags |= *total_flags & FIF_##_flag;                    \
 108                dev->rxfilter &= ~(_hw);                                \
 109                dev->rxfilter |= !(flags & FIF_##_flag) * (_hw);        \
 110        } while (0)
 111
 112        mutex_lock(&dev->mutex);
 113
 114        dev->rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS;
 115
 116        MT76_FILTER(OTHER_BSS, MT_RX_FILTR_CFG_PROMISC);
 117        MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR);
 118        MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR);
 119        MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK |
 120                             MT_RX_FILTR_CFG_CTS |
 121                             MT_RX_FILTR_CFG_CFEND |
 122                             MT_RX_FILTR_CFG_CFACK |
 123                             MT_RX_FILTR_CFG_BA |
 124                             MT_RX_FILTR_CFG_CTRL_RSV);
 125        MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL);
 126
 127        *total_flags = flags;
 128        mt76_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter);
 129
 130        mutex_unlock(&dev->mutex);
 131}
 132
 133static void
 134mt7601u_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 135                         struct ieee80211_bss_conf *info, u32 changed)
 136{
 137        struct mt7601u_dev *dev = hw->priv;
 138
 139        mutex_lock(&dev->mutex);
 140
 141        if (changed & BSS_CHANGED_ASSOC)
 142                mt7601u_phy_con_cal_onoff(dev, info);
 143
 144        if (changed & BSS_CHANGED_BSSID) {
 145                mt7601u_addr_wr(dev, MT_MAC_BSSID_DW0, info->bssid);
 146
 147                /* Note: this is a hack because beacon_int is not changed
 148                 *       on leave nor is any more appropriate event generated.
 149                 *       rt2x00 doesn't seem to be bothered though.
 150                 */
 151                if (is_zero_ether_addr(info->bssid))
 152                        mt7601u_mac_config_tsf(dev, false, 0);
 153        }
 154
 155        if (changed & BSS_CHANGED_BASIC_RATES) {
 156                mt7601u_wr(dev, MT_LEGACY_BASIC_RATE, info->basic_rates);
 157                mt7601u_wr(dev, MT_HT_FBK_CFG0, 0x65432100);
 158                mt7601u_wr(dev, MT_HT_FBK_CFG1, 0xedcba980);
 159                mt7601u_wr(dev, MT_LG_FBK_CFG0, 0xedcba988);
 160                mt7601u_wr(dev, MT_LG_FBK_CFG1, 0x00002100);
 161        }
 162
 163        if (changed & BSS_CHANGED_BEACON_INT)
 164                mt7601u_mac_config_tsf(dev, true, info->beacon_int);
 165
 166        if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
 167                mt7601u_mac_set_protection(dev, info->use_cts_prot,
 168                                           info->ht_operation_mode);
 169
 170        if (changed & BSS_CHANGED_ERP_PREAMBLE)
 171                mt7601u_mac_set_short_preamble(dev, info->use_short_preamble);
 172
 173        if (changed & BSS_CHANGED_ERP_SLOT) {
 174                int slottime = info->use_short_slot ? 9 : 20;
 175
 176                mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG,
 177                               MT_BKOFF_SLOT_CFG_SLOTTIME, slottime);
 178        }
 179
 180        if (changed & BSS_CHANGED_ASSOC)
 181                mt7601u_phy_recalibrate_after_assoc(dev);
 182
 183        mutex_unlock(&dev->mutex);
 184}
 185
 186static int
 187mt76_wcid_alloc(struct mt7601u_dev *dev)
 188{
 189        int i, idx = 0;
 190
 191        for (i = 0; i < ARRAY_SIZE(dev->wcid_mask); i++) {
 192                idx = ffs(~dev->wcid_mask[i]);
 193                if (!idx)
 194                        continue;
 195
 196                idx--;
 197                dev->wcid_mask[i] |= BIT(idx);
 198                break;
 199        }
 200
 201        idx = i * BITS_PER_LONG + idx;
 202        if (idx > 119)
 203                return -1;
 204
 205        return idx;
 206}
 207
 208static int
 209mt7601u_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 210                struct ieee80211_sta *sta)
 211{
 212        struct mt7601u_dev *dev = hw->priv;
 213        struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
 214        struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
 215        int ret = 0;
 216        int idx = 0;
 217
 218        mutex_lock(&dev->mutex);
 219
 220        idx = mt76_wcid_alloc(dev);
 221        if (idx < 0) {
 222                ret = -ENOSPC;
 223                goto out;
 224        }
 225
 226        msta->wcid.idx = idx;
 227        msta->wcid.hw_key_idx = -1;
 228        mt7601u_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
 229        mt76_clear(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
 230        rcu_assign_pointer(dev->wcid[idx], &msta->wcid);
 231        mt7601u_mac_set_ampdu_factor(dev);
 232
 233out:
 234        mutex_unlock(&dev->mutex);
 235
 236        return ret;
 237}
 238
 239static int
 240mt7601u_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 241                   struct ieee80211_sta *sta)
 242{
 243        struct mt7601u_dev *dev = hw->priv;
 244        struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
 245        int idx = msta->wcid.idx;
 246
 247        mutex_lock(&dev->mutex);
 248        rcu_assign_pointer(dev->wcid[idx], NULL);
 249        mt76_set(dev, MT_WCID_DROP(idx), MT_WCID_DROP_MASK(idx));
 250        dev->wcid_mask[idx / BITS_PER_LONG] &= ~BIT(idx % BITS_PER_LONG);
 251        mt7601u_mac_wcid_setup(dev, idx, 0, NULL);
 252        mt7601u_mac_set_ampdu_factor(dev);
 253        mutex_unlock(&dev->mutex);
 254
 255        return 0;
 256}
 257
 258static void
 259mt7601u_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 260                   enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
 261{
 262}
 263
 264static void
 265mt7601u_sw_scan(struct ieee80211_hw *hw,
 266                struct ieee80211_vif *vif,
 267                const u8 *mac_addr)
 268{
 269        struct mt7601u_dev *dev = hw->priv;
 270
 271        mt7601u_agc_save(dev);
 272        set_bit(MT7601U_STATE_SCANNING, &dev->state);
 273}
 274
 275static void
 276mt7601u_sw_scan_complete(struct ieee80211_hw *hw,
 277                         struct ieee80211_vif *vif)
 278{
 279        struct mt7601u_dev *dev = hw->priv;
 280
 281        mt7601u_agc_restore(dev);
 282        clear_bit(MT7601U_STATE_SCANNING, &dev->state);
 283
 284        ieee80211_queue_delayed_work(dev->hw, &dev->cal_work,
 285                                     MT_CALIBRATE_INTERVAL);
 286        if (dev->freq_cal.enabled)
 287                ieee80211_queue_delayed_work(dev->hw, &dev->freq_cal.work,
 288                                             MT_FREQ_CAL_INIT_DELAY);
 289}
 290
 291static int
 292mt7601u_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 293                struct ieee80211_vif *vif, struct ieee80211_sta *sta,
 294                struct ieee80211_key_conf *key)
 295{
 296        struct mt7601u_dev *dev = hw->priv;
 297        struct mt76_vif *mvif = (struct mt76_vif *) vif->drv_priv;
 298        struct mt76_sta *msta = sta ? (struct mt76_sta *) sta->drv_priv : NULL;
 299        struct mt76_wcid *wcid = msta ? &msta->wcid : &mvif->group_wcid;
 300        int idx = key->keyidx;
 301        int ret;
 302
 303        /* fall back to sw encryption for unsupported ciphers */
 304        switch (key->cipher) {
 305        case WLAN_CIPHER_SUITE_WEP40:
 306        case WLAN_CIPHER_SUITE_WEP104:
 307        case WLAN_CIPHER_SUITE_TKIP:
 308        case WLAN_CIPHER_SUITE_CCMP:
 309                break;
 310        default:
 311                return -EOPNOTSUPP;
 312        }
 313
 314        if (cmd == SET_KEY) {
 315                key->hw_key_idx = wcid->idx;
 316                wcid->hw_key_idx = idx;
 317        } else {
 318                if (idx == wcid->hw_key_idx)
 319                        wcid->hw_key_idx = -1;
 320
 321                key = NULL;
 322        }
 323
 324        if (!msta) {
 325                if (key || wcid->hw_key_idx == idx) {
 326                        ret = mt76_mac_wcid_set_key(dev, wcid->idx, key);
 327                        if (ret)
 328                                return ret;
 329                }
 330
 331                return mt76_mac_shared_key_setup(dev, mvif->idx, idx, key);
 332        }
 333
 334        return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key);
 335}
 336
 337static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 338{
 339        struct mt7601u_dev *dev = hw->priv;
 340
 341        mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, value);
 342
 343        return 0;
 344}
 345
 346static int
 347mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 348                  struct ieee80211_ampdu_params *params)
 349{
 350        struct mt7601u_dev *dev = hw->priv;
 351        struct ieee80211_sta *sta = params->sta;
 352        enum ieee80211_ampdu_mlme_action action = params->action;
 353        u16 tid = params->tid;
 354        u16 ssn = params->ssn;
 355        struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
 356
 357        WARN_ON(msta->wcid.idx > GROUP_WCID(0));
 358
 359        switch (action) {
 360        case IEEE80211_AMPDU_RX_START:
 361                mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid));
 362                break;
 363        case IEEE80211_AMPDU_RX_STOP:
 364                mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4,
 365                           BIT(16 + tid));
 366                break;
 367        case IEEE80211_AMPDU_TX_OPERATIONAL:
 368                ieee80211_send_bar(vif, sta->addr, tid, msta->agg_ssn[tid]);
 369                break;
 370        case IEEE80211_AMPDU_TX_STOP_FLUSH:
 371        case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
 372                break;
 373        case IEEE80211_AMPDU_TX_START:
 374                msta->agg_ssn[tid] = ssn << 4;
 375                return IEEE80211_AMPDU_TX_START_IMMEDIATE;
 376        case IEEE80211_AMPDU_TX_STOP_CONT:
 377                ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
 378                break;
 379        }
 380
 381        return 0;
 382}
 383
 384static void
 385mt76_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 386                         struct ieee80211_sta *sta)
 387{
 388        struct mt7601u_dev *dev = hw->priv;
 389        struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
 390        struct ieee80211_sta_rates *rates;
 391        struct ieee80211_tx_rate rate = {};
 392
 393        rcu_read_lock();
 394        rates = rcu_dereference(sta->rates);
 395
 396        if (!rates)
 397                goto out;
 398
 399        rate.idx = rates->rate[0].idx;
 400        rate.flags = rates->rate[0].flags;
 401        mt76_mac_wcid_set_rate(dev, &msta->wcid, &rate);
 402
 403out:
 404        rcu_read_unlock();
 405}
 406
 407const struct ieee80211_ops mt7601u_ops = {
 408        .tx = mt7601u_tx,
 409        .start = mt7601u_start,
 410        .stop = mt7601u_stop,
 411        .add_interface = mt7601u_add_interface,
 412        .remove_interface = mt7601u_remove_interface,
 413        .config = mt7601u_config,
 414        .configure_filter = mt76_configure_filter,
 415        .bss_info_changed = mt7601u_bss_info_changed,
 416        .sta_add = mt7601u_sta_add,
 417        .sta_remove = mt7601u_sta_remove,
 418        .sta_notify = mt7601u_sta_notify,
 419        .set_key = mt7601u_set_key,
 420        .conf_tx = mt7601u_conf_tx,
 421        .sw_scan_start = mt7601u_sw_scan,
 422        .sw_scan_complete = mt7601u_sw_scan_complete,
 423        .ampdu_action = mt76_ampdu_action,
 424        .sta_rate_tbl_update = mt76_sta_rate_tbl_update,
 425        .set_rts_threshold = mt7601u_set_rts_threshold,
 426};
 427