]> Git Repo - linux.git/commitdiff
Merge tag 'for-linville-20141024' of git://github.com/kvalo/ath
authorJohn W. Linville <[email protected]>
Mon, 27 Oct 2014 18:09:36 +0000 (14:09 -0400)
committerJohn W. Linville <[email protected]>
Mon, 27 Oct 2014 18:09:36 +0000 (14:09 -0400)
Conflicts:
drivers/net/wireless/ath/wil6210/wil6210.h

1  2 
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/wil6210/wil6210.h

index 46709301a51e1986bb4b505b659d7f94bbfca6d9,caaa3690af691f964d66e20591e3a161e8269a05..f6d2fd0887d39ffc8dd0e70f343571f88dc10c90
@@@ -479,6 -479,40 +479,40 @@@ static void ath10k_peer_cleanup_all(str
  /* 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;
@@@ -590,9 -624,9 +624,9 @@@ static int ath10k_monitor_vdev_create(s
                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,
                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);
  
@@@ -623,7 -657,7 +657,7 @@@ static int ath10k_monitor_vdev_delete(s
                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);
@@@ -909,15 -943,7 +943,7 @@@ static void ath10k_control_beaconing(st
                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;
@@@ -966,14 -992,6 +992,6 @@@ static void ath10k_control_ibss(struct 
                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;
@@@ -1042,51 -1060,45 +1060,45 @@@ static int ath10k_mac_vif_setup_ps(stru
  /* 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);
  
        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;
@@@ -1343,11 -1355,12 +1355,12 @@@ static void ath10k_peer_assoc_h_vht(str
  }
  
  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)
                }
                break;
        case WMI_VDEV_TYPE_STA:
-               if (bss_conf->qos)
+               if (vif->bss_conf.qos)
                        arg->peer_flags |= WMI_PEER_QOS;
                break;
        default:
  }
  
  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)
  {
  }
  
  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;
  }
@@@ -1480,6 -1492,9 +1492,9 @@@ static void ath10k_bss_assoc(struct iee
  
        lockdep_assert_held(&ar->conf_mutex);
  
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
+                  arvif->vdev_id, arvif->bssid, arvif->aid);
        rcu_read_lock();
  
        ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
         * 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);
                   "mac vdev %d up (associated) bssid %pM aid %d\n",
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
  
+       WARN_ON(arvif->is_up);
        arvif->aid = bss_conf->aid;
        ether_addr_copy(arvif->bssid, bss_conf->bssid);
  
        arvif->is_up = true;
  }
  
- /*
-  * FIXME: flush TIDs
-  */
  static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif)
  {
  
        lockdep_assert_held(&ar->conf_mutex);
  
-       /*
-        * For some reason, calling VDEV-DOWN before VDEV-STOP
-        * makes the FW to send frames via HTT after disassociation.
-        * No idea why this happens, even though VDEV-DOWN is supposed
-        * to be analogous to link down, so just stop the VDEV.
-        */
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
-                  arvif->vdev_id);
-       /* FIXME: check return value */
-       ret = ath10k_vdev_stop(arvif);
-       /*
-        * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and
-        * report beacons from previously associated network through HTT.
-        * This in turn would spam mac80211 WARN_ON if we bring down all
-        * interfaces as it expects there is no rx when no interface is
-        * running.
-        */
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
+                  arvif->vdev_id, arvif->bssid);
  
-       /* FIXME: why don't we print error if wmi call fails? */
        ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+       if (ret)
+               ath10k_warn(ar, "faield to down vdev %i: %d\n",
+                           arvif->vdev_id, ret);
  
        arvif->def_wep_key_idx = 0;
-       arvif->is_started = false;
        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);
                return ret;
        }
  
