]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'wireless-drivers-next-for-davem-2015-02-07' of git://git.kernel.org/pub...
authorDavid S. Miller <davem@davemloft.net>
Mon, 9 Feb 2015 20:07:20 +0000 (12:07 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Feb 2015 20:13:58 +0000 (12:13 -0800)
Major changes:

iwlwifi:

* more work for new devices (4165 / 8260)
* cleanups / improvemnts in rate control
* fixes for TDLS
* major statistics work from Johannes - more to come
* improvements for the fw error dump infrastructure
* usual amount of small fixes here and there (scan, D0i3 etc...)
* add support for beamforming
* enable stuck queue detection for iwlmvm
* a few fixes for EBS scan
* fixes for various failure paths
* improvements for TDLS Offchannel

wil6210:

* performance tuning
* some AP features

brcm80211:

* rework some code in SDIO part of the brcmfmac driver related to
  suspend/resume that were found doing stress testing
* in PCIe part scheduling of worker thread needed to be relaxed
* minor fixes and exposing firmware revision information to
  user-space, ie. ethtool.

mwifiex:

* enhancements for change virtual interface handling
* remove coupling between netdev and FW supported interface
  combination, now conversion from any type of supported interface
  types to any other type is possible
* DFS support in AP mode

ath9k:

* fix calibration issues on some boards
* Wake-on-WLAN improvements

ath10k:

* add support for qca6174 hardware
* enable RX batching to reduce CPU load

Conflicts:
drivers/net/wireless/rtlwifi/pci.c

Conflict resolution is to get rid of the 'end' label and keep
the rest.

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/rtlwifi/pci.c

index 60a524b732079c6487a68b5494d8ad74c938815f,1cebd32190686411fb88f53c61448a74ba089a77..d6d2f0f00caad18ec00ba69f5635c79f161b2ba7
@@@ -37,7 -37,7 +37,7 @@@
  static int ath10k_send_key(struct ath10k_vif *arvif,
                           struct ieee80211_key_conf *key,
                           enum set_key_cmd cmd,
-                          const u8 *macaddr)
+                          const u8 *macaddr, bool def_idx)
  {
        struct ath10k *ar = arvif->ar;
        struct wmi_vdev_install_key_arg arg = {
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_CCMP:
                arg.key_cipher = WMI_CIPHER_AES_CCM;
-               if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
-               else
-                       key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
                break;
        case WLAN_CIPHER_SUITE_TKIP:
                arg.key_cipher = WMI_CIPHER_TKIP;
                 * Otherwise pairwise key must be set */
                if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN))
                        arg.key_flags = WMI_KEY_PAIRWISE;
+               if (def_idx)
+                       arg.key_flags |= WMI_KEY_TX_USAGE;
                break;
 +      case WLAN_CIPHER_SUITE_AES_CMAC:
 +              /* this one needs to be done in software */
 +              return 1;
        default:
                ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
                return -EOPNOTSUPP;
@@@ -95,7 -92,7 +95,7 @@@
  static int ath10k_install_key(struct ath10k_vif *arvif,
                              struct ieee80211_key_conf *key,
                              enum set_key_cmd cmd,
-                             const u8 *macaddr)
+                             const u8 *macaddr, bool def_idx)
  {
        struct ath10k *ar = arvif->ar;
        int ret;
  
        reinit_completion(&ar->install_key_done);
  
-       ret = ath10k_send_key(arvif, key, cmd, macaddr);
+       ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx);
        if (ret)
                return ret;
  
@@@ -122,6 -119,7 +122,7 @@@ static int ath10k_install_peer_wep_keys
        struct ath10k_peer *peer;
        int ret;
        int i;
+       bool def_idx;
  
        lockdep_assert_held(&ar->conf_mutex);
  
        for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
                if (arvif->wep_keys[i] == NULL)
                        continue;
+               /* set TX_USAGE flag for default key id */
+               if (arvif->def_wep_key_idx == i)
+                       def_idx = true;
+               else
+                       def_idx = false;
  
                ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
