ath10k: clean up assoc code
[cascardo/linux.git] / drivers / net / wireless / ath / ath10k / mac.c
index 4e30e57..39c4029 100644 (file)
@@ -26,6 +26,7 @@
 #include "wmi.h"
 #include "htt.h"
 #include "txrx.h"
+#include "testmode.h"
 
 /**********/
 /* Crypto */
@@ -198,7 +199,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
                list_for_each_entry(peer, &ar->peers, list) {
                        for (i = 0; i < ARRAY_SIZE(peer->keys); i++) {
                                if (peer->keys[i] == key) {
-                                       memcpy(addr, peer->addr, ETH_ALEN);
+                                       ether_addr_copy(addr, peer->addr);
                                        peer->keys[i] = NULL;
                                        break;
                                }
@@ -224,7 +225,6 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
        return first_errno;
 }
 
-
 /*********************/
 /* General utilities */
 /*********************/
@@ -479,6 +479,40 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 /* Interface management */
 /************************/
 
+void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->data_lock);
+
+       if (!arvif->beacon)
+               return;
+
+       if (!arvif->beacon_buf)
+               dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
+                                arvif->beacon->len, DMA_TO_DEVICE);
+
+       dev_kfree_skb_any(arvif->beacon);
+
+       arvif->beacon = NULL;
+       arvif->beacon_sent = false;
+}
+
+static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->data_lock);
+
+       ath10k_mac_vif_beacon_free(arvif);
+
+       if (arvif->beacon_buf) {
+               dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+                                 arvif->beacon_buf, arvif->beacon_paddr);
+               arvif->beacon_buf = NULL;
+       }
+}
+
 static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
 {
        int ret;
@@ -493,19 +527,6 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
        return 0;
 }
 
-static bool ath10k_monitor_is_enabled(struct ath10k *ar)
-{
-       lockdep_assert_held(&ar->conf_mutex);
-
-       ath10k_dbg(ar, ATH10K_DBG_MAC,
-                  "mac monitor refs: promisc %d monitor %d cac %d\n",
-                  ar->promisc, ar->monitor,
-                  test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
-
-       return ar->promisc || ar->monitor ||
-              test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
-}
-
 static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 {
        struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -603,9 +624,9 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
                return -ENOMEM;
        }
 
-       bit = ffs(ar->free_vdev_map);
+       bit = __ffs64(ar->free_vdev_map);
 
-       ar->monitor_vdev_id = bit - 1;
+       ar->monitor_vdev_id = bit;
 
        ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
                                     WMI_VDEV_TYPE_MONITOR,
@@ -616,7 +637,7 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
                return ret;
        }
 
-       ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+       ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
                   ar->monitor_vdev_id);
 
@@ -636,7 +657,7 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar)
                return ret;
        }
 
-       ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
+       ar->free_vdev_map |= 1LL << ar->monitor_vdev_id;
 
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
                   ar->monitor_vdev_id);
@@ -649,16 +670,6 @@ static int ath10k_monitor_start(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (!ath10k_monitor_is_enabled(ar)) {
-               ath10k_warn(ar, "trying to start monitor with no references\n");
-               return 0;
-       }
-
-       if (ar->monitor_started) {
-               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n");
-               return 0;
-       }
-
        ret = ath10k_monitor_vdev_create(ar);
        if (ret) {
                ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
@@ -678,34 +689,51 @@ static int ath10k_monitor_start(struct ath10k *ar)
        return 0;
 }
 
-static void ath10k_monitor_stop(struct ath10k *ar)
+static int ath10k_monitor_stop(struct ath10k *ar)
 {
        int ret;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (ath10k_monitor_is_enabled(ar)) {
-               ath10k_dbg(ar, ATH10K_DBG_MAC,
-                          "mac monitor will be stopped later\n");
-               return;
-       }
-
-       if (!ar->monitor_started) {
-               ath10k_dbg(ar, ATH10K_DBG_MAC,
-                          "mac monitor probably failed to start earlier\n");
-               return;
-       }
-
        ret = ath10k_monitor_vdev_stop(ar);
-       if (ret)
+       if (ret) {
                ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
+               return ret;
+       }
 
        ret = ath10k_monitor_vdev_delete(ar);
-       if (ret)
+       if (ret) {
                ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
+               return ret;
+       }
 
        ar->monitor_started = false;
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
+
+       return 0;
+}
+
+static int ath10k_monitor_recalc(struct ath10k *ar)
+{
+       bool should_start;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       should_start = ar->monitor ||
+                      ar->filter_flags & FIF_PROMISC_IN_BSS ||
+                      test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
+                  "mac monitor recalc started? %d should? %d\n",
+                  ar->monitor_started, should_start);
+
+       if (should_start == ar->monitor_started)
+               return 0;
+
+       if (should_start)
+               return ath10k_monitor_start(ar);
+
+       return ath10k_monitor_stop(ar);
 }
 
 static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -736,7 +764,7 @@ static int ath10k_start_cac(struct ath10k *ar)
 
        set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
 