-       ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
-       if (ret) {
-               ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
-                           arvif->vdev_id, ret);
-               return ret;
-       }
-       if (!sta->wme && !reassoc) {
-               arvif->num_legacy_stations++;
-               ret  = ath10k_recalc_rtscts_prot(arvif);
+       /* Re-assoc is run only to update supported rates for given station. It
+        * doesn't make much sense to reconfigure the peer completely.
+        */
+       if (!reassoc) {
+               ret = ath10k_setup_peer_smps(ar, arvif, sta->addr,
+                                            &sta->ht_cap);
                if (ret) {
-                       ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
-       }
  
-       ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
-       if (ret) {
-               ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
-                           arvif->vdev_id, ret);
-               return ret;
-       }
+               ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
+               if (ret) {
+                       ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
+                                   sta->addr, arvif->vdev_id, ret);
+                       return ret;
+               }
  
-       ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
-       if (ret) {
-               ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
-                           sta->addr, arvif->vdev_id, ret);
-               return ret;
+               if (!sta->wme) {
+                       arvif->num_legacy_stations++;
+                       ret  = ath10k_recalc_rtscts_prot(arvif);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+                                           arvif->vdev_id, ret);
+                               return ret;
+                       }
+               }
+               ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
+               if (ret) {
+                       ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
        }
  
        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);
@@@ -1729,6 -1735,7 +1735,7 @@@ static int ath10k_update_channel_list(s
                        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;
@@@ -2376,16 -2383,8 +2383,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);
  }
  
@@@ -2677,12 -2676,68 +2676,68 @@@ static void ath10k_config_chan(struct a
        ath10k_monitor_recalc(ar);
  }
  
+ static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
+ {
+       int ret;
+       u32 param;
+       lockdep_assert_held(&ar->conf_mutex);
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower);
+       param = ar->wmi.pdev_param->txpower_limit2g;
+       ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
+       if (ret) {
+               ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
+                           txpower, ret);
+               return ret;
+       }
+       param = ar->wmi.pdev_param->txpower_limit5g;
+       ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
+       if (ret) {
+               ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
+                           txpower, ret);
+               return ret;
+       }
+       return 0;
+ }
+ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
+ {
+       struct ath10k_vif *arvif;
+       int ret, txpower = -1;
+       lockdep_assert_held(&ar->conf_mutex);
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               WARN_ON(arvif->txpower < 0);
+               if (txpower == -1)
+                       txpower = arvif->txpower;
+               else
+                       txpower = min(txpower, arvif->txpower);
+       }
+       if (WARN_ON(txpower == -1))
+               return -EINVAL;
+       ret = ath10k_mac_txpower_setup(ar, txpower);
+       if (ret) {
+               ath10k_warn(ar, "failed to setup tx power %d: %d\n",
+                           txpower, ret);
+               return ret;
+       }
+       return 0;
+ }
  static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
  {
        struct ath10k *ar = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
        int ret = 0;
-       u32 param;
  
        mutex_lock(&ar->conf_mutex);
  
                }
        }
  
-       if (changed & IEEE80211_CONF_CHANGE_POWER) {
-               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
-                          hw->conf.power_level);
-               param = ar->wmi.pdev_param->txpower_limit2g;
-               ret = ath10k_wmi_pdev_set_param(ar, param,
-                                               hw->conf.power_level * 2);
-               if (ret)
-                       ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
-                                   hw->conf.power_level, ret);
-               param = ar->wmi.pdev_param->txpower_limit5g;
-               ret = ath10k_wmi_pdev_set_param(ar, param,
-                                               hw->conf.power_level * 2);
-               if (ret)
-                       ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
-                                   hw->conf.power_level, ret);
-       }
        if (changed & IEEE80211_CONF_CHANGE_PS)
                ath10k_config_ps(ar);
  
@@@ -2772,9 -2808,12 +2808,12 @@@ static int ath10k_add_interface(struct 
                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)
                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);
                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;
                goto err_peer_delete;
        }
  