-                                        addr);
+                                        addr, def_idx);
                if (ret)
                        return ret;
  
@@@ -171,8 -174,9 +177,9 @@@ static int ath10k_clear_peer_keys(struc
                if (peer->keys[i] == NULL)
                        continue;
  
+               /* key flags are not required to delete the key */
                ret = ath10k_install_key(arvif, peer->keys[i],
-                                        DISABLE_KEY, addr);
+                                        DISABLE_KEY, addr, false);
                if (ret && first_errno == 0)
                        first_errno = ret;
  
@@@ -246,8 -250,8 +253,8 @@@ static int ath10k_clear_vdev_key(struc
  
                if (i == ARRAY_SIZE(peer->keys))
                        break;
-               ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr);
+               /* key flags are not required to delete the key */
+               ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false);
                if (ret && first_errno == 0)
                        first_errno = ret;
  
@@@ -527,10 -531,14 +534,14 @@@ void ath10k_mac_vif_beacon_free(struct 
                dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
                                 arvif->beacon->len, DMA_TO_DEVICE);
  
+       if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED &&
+                   arvif->beacon_state != ATH10K_BEACON_SENT))
+               return;
        dev_kfree_skb_any(arvif->beacon);
  
        arvif->beacon = NULL;
-       arvif->beacon_sent = false;
+       arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
  }
  
  static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
@@@ -970,6 -978,143 +981,143 @@@ static int ath10k_vdev_stop(struct ath1
        return ret;
  }
  
+ static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
+                                      struct sk_buff *bcn)
+ {
+       struct ath10k *ar = arvif->ar;
+       struct ieee80211_mgmt *mgmt;
+       const u8 *p2p_ie;
+       int ret;
+       if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+               return 0;
+       if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
+               return 0;
+       mgmt = (void *)bcn->data;
+       p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+                                        mgmt->u.beacon.variable,
+                                        bcn->len - (mgmt->u.beacon.variable -
+                                                    bcn->data));
+       if (!p2p_ie)
+               return -ENOENT;
+       ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie);
+       if (ret) {
+               ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+       return 0;
+ }
+ static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui,
+                                      u8 oui_type, size_t ie_offset)
+ {
+       size_t len;
+       const u8 *next;
+       const u8 *end;
+       u8 *ie;
+       if (WARN_ON(skb->len < ie_offset))
+               return -EINVAL;
+       ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
+                                          skb->data + ie_offset,
+                                          skb->len - ie_offset);
+       if (!ie)
+               return -ENOENT;
+       len = ie[1] + 2;
+       end = skb->data + skb->len;
+       next = ie + len;
+       if (WARN_ON(next > end))
+               return -EINVAL;
+       memmove(ie, next, end - next);
+       skb_trim(skb, skb->len - len);
+       return 0;
+ }
+ static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif)
+ {
+       struct ath10k *ar = arvif->ar;
+       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_vif *vif = arvif->vif;
+       struct ieee80211_mutable_offsets offs = {};
+       struct sk_buff *bcn;
+       int ret;
+       if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
+               return 0;
+       bcn = ieee80211_beacon_get_template(hw, vif, &offs);
+       if (!bcn) {
+               ath10k_warn(ar, "failed to get beacon template from mac80211\n");
+               return -EPERM;
+       }
+       ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn);
+       if (ret) {
+               ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret);
+               kfree_skb(bcn);
+               return ret;
+       }
+       /* P2P IE is inserted by firmware automatically (as configured above)
+        * so remove it from the base beacon template to avoid duplicate P2P
+        * IEs in beacon frames.
+        */
+       ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+                                   offsetof(struct ieee80211_mgmt,
+                                            u.beacon.variable));
+       ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0,
+                                 0, NULL, 0);
+       kfree_skb(bcn);
+       if (ret) {
+               ath10k_warn(ar, "failed to submit beacon template command: %d\n",
+                           ret);
+               return ret;
+       }
+       return 0;
+ }
+ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
+ {
+       struct ath10k *ar = arvif->ar;
+       struct ieee80211_hw *hw = ar->hw;
+       struct ieee80211_vif *vif = arvif->vif;
+       struct sk_buff *prb;
+       int ret;
+       if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
+               return 0;
+       prb = ieee80211_proberesp_get(hw, vif);
+       if (!prb) {
+               ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
+               return -EPERM;
+       }
+       ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb);
+       kfree_skb(prb);
+       if (ret) {
+               ath10k_warn(ar, "failed to submit probe resp template command: %d\n",
+                           ret);
+               return ret;
+       }
+       return 0;
+ }
  static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                                     struct ieee80211_bss_conf *info)
  {
@@@ -1155,6 -1300,38 +1303,38 @@@ static int ath10k_mac_vif_setup_ps(stru
        return 0;
  }
  
+ static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif)
+ {
+       struct ath10k *ar = arvif->ar;
+       struct wmi_sta_keepalive_arg arg = {};
+       int ret;
+       lockdep_assert_held(&arvif->ar->conf_mutex);
+       if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+               return 0;
+       if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map))
+               return 0;
+       /* Some firmware revisions have a bug and ignore the `enabled` field.
+        * Instead use the interval to disable the keepalive.
+        */
+       arg.vdev_id = arvif->vdev_id;
+       arg.enabled = 1;
+       arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME;
+       arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE;
+       ret = ath10k_wmi_sta_keepalive(ar, &arg);
+       if (ret) {
+               ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+               return ret;
+       }
+       return 0;
+ }
  /**********************/
  /* Station management */
  /**********************/
