summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
diff options
context:
space:
mode:
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>2014-05-25 17:24:22 +0300
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-07-07 21:41:21 +0300
commit003e5236a1fcab3fc4576fe643e31a3d83027256 (patch)
treea02e051c9e0833c8e4112df7ab6503b9964a1366 /drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
parent7f0a7c671cdc0396f99b60b77bd02e2dee7c4838 (diff)
downloadlinux-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.c25
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;
}