mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:38:03 +00:00
wifi: iwlwifi: mvm: Block EMLSR when a p2p/softAP vif is active
When there's an active link in a non-station vif, the station vif is not allowed to enter EMLSR Note that blocking EMLSR by calling iwl_mvm_block_esr() we will schedule an exit from EMLSR worker, but the worker cannot run before the activation of the non-BSS link, as ieee80211_remain_on_channel already holds the wiphy mutex. Handle that by explicitly calling ieee80211_set_active_links() to leave EMLSR, and then doing iwl_mvm_block_esr() only for consistency and to avoid re-entering it before ready. Note that a call to ieee80211_set_active_links requires to release the mvm mutex, but that's ok since we still hold the wiphy lock. The only thing that might race here is the ESR_MODE_NOTIF, so this changes its handler to run under the wiphy lock. Signed-off-by: Yedidya Benshimol <yedidya.ben.shimol@intel.com> Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://msgid.link/20240505091420.916193759f8a.Idf3a3caf5cdc3e69c81710b7ceb57e87f2de87e4@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
eead359109
commit
a1efeb8230
@ -1243,7 +1243,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
.data[0] = &d3_cfg_cmd_data,
|
||||
.len[0] = sizeof(d3_cfg_cmd_data),
|
||||
};
|
||||
int ret, primary_link;
|
||||
int ret;
|
||||
int len __maybe_unused;
|
||||
bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
|
||||
@ -1261,18 +1261,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
if (IS_ERR_OR_NULL(vif))
|
||||
return 1;
|
||||
|
||||
primary_link = iwl_mvm_get_primary_link(vif);
|
||||
|
||||
/* leave ESR immediately, not only async with iwl_mvm_block_esr() */
|
||||
if (ieee80211_vif_is_mld(vif)) {
|
||||
ret = ieee80211_set_active_links(vif, BIT(primary_link));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
/* only additionally block for consistency and to avoid concurrency */
|
||||
iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN, primary_link);
|
||||
|
||||
set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
|
||||
|
||||
@ -1280,7 +1273,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
mvm_link = mvmvif->link[primary_link];
|
||||
mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)];
|
||||
if (WARN_ON_ONCE(!mvm_link)) {
|
||||
ret = -EINVAL;
|
||||
goto out_noreset;
|
||||
|
@ -108,6 +108,65 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
|
||||
}
|
||||
|
||||
struct iwl_mvm_esr_iter_data {
|
||||
struct ieee80211_vif *vif;
|
||||
unsigned int link_id;
|
||||
bool lift_block;
|
||||
};
|
||||
|
||||
static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_esr_iter_data *data = _data;
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int link_id;
|
||||
|
||||
if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
|
||||
return;
|
||||
|
||||
for_each_mvm_vif_valid_link(mvmvif, link_id) {
|
||||
struct iwl_mvm_vif_link_info *link_info =
|
||||
mvmvif->link[link_id];
|
||||
if (vif == data->vif && link_id == data->link_id)
|
||||
continue;
|
||||
if (link_info->active)
|
||||
data->lift_block = false;
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
unsigned int link_id, bool active)
|
||||
{
|
||||
/* An active link of a non-station vif blocks EMLSR. Upon activation
|
||||
* block EMLSR on the bss vif. Upon deactivation, check if this link
|
||||
* was the last non-station link active, and if so unblock the bss vif
|
||||
*/
|
||||
struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
|
||||
struct iwl_mvm_esr_iter_data data = {
|
||||
.vif = vif,
|
||||
.link_id = link_id,
|
||||
.lift_block = true,
|
||||
};
|
||||
|
||||
if (IS_ERR_OR_NULL(bss_vif))
|
||||
return 0;
|
||||
|
||||
if (active)
|
||||
return iwl_mvm_block_esr_sync(mvm, bss_vif,
|
||||
IWL_MVM_ESR_BLOCKED_NON_BSS);
|
||||
|
||||
ieee80211_iterate_active_interfaces(mvm->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mvm_esr_vif_iterator, &data);
|
||||
if (data.lift_block) {
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf,
|
||||
u32 changes, bool active)
|
||||
@ -924,6 +983,32 @@ void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
|
||||
}
|
||||
|
||||
int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
enum iwl_mvm_esr_state reason)
|
||||
{
|
||||
int primary_link = iwl_mvm_get_primary_link(vif);
|
||||
int ret;
|
||||
|
||||
if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif))
|
||||
return 0;
|
||||
|
||||
/* This should be called only with blocking reasons */
|
||||
if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
|
||||
return 0;
|
||||
|
||||
/* leave ESR immediately, not only async with iwl_mvm_block_esr() */
|
||||
ret = ieee80211_set_active_links(vif, BIT(primary_link));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
/* only additionally block for consistency and to avoid concurrency */
|
||||
iwl_mvm_block_esr(mvm, vif, reason, primary_link);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -4830,6 +4830,10 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
*/
|
||||
flush_work(&mvm->roc_done_wk);
|
||||
|
||||
ret = iwl_mvm_esr_non_bss_link(mvm, vif, 0, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
switch (vif->type) {
|
||||
@ -4873,9 +4877,7 @@ int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
|
||||
|
||||
IWL_DEBUG_MAC80211(mvm, "enter\n");
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
iwl_mvm_stop_roc(mvm, vif);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
IWL_DEBUG_MAC80211(mvm, "leave\n");
|
||||
return 0;
|
||||
|
@ -391,6 +391,18 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int ret;
|
||||
|
||||
/* update EMLSR mode */
|
||||
if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
|
||||
ret = iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id,
|
||||
true);
|
||||
/*
|
||||
* Don't activate this link if failed to exit EMLSR in
|
||||
* the BSS interface
|
||||
*/
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
ret = __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
@ -514,6 +526,10 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
iwl_mvm_add_link(mvm, vif, link_conf);
|
||||
}
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
/* update EMLSR mode */
|
||||
if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION)
|
||||
iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, false);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -358,6 +358,7 @@ struct iwl_mvm_vif_link_info {
|
||||
* @IWL_MVM_ESR_BLOCKED_WOWLAN: WOWLAN is preventing the enablement of EMLSR
|
||||
* @IWL_MVM_ESR_BLOCKED_TPT: block EMLSR when there is not enough traffic
|
||||
* @IWL_MVM_ESR_BLOCKED_FW: FW didn't recommended/forced exit from EMLSR
|
||||
* @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-bssid link's preventing EMLSR
|
||||
* @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons
|
||||
* @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR
|
||||
* due to low RSSI.
|
||||
@ -372,6 +373,7 @@ enum iwl_mvm_esr_state {
|
||||
IWL_MVM_ESR_BLOCKED_WOWLAN = 0x2,
|
||||
IWL_MVM_ESR_BLOCKED_TPT = 0x4,
|
||||
IWL_MVM_ESR_BLOCKED_FW = 0x8,
|
||||
IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10,
|
||||
IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000,
|
||||
IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000,
|
||||
IWL_MVM_ESR_EXIT_COEX = 0x40000,
|
||||
@ -2888,6 +2890,8 @@ bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
enum iwl_mvm_esr_state reason,
|
||||
u8 link_to_keep);
|
||||
int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
enum iwl_mvm_esr_state reason);
|
||||
void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
enum iwl_mvm_esr_state reason);
|
||||
void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
@ -2904,4 +2908,6 @@ iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
s32 link_rssi,
|
||||
bool primary);
|
||||
int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
unsigned int link_id, bool active);
|
||||
#endif /* __IWL_MVM_H__ */
|
||||
|
@ -445,7 +445,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
|
||||
struct iwl_channel_switch_error_notif),
|
||||
|
||||
RX_HANDLER_GRP(DATA_PATH_GROUP, ESR_MODE_NOTIF,
|
||||
iwl_mvm_rx_esr_mode_notif, RX_HANDLER_ASYNC_LOCKED,
|
||||
iwl_mvm_rx_esr_mode_notif,
|
||||
RX_HANDLER_ASYNC_LOCKED_WIPHY,
|
||||
struct iwl_mvm_esr_mode_notif),
|
||||
|
||||
RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF,
|
||||
|
@ -47,6 +47,10 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
|
||||
|
||||
static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct ieee80211_vif *vif = mvm->p2p_device_vif;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/*
|
||||
* Clear the ROC_RUNNING status bit.
|
||||
* This will cause the TX path to drop offchannel transmissions.
|
||||
@ -70,9 +74,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
|
||||
* not really racy.
|
||||
*/
|
||||
|
||||
if (!WARN_ON(!mvm->p2p_device_vif)) {
|
||||
struct ieee80211_vif *vif = mvm->p2p_device_vif;
|
||||
|
||||
if (!WARN_ON(!vif)) {
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
iwl_mvm_flush_sta(mvm, mvmvif->deflink.bcast_sta.sta_id,
|
||||
mvmvif->deflink.bcast_sta.tfd_queue_msk);
|
||||
@ -106,6 +108,7 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
|
||||
|
||||
if (mvm->mld_api_is_used) {
|
||||
iwl_mvm_mld_rm_aux_sta(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -115,6 +118,10 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
|
||||
if (iwl_mvm_has_new_station_api(mvm->fw))
|
||||
iwl_mvm_rm_aux_sta(mvm);
|
||||
}
|
||||
|
||||
mutex_unlock(&mvm->mutex);
|
||||
if (vif)
|
||||
iwl_mvm_esr_non_bss_link(mvm, vif, 0, false);
|
||||
}
|
||||
|
||||
void iwl_mvm_roc_done_wk(struct work_struct *wk)
|
||||
@ -122,8 +129,8 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
|
||||
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, roc_done_wk);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
/* Mutex is released inside */
|
||||
iwl_mvm_cleanup_roc(mvm);
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
|
||||
@ -1220,6 +1227,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
struct iwl_mvm_time_event_data *te_data;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) {
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
@ -1263,6 +1272,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
set_bit(vif->type == NL80211_IFTYPE_P2P_DEVICE ?
|
||||
IWL_MVM_STATUS_ROC_RUNNING : IWL_MVM_STATUS_ROC_AUX_RUNNING,
|
||||
&mvm->status);
|
||||
|
||||
/* Mutex is released inside this function */
|
||||
iwl_mvm_cleanup_roc(mvm);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user