@@@ -1423,6 -1600,10 +1603,10 @@@ static void ath10k_peer_assoc_h_vht(str
                return;
  
        arg->peer_flags |= WMI_PEER_VHT;
+       if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
+               arg->peer_flags |= WMI_PEER_VHT_2G;
        arg->peer_vht_caps = vht_cap->cap;
  
        ampdu_factor = (vht_cap->cap &
@@@ -1501,7 -1682,12 +1685,12 @@@ static void ath10k_peer_assoc_h_phymode
  
        switch (ar->hw->conf.chandef.chan->band) {
        case IEEE80211_BAND_2GHZ:
-               if (sta->ht_cap.ht_supported) {
+               if (sta->vht_cap.vht_supported) {
+                       if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+                               phymode = MODE_11AC_VHT40;
+                       else
+                               phymode = MODE_11AC_VHT20;
+               } else if (sta->ht_cap.ht_supported) {
                        if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
                                phymode = MODE_11NG_HT40;
                        else
@@@ -1683,7 -1869,8 +1872,8 @@@ static void ath10k_bss_disassoc(struct 
                ath10k_warn(ar, "faield to down vdev %i: %d\n",
                            arvif->vdev_id, ret);
  
-       arvif->def_wep_key_idx = 0;
+       arvif->def_wep_key_idx = -1;
        arvif->is_up = false;
  }
  
@@@ -1742,11 -1929,14 +1932,14 @@@ static int ath10k_station_assoc(struct 
                        }
                }
  
-               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;
+               /* Plumb cached keys only for static WEP */
+               if (arvif->def_wep_key_idx != -1) {
+                       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;
+                       }
                }
        }
  
@@@ -2011,75 -2201,13 +2204,13 @@@ static void ath10k_tx_h_nwifi(struct ie
         * used only for CQM purposes (e.g. hostapd station keepalive ping) so
         * it is safe to downgrade to NullFunc.
         */
+       hdr = (void *)skb->data;
        if (ieee80211_is_qos_nullfunc(hdr->frame_control)) {
                hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
                cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
        }
  }
  
- static void ath10k_tx_wep_key_work(struct work_struct *work)
- {
-       struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
-                                               wep_key_work);
-       struct ath10k *ar = arvif->ar;
-       int ret, keyidx = arvif->def_wep_key_newidx;
-       mutex_lock(&arvif->ar->conf_mutex);
-       if (arvif->ar->state != ATH10K_STATE_ON)
-               goto unlock;
-       if (arvif->def_wep_key_idx == keyidx)
-               goto unlock;
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
-                  arvif->vdev_id, keyidx);
-       ret = ath10k_wmi_vdev_set_param(arvif->ar,
-                                       arvif->vdev_id,
-                                       arvif->ar->wmi.vdev_param->def_keyid,
-                                       keyidx);
-       if (ret) {
-               ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
-                           arvif->vdev_id,
-                           ret);
-               goto unlock;
-       }
-       arvif->def_wep_key_idx = keyidx;
- unlock:
-       mutex_unlock(&arvif->ar->conf_mutex);
- }
- static void ath10k_tx_h_update_wep_key(struct ieee80211_vif *vif,
-                                      struct ieee80211_key_conf *key,
-                                      struct sk_buff *skb)
- {
-       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
-       struct ath10k *ar = arvif->ar;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       if (!ieee80211_has_protected(hdr->frame_control))
-               return;
-       if (!key)
-               return;
-       if (key->cipher != WLAN_CIPHER_SUITE_WEP40 &&
-           key->cipher != WLAN_CIPHER_SUITE_WEP104)
-               return;
-       if (key->keyidx == arvif->def_wep_key_idx)
-               return;
-       /* FIXME: Most likely a few frames will be TXed with an old key. Simply
-        * queueing frames until key index is updated is not an option because
-        * sk_buff may need more processing to be done, e.g. offchannel */
-       arvif->def_wep_key_newidx = key->keyidx;
-       ieee80211_queue_work(ar->hw, &arvif->wep_key_work);
- }
  static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
                                       struct ieee80211_vif *vif,
                                       struct sk_buff *skb)
