Skip to content

Commit 3b087c2

Browse files
Sriram Rgregkh
authored andcommitted
ath11k: Avoid race during regd updates
[ Upstream commit 1db2b0d ] Whenever ath11k is bootup with a user country already set, cfg80211 notifies this country info to ath11k soon after registration, where the notification is sent to the firmware for fetching the rules of this user country input. Multiple race conditions could be seen in this scenario where a new request is either lost as pointed in [1] or a new regd overwrites the default regd provided by the firmware during bootup. Note that, the default regd is used for intersection purpose and hence it should not be overwritten. The main reason as pointed by [1] is the usage of ATH11K_FLAG_REGISTERED flag which is updated after completion of core registration, whereas the reg notification from cfg80211 and wmi events for the corresponding request can happen much before that. Since the ATH11K_FLAG_REGISTERED is currently used to determine if the event containing reg rules belong to default regd or for user request, there is a possibility of the default regd getting overwritten. Since the default reg rules will be received only once per pdev on firmware load, the above flag based check can be replaced with a check to see if default_regd is already set, so that we can now always update the new_regd. Also if the new_regd is set, this will be always used to update the reg rules for the registered phy. [1] https://patchwork.kernel.org/project/linux-wireless/patch/1829665.1PRlr7bOQj@ripper/ Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01460-QCAHKSWPL_SILICONZ-1 Fixes: d5c6515 ("ath11k: driver for Qualcomm IEEE 802.11ax devices") Signed-off-by: Sriram R <srirrama@codeaurora.org> Signed-off-by: Jouni Malinen <jouni@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/20210721212029.142388-4-jouni@codeaurora.org Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 9b59c76 commit 3b087c2

4 files changed

Lines changed: 14 additions & 17 deletions

File tree

drivers/net/wireless/ath/ath11k/mac.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6590,7 +6590,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
65906590
ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
65916591

65926592
/* Apply the regd received during initialization */
6593-
ret = ath11k_regd_update(ar, true);
6593+
ret = ath11k_regd_update(ar);
65946594
if (ret) {
65956595
ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret);
65966596
goto err_unregister_hw;

drivers/net/wireless/ath/ath11k/reg.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static void ath11k_copy_regd(struct ieee80211_regdomain *regd_orig,
198198
sizeof(struct ieee80211_reg_rule));
199199
}
200200

201-
int ath11k_regd_update(struct ath11k *ar, bool init)
201+
int ath11k_regd_update(struct ath11k *ar)
202202
{
203203
struct ieee80211_regdomain *regd, *regd_copy = NULL;
204204
int ret, regd_len, pdev_id;
@@ -209,7 +209,10 @@ int ath11k_regd_update(struct ath11k *ar, bool init)
209209

210210
spin_lock_bh(&ab->base_lock);
211211

212-
if (init) {
212+
/* Prefer the latest regd update over default if it's available */
213+
if (ab->new_regd[pdev_id]) {
214+
regd = ab->new_regd[pdev_id];
215+
} else {
213216
/* Apply the regd received during init through
214217
* WMI_REG_CHAN_LIST_CC event. In case of failure to
215218
* receive the regd, initialize with a default world
@@ -222,8 +225,6 @@ int ath11k_regd_update(struct ath11k *ar, bool init)
222225
"failed to receive default regd during init\n");
223226
regd = (struct ieee80211_regdomain *)&ath11k_world_regd;
224227
}
225-
} else {
226-
regd = ab->new_regd[pdev_id];
227228
}
228229

229230
if (!regd) {
@@ -683,7 +684,7 @@ void ath11k_regd_update_work(struct work_struct *work)
683684
regd_update_work);
684685
int ret;
685686

686-
ret = ath11k_regd_update(ar, false);
687+
ret = ath11k_regd_update(ar);
687688
if (ret) {
688689
/* Firmware has already moved to the new regd. We need
689690
* to maintain channel consistency across FW, Host driver

drivers/net/wireless/ath/ath11k/reg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ void ath11k_regd_update_work(struct work_struct *work);
3131
struct ieee80211_regdomain *
3232
ath11k_reg_build_regd(struct ath11k_base *ab,
3333
struct cur_regulatory_info *reg_info, bool intersect);
34-
int ath11k_regd_update(struct ath11k *ar, bool init);
34+
int ath11k_regd_update(struct ath11k *ar);
3535
int ath11k_reg_update_chan_list(struct ath11k *ar);
3636
#endif

drivers/net/wireless/ath/ath11k/wmi.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5841,10 +5841,10 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
58415841
}
58425842

58435843
spin_lock(&ab->base_lock);
5844-
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
5845-
/* Once mac is registered, ar is valid and all CC events from
5846-
* fw is considered to be received due to user requests
5847-
* currently.
5844+
if (ab->default_regd[pdev_idx]) {
5845+
/* The initial rules from FW after WMI Init is to build
5846+
* the default regd. From then on, any rules updated for
5847+
* the pdev could be due to user reg changes.
58485848
* Free previously built regd before assigning the newly
58495849
* generated regd to ar. NULL pointer handling will be
58505850
* taken care by kfree itself.
@@ -5854,13 +5854,9 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk
58545854
ab->new_regd[pdev_idx] = regd;
58555855
ieee80211_queue_work(ar->hw, &ar->regd_update_work);
58565856
} else {
5857-
/* Multiple events for the same *ar is not expected. But we
5858-
* can still clear any previously stored default_regd if we
5859-
* are receiving this event for the same radio by mistake.
5860-
* NULL pointer handling will be taken care by kfree itself.
5857+
/* This regd would be applied during mac registration and is
5858+
* held constant throughout for regd intersection purpose
58615859
*/
5862-
kfree(ab->default_regd[pdev_idx]);
5863-
/* This regd would be applied during mac registration */
58645860
ab->default_regd[pdev_idx] = regd;
58655861
}
58665862
ab->dfs_region = reg_info->dfs_region;

0 commit comments

Comments
 (0)