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