@@@ -2231,7 -2359,7 +2362,7 @@@ void ath10k_offchan_tx_work(struct work
  
                ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
                                                  3 * HZ);
-               if (ret <= 0)
+               if (ret == 0)
                        ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
                                    skb);
  
@@@ -2293,6 -2421,7 +2424,7 @@@ void __ath10k_scan_finish(struct ath10
        case ATH10K_SCAN_RUNNING:
                if (ar->scan.is_roc)
                        ieee80211_remain_on_channel_expired(ar->hw);
+               /* fall through */
        case ATH10K_SCAN_ABORTING:
                if (!ar->scan.is_roc)
                        ieee80211_scan_completed(ar->hw,
@@@ -2439,7 -2568,6 +2571,6 @@@ static void ath10k_tx(struct ieee80211_
        struct ath10k *ar = hw->priv;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_vif *vif = info->control.vif;
-       struct ieee80211_key_conf *key = info->control.hw_key;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
  
        /* We should disable CCK RATE due to P2P */
        /* it makes no sense to process injected frames like that */
        if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
                ath10k_tx_h_nwifi(hw, skb);
-               ath10k_tx_h_update_wep_key(vif, key, skb);
                ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
                ath10k_tx_h_seq_no(vif, skb);
        }
@@@ -2960,7 -3087,6 +3090,6 @@@ static int ath10k_add_interface(struct 
        arvif->ar = ar;
        arvif->vif = vif;
  
-       INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
        INIT_LIST_HEAD(&arvif->list);
  
        if (ar->free_vdev_map == 0) {
        ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
        list_add(&arvif->list, &ar->arvifs);
  
-       vdev_param = ar->wmi.vdev_param->def_keyid;
-       ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
-                                       arvif->def_wep_key_idx);
+       /* It makes no sense to have firmware do keepalives. mac80211 already
+        * takes care of this with idle connection polling.
+        */
+       ret = ath10k_mac_vif_disable_keepalive(arvif);
        if (ret) {
-               ath10k_warn(ar, "failed to set vdev %i default key id: %d\n",
+               ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                goto err_vdev_delete;
        }
  
+       arvif->def_wep_key_idx = -1;
        vdev_param = ar->wmi.vdev_param->tx_encap_type;
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                        ATH10K_HW_TXRX_NATIVE_WIFI);
@@@ -3176,8 -3305,6 +3308,6 @@@ static void ath10k_remove_interface(str
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        int ret;
  
-       cancel_work_sync(&arvif->wep_key_work);
        mutex_lock(&ar->conf_mutex);
  
        spin_lock_bh(&ar->data_lock);
@@@ -3288,9 -3415,21 +3418,21 @@@ static void ath10k_bss_info_changed(str
                if (ret)
                        ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
+               ret = ath10k_mac_setup_bcn_tmpl(arvif);
+               if (ret)
+                       ath10k_warn(ar, "failed to update beacon template: %d\n",
+                                   ret);
+       }
+       if (changed & BSS_CHANGED_AP_PROBE_RESP) {
+               ret = ath10k_mac_setup_prb_tmpl(arvif);
+               if (ret)
+                       ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n",
+                                   arvif->vdev_id, ret);
        }
  
-       if (changed & BSS_CHANGED_BEACON_INFO) {
+       if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
                arvif->dtim_period = info->dtim_period;
  
                ath10k_dbg(ar, ATH10K_DBG_MAC,
@@@ -3537,6 -3676,7 +3679,7 @@@ static int ath10k_set_key(struct ieee80
        const u8 *peer_addr;
        bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
                      key->cipher == WLAN_CIPHER_SUITE_WEP104;
+       bool def_idx = false;
        int ret = 0;
  
        if (key->keyidx > WMI_MAX_KEY_INDEX)
                        ath10k_clear_vdev_key(arvif, key);
        }
  
-       ret = ath10k_install_key(arvif, key, cmd, peer_addr);
+       /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For
+        * static WEP, do not set this flag for the keys whose key id
+        * is  greater than default key id.
+        */
+       if (arvif->def_wep_key_idx == -1)
+               def_idx = true;
+       ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx);
        if (ret) {
                ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
                            arvif->vdev_id, peer_addr, ret);
@@@ -3607,6 -3754,39 +3757,39 @@@ exit
        return ret;
  }
  
+ static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif,
+                                          int keyidx)
+ {
+       struct ath10k *ar = hw->priv;
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       int ret;
+       mutex_lock(&arvif->ar->conf_mutex);
+       if (arvif->ar->state != ATH10K_STATE_ON)
+               goto unlock;
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
+                  arvif->vdev_id, keyidx);
+       ret = ath10k_wmi_vdev_set_param(arvif->ar,
+                                       arvif->vdev_id,
+                                       arvif->ar->wmi.vdev_param->def_keyid,
+                                       keyidx);
+       if (ret) {
+               ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
+                           arvif->vdev_id,
+                           ret);
+               goto unlock;
+       }
+       arvif->def_wep_key_idx = keyidx;
+ unlock:
+       mutex_unlock(&arvif->ar->conf_mutex);
+ }
  static void ath10k_sta_rc_update_wk(struct work_struct *wk)
  {
        struct ath10k *ar;
@@@ -3842,6 -4022,8 +4025,8 @@@ static int ath10k_conf_tx_uapsd(struct 
                                u16 ac, bool enable)
  {
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       struct wmi_sta_uapsd_auto_trig_arg arg = {};
+       u32 prio = 0, acc = 0;
        u32 value = 0;
        int ret = 0;
  
        case IEEE80211_AC_VO:
                value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
                        WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
+               prio = 7;
+               acc = 3;
                break;
        case IEEE80211_AC_VI:
                value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
                        WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
+               prio = 5;
+               acc = 2;
                break;
        case IEEE80211_AC_BE:
                value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
                        WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
+               prio = 2;
+               acc = 1;
                break;
        case IEEE80211_AC_BK:
                value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
                        WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
+               prio = 0;
+               acc = 0;
                break;
        }
  
                return ret;
        }
  
