diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 109 | 
1 files changed, 89 insertions, 20 deletions
| diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index d70a1716f3e0..76e649c680a1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -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 = ¶ms->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); @@ -884,10 +887,10 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,  			ret = -EINVAL;  			break;  		} -		ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true); +		ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size);  		break;  	case IEEE80211_AMPDU_RX_STOP: -		ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false); +		ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size);  		break;  	case IEEE80211_AMPDU_TX_START:  		if (!iwl_enable_tx_ampdu(mvm->cfg)) { @@ -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 *)¬if->membership_status, +					   (u8 *)¬if->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;  		} | 