-       ret = ath10k_monitor_start(ar);
+       ret = ath10k_monitor_recalc(ar);
        if (ret) {
                ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
                clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
@@ -901,7 +929,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 }
 
 static void ath10k_control_beaconing(struct ath10k_vif *arvif,
-                               struct ieee80211_bss_conf *info)
+                                    struct ieee80211_bss_conf *info)
 {
        struct ath10k *ar = arvif->ar;
        int ret = 0;
@@ -915,15 +943,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                arvif->is_up = false;
 
                spin_lock_bh(&arvif->ar->data_lock);
-               if (arvif->beacon) {
-                       dma_unmap_single(arvif->ar->dev,
-                                        ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                        arvif->beacon->len, DMA_TO_DEVICE);
-                       dev_kfree_skb_any(arvif->beacon);
-
-                       arvif->beacon = NULL;
-                       arvif->beacon_sent = false;
-               }
+               ath10k_mac_vif_beacon_free(arvif);
                spin_unlock_bh(&arvif->ar->data_lock);
 
                return;
@@ -936,7 +956,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                return;
 
        arvif->aid = 0;
-       memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+       ether_addr_copy(arvif->bssid, info->bssid);
 
        ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
                                 arvif->bssid);
@@ -972,14 +992,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
                if (is_zero_ether_addr(arvif->bssid))
                        return;
 
-               ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
-                                        arvif->bssid);
-               if (ret) {
-                       ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
-                                   arvif->bssid, arvif->vdev_id, ret);
-                       return;
-               }
-
                memset(arvif->bssid, 0, ETH_ALEN);
 
                return;
@@ -1048,51 +1060,45 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
 /* Station management */
 /**********************/
 
+static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar,
+                                            struct ieee80211_vif *vif)
+{
+       /* Some firmware revisions have unstable STA powersave when listen
+        * interval is set too high (e.g. 5). The symptoms are firmware doesn't
+        * generate NullFunc frames properly even if buffered frames have been
+        * indicated in Beacon TIM. Firmware would seldom wake up to pull
+        * buffered frames. Often pinging the device from AP would simply fail.
+        *
+        * As a workaround set it to 1.
+        */
+       if (vif->type == NL80211_IFTYPE_STATION)
+               return 1;
+
+       return ar->hw->conf.listen_interval;
+}
+
 static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
-                                     struct ath10k_vif *arvif,
+                                     struct ieee80211_vif *vif,
                                      struct ieee80211_sta *sta,
-                                     struct ieee80211_bss_conf *bss_conf,
                                      struct wmi_peer_assoc_complete_arg *arg)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
        lockdep_assert_held(&ar->conf_mutex);
 
-       memcpy(arg->addr, sta->addr, ETH_ALEN);
+       ether_addr_copy(arg->addr, sta->addr);
        arg->vdev_id = arvif->vdev_id;
        arg->peer_aid = sta->aid;
        arg->peer_flags |= WMI_PEER_AUTH;