+       if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) ||
+           test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) {
+               /* Only userspace can make an educated decision when to send
+                * trigger frame. The following effectively disables u-UAPSD
+                * autotrigger in firmware (which is enabled by default
+                * provided the autotrigger service is available).
+                */
+               arg.wmm_ac = acc;
+               arg.user_priority = prio;
+               arg.service_interval = 0;
+               arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC;
+               arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC;
+               ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id,
+                                               arvif->bssid, &arg, 1);
+               if (ret) {
+                       ath10k_warn(ar, "failed to set uapsd auto trigger %d\n",
+                                   ret);
+                       return ret;
+               }
+       }
  exit:
        return ret;
  }
@@@ -3916,6 -4129,7 +4132,7 @@@ static int ath10k_conf_tx(struct ieee80
                          const struct ieee80211_tx_queue_params *params)
  {
        struct ath10k *ar = hw->priv;
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        struct wmi_wmm_params_arg *p = NULL;
        int ret;
  
  
        switch (ac) {
        case IEEE80211_AC_VO:
-               p = &ar->wmm_params.ac_vo;
+               p = &arvif->wmm_params.ac_vo;
                break;
        case IEEE80211_AC_VI:
-               p = &ar->wmm_params.ac_vi;
+               p = &arvif->wmm_params.ac_vi;
                break;
        case IEEE80211_AC_BE:
-               p = &ar->wmm_params.ac_be;
+               p = &arvif->wmm_params.ac_be;
                break;
        case IEEE80211_AC_BK:
-               p = &ar->wmm_params.ac_bk;
+               p = &arvif->wmm_params.ac_bk;
                break;
        }
  
         */
        p->txop = params->txop * 32;
  
-       /* FIXME: FW accepts wmm params per hw, not per vif */
-       ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
-       if (ret) {
-               ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
-               goto exit;
+       if (ar->wmi.ops->gen_vdev_wmm_conf) {
+               ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id,
+                                              &arvif->wmm_params);
+               if (ret) {
+                       ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n",
+                                   arvif->vdev_id, ret);
+                       goto exit;
+               }
+       } else {
+               /* This won't work well with multi-interface cases but it's
+                * better than nothing.
+                */
+               ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params);
+               if (ret) {
+                       ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
+                       goto exit;
+               }
        }
  
        ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
