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>
This commit is contained in:
parent
4741dd049a
commit
dc88b4baa9
|
@ -2891,7 +2891,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct ieee80211_vif *disabled_vif = NULL;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
|
@ -2925,12 +2924,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
|
||||
disabled_vif = vif;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
|
||||
mvmvif->ap_sta_id);
|
||||
|
||||
if (!WARN_ON(!mvmsta))
|
||||
iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
|
||||
|
||||
iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
|
||||
break;
|
||||
default:
|
||||
|
@ -3167,6 +3160,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
|||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
struct ieee80211_vif *csa_vif;
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
u32 apply_time;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
@ -3194,6 +3188,17 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
|||
}
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
apply_time = chsw->timestamp +
|
||||
(vif->bss_conf.beacon_int * chsw->count * 1024);
|
||||
|
||||
if (chsw->block_tx)
|
||||
iwl_mvm_csa_client_absent(mvm, vif);
|
||||
|
||||
iwl_mvm_schedule_csa_period(mvm, vif,
|
||||
IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT,
|
||||
apply_time);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -87,11 +87,12 @@
|
|||
/* A TimeUnit is 1024 microsecond */
|
||||
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
|
||||
|
||||
/* This value represents the number of TUs before CSA "beacon 0" TBTT
|
||||
* when the CSA time-event needs to be scheduled to start. It must be
|
||||
* big enough to ensure that we switch in time.
|
||||
/* These values represent the number of TUs before CSA "beacon 0" TBTT
|
||||
* when the CSA time-event needs to be scheduled to start. They must
|
||||
* be big enough to ensure that we switch in time.
|
||||
*/
|
||||
#define IWL_MVM_CHANNEL_SWITCH_TIME_GO 40
|
||||
#define IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT 110
|
||||
|
||||
/*
|
||||
* 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)
|
|||
test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status);
|
||||
}
|
||||
|
||||
/* Must be called with rcu_read_lock() held and it can only be
|
||||
* released when mvmsta is not needed anymore.
|
||||
*/
|
||||
static inline struct iwl_mvm_sta *
|
||||
iwl_mvm_sta_from_staid_rcu(struct iwl_mvm *mvm, u8 sta_id)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
|
||||
if (sta_id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))
|
||||
return NULL;
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
|
||||
/* This can happen if the station has been removed right now */
|
||||
if (IS_ERR_OR_NULL(sta))
|
||||
return NULL;
|
||||
|
||||
return iwl_mvm_sta_from_mac80211(sta);
|
||||
}
|
||||
|
||||
static inline struct iwl_mvm_sta *
|
||||
iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id)
|
||||
{
|
||||
|
|
|
@ -1732,3 +1732,18 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
|
|||
iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, disable);
|
||||
}
|
||||
}
|
||||
|
||||
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, mvmvif->ap_sta_id);
|
||||
|
||||
if (!WARN_ON(!mvmsta))
|
||||
iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -422,5 +422,6 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
|
|||
void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_vif *mvmvif,
|
||||
bool disable);
|
||||
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
|
||||
#endif /* __sta_h__ */
|
||||
|
|
|
@ -191,6 +191,33 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_time_event_data *te_data,
|
||||
struct iwl_time_event_notif *notif)
|
||||
{
|
||||
if (!le32_to_cpu(notif->status)) {
|
||||
IWL_DEBUG_TE(mvm, "CSA time event failed to start\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (te_data->vif->type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
iwl_mvm_csa_noa_start(mvm);
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
iwl_mvm_csa_client_absent(mvm, te_data->vif);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
WARN_ON_ONCE(1);
|
||||
break;
|
||||
}
|
||||
|
||||
/* we don't need it anymore */
|
||||
iwl_mvm_te_clear_data(mvm, te_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles a FW notification for an event that is known to the driver.
|
||||
*
|
||||
|
@ -252,14 +279,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
|
|||
set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status);
|
||||
iwl_mvm_ref(mvm, IWL_MVM_REF_ROC);
|
||||
ieee80211_ready_on_channel(mvm->hw);
|
||||
} else if (te_data->vif->type == NL80211_IFTYPE_AP) {
|
||||
if (le32_to_cpu(notif->status))
|
||||
iwl_mvm_csa_noa_start(mvm);
|
||||
else
|
||||
IWL_DEBUG_TE(mvm, "CSA NOA failed to start\n");
|
||||
|
||||
/* we don't need it anymore */
|
||||
iwl_mvm_te_clear_data(mvm, te_data);
|
||||
} else if (te_data->id == TE_CHANNEL_SWITCH_PERIOD) {
|
||||
iwl_mvm_te_handle_notify_csa(mvm, te_data, notif);
|
||||
}
|
||||
} else {
|
||||
IWL_WARN(mvm, "Got TE with unknown action\n");
|
||||
|
|
Loading…
Reference in New Issue