diff options
author | Andrei Otcheretianski <andrei.otcheretianski@intel.com> | 2014-05-25 17:24:22 +0300 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-07-07 21:41:21 +0300 |
commit | 003e5236a1fcab3fc4576fe643e31a3d83027256 (patch) | |
tree | a02e051c9e0833c8e4112df7ab6503b9964a1366 /drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |
parent | 7f0a7c671cdc0396f99b60b77bd02e2dee7c4838 (diff) | |
download | linux-003e5236a1fcab3fc4576fe643e31a3d83027256.tar.bz2 |
iwlwifi: mvm: Use CS tx block bit for AP/GO
An AP/GO may perform the channel switch slightly before its stations.
This scenario may result in packet loss, since the transmission may start
before the client is actually on a new channel. In order to prevent
potential packet loss disable tx to all the stations when the channel
switch flow starts. Clear the disable_tx bit when a station is seen on a
target channel, or after IWL_MVM_CS_UNBLOCK_TX_TIMEOUT beacons on a new
channel. In addition call ieee80211_sta_block_awake in order to inform
mac80211 that the frames for this station should be buffered.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index a176d008dab1..96b9cf8137e7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -1237,6 +1237,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); 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); @@ -1267,6 +1268,30 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, 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); + } + } + return 0; } |