@@@ -4726,6 -4952,7 +4955,7 @@@ static const struct ieee80211_ops ath10
        .hw_scan                        = ath10k_hw_scan,
        .cancel_hw_scan                 = ath10k_cancel_hw_scan,
        .set_key                        = ath10k_set_key,
+       .set_default_unicast_key        = ath10k_set_default_unicast_key,
        .sta_state                      = ath10k_sta_state,
        .conf_tx                        = ath10k_conf_tx,
        .remain_on_channel              = ath10k_remain_on_channel,
        .suspend                        = ath10k_suspend,
        .resume                         = ath10k_resume,
  #endif
+ #ifdef CONFIG_MAC80211_DEBUGFS
+       .sta_add_debugfs                = ath10k_sta_add_debugfs,
+ #endif
  };
  
  #define RATETAB_ENT(_rate, _rateid, _flags) { \
@@@ -5038,13 -5268,6 +5271,13 @@@ struct ath10k_vif *ath10k_get_arvif(str
  
  int ath10k_mac_register(struct ath10k *ar)
  {
 +      static const u32 cipher_suites[] = {
 +              WLAN_CIPHER_SUITE_WEP40,
 +              WLAN_CIPHER_SUITE_WEP104,
 +              WLAN_CIPHER_SUITE_TKIP,
 +              WLAN_CIPHER_SUITE_CCMP,
 +              WLAN_CIPHER_SUITE_AES_CMAC,
 +      };
        struct ieee80211_supported_band *band;
        struct ieee80211_sta_vht_cap vht_cap;
        struct ieee80211_sta_ht_cap ht_cap;
                band->bitrates = ath10k_g_rates;
                band->ht_cap = ht_cap;
  
-               /* vht is not supported in 2.4 GHz */
+               /* Enable the VHT support at 2.4 GHz */
+               band->vht_cap = vht_cap;
  
                ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band;
        }
                        IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                        IEEE80211_HW_HAS_RATE_CONTROL |
                        IEEE80211_HW_AP_LINK_PS |
 -                      IEEE80211_HW_SPECTRUM_MGMT;
 +                      IEEE80211_HW_SPECTRUM_MGMT |
 +                      IEEE80211_HW_SW_CRYPTO_CONTROL;
  
        ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
  
  
        ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
  
+       if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) {
+               ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+               /* Firmware delivers WPS/P2P Probe Requests frames to driver so
+                * that userspace (e.g. wpa_supplicant/hostapd) can generate
+                * correct Probe Responses. This is more of a hack advert..
+                */
+               ar->hw->wiphy->probe_resp_offload |=
+                       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+                       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+                       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
+       }
        ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
        ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
        ar->hw->wiphy->max_remain_on_channel_duration = 5000;
                goto err_free;
        }
  
 +      ar->hw->wiphy->cipher_suites = cipher_suites;
 +      ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
 +
        ret = ieee80211_register_hw(ar->hw);
        if (ret) {
                ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
index 62b0bf4fdf6b0144f4696703113f344b2993546c,98b1e4aa150658adb06577b4d6bee13b7eaf3f08..9ede991b8d767cfd2268a9137dcaa57d171af174
@@@ -285,7 -285,6 +285,7 @@@ static int ath_reset_internal(struct at
  
        __ath_cancel_work(sc);
  
 +      disable_irq(sc->irq);
        tasklet_disable(&sc->intr_tq);
        tasklet_disable(&sc->bcon_tasklet);
        spin_lock_bh(&sc->sc_pcu_lock);
                r = -EIO;
  
  out:
 +      enable_irq(sc->irq);
        spin_unlock_bh(&sc->sc_pcu_lock);
        tasklet_enable(&sc->bcon_tasklet);
        tasklet_enable(&sc->intr_tq);
@@@ -514,6 -512,9 +514,6 @@@ irqreturn_t ath_isr(int irq, void *dev
        if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
                return IRQ_NONE;
  
 -      if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
 -              return IRQ_NONE;
 -
        /* shared irq, not for us */
        if (!ath9k_hw_intrpend(ah))
                return IRQ_NONE;
        ath9k_debug_sync_cause(sc, sync_cause);
        status &= ah->imask;    /* discard unasked-for bits */
  
 -      if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
 +      if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
                return IRQ_HANDLED;
  
        /*
            (status & ATH9K_INT_BB_WATCHDOG))
                goto chip_reset;
  
- #ifdef CONFIG_ATH9K_WOW
-       if (status & ATH9K_INT_BMISS) {
-               if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
-                       atomic_inc(&sc->wow_got_bmiss_intr);
-                       atomic_dec(&sc->wow_sleep_proc_intr);
-               }
-       }
- #endif
        if (status & ATH9K_INT_SWBA)
                tasklet_schedule(&sc->bcon_tasklet);
  
index c70efb9a6e78ccf22170bb8bbfe0abe89be695ef,88331d729b0e798d1ae6cf4c2047f23effeefb0a..ec456f0d972eb583f4f2bbfda84472680b2513f0
@@@ -578,6 -578,13 +578,13 @@@ static void _rtl_pci_tx_isr(struct ieee
                else
                        entry = (u8 *)(&ring->desc[ring->idx]);
  
+               if (rtlpriv->cfg->ops->get_available_desc &&
+                   rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
+                       RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
+                                "no available desc!\n");
+                       return;
+               }
                if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
                        return;
                ring->idx = (ring->idx + 1) % ring->entries;
  
                ieee80211_tx_status_irqsafe(hw, skb);
  
-               if ((ring->entries - skb_queue_len(&ring->queue))
-                               == 2) {
+               if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) {
  
-                       RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
                                 "more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
                                 prio, ring->idx,
                                 skb_queue_len(&ring->queue));
@@@ -666,8 -672,7 +672,8 @@@ tx_status_ok
  }
  
  static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
 -                                  u8 *entry, int rxring_idx, int desc_idx)
 +                                  struct sk_buff *new_skb, u8 *entry,
 +                                  int rxring_idx, int desc_idx)
  {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        u8 tmp_one = 1;
        struct sk_buff *skb;
  
 +      if (likely(new_skb)) {
 +              skb = new_skb;
 +              goto remap;
 +      }
        skb = dev_alloc_skb(rtlpci->rxbuffersize);
        if (!skb)
                return 0;
 -      rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
  
 +remap:
        /* just set skb->cb to mapping addr for pci_unmap_single use */
        *((dma_addr_t *)skb->cb) =
                pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
        bufferaddress = *((dma_addr_t *)skb->cb);
        if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
                return 0;
 +      rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
        if (rtlpriv->use_new_trx_flow) {
                rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
                                            HW_DESC_RX_PREPARE,
@@@ -787,13 -787,12 +793,13 @@@ static void _rtl_pci_rx_interrupt(struc
                /*rx pkt */
                struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
                                      rtlpci->rx_ring[rxring_idx].idx];
 +              struct sk_buff *new_skb;
  
                if (rtlpriv->use_new_trx_flow) {
                        rx_remained_cnt =
                                rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
                                                                      hw_queue);
-                       if (rx_remained_cnt < 1)
+                       if (rx_remained_cnt == 0)
                                return;
  
                } else {        /* rx descriptor */
                pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
                                 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
  
 +              /* get a new skb - if fail, old one will be reused */
 +              new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
 +              if (unlikely(!new_skb)) {
 +                      pr_err("Allocation of new skb failed in %s\n",
 +                             __func__);
 +                      goto no_new;
 +              }
                if (rtlpriv->use_new_trx_flow) {
                        buffer_desc =
                          &rtlpci->rx_ring[rxring_idx].buffer_desc
                        else
                                skb_reserve(skb, stats.rx_drvinfo_size +
                                            stats.rx_bufshift);
                } else {
                        RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                                 "skb->end - skb->tail = %d, len is %d\n",
                                 skb->end - skb->tail, len);
-                       break;
+                       dev_kfree_skb_any(skb);
+                       goto new_trx_end;
                }
                /* handle command packet here */
                if (rtlpriv->cfg->ops->rx_command_packet &&
                    rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
                                dev_kfree_skb_any(skb);
-                               goto end;
+                               goto new_trx_end;
                }
  
                /*
                } else {
                        dev_kfree_skb_any(skb);
                }
+ new_trx_end:
                if (rtlpriv->use_new_trx_flow) {
                        rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
                        rtlpci->rx_ring[hw_queue].next_rx_rp %=
                        rtlpriv->enter_ps = false;
                        schedule_work(&rtlpriv->works.lps_change_work);
                }
- end:
 +              skb = new_skb;
 +no_new:
                if (rtlpriv->use_new_trx_flow) {
 -                      _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
 +                      _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc,
                                                 rxring_idx,
 -                                             rtlpci->rx_ring[rxring_idx].idx);
 +                                               rtlpci->rx_ring[rxring_idx].idx);
                } else {
 -                      _rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx,
 +                      _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc,
 +                                               rxring_idx,
                                                 rtlpci->rx_ring[rxring_idx].idx);
 -
                        if (rtlpci->rx_ring[rxring_idx].idx ==
                            rtlpci->rxringcount - 1)
                                rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc,
@@@ -1323,7 -1313,7 +1329,7 @@@ static int _rtl_pci_init_rx_ring(struc
                rtlpci->rx_ring[rxring_idx].idx = 0;
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
 -                      if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
 +                      if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
                                                      rxring_idx, i))
                                return -ENOMEM;
                }
  
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        entry = &rtlpci->rx_ring[rxring_idx].desc[i];
 -                      if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
 +                      if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
                                                      rxring_idx, i))
                                return -ENOMEM;
                }
@@@ -1688,6 -1678,15 +1694,15 @@@ static int rtl_pci_tx(struct ieee80211_
                }
        }
  
+       if (rtlpriv->cfg->ops->get_available_desc &&
+           rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) {
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                "get_available_desc fail\n");
+                       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+                                              flags);
+                       return skb->len;
+       }
        if (ieee80211_is_data_qos(fc)) {
                tid = rtl_get_tid(skb);
                if (sta) {