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