+       arvif->txpower = vif->bss_conf.txpower;
+       ret = ath10k_mac_txpower_recalc(ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+               goto err_peer_delete;
+       }
        mutex_unlock(&ar->conf_mutex);
        return 0;
  
@@@ -2908,10 -2985,16 +2985,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;
@@@ -2929,14 -3012,7 +3012,7 @@@ static void ath10k_remove_interface(str
        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);
                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) {
@@@ -3068,54 -3144,8 +3144,8 @@@ static void ath10k_bss_info_changed(str
                arvif->u.ap.hidden_ssid = info->hidden_ssid;
        }
  
-       /*
-        * Firmware manages AP self-peer internally so make sure to not create
-        * it in driver. Otherwise AP self-peer deletion may timeout later.
-        */
-       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) {
-                               /*
-                                * this is never erased as we it for crypto key
-                                * clearing; this is FW requirement
-                                */
-                               ether_addr_copy(arvif->bssid, info->bssid);
-                               ath10k_dbg(ar, ATH10K_DBG_MAC,
-                                          "mac vdev %d start %pM\n",
-                                          arvif->vdev_id, info->bssid);
-                               ret = ath10k_vdev_start(arvif);
-                               if (ret) {
-                                       ath10k_warn(ar, "failed to start vdev %i: %d\n",
-                                                   arvif->vdev_id, ret);
-                                       goto exit;
-                               }
-                               arvif->is_started = true;
-                       }
-                       /*
-                        * Mac80211 does not keep IBSS bssid when leaving IBSS,
-                        * so driver need to store it. It is needed when leaving
-                        * IBSS in order to remove BSSID peer.
-                        */
-                       if (vif->type == NL80211_IFTYPE_ADHOC)
-                               memcpy(arvif->bssid, info->bssid,
-                                      ETH_ALEN);
-               }
-       }
+       if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
+               ether_addr_copy(arvif->bssid, info->bssid);
  
        if (changed & BSS_CHANGED_BEACON_ENABLED)
                ath10k_control_beaconing(arvif, info);
                                ath10k_monitor_stop(ar);
                        ath10k_bss_assoc(hw, vif, info);
                        ath10k_monitor_recalc(ar);
+               } else {
+                       ath10k_bss_disassoc(hw, vif);
                }
        }
  
- exit:
+       if (changed & BSS_CHANGED_TXPOWER) {
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n",
+                          arvif->vdev_id, info->txpower);
+               arvif->txpower = info->txpower;
+               ret = ath10k_mac_txpower_recalc(ar);
+               if (ret)
+                       ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+       }
        mutex_unlock(&ar->conf_mutex);
  }
  
@@@ -3453,7 -3494,7 +3494,7 @@@ static void ath10k_sta_rc_update_wk(str
                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);
