diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 137 | 
1 files changed, 91 insertions, 46 deletions
| diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a67aa1f5a51c..bcde1ba0f1c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -84,7 +84,7 @@  #include "iwl-eeprom-parse.h"  #include "iwl-phy-db.h"  #include "testmode.h" -#include "iwl-fw-error-dump.h" +#include "fw/error-dump.h"  #include "iwl-prph.h"  #include "iwl-nvm-parse.h"  #include "fw-dbg.h" @@ -493,7 +493,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	 * firmware will interpret some mgmt packets, so enabling it  	 * with software crypto isn't safe).  	 */ -	if (!iwlwifi_mod_params.sw_crypto) { +	if (!iwlwifi_mod_params.swcrypto) {  		ieee80211_hw_set(hw, MFP_CAPABLE);  		mvm->ciphers[hw->wiphy->n_cipher_suites] =  			WLAN_CIPHER_SUITE_AES_CMAC; @@ -687,7 +687,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  				     WIPHY_WOWLAN_EAP_IDENTITY_REQ |  				     WIPHY_WOWLAN_RFKILL_RELEASE |  				     WIPHY_WOWLAN_NET_DETECT; -		if (!iwlwifi_mod_params.sw_crypto) +		if (!iwlwifi_mod_params.swcrypto)  			mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |  					     WIPHY_WOWLAN_GTK_REKEY_FAILURE |  					     WIPHY_WOWLAN_4WAY_HANDSHAKE; @@ -735,6 +735,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)  	ret = ieee80211_register_hw(mvm->hw);  	if (ret)  		iwl_mvm_leds_exit(mvm); +	mvm->init_status |= IWL_MVM_INIT_STATUS_REG_HW_INIT_COMPLETE;  	if (mvm->cfg->vht_mu_mimo_supported)  		wiphy_ext_feature_set(hw->wiphy, @@ -1243,6 +1244,17 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)  	flush_work(&mvm->d0i3_exit_work);  	flush_work(&mvm->async_handlers_wk);  	flush_work(&mvm->add_stream_wk); + +	/* +	 * Lock and clear the firmware running bit here already, so that +	 * new commands coming in elsewhere, e.g. from debugfs, will not +	 * be able to proceed. This is important here because one of those +	 * debugfs files causes the fw_dump_wk to be triggered, and if we +	 * don't stop debugfs accesses before canceling that it could be +	 * retriggered after we flush it but before we've cleared the bit. +	 */ +	clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); +  	cancel_delayed_work_sync(&mvm->fw_dump_wk);  	cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);  	cancel_delayed_work_sync(&mvm->scan_timeout_dwork); @@ -1451,7 +1463,7 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,  {  	u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); -	if (tfd_msk) { +	if (tfd_msk && !iwl_mvm_is_dqa_supported(mvm)) {  		/*  		 * mac80211 first removes all the stations of the vif and  		 * then removes the vif. When it removes a station it also @@ -1460,6 +1472,8 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,  		 * of these AMPDU sessions are properly closed.  		 * We still need to take care of the shared queues of the vif.  		 * Flush them here. +		 * For DQA mode there is no need - broacast and multicast queue +		 * are flushed separately.  		 */  		mutex_lock(&mvm->mutex);  		iwl_mvm_flush_tx_path(mvm, tfd_msk, 0); @@ -1974,14 +1988,32 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,  			WARN_ONCE(iwl_mvm_sf_update(mvm, vif, false),  				  "Failed to update SF upon disassociation\n"); -			/* remove AP station now that the MAC is unassoc */ -			ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); -			if (ret) -				IWL_ERR(mvm, "failed to remove AP station\n"); +			/* +			 * If we get an assert during the connection (after the +			 * station has been added, but before the vif is set +			 * to associated), mac80211 will re-add the station and +			 * then configure the vif. Since the vif is not +			 * associated, we would remove the station here and +			 * this would fail the recovery. +			 */ +			if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, +				      &mvm->status)) { +				/* +				 * Remove AP station now that +				 * the MAC is unassoc +				 */ +				ret = iwl_mvm_rm_sta_id(mvm, vif, +							mvmvif->ap_sta_id); +				if (ret) +					IWL_ERR(mvm, +						"failed to remove AP station\n"); + +				if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) +					mvm->d0i3_ap_sta_id = +						IWL_MVM_INVALID_STA; +				mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; +			} -			if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) -				mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; -			mvmvif->ap_sta_id = IWL_MVM_INVALID_STA;  			/* remove quota for this interface */  			ret = iwl_mvm_update_quotas(mvm, false, NULL);  			if (ret) @@ -2381,7 +2413,7 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,  		__set_bit(tid_data->txq_id, &txqs); -		if (iwl_mvm_tid_queued(tid_data) == 0) +		if (iwl_mvm_tid_queued(mvm, tid_data) == 0)  			continue;  		__set_bit(tid, &tids); @@ -2856,7 +2888,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  	int ret;  	u8 key_offset; -	if (iwlwifi_mod_params.sw_crypto) { +	if (iwlwifi_mod_params.swcrypto) {  		IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");  		return -EOPNOTSUPP;  	} @@ -2869,7 +2901,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  	case WLAN_CIPHER_SUITE_CCMP:  	case WLAN_CIPHER_SUITE_GCMP:  	case WLAN_CIPHER_SUITE_GCMP_256: -		key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; +		if (!iwl_mvm_has_new_tx_api(mvm)) +			key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;  		break;  	case WLAN_CIPHER_SUITE_AES_CMAC:  	case WLAN_CIPHER_SUITE_BIP_GMAC_128: @@ -2915,8 +2948,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,  				ret = -EOPNOTSUPP;  			else  				ret = 0; -			key->hw_key_idx = STA_KEY_IDX_INVALID; -			break; + +			if (key->cipher != WLAN_CIPHER_SUITE_GCMP && +			    key->cipher != WLAN_CIPHER_SUITE_GCMP_256 && +			    !iwl_mvm_has_new_tx_api(mvm)) { +				key->hw_key_idx = STA_KEY_IDX_INVALID; +				break; +			}  		}  		/* During FW restart, in order to restore the state as it was, @@ -3717,6 +3755,13 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,  	return ret;  } +static int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw) +{ +	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + +	return mvm->ibss_manager; +} +  static int iwl_mvm_set_tim(struct ieee80211_hw *hw,  			   struct ieee80211_sta *sta,  			   bool set) @@ -3988,21 +4033,23 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,  		/* make sure only TDLS peers or the AP are flushed */  		WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls); -		msk |= mvmsta->tfd_queue_msk; +		if (drop) { +			if (iwl_mvm_flush_sta(mvm, mvmsta, false, 0)) +				IWL_ERR(mvm, "flush request fail\n"); +		} else { +			msk |= mvmsta->tfd_queue_msk; +			if (iwl_mvm_has_new_tx_api(mvm)) +				iwl_mvm_wait_sta_queues_empty(mvm, mvmsta); +		}  	} -	if (drop) { -		if (iwl_mvm_flush_tx_path(mvm, msk, 0)) -			IWL_ERR(mvm, "flush request fail\n"); -		mutex_unlock(&mvm->mutex); -	} else { -		mutex_unlock(&mvm->mutex); +	mutex_unlock(&mvm->mutex); -		/* this can take a while, and we may need/want other operations -		 * to succeed while doing this, so do it without the mutex held -		 */ +	/* this can take a while, and we may need/want other operations +	 * to succeed while doing this, so do it without the mutex held +	 */ +	if (!drop && !iwl_mvm_has_new_tx_api(mvm))  		iwl_trans_wait_tx_queues_empty(mvm->trans, msk); -	}  }  static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx, @@ -4023,7 +4070,7 @@ static int iwl_mvm_mac_get_survey(struct ieee80211_hw *hw, int idx,  	mutex_lock(&mvm->mutex); -	if (mvm->ucode_loaded) { +	if (iwl_mvm_firmware_running(mvm)) {  		ret = iwl_mvm_request_statistics(mvm, false);  		if (ret)  			goto out; @@ -4104,11 +4151,11 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,  					struct ieee80211_vif *vif,  					const struct ieee80211_event *event)  { -#define CHECK_MLME_TRIGGER(_mvm, _trig, _buf, _cnt, _fmt...)	\ +#define CHECK_MLME_TRIGGER(_cnt, _fmt...)			\  	do {							\ -		if ((_cnt) && --(_cnt))				\ +		if ((trig_mlme->_cnt) && --(trig_mlme->_cnt))	\  			break;					\ -		iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt);\ +		iwl_mvm_fw_dbg_collect_trig(mvm, trig, _fmt);	\  	} while (0)  	struct iwl_fw_dbg_trigger_tlv *trig; @@ -4124,31 +4171,25 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm,  	if (event->u.mlme.data == ASSOC_EVENT) {  		if (event->u.mlme.status == MLME_DENIED) -			CHECK_MLME_TRIGGER(mvm, trig, buf, -					   trig_mlme->stop_assoc_denied, +			CHECK_MLME_TRIGGER(stop_assoc_denied,  					   "DENIED ASSOC: reason %d",  					    event->u.mlme.reason);  		else if (event->u.mlme.status == MLME_TIMEOUT) -			CHECK_MLME_TRIGGER(mvm, trig, buf, -					   trig_mlme->stop_assoc_timeout, +			CHECK_MLME_TRIGGER(stop_assoc_timeout,  					   "ASSOC TIMEOUT");  	} else if (event->u.mlme.data == AUTH_EVENT) {  		if (event->u.mlme.status == MLME_DENIED) -			CHECK_MLME_TRIGGER(mvm, trig, buf, -					   trig_mlme->stop_auth_denied, +			CHECK_MLME_TRIGGER(stop_auth_denied,  					   "DENIED AUTH: reason %d",  					   event->u.mlme.reason);  		else if (event->u.mlme.status == MLME_TIMEOUT) -			CHECK_MLME_TRIGGER(mvm, trig, buf, -					   trig_mlme->stop_auth_timeout, +			CHECK_MLME_TRIGGER(stop_auth_timeout,  					   "AUTH TIMEOUT");  	} else if (event->u.mlme.data == DEAUTH_RX_EVENT) { -		CHECK_MLME_TRIGGER(mvm, trig, buf, -				   trig_mlme->stop_rx_deauth, +		CHECK_MLME_TRIGGER(stop_rx_deauth,  				   "DEAUTH RX %d", event->u.mlme.reason);  	} else if (event->u.mlme.data == DEAUTH_TX_EVENT) { -		CHECK_MLME_TRIGGER(mvm, trig, buf, -				   trig_mlme->stop_tx_deauth, +		CHECK_MLME_TRIGGER(stop_tx_deauth,  				   "DEAUTH TX %d", event->u.mlme.reason);  	}  #undef CHECK_MLME_TRIGGER @@ -4248,11 +4289,13 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,  		goto out;  	} -	if (notif->sync) +	if (notif->sync) {  		ret = wait_event_timeout(mvm->rx_sync_waitq, -					 atomic_read(&mvm->queue_sync_counter) == 0, +					 atomic_read(&mvm->queue_sync_counter) == 0 || +					 iwl_mvm_is_radio_killed(mvm),  					 HZ); -	WARN_ON_ONCE(!ret); +		WARN_ON_ONCE(!ret && !iwl_mvm_is_radio_killed(mvm)); +	}  out:  	atomic_set(&mvm->queue_sync_counter, 0); @@ -4316,6 +4359,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = {  	.join_ibss = iwl_mvm_start_ap_ibss,  	.leave_ibss = iwl_mvm_stop_ap_ibss, +	.tx_last_beacon = iwl_mvm_tx_last_beacon, +  	.set_tim = iwl_mvm_set_tim,  	.channel_switch = iwl_mvm_channel_switch, | 