-
-       if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
-               /*
-                * Seems FW have problems with Power Save in STA
-                * mode when we setup this parameter to high (eg. 5).
-                * Often we see that FW don't send NULL (with clean P flags)
-                * frame even there is info about buffered frames in beacons.
-                * Sometimes we have to wait more than 10 seconds before FW
-                * will wakeup. Often sending one ping from AP to our device
-                * just fail (more than 50%).
-                *
-                * Seems setting this FW parameter to 1 couse FW
-                * will check every beacon and will wakup immediately
-                * after detection buffered data.
-                */
-               arg->peer_listen_intval = 1;
-       else
-               arg->peer_listen_intval = ar->hw->conf.listen_interval;
-
+       arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
        arg->peer_num_spatial_streams = 1;
-
-       /*
-        * The assoc capabilities are available only in managed mode.
-        */
-       if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf)
-               arg->peer_caps = bss_conf->assoc_capability;
+       arg->peer_caps = vif->bss_conf.assoc_capability;
 }
 
 static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
-                                      struct ath10k_vif *arvif,
+                                      struct ieee80211_vif *vif,
                                       struct wmi_peer_assoc_complete_arg *arg)
 {
-       struct ieee80211_vif *vif = arvif->vif;
        struct ieee80211_bss_conf *info = &vif->bss_conf;
        struct cfg80211_bss *bss;
        const u8 *rsnie = NULL;
@@ -1111,9 +1117,9 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
                ies = rcu_dereference(bss->ies);
 
                wpaie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
-                               WLAN_OUI_TYPE_MICROSOFT_WPA,
-                               ies->data,
-                               ies->len);
+                                               WLAN_OUI_TYPE_MICROSOFT_WPA,
+                                               ies->data,
+                                               ies->len);
                rcu_read_unlock();
                cfg80211_put_bss(ar->hw->wiphy, bss);
        }
@@ -1163,6 +1169,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
 {
        const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
        int i, n;
+       u32 stbc;
 
        lockdep_assert_held(&ar->conf_mutex);
 
@@ -1199,7 +1206,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
        }
 
        if (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) {
-               u32 stbc;
                stbc = ht_cap->cap & IEEE80211_HT_CAP_RX_STBC;
                stbc = stbc >> IEEE80211_HT_CAP_RX_STBC_SHIFT;
                stbc = stbc << WMI_RC_RX_STBC_FLAG_S;
@@ -1267,7 +1273,6 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
                        uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN |
                                 WMI_AP_PS_UAPSD_AC0_TRIGGER_EN;
 
-
                if (sta->max_sp < MAX_WMI_AP_PS_PEER_PARAM_MAX_SP)
                        max_sp = sta->max_sp;
 
@@ -1296,7 +1301,8 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
                   sta->listen_interval - mac80211 patch required.
                   Currently use 10 seconds */
                ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
-                                       WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
+                                                WMI_AP_PS_PEER_PARAM_AGEOUT_TIME,
+                                                10);
                if (ret) {
                        ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
                                    arvif->vdev_id, ret);
@@ -1320,7 +1326,6 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
        arg->peer_flags |= WMI_PEER_VHT;
        arg->peer_vht_caps = vht_cap->cap;
 
-
        ampdu_factor = (vht_cap->cap &
                        IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK) >>
                       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
@@ -1350,11 +1355,12 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
 }
 
 static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
-                                   struct ath10k_vif *arvif,
+                                   struct ieee80211_vif *vif,
                                    struct ieee80211_sta *sta,
-                                   struct ieee80211_bss_conf *bss_conf,
                                    struct wmi_peer_assoc_complete_arg *arg)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
        switch (arvif->vdev_type) {
        case WMI_VDEV_TYPE_AP:
                if (sta->wme)
@@ -1366,7 +1372,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
                }
                break;
        case WMI_VDEV_TYPE_STA:
-               if (bss_conf->qos)
+               if (vif->bss_conf.qos)
                        arg->peer_flags |= WMI_PEER_QOS;
                break;
        default:
@@ -1375,7 +1381,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
 }
 
 static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