@@@ -3489,8 -3530,7 +3530,7 @@@ static int ath10k_sta_state(struct ieee
        mutex_lock(&ar->conf_mutex);
  
        if (old_state == IEEE80211_STA_NOTEXIST &&
-           new_state == IEEE80211_STA_NONE &&
-           vif->type != NL80211_IFTYPE_STATION) {
+           new_state == IEEE80211_STA_NONE) {
                /*
                 * New station addition.
                 */
                if (ret)
                        ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       WARN_ON(arvif->is_started);
+                       ret = ath10k_vdev_start(arvif);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to start vdev %i: %d\n",
+                                           arvif->vdev_id, ret);
+                               WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
+                                                          sta->addr));
+                               goto exit;
+                       }
+                       arvif->is_started = true;
+               }
        } else if ((old_state == IEEE80211_STA_NONE &&
                    new_state == IEEE80211_STA_NOTEXIST)) {
                /*
                ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d peer delete %pM (sta gone)\n",
                           arvif->vdev_id, sta->addr);
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       WARN_ON(!arvif->is_started);
+                       ret = ath10k_vdev_stop(arvif);
+                       if (ret)
+                               ath10k_warn(ar, "failed to stop vdev %i: %d\n",
+                                           arvif->vdev_id, ret);
+                       arvif->is_started = false;
+               }
                ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
                if (ret)
                        ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
  
-               if (vif->type == NL80211_IFTYPE_STATION)
-                       ath10k_bss_disassoc(hw, vif);
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC &&
                   (vif->type == NL80211_IFTYPE_AP ||
                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);
                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);
@@@ -4456,6 -4521,9 +4521,9 @@@ static const struct ieee80211_ops ath10
        .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)
  
@@@ -4800,15 -4868,6 +4868,6 @@@ int ath10k_mac_register(struct ath10k *
                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;
  
                        IEEE80211_HW_MFP_CAPABLE |
                        IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                        IEEE80211_HW_HAS_RATE_CONTROL |
 -                      IEEE80211_HW_SUPPORTS_STATIC_SMPS |
                        IEEE80211_HW_AP_LINK_PS |
                        IEEE80211_HW_SPECTRUM_MGMT;
  
         * bytes is used for padding/alignment if necessary. */
        ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
  
 +      ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
 +
        if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
 -              ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
 +              ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
  
        if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) {
                ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
index ce6488e42091cf8a935bfe87dd84baad34224656,1300b55051519cd0bcec0ddbba1d76414b0a5ce6..7ffaf2fce097ef212b41a15f1ddcc3f0e41896c5
  #include <linux/wireless.h>
  #include <net/cfg80211.h>
  #include <linux/timex.h>
 +#include "wil_platform.h"
 +
 +extern bool no_fw_recovery;
  
  #define WIL_NAME "wil6210"
 +#define WIL_FW_NAME "wil6210.fw"
 +
 +#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
  
  struct wil_board {
        int board;
@@@ -53,9 -47,7 +53,9 @@@ static inline u32 WIL_GET_BITS(u32 x, i
  #define WIL6210_MAX_TX_RINGS  (24) /* HW limit */
  #define WIL6210_MAX_CID               (8) /* HW limit */
  #define WIL6210_NAPI_BUDGET   (16) /* arbitrary */
 -#define WIL6210_ITR_TRSH      (10000) /* arbitrary - about 15 IRQs/msec */
 +/* Max supported by wil6210 value for interrupt threshold is 5sec. */
 +#define WIL6210_ITR_TRSH_MAX (5000000)
 +#define WIL6210_ITR_TRSH_DEFAULT      (300) /* usec */
  #define WIL6210_FW_RECOVERY_RETRIES   (5) /* try to recover this many times */
  #define WIL6210_FW_RECOVERY_TO        msecs_to_jiffies(5000)
  #define WIL6210_SCAN_TO               msecs_to_jiffies(10000)
@@@ -94,29 -86,22 +94,29 @@@ struct RGF_ICR 
  
  /* registers - FW addresses */
  #define RGF_USER_USAGE_1              (0x880004)
 +#define RGF_USER_USAGE_6              (0x880018)
  #define RGF_USER_HW_MACHINE_STATE     (0x8801dc)
        #define HW_MACHINE_BOOT_DONE    (0x3fffffd)
  #define RGF_USER_USER_CPU_0           (0x8801e0)
 +      #define BIT_USER_USER_CPU_MAN_RST       BIT(1) /* user_cpu_man_rst */
  #define RGF_USER_MAC_CPU_0            (0x8801fc)
 +      #define BIT_USER_MAC_CPU_MAN_RST        BIT(1) /* mac_cpu_man_rst */
  #define RGF_USER_USER_SCRATCH_PAD     (0x8802bc)
  #define RGF_USER_FW_REV_ID            (0x880a8c) /* chip revision */
  #define RGF_USER_CLKS_CTL_0           (0x880abc)
 +      #define BIT_USER_CLKS_CAR_AHB_SW_SEL    BIT(1) /* ref clk/PLL */
        #define BIT_USER_CLKS_RST_PWGD  BIT(11) /* reset on "power good" */
  #define RGF_USER_CLKS_CTL_SW_RST_VEC_0        (0x880b04)
  #define RGF_USER_CLKS_CTL_SW_RST_VEC_1        (0x880b08)
  #define RGF_USER_CLKS_CTL_SW_RST_VEC_2        (0x880b0c)
  #define RGF_USER_CLKS_CTL_SW_RST_VEC_3        (0x880b10)
  #define RGF_USER_CLKS_CTL_SW_RST_MASK_0       (0x880b14)
 +      #define BIT_HPAL_PERST_FROM_PAD BIT(6)
 +      #define BIT_CAR_PERST_RST       BIT(7)
  #define RGF_USER_USER_ICR             (0x880b4c) /* struct RGF_ICR */
        #define BIT_USER_USER_ICR_SW_INT_2      BIT(18)
  #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0    (0x880c18)
 +#define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1    (0x880c2c)
  
  #define RGF_DMA_EP_TX_ICR             (0x881bb4) /* struct RGF_ICR */
        #define BIT_DMA_EP_TX_ICR_TX_DONE       BIT(0)
  /* MAC timer, usec, for packet lifetime */
  #define RGF_MAC_MTRL_COUNTER_0                (0x886aa8)
  
 +#define RGF_CAF_ICR                   (0x88946c) /* struct RGF_ICR */
 +
  /* popular locations */
  #define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
  #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@@ -171,7 -154,6 +171,7 @@@ struct fw_map 
        u32 host; /* PCI/Host address - BAR0 + 0x880000 */
        const char *name; /* for debugfs */
  };
 +
  /* array size should be in sync with actual definition in the wmi.c */
  extern const struct fw_map fw_mapping[7];
  
@@@ -321,12 -303,18 +321,12 @@@ struct pci_dev
   * @timeout: reset timer value (in TUs).
   * @dialog_token: dialog token for aggregation session
   * @rcu_head: RCU head used for freeing this struct
 - * @reorder_lock: serializes access to reorder buffer, see below.
   *
   * This structure's lifetime is managed by RCU, assignments to
   * the array holding it must hold the aggregation mutex.
   *
 - * The @reorder_lock is used to protect the members of this
 - * struct, except for @timeout, @buf_size and @dialog_token,
 - * which are constant across the lifetime of the struct (the
 - * dialog token being used only for debugging).
   */
  struct wil_tid_ampdu_rx {
 -      spinlock_t reorder_lock; /* see above */
        struct sk_buff **reorder_buf;
        unsigned long *reorder_time;
        struct timer_list session_timer;
@@@ -375,17 -363,10 +375,17 @@@ struct wil_sta_info 
        bool data_port_open; /* can send any data, not only EAPOL */
        /* Rx BACK */
        struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
 +      spinlock_t tid_rx_lock; /* guarding tid_rx array */
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(WIL_STA_TID_NUM)];
        unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
  };
  
 +enum {
 +      fw_recovery_idle = 0,
 +      fw_recovery_pending = 1,
 +      fw_recovery_running = 2,
 +};
 +
  struct wil6210_priv {
        struct pci_dev *pdev;
        int n_msi;
        u32 hw_version;
        struct wil_board *board;
        u8 n_mids; /* number of additional MIDs as reported by FW */
 -      int recovery_count; /* num of FW recovery attempts in a short time */
 +      u32 recovery_count; /* num of FW recovery attempts in a short time */
 +      u32 recovery_state; /* FW recovery state machine */
        unsigned long last_fw_recovery; /* jiffies of last fw recovery */
 +      wait_queue_head_t wq; /* for all wait_event() use */
        /* profile */
        u32 monitor_flags;
        u32 secure_pcp; /* create secure PCP? */
        int sinfo_gen;
 +      u32 itr_trsh;
        /* cached ISR registers */
        u32 isr_misc;
        /* mailbox related */
        struct mutex wmi_mutex;
        struct wil6210_mbox_ctl mbox_ctl;
        struct completion wmi_ready;
 +      struct completion wmi_call;
        u16 wmi_seq;
        u16 reply_id; /**< wait for this WMI event */
        void *reply_buf;
        /* debugfs */
        struct dentry *debug;
        struct debugfs_blob_wrapper blobs[ARRAY_SIZE(fw_mapping)];
 +
 +      void *platform_handle;
 +      struct wil_platform_ops platform_ops;
  };
  
  #define wil_to_wiphy(i) (i->wdev->wiphy)
  #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
  #define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
  #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
 +#define wil_to_pcie_dev(i) (&i->pdev->dev)
  
 -int wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
+ __printf(2, 3)
 +void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
+ __printf(2, 3)
  void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
+ __printf(2, 3)
  void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
  #define wil_dbg(wil, fmt, arg...) do { \
        netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
  #define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
  #define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
  
 +#if defined(CONFIG_DYNAMIC_DEBUG)
  #define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize,   \
                          groupsize, buf, len, ascii)           \
                          print_hex_dump_debug("DBG[TXRX]" prefix_str,\
                         print_hex_dump_debug("DBG[ WMI]" prefix_str,\
                                        prefix_type, rowsize,   \
                                        groupsize, buf, len, ascii)
 +#else /* defined(CONFIG_DYNAMIC_DEBUG) */
 +static inline
 +void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize,
 +                     int groupsize, const void *buf, size_t len, bool ascii)
 +{
 +}
 +
 +static inline
 +void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize,
 +                    int groupsize, const void *buf, size_t len, bool ascii)
 +{
 +}
 +#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
  
  void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
                          size_t count);
@@@ -514,18 -476,13 +517,18 @@@ void wil_if_remove(struct wil6210_priv 
  int wil_priv_init(struct wil6210_priv *wil);
  void wil_priv_deinit(struct wil6210_priv *wil);
  int wil_reset(struct wil6210_priv *wil);
 +void wil_set_itr_trsh(struct wil6210_priv *wil);
  void wil_fw_error_recovery(struct wil6210_priv *wil);
 +void wil_set_recovery_state(struct wil6210_priv *wil, int state);
  void wil_link_on(struct wil6210_priv *wil);
  void wil_link_off(struct wil6210_priv *wil);
  int wil_up(struct wil6210_priv *wil);
 +int __wil_up(struct wil6210_priv *wil);
  int wil_down(struct wil6210_priv *wil);
 +int __wil_down(struct wil6210_priv *wil);
  void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
  int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
 +void wil_set_ethtoolops(struct net_device *ndev);
  
  void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
  void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
@@@ -556,10 -513,8 +559,10 @@@ int wmi_disconnect_sta(struct wil6210_p
  void wil6210_clear_irq(struct wil6210_priv *wil);
  int wil6210_init_irq(struct wil6210_priv *wil, int irq);
  void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
 -void wil6210_disable_irq(struct wil6210_priv *wil);
 -void wil6210_enable_irq(struct wil6210_priv *wil);
 +void wil_mask_irq(struct wil6210_priv *wil);
 +void wil_unmask_irq(struct wil6210_priv *wil);
 +void wil_disable_irq(struct wil6210_priv *wil);
 +void wil_enable_irq(struct wil6210_priv *wil);
  int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                         struct cfg80211_mgmt_tx_params *params,
                         u64 *cookie);
@@@ -595,7 -550,4 +598,7 @@@ void wil6210_unmask_irq_rx(struct wil62
  
  int wil_iftype_nl2wmi(enum nl80211_iftype type);
  
 +int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
 +int wil_request_firmware(struct wil6210_priv *wil, const char *name);
 +
  #endif /* __WIL6210_H__ */
This page took 0.114661 seconds and 4 git commands to generate.