diff options
author | Luciano Coelho <luciano.coelho@intel.com> | 2014-11-10 04:10:14 -0500 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-11-24 01:30:31 -0500 |
commit | dc88b4baa9d16fdf15f76b6277461e6d9e4eb8e6 (patch) | |
tree | 8b5f98f7c7bbeb80d5fff39f2d048bf4a991c51b /drivers/net | |
parent | 4741dd049a27fa6490e502d42ff51417c58ac7cd (diff) |
iwlwifi: mvm: add CSA absent time event for clients
Add an absent time event when pre_channel_switch is called and use the
time event started indication to set the disable_tx bit instead of
doing it in unassign_vif(). This is done so that the firmware queues
are stopped before the actual switch takes place to avoid losing
packets while the AP/GO is performing its actual switch.
Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 19 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 27 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/time-event.c | 37 |
5 files changed, 81 insertions, 18 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index fdeaab3457a3..ac1cef6a6b03 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -2891,7 +2891,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
2891 | { | 2891 | { |
2892 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 2892 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
2893 | struct ieee80211_vif *disabled_vif = NULL; | 2893 | struct ieee80211_vif *disabled_vif = NULL; |
2894 | struct iwl_mvm_sta *mvmsta; | ||
2895 | 2894 | ||
2896 | lockdep_assert_held(&mvm->mutex); | 2895 | lockdep_assert_held(&mvm->mutex); |
2897 | 2896 | ||
@@ -2925,12 +2924,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
2925 | 2924 | ||
2926 | disabled_vif = vif; | 2925 | disabled_vif = vif; |
2927 | 2926 | ||
2928 | mvmsta = iwl_mvm_sta_from_staid_protected(mvm, | ||
2929 | mvmvif->ap_sta_id); | ||
2930 | |||
2931 | if (!WARN_ON(!mvmsta)) | ||
2932 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); | ||
2933 | |||
2934 | iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); | 2927 | iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL); |
2935 | break; | 2928 | break; |
2936 | default: | 2929 | default: |
@@ -3167,6 +3160,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, | |||
3167 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3160 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
3168 | struct ieee80211_vif *csa_vif; | 3161 | struct ieee80211_vif *csa_vif; |
3169 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 3162 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
3163 | u32 apply_time; | ||
3170 | int ret; | 3164 | int ret; |
3171 | 3165 | ||
3172 | mutex_lock(&mvm->mutex); | 3166 | mutex_lock(&mvm->mutex); |
@@ -3194,6 +3188,17 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, | |||
3194 | } | 3188 | } |
3195 | 3189 | ||
3196 | break; | 3190 | break; |
3191 | case NL80211_IFTYPE_STATION: | ||
3192 | apply_time = chsw->timestamp + | ||
3193 | (vif->bss_conf.beacon_int * chsw->count * 1024); | ||
3194 | |||
3195 | if (chsw->block_tx) | ||
3196 | iwl_mvm_csa_client_absent(mvm, vif); | ||
3197 | |||
3198 | iwl_mvm_schedule_csa_period(mvm, vif, | ||
3199 | IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT, | ||
3200 | apply_time); | ||
3201 | break; | ||
3197 | default: | 3202 | default: |
3198 | break; | 3203 | break; |
3199 | } | 3204 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2c54c522b8c6..2816c6b9222b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -87,11 +87,12 @@ | |||
87 | /* A TimeUnit is 1024 microsecond */ | 87 | /* A TimeUnit is 1024 microsecond */ |
88 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 88 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
89 | 89 | ||
90 | /* This value represents the number of TUs before CSA "beacon 0" TBTT | 90 | /* These values represent the number of TUs before CSA "beacon 0" TBTT |
91 | * when the CSA time-event needs to be scheduled to start. It must be | 91 | * when the CSA time-event needs to be scheduled to start. They must |
92 | * big enough to ensure that we switch in time. | 92 | * be big enough to ensure that we switch in time. |
93 | */ | 93 | */ |
94 | #define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 | 94 | #define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40 |
95 | #define IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT 110 | ||
95 | 96 | ||
96 | /* | 97 | /* |
97 | * This value (in TUs) is used to fine tune the CSA NoA end time which should | 98 | * This value (in TUs) is used to fine tune the CSA NoA end time which should |
@@ -797,6 +798,26 @@ static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm) | |||
797 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); | 798 | test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status); |
798 | } | 799 | } |
799 | 800 | ||
801 | /* Must be called with rcu_read_lock() held and it can only be | ||
802 | * released when mvmsta is not needed anymore. | ||
803 | */ | ||
804 | static inline struct iwl_mvm_sta * | ||
805 | iwl_mvm_sta_from_staid_rcu(struct iwl_mvm *mvm, u8 sta_id) | ||
806 | { | ||
807 | struct ieee80211_sta *sta; | ||
808 | |||
809 | if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id)) | ||
810 | return NULL; | ||
811 | |||
812 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
813 | |||
814 | /* This can happen if the station has been removed right now */ | ||
815 | if (IS_ERR_OR_NULL(sta)) | ||
816 | return NULL; | ||
817 | |||
818 | return iwl_mvm_sta_from_mac80211(sta); | ||
819 | } | ||
820 | |||
800 | static inline struct iwl_mvm_sta * | 821 | static inline struct iwl_mvm_sta * |
801 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) | 822 | iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id) |
802 | { | 823 | { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index a38f1f151ff5..d86fe432e51f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -1732,3 +1732,18 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, | |||
1732 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); | 1732 | iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable); |
1733 | } | 1733 | } |
1734 | } | 1734 | } |
1735 | |||
1736 | void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | ||
1737 | { | ||
1738 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
1739 | struct iwl_mvm_sta *mvmsta; | ||
1740 | |||
1741 | rcu_read_lock(); | ||
1742 | |||
1743 | mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id); | ||
1744 | |||
1745 | if (!WARN_ON(!mvmsta)) | ||
1746 | iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true); | ||
1747 | |||
1748 | rcu_read_unlock(); | ||
1749 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 2c869bcb9490..d8f48975ad08 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -422,5 +422,6 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, | |||
422 | void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, | 422 | void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm, |
423 | struct iwl_mvm_vif *mvmvif, | 423 | struct iwl_mvm_vif *mvmvif, |
424 | bool disable); | 424 | bool disable); |
425 | void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif); | ||
425 | 426 | ||
426 | #endif /* __sta_h__ */ | 427 | #endif /* __sta_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 8cf246b695c4..1a537be216ce 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -191,6 +191,33 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, | |||
191 | return true; | 191 | return true; |
192 | } | 192 | } |
193 | 193 | ||
194 | static void | ||
195 | iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, | ||
196 | struct iwl_mvm_time_event_data *te_data, | ||
197 | struct iwl_time_event_notif *notif) | ||
198 | { | ||
199 | if (!le32_to_cpu(notif->status)) { | ||
200 | IWL_DEBUG_TE(mvm, "CSA time event failed to start\n"); | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | switch (te_data->vif->type) { | ||
205 | case NL80211_IFTYPE_AP: | ||
206 | iwl_mvm_csa_noa_start(mvm); | ||
207 | break; | ||
208 | case NL80211_IFTYPE_STATION: | ||
209 | iwl_mvm_csa_client_absent(mvm, te_data->vif); | ||
210 | break; | ||
211 | default: | ||
212 | /* should never happen */ | ||
213 | WARN_ON_ONCE(1); | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | /* we don't need it anymore */ | ||
218 | iwl_mvm_te_clear_data(mvm, te_data); | ||
219 | } | ||
220 | |||
194 | /* | 221 | /* |
195 | * Handles a FW notification for an event that is known to the driver. | 222 | * Handles a FW notification for an event that is known to the driver. |
196 | * | 223 | * |
@@ -252,14 +279,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
252 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); | 279 | set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); |
253 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); | 280 | iwl_mvm_ref(mvm, IWL_MVM_REF_ROC); |
254 | ieee80211_ready_on_channel(mvm->hw); | 281 | ieee80211_ready_on_channel(mvm->hw); |
255 | } else if (te_data->vif->type == NL80211_IFTYPE_AP) { | 282 | } else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) { |
256 | if (le32_to_cpu(notif->status)) | 283 | iwl_mvm_te_handle_notify_csa(mvm, te_data, notif); |
257 | iwl_mvm_csa_noa_start(mvm); | ||
258 | else | ||
259 | IWL_DEBUG_TE(mvm, "CSA NOA failed to start\n"); | ||
260 | |||
261 | /* we don't need it anymore */ | ||
262 | iwl_mvm_te_clear_data(mvm, te_data); | ||
263 | } | 284 | } |
264 | } else { | 285 | } else { |
265 | IWL_WARN(mvm, "Got TE with unknown action\n"); | 286 | IWL_WARN(mvm, "Got TE with unknown action\n"); |