-                                       struct ath10k_vif *arvif,
+                                       struct ieee80211_vif *vif,
                                        struct ieee80211_sta *sta,
                                        struct wmi_peer_assoc_complete_arg *arg)
 {
@@ -1426,22 +1432,21 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
 }
 
 static int ath10k_peer_assoc_prepare(struct ath10k *ar,
-                                    struct ath10k_vif *arvif,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_sta *sta,
-                                    struct ieee80211_bss_conf *bss_conf,
                                     struct wmi_peer_assoc_complete_arg *arg)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
        memset(arg, 0, sizeof(*arg));
 
-       ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
-       ath10k_peer_assoc_h_crypto(ar, arvif, arg);
+       ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
+       ath10k_peer_assoc_h_crypto(ar, vif, arg);
        ath10k_peer_assoc_h_rates(ar, sta, arg);
        ath10k_peer_assoc_h_ht(ar, sta, arg);
        ath10k_peer_assoc_h_vht(ar, sta, arg);
-       ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
-       ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
+       ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
+       ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
 
        return 0;
 }
@@ -1501,8 +1506,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
         * before calling ath10k_setup_peer_smps() which might sleep. */
        ht_cap = ap_sta->ht_cap;
 
-       ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
-                                       bss_conf, &peer_arg);
+       ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
        if (ret) {
                ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
                            bss_conf->bssid, arvif->vdev_id, ret);
@@ -1531,7 +1535,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 
        arvif->aid = bss_conf->aid;
-       memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
+       ether_addr_copy(arvif->bssid, bss_conf->bssid);
 
        ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
        if (ret) {
@@ -1585,15 +1589,18 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
        arvif->is_up = false;
 }
 
-static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
-                               struct ieee80211_sta *sta, bool reassoc)
+static int ath10k_station_assoc(struct ath10k *ar,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_sta *sta,
+                               bool reassoc)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        struct wmi_peer_assoc_complete_arg peer_arg;
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
+       ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg);
        if (ret) {
                ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
                            sta->addr, arvif->vdev_id, ret);
@@ -1642,9 +1649,11 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
        return ret;
 }
 
-static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
+static int ath10k_station_disassoc(struct ath10k *ar,
+                                  struct ieee80211_vif *vif,
                                   struct ieee80211_sta *sta)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -1736,6 +1745,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                        ch->passive = passive;
 
                        ch->freq = channel->center_freq;
+                       ch->band_center_freq1 = channel->center_freq;
                        ch->min_power = 0;
                        ch->max_power = channel->max_power * 2;
                        ch->max_reg_power = channel->max_reg_power * 2;
@@ -1863,11 +1873,10 @@ static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
        return ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
 }
 
-static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
-                                 struct ieee80211_tx_info *info)
+static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar, struct ieee80211_vif *vif)
 {
-       if (info->control.vif)
-               return ath10k_vif_to_arvif(info->control.vif)->vdev_id;
+       if (vif)
+               return ath10k_vif_to_arvif(vif)->vdev_id;
 
        if (ar->monitor_started)
                return ar->monitor_vdev_id;
@@ -2323,7 +2332,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 
        ATH10K_SKB_CB(skb)->htt.is_offchan = false;
        ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
-       ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, info);
+       ATH10K_SKB_CB(skb)->vdev_id = ath10k_tx_h_get_vdev_id(ar, vif);
 
        /* it makes no sense to process injected frames like that */
        if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
@@ -2369,12 +2378,14 @@ void ath10k_halt(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       if (ath10k_monitor_is_enabled(ar)) {
-               clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
-               ar->promisc = false;
-               ar->monitor = false;
+       clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
+       ar->filter_flags = 0;
+       ar->monitor = false;
+
+       if (ar->monitor_started)
                ath10k_monitor_stop(ar);
-       }
+
+       ar->monitor_started = false;
 
        ath10k_scan_finish(ar);
        ath10k_peer_cleanup_all(ar);
@@ -2382,16 +2393,8 @@ void ath10k_halt(struct ath10k *ar)
        ath10k_hif_power_down(ar);
 
        spin_lock_bh(&ar->data_lock);
-       list_for_each_entry(arvif, &ar->arvifs, list) {
-               if (!arvif->beacon)
-                       continue;
-
-               dma_unmap_single(arvif->ar->dev,
-                                ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                arvif->beacon->len, DMA_TO_DEVICE);
-               dev_kfree_skb_any(arvif->beacon);
-               arvif->beacon = NULL;
-       }
+       list_for_each_entry(arvif, &ar->arvifs, list)
+               ath10k_mac_vif_beacon_cleanup(arvif);
        spin_unlock_bh(&ar->data_lock);
 }
 
