diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 121 | 
1 files changed, 93 insertions, 28 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 8b79081d4885..8242e689ddb1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -67,6 +67,7 @@  #include "iwl-prph.h"  #include "fw-api.h"  #include "mvm.h" +#include "time-event.h"  const u8 iwl_mvm_ac_to_tx_fifo[] = {  	IWL_MVM_TX_FIFO_VO, @@ -720,11 +721,6 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,  	    !force_assoc_off) {  		u32 dtim_offs; -		/* Allow beacons to pass through as long as we are not -		 * associated, or we do not have dtim period information. -		 */ -		cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON); -  		/*  		 * The DTIM count counts down, so when it is N that means N  		 * more beacon intervals happen until the DTIM TBTT. Therefore @@ -758,6 +754,11 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,  		ctxt_sta->is_assoc = cpu_to_le32(1);  	} else {  		ctxt_sta->is_assoc = cpu_to_le32(0); + +		/* Allow beacons to pass through as long as we are not +		 * associated, or we do not have dtim period information. +		 */ +		cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);  	}  	ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); @@ -903,7 +904,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,  	struct iwl_mac_beacon_cmd beacon_cmd = {};  	struct ieee80211_tx_info *info;  	u32 beacon_skb_len; -	u32 rate; +	u32 rate, tx_flags;  	if (WARN_ON(!beacon))  		return -EINVAL; @@ -913,14 +914,17 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,  	/* TODO: for now the beacon template id is set to be the mac context id.  	 * Might be better to handle it as another resource ... */  	beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); +	info = IEEE80211_SKB_CB(beacon);  	/* Set up TX command fields */  	beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);  	beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;  	beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); -	beacon_cmd.tx.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | -					     TX_CMD_FLG_BT_DIS  | -					     TX_CMD_FLG_TSF); +	tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF; +	tx_flags |= +		iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) << +						TX_CMD_FLG_BT_PRIO_POS; +	beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);  	mvm->mgmt_last_antenna_idx =  		iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant, @@ -930,8 +934,6 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,  		cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<  			    RATE_MCS_ANT_POS); -	info = IEEE80211_SKB_CB(beacon); -  	if (info->band == IEEE80211_BAND_5GHZ || vif->p2p) {  		rate = IWL_FIRST_OFDM_RATE;  	} else { @@ -968,7 +970,7 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,  	WARN_ON(vif->type != NL80211_IFTYPE_AP &&  		vif->type != NL80211_IFTYPE_ADHOC); -	beacon = ieee80211_beacon_get(mvm->hw, vif); +	beacon = ieee80211_beacon_get_template(mvm->hw, vif, NULL);  	if (!beacon)  		return -ENOMEM; @@ -1210,31 +1212,94 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)  	return 0;  } +static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, +				   struct ieee80211_vif *csa_vif, u32 gp2) +{ +	struct iwl_mvm_vif *mvmvif = +			iwl_mvm_vif_from_mac80211(csa_vif); + +	if (!ieee80211_csa_is_complete(csa_vif)) { +		int c = ieee80211_csa_update_counter(csa_vif); + +		iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); +		if (csa_vif->p2p && +		    !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { +			u32 rel_time = (c + 1) * +				       csa_vif->bss_conf.beacon_int - +				       IWL_MVM_CHANNEL_SWITCH_TIME; +			u32 apply_time = gp2 + rel_time * 1024; + +			iwl_mvm_schedule_csa_noa(mvm, csa_vif, +						 IWL_MVM_CHANNEL_SWITCH_TIME - +						 IWL_MVM_CHANNEL_SWITCH_MARGIN, +						 apply_time); +		} +	} else if (!iwl_mvm_te_scheduled(&mvmvif->time_event_data)) { +		/* we don't have CSA NoA scheduled yet, switch now */ +		ieee80211_csa_finish(csa_vif); +		RCU_INIT_POINTER(mvm->csa_vif, NULL); +	} +} +  int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,  			    struct iwl_rx_cmd_buffer *rxb,  			    struct iwl_device_cmd *cmd)  {  	struct iwl_rx_packet *pkt = rxb_addr(rxb); -	struct iwl_beacon_notif *beacon = (void *)pkt->data; -	u16 status __maybe_unused = -		le16_to_cpu(beacon->beacon_notify_hdr.status.status); -	u32 rate __maybe_unused = -		le32_to_cpu(beacon->beacon_notify_hdr.initial_rate); +	struct iwl_mvm_tx_resp *beacon_notify_hdr; +	struct ieee80211_vif *csa_vif; +	struct ieee80211_vif *tx_blocked_vif; +	u64 tsf;  	lockdep_assert_held(&mvm->mutex); -	IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", -		     status & TX_STATUS_MSK, -		     beacon->beacon_notify_hdr.failure_frame, -		     le64_to_cpu(beacon->tsf), -		     rate); +	if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_CAPA_EXTENDED_BEACON) { +		struct iwl_extended_beacon_notif *beacon = (void *)pkt->data; -	if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { -		if (!ieee80211_csa_is_complete(mvm->csa_vif)) { -			iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif); -		} else { -			ieee80211_csa_finish(mvm->csa_vif); -			mvm->csa_vif = NULL; +		beacon_notify_hdr = &beacon->beacon_notify_hdr; +		tsf = le64_to_cpu(beacon->tsf); +		mvm->ap_last_beacon_gp2 = le32_to_cpu(beacon->gp2); +	} else { +		struct iwl_beacon_notif *beacon = (void *)pkt->data; + +		beacon_notify_hdr = &beacon->beacon_notify_hdr; +		tsf = le64_to_cpu(beacon->tsf); +	} + +	IWL_DEBUG_RX(mvm, +		     "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", +		     le16_to_cpu(beacon_notify_hdr->status.status) & +								TX_STATUS_MSK, +		     beacon_notify_hdr->failure_frame, tsf, +		     mvm->ap_last_beacon_gp2, +		     le32_to_cpu(beacon_notify_hdr->initial_rate)); + +	csa_vif = rcu_dereference_protected(mvm->csa_vif, +					    lockdep_is_held(&mvm->mutex)); +	if (unlikely(csa_vif && csa_vif->csa_active)) +		iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); + +	tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, +						lockdep_is_held(&mvm->mutex)); +	if (unlikely(tx_blocked_vif)) { +		struct iwl_mvm_vif *mvmvif = +			iwl_mvm_vif_from_mac80211(tx_blocked_vif); + +		/* +		 * The channel switch is started and we have blocked the +		 * stations. If this is the first beacon (the timeout wasn't +		 * set), set the unblock timeout, otherwise countdown +		 */ +		if (!mvm->csa_tx_block_bcn_timeout) +			mvm->csa_tx_block_bcn_timeout = +				IWL_MVM_CS_UNBLOCK_TX_TIMEOUT; +		else +			mvm->csa_tx_block_bcn_timeout--; + +		/* Check if the timeout is expired, and unblock tx */ +		if (mvm->csa_tx_block_bcn_timeout == 0) { +			iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false); +			RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);  		}  	}  | 
