diff options
author | Miri Korenblit <miriam.rachel.korenblit@intel.com> | 2024-03-20 08:08:58 +0200 |
---|---|---|
committer | iwlwifi publisher <> | 2024-04-17 13:41:45 +0000 |
commit | 14b63a115522a9266fb6b2175a90596237fc27e9 (patch) | |
tree | 0baa02a4f5db47a35f1462af283b415426d19a42 | |
parent | db634e35cf35223e7ff28a9cdd6c165b3fe29b32 (diff) | |
download | backport-iwlwifi-14b63a115522a9266fb6b2175a90596237fc27e9.tar.gz |
[BUGFIX] wifi: iwlwifi: mvm: leave EMLSR before activating non-BSS link
The call to 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.
Fix 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.
type=bugfix
ticket=jira:WIFI-397899
fixes=Idf3a3caf5cdc3e69c81710b7ceb57e87f2de87e4
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Change-Id: Ib56c3dec69f5d9ef1c67241be554013af8bde056
Reviewed-on: https://gerritwcs.ir.intel.com/c/iwlwifi-stack-dev/+/100195
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
tested: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM>
Tested-by: iil_jenkins iil_jenkins <EC.GER.UNIX.IIL.JENKINS@INTEL.COM>
(cherry picked from commit 549cd3b72a5b2ee34520c51e90e7b59e1fc4ced7)
Reviewed-on: https://gerritwcs.ir.intel.com/c/iwlwifi-stack-dev/+/101525
x-iwlwifi-stack-dev: a0cea6cb1d5f3bd2b1c9caae9fb43904824e6a39
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/link.c | 53 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 18 | ||||
-rw-r--r-- | versions | 2 |
8 files changed, 83 insertions, 36 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 1f6dd7cd00..b676afb6ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -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; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 0c8909f0b1..a25351a234 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -162,10 +162,8 @@ static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac, } } -static void iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - unsigned int link_id, - bool active) +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 @@ -179,20 +177,21 @@ static void iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, }; if (IS_ERR_OR_NULL(bss_vif)) - return; + return 0; - if (active) { - iwl_mvm_block_esr(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_NON_BSS, - iwl_mvm_get_primary_link(bss_vif)); - return; - } + 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) + 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, @@ -233,10 +232,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ if (!active && vif->type == NL80211_IFTYPE_STATION) iwl_mvm_stop_session_protection(mvm, vif); - - /* update EMLSR mode */ - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) - iwl_mvm_esr_non_bss_link(mvm, vif, link_id, active); } cmd.link_id = cpu_to_le32(link_info->fw_link_id); @@ -1030,6 +1025,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) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index be7574ecd5..3d06da0fd0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5051,6 +5051,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) { @@ -5094,9 +5098,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; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index be951b5c1f..91e8dabf3e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -412,6 +412,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); @@ -533,6 +545,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 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 621d65390e..a5847e02da 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2952,6 +2952,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, @@ -2968,4 +2970,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__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index cd206bc42c..a42be7d2a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -486,7 +486,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_NO_SIZE(DEBUG_LOG_MSG, iwl_mvm_rx_fw_logs, RX_HANDLER_SYNC), #endif 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, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index fa5ddb758d..3a69653fcb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -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); @@ -115,6 +117,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 +128,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 +1226,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 +1271,8 @@ cleanup_roc: 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); } @@ -2,5 +2,5 @@ BACKPORTS_VERSION="(see git)" BACKPORTED_KERNEL_VERSION="(see git)" BACKPORTED_KERNEL_NAME="iwlwifi" BACKPORTS_BUILD_TSTAMP=__DATE__ \" \" __TIME__ -BACKPORTS_GIT_TRACKED="iwlwifi-stack-public:release/core87:12047:9e52a05c" +BACKPORTS_GIT_TRACKED="iwlwifi-stack-public:release/core87:12048:a0cea6cb" BACKPORTS_BRANCH_TSTAMP="Apr 17 2024 13:11:40" |