@@ -2485,6 +2488,9 @@ static int ath10k_start(struct ieee80211_hw *hw)
                WARN_ON(1);
                ret = -EINVAL;
                goto err;
+       case ATH10K_STATE_UTF:
+               ret = -EBUSY;
+               goto err;
        }
 
        ret = ath10k_hif_power_up(ar);
@@ -2493,7 +2499,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
                goto err_off;
        }
 
-       ret = ath10k_core_start(ar);
+       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
        if (ret) {
                ath10k_err(ar, "Could not init core: %d\n", ret);
                goto err_power_down;
@@ -2629,7 +2635,7 @@ static void ath10k_config_chan(struct ath10k *ar)
        /* First stop monitor interface. Some FW versions crash if there's a
         * lone monitor interface. */
        if (ar->monitor_started)
-               ath10k_monitor_vdev_stop(ar);
+               ath10k_monitor_stop(ar);
 
        list_for_each_entry(arvif, &ar->arvifs, list) {
                if (!arvif->is_started)
@@ -2677,8 +2683,7 @@ static void ath10k_config_chan(struct ath10k *ar)
                }
        }
 
-       if (ath10k_monitor_is_enabled(ar))
-               ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
+       ath10k_monitor_recalc(ar);
 }
 
 static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2733,19 +2738,10 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                ath10k_config_ps(ar);
 
        if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
-               if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) {
-                       ar->monitor = true;
-                       ret = ath10k_monitor_start(ar);
-                       if (ret) {
-                               ath10k_warn(ar, "failed to start monitor (config): %d\n",
-                                           ret);
-                               ar->monitor = false;
-                       }
-               } else if (!(conf->flags & IEEE80211_CONF_MONITOR) &&
-                          ar->monitor) {
-                       ar->monitor = false;
-                       ath10k_monitor_stop(ar);
-               }
+               ar->monitor = conf->flags & IEEE80211_CONF_MONITOR;
+               ret = ath10k_monitor_recalc(ar);
+               if (ret)
+                       ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
        }
 
        mutex_unlock(&ar->conf_mutex);
@@ -2785,9 +2781,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = -EBUSY;
                goto err;
        }
-       bit = ffs(ar->free_vdev_map);
+       bit = __ffs64(ar->free_vdev_map);
+
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n",
+                  bit, ar->free_vdev_map);
 
-       arvif->vdev_id = bit - 1;
+       arvif->vdev_id = bit;
        arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
 
        if (ar->p2p)
