Currently ath11k call regulatory_set_wiphy_regd() in ath11k_regd_update() to notify the reg domain change to cfg80211, and then ath11k update the channel list to firmware by ath11k_reg_update_chan_list() immediately in ath11k_regd_update(), they are running in two threads, it leads the channel list data out of sync caused by muti-threads without synchronization. cfg80211 calculate the flags of ieee80211_channel asynchronously in its reg_work, it is calculated by the callstack below and ath11k get the flags of ieee80211_channel in another thread without synchronization for the channel list data. callstack: handle_channel_custom() handle_band_custom() reg_process_self_managed_hint() reg_process_self_managed_hints() reg_todo() ath11k_reg_update_chan_list() need to use the flags calculated by the reg_work, they are two thread and have no synchronization for the flags, then ath11k_reg_update_chan_list() maybe get the wrong flags value before the calculation finished. The correct flow is ath11k_reg_update_chan_list() should be called after the flags finished calculation by reg_work. reg_call_notifier() with initiator type NL80211_REGDOM_SET_BY_DRIVER will be called by reg_process_self_managed_hint() after the calculation finished. So change to update channel list in ath11k_reg_notifier() for initiator type NL80211_REGDOM_SET_BY_DRIVER, then the calculation of flags of ieee80211_channel has already finished and ath11k_reg_update_chan_list() will use the correct value of flags. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3 Fixes: f45cb6b29cd3 ("wifi: ath11k: avoid deadlock during regulatory update in ath11k_regd_update()") Signed-off-by: Wen Gong <quic_wgong@xxxxxxxxxxx> --- drivers/net/wireless/ath/ath11k/reg.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 6fae4e61ede7..f50740219202 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -55,6 +55,17 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) ath11k_dbg(ar->ab, ATH11K_DBG_REG, "Regulatory Notification received for %s\n", wiphy_name(wiphy)); + if ((request->initiator == NL80211_REGDOM_SET_BY_DRIVER) && + (ar->state == ATH11K_STATE_ON)) { + ath11k_dbg(ar->ab, ATH11K_DBG_REG, + "dynamically updated by driver\n"); + ret = ath11k_reg_update_chan_list(ar, true); + if (ret) + ath11k_warn(ar->ab, "failed to update channel list: %d\n", ret); + + return; + } + /* Currently supporting only General User Hints. Cell base user * hints to be handled later. * Hints from other sources like Core, Beacons are not expected for @@ -294,12 +305,6 @@ int ath11k_regd_update(struct ath11k *ar) if (ret) goto err; - if (ar->state == ATH11K_STATE_ON) { - ret = ath11k_reg_update_chan_list(ar, true); - if (ret) - goto err; - } - return 0; err: ath11k_warn(ab, "failed to perform regd update : %d\n", ret); @@ -743,6 +748,7 @@ void ath11k_regd_update_work(struct work_struct *work) void ath11k_reg_init(struct ath11k *ar) { ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; + ar->hw->wiphy->flags |= WIPHY_FLAG_NOTIFY_REGDOM_BY_DRIVER; ar->hw->wiphy->reg_notifier = ath11k_reg_notifier; } -- 2.31.1