]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
Merge tag 'iwlwifi-next-for-kalle-2016-03-09_2' of https://git.kernel.org/pub/scm...
[karo-tx-linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / mac80211.c
index 01476f5456956b199b262d58efa840eda62dbdb2..76e649c680a16bb5930f7c6d137aa429b779360d 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -69,7 +70,6 @@
 #include <linux/etherdevice.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
-#include <linux/devcoredump.h>
 #include <linux/time.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
@@ -85,7 +85,6 @@
 #include "testmode.h"
 #include "iwl-fw-error-dump.h"
 #include "iwl-prph.h"
-#include "iwl-csr.h"
 #include "iwl-nvm-parse.h"
 #include "fw-dbg.h"
 
@@ -837,13 +836,17 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
 static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
-                                   enum ieee80211_ampdu_mlme_action action,
-                                   struct ieee80211_sta *sta, u16 tid,
-                                   u16 *ssn, u8 buf_size, bool amsdu)
+                                   struct ieee80211_ampdu_params *params)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
        bool tx_agg_ref = false;
+       struct ieee80211_sta *sta = params->sta;
+       enum ieee80211_ampdu_mlme_action action = params->action;
+       u16 tid = params->tid;
+       u16 *ssn = &params->ssn;
+       u8 buf_size = params->buf_size;
+       bool amsdu = params->amsdu;
 
        IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
                     sta->addr, tid, action);
@@ -904,7 +907,8 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
-               ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
+               ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid,
+                                             buf_size, amsdu);
                break;
        default:
                WARN_ON_ONCE(1);
@@ -966,7 +970,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
         */
        iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
 
-       iwl_trans_stop_device(mvm->trans);
+       iwl_mvm_stop_device(mvm);
 
        mvm->scan_status = 0;
        mvm->ps_disabled = false;
@@ -1135,7 +1139,7 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
         */
        flush_work(&mvm->roc_done_wk);
 
-       iwl_trans_stop_device(mvm->trans);
+       iwl_mvm_stop_device(mvm);
 
        iwl_mvm_async_handlers_purge(mvm);
        /* async_handlers_list is empty and will stay empty: HW is stopped */
@@ -1166,8 +1170,6 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
                                mvm->scan_uid_status[i] = 0;
                }
        }
-
-       mvm->ucode_loaded = false;
 }
 
 static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
@@ -1759,6 +1761,50 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm)
 }
 #endif
 
+static int iwl_mvm_update_mu_groups(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif)
+{
+       struct iwl_mu_group_mgmt_cmd cmd = {};
+
+       memcpy(cmd.membership_status, vif->bss_conf.mu_group.membership,
+              WLAN_MEMBERSHIP_LEN);
+       memcpy(cmd.user_position, vif->bss_conf.mu_group.position,
+              WLAN_USER_POSITION_LEN);
+
+       return iwl_mvm_send_cmd_pdu(mvm,
+                                   WIDE_ID(DATA_PATH_GROUP,
+                                           UPDATE_MU_GROUPS_CMD),
+                                   0, sizeof(cmd), &cmd);
+}
+
+static void iwl_mvm_mu_mimo_iface_iterator(void *_data, u8 *mac,
+                                          struct ieee80211_vif *vif)
+{
+       if (vif->mu_mimo_owner) {
+               struct iwl_mu_group_mgmt_notif *notif = _data;
+
+               /*
+                * MU-MIMO Group Id action frame is little endian. We treat
+                * the data received from firmware as if it came from the
+                * action frame, so no conversion is needed.
+                */
+               ieee80211_update_mu_groups(vif,
+                                          (u8 *)&notif->membership_status,
+                                          (u8 *)&notif->user_position);
+       }
+}
+
+void iwl_mvm_mu_mimo_grp_notif(struct iwl_mvm *mvm,
+                              struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_mu_group_mgmt_notif *notif = (void *)pkt->data;
+
+       ieee80211_iterate_active_interfaces_atomic(
+                       mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                       iwl_mvm_mu_mimo_iface_iterator, notif);
+}
+
 static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                             struct ieee80211_vif *vif,
                                             struct ieee80211_bss_conf *bss_conf,
@@ -1867,6 +1913,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                        vif->addr);
                }
 
+               /*
+                * The firmware tracks the MU-MIMO group on its own.
+                * However, on HW restart we should restore this data.
+                */
+               if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+                   (changes & BSS_CHANGED_MU_GROUPS) && vif->mu_mimo_owner) {
+                       ret = iwl_mvm_update_mu_groups(mvm, vif);
+                       if (ret)
+                               IWL_ERR(mvm,
+                                       "failed to update VHT MU_MIMO groups\n");
+               }
+
                iwl_mvm_recalc_multicast(mvm);
                iwl_mvm_configure_bcast_filter(mvm);
 
@@ -1893,7 +1951,12 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
        }
 
-       if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) {
+       if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS |
+                      /*
+                       * Send power command on every beacon change,
+                       * because we may have not enabled beacon abort yet.
+                       */
+                      BSS_CHANGED_BEACON_INFO)) {
                ret = iwl_mvm_power_update_mac(mvm);
                if (ret)
                        IWL_ERR(mvm, "failed to update power mode\n");
@@ -2080,7 +2143,6 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
                                bss_conf->txpower);
                iwl_mvm_set_tx_power(mvm, vif, bss_conf->txpower);
        }
-
 }
 
 static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
@@ -2273,6 +2335,11 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
                return;
 
+       if (vif->p2p && !iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) {
+               vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
+               return;
+       }
+
        if (iwlwifi_mod_params.uapsd_disable) {
                vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
                return;
@@ -2487,10 +2554,8 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       u32 duration = min(IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS,
-                          200 + vif->bss_conf.beacon_int);
-       u32 min_duration = min(IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS,
-                              100 + vif->bss_conf.beacon_int);
+       u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
+       u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
 
        if (WARN_ON_ONCE(vif->bss_conf.assoc))
                return;
@@ -2582,7 +2647,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
        switch (key->cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
                key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-               key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+               key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
                key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
@@ -2621,8 +2686,12 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
                         * GTK on AP interface is a TX-only key, return 0;
                         * on IBSS they're per-station and because we're lazy
                         * we don't support them for RX, so do the same.
+                        * CMAC in AP/IBSS modes must be done in software.
                         */
-                       ret = 0;
+                       if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+                               ret = -EOPNOTSUPP;
+                       else
+                               ret = 0;
                        key->hw_key_idx = STA_KEY_IDX_INVALID;
                        break;
                }