@@ -2817,8 +2816,39 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                break;
        }
 
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
-                  arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
+       /* Some firmware revisions don't wait for beacon tx completion before
+        * sending another SWBA event. This could lead to hardware using old
+        * (freed) beacon data in some cases, e.g. tx credit starvation
+        * combined with missed TBTT. This is very very rare.
+        *
+        * On non-IOMMU-enabled hosts this could be a possible security issue
+        * because hw could beacon some random data on the air.  On
+        * IOMMU-enabled hosts DMAR faults would occur in most cases and target
+        * device would crash.
+        *
+        * Since there are no beacon tx completions (implicit nor explicit)
+        * propagated to host the only workaround for this is to allocate a
+        * DMA-coherent buffer for a lifetime of a vif and use it for all
+        * beacon tx commands. Worst case for this approach is some beacons may
+        * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC ||
+           vif->type == NL80211_IFTYPE_AP) {
+               arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
+                                                       IEEE80211_MAX_FRAME_LEN,
+                                                       &arvif->beacon_paddr,
+                                                       GFP_ATOMIC);
+               if (!arvif->beacon_buf) {
+                       ret = -ENOMEM;
+                       ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
+                                   ret);
+                       goto err;
+               }
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",
+                  arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
+                  arvif->beacon_buf ? "single-buf" : "per-skb");
 
        ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
                                     arvif->vdev_subtype, vif->addr);
@@ -2828,7 +2858,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                goto err;
        }
 
-       ar->free_vdev_map &= ~(1 << arvif->vdev_id);
+       ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
        list_add(&arvif->list, &ar->arvifs);
 
        vdev_param = ar->wmi.vdev_param->def_keyid;
@@ -2921,10 +2951,16 @@ err_peer_delete:
 
 err_vdev_delete:
        ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
-       ar->free_vdev_map |= 1 << arvif->vdev_id;
+       ar->free_vdev_map |= 1LL << arvif->vdev_id;
        list_del(&arvif->list);
 
 err:
+       if (arvif->beacon_buf) {
+               dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+                                 arvif->beacon_buf, arvif->beacon_paddr);
+               arvif->beacon_buf = NULL;
+       }
+
        mutex_unlock(&ar->conf_mutex);
 
        return ret;
@@ -2942,14 +2978,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
        cancel_work_sync(&arvif->wep_key_work);
 
        spin_lock_bh(&ar->data_lock);
-       if (arvif->beacon) {
-               dma_unmap_single(arvif->ar->dev,
-                                ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                arvif->beacon->len, DMA_TO_DEVICE);
-               dev_kfree_skb_any(arvif->beacon);
-               arvif->beacon = NULL;
-       }
-
+       ath10k_mac_vif_beacon_cleanup(arvif);
        spin_unlock_bh(&ar->data_lock);
 
        ret = ath10k_spectral_vif_stop(arvif);
@@ -2957,7 +2986,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
                ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
                            arvif->vdev_id, ret);
 
-       ar->free_vdev_map |= 1 << arvif->vdev_id;
+       ar->free_vdev_map |= 1LL << arvif->vdev_id;
        list_del(&arvif->list);
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
@@ -3009,18 +3038,9 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
        *total_flags &= SUPPORTED_FILTERS;
        ar->filter_flags = *total_flags;
 
-       if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) {
-               ar->promisc = true;
-               ret = ath10k_monitor_start(ar);
-               if (ret) {
-                       ath10k_warn(ar, "failed to start monitor (promisc): %d\n",
-                                   ret);
-                       ar->promisc = false;
-               }
-       } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) {
-               ar->promisc = false;
-               ath10k_monitor_stop(ar);
-       }
+       ret = ath10k_monitor_recalc(ar);
+       if (ret)
+               ath10k_warn(ar, "failed to recalc montior: %d\n", ret);
 
        mutex_unlock(&ar->conf_mutex);
 }
@@ -3033,7 +3053,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        int ret = 0;
-       u32 vdev_param, pdev_param;
+       u32 vdev_param, pdev_param, slottime, preamble;
 
        mutex_lock(&ar->conf_mutex);
 
@@ -3097,22 +3117,22 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_BSSID &&
            vif->type != NL80211_IFTYPE_AP) {
                if (!is_zero_ether_addr(info->bssid)) {
-                       ath10k_dbg(ar, ATH10K_DBG_MAC,
-                                  "mac vdev %d create peer %pM\n",
-                                  arvif->vdev_id, info->bssid);
-
-                       ret = ath10k_peer_create(ar, arvif->vdev_id,
-                                                info->bssid);
-                       if (ret)
-                               ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
-                                           info->bssid, arvif->vdev_id, ret);
-
                        if (vif->type == NL80211_IFTYPE_STATION) {
+                               ath10k_dbg(ar, ATH10K_DBG_MAC,
+                                          "mac vdev %d create peer %pM\n",
+                                          arvif->vdev_id, info->bssid);
+
+                               ret = ath10k_peer_create(ar, arvif->vdev_id,
+                                                        info->bssid);
+                               if (ret)
+                                       ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
+                                                   info->bssid, arvif->vdev_id,
+                                                   ret);
                                /*
                                 * this is never erased as we it for crypto key
                                 * clearing; this is FW requirement
                                 */
-                               memcpy(arvif->bssid, info->bssid, ETH_ALEN);
+                               ether_addr_copy(arvif->bssid, info->bssid);
 
                                ath10k_dbg(ar, ATH10K_DBG_MAC,
                                           "mac vdev %d start %pM\n",
@@ -3154,7 +3174,6 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_ERP_SLOT) {
-               u32 slottime;
                if (info->use_short_slot)
                        slottime = WMI_VDEV_SLOT_TIME_SHORT; /* 9us */
 
@@ -3173,7 +3192,6 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
-               u32 preamble;
                if (info->use_short_preamble)
                        preamble = WMI_VDEV_PREAMBLE_SHORT;
                else
@@ -3192,8 +3210,16 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_ASSOC) {
-               if (info->assoc)
+               if (info->assoc) {
+                       /* Workaround: Make sure monitor vdev is not running
+                        * when associating to prevent some firmware revisions
+                        * (e.g. 10.1 and 10.2) from crashing.
+                        */
+                       if (ar->monitor_started)
+                               ath10k_monitor_stop(ar);
                        ath10k_bss_assoc(hw, vif, info);
+                       ath10k_monitor_recalc(ar);
+               }
        }
 
 exit:
@@ -3469,7 +3495,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
                ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
                           sta->addr);
 
-               err = ath10k_station_assoc(ar, arvif, sta, true);
+               err = ath10k_station_assoc(ar, arvif->vif, sta, true);
                if (err)
                        ath10k_warn(ar, "failed to reassociate station: %pM\n",
                                    sta->addr);
@@ -3555,7 +3581,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
                           sta->addr);
 
-               ret = ath10k_station_assoc(ar, arvif, sta, false);
+               ret = ath10k_station_assoc(ar, vif, sta, false);
                if (ret)
                        ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
@@ -3569,7 +3595,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
                           sta->addr);
 
-               ret = ath10k_station_disassoc(ar, arvif, sta);
+               ret = ath10k_station_disassoc(ar, vif, sta);
                if (ret)
                        ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
@@ -3580,7 +3606,7 @@ exit:
 }
 
 static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
-                                u16 ac, bool enable)
+                               u16 ac, bool enable)
 {
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        u32 value = 0;
@@ -4081,8 +4107,8 @@ ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
                        continue;
                else if (mask->control[band].ht_mcs[i] == 0x00)
                        break;
-               else
-                       return false;
+
+               return false;
        }
 
        ht_nss = i;
@@ -4093,8 +4119,8 @@ ath10k_bitrate_mask_nss(const struct cfg80211_bitrate_mask *mask,
                        continue;
                else if (mask->control[band].vht_mcs[i] == 0x0000)
                        break;
-               else
-                       return false;
+
+               return false;
        }
 
        vht_nss = i;
@@ -4472,6 +4498,12 @@ static const struct ieee80211_ops ath10k_ops = {
        .sta_rc_update                  = ath10k_sta_rc_update,
        .get_tsf                        = ath10k_get_tsf,
        .ampdu_action                   = ath10k_ampdu_action,
+       .get_et_sset_count              = ath10k_debug_get_et_sset_count,
+       .get_et_stats                   = ath10k_debug_get_et_stats,
+       .get_et_strings                 = ath10k_debug_get_et_strings,
+
+       CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
+
 #ifdef CONFIG_PM
        .suspend                        = ath10k_suspend,
        .resume                         = ath10k_resume,
@@ -4723,7 +4755,6 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
        return ht_cap;
 }
 
-
 static void ath10k_get_arvif_iter(void *data, u8 *mac,
                                  struct ieee80211_vif *vif)
 {
@@ -4814,15 +4845,6 @@ int ath10k_mac_register(struct ath10k *ar)
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_AP);
 
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-               /* TODO:  Have to deal with 2x2 chips if/when the come out. */
-               ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK;
-               ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK;
-       } else {
-               ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK;
-               ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK;
-       }
-
        ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
        ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;