From: Johannes Berg Move the variable inside the CONFIG_CFG80211_REG_CELLULAR_HINTS block where it's actually used, and add a small helper to change it to avoid a warning from clang that it's set but not used. Signed-off-by: Johannes Berg --- net/wireless/reg.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 50f50e768f01..87eb581aee34 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -104,13 +104,6 @@ static struct faux_device *reg_fdev; */ const struct ieee80211_regdomain __rcu *cfg80211_regdomain; -/* - * Number of devices that registered to the core - * that support cellular base station regulatory hints - * (protected by cfg80211_mutex) - */ -static int reg_num_devs_support_basehint; - /* * State variable indicating if the platform on which the devices * are attached is operating in an indoor environment. The state variable @@ -2053,6 +2046,13 @@ bool reg_last_request_cell_base(void) } #ifdef CONFIG_CFG80211_REG_CELLULAR_HINTS +/* + * Number of devices that registered to the core + * that support cellular base station regulatory hints + * (protected by cfg80211_mutex) + */ +static int reg_num_devs_support_basehint; + /* Core specific check */ static enum reg_request_treatment reg_ignore_cell_hint(struct regulatory_request *pending_request) @@ -2074,6 +2074,12 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) { return !(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS); } + +static void reg_update_cell_hint_num(struct wiphy *wiphy, int delta) +{ + if (!reg_dev_ignore_cell_hint(wiphy)) + reg_num_devs_support_basehint += delta; +} #else static enum reg_request_treatment reg_ignore_cell_hint(struct regulatory_request *pending_request) @@ -2085,6 +2091,10 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) { return true; } + +static void reg_update_cell_hint_num(struct wiphy *wiphy, int delta) +{ +} #endif static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) @@ -4179,7 +4189,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy) } if (!reg_dev_ignore_cell_hint(wiphy)) - reg_num_devs_support_basehint++; + reg_update_cell_hint_num(wiphy, 1); wiphy_update_regulatory(wiphy, lr->initiator); wiphy_all_share_dfs_chan_state(wiphy); @@ -4197,8 +4207,7 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy) lr = get_last_request(); - if (!reg_dev_ignore_cell_hint(wiphy)) - reg_num_devs_support_basehint--; + reg_update_cell_hint_num(wiphy, -1); rcu_free_regdom(get_wiphy_regdom(wiphy)); RCU_INIT_POINTER(wiphy->regd, NULL); -- 2.56.0 From: Johannes Berg This order is going to become required, since userspace can query the regulatory in the window between the two registrations. Signed-off-by: Johannes Berg --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index d9c84d5ce254..139f67adead7 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -1231,13 +1231,18 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) sizeof(wiphy->fw_version)); wiphy->hw_version = hw_info->hw_version; + if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { + ret = regulatory_set_wiphy_regd(wiphy, mac->rd); + if (ret < 0) + goto out; + } + ret = wiphy_register(wiphy); if (ret < 0) goto out; - if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) - ret = regulatory_set_wiphy_regd(wiphy, mac->rd); - else if (regdomain_is_known) + if (regdomain_is_known && + !(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)) ret = regulatory_hint(wiphy, mac->rd->alpha2); out: -- 2.56.0 From: Johannes Berg This order is going to become required, since userspace can query the regulatory in the window between the two registrations. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath11k/mac.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 1a237adaa37d..04acd526a3ab 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -10649,6 +10649,13 @@ static int __ath11k_mac_register(struct ath11k *ar) ab->hw_params.bios_sar_capa) ar->hw->wiphy->sar_capa = ab->hw_params.bios_sar_capa; + /* Apply the regd received during initialization. */ + ret = ath11k_regd_update(ar); + if (ret) { + ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret); + goto err_free_if_combs; + } + ret = ieee80211_register_hw(ar->hw); if (ret) { ath11k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); @@ -10663,13 +10670,6 @@ static int __ath11k_mac_register(struct ath11k *ar) */ ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); - /* Apply the regd received during initialization */ - ret = ath11k_regd_update(ar); - if (ret) { - ath11k_err(ar->ab, "ath11k regd update failed: %d\n", ret); - goto err_unregister_hw; - } - if (ab->hw_params.current_cc_support && ab->new_alpha2[0]) { memcpy(&ar->alpha2, ab->new_alpha2, 2); ret = ath11k_reg_set_cc(ar); -- 2.56.0 From: Johannes Berg This order is going to become required, since userspace can query the regulatory in the window between the two registrations. Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath12k/mac.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 01f8c6572f65..2b52f76cff10 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -15094,6 +15094,14 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) for_each_ar(ah, ar, i) complete_all(&ar->regd_update_completed); + for_each_ar(ah, ar, i) { + ret = ath12k_regd_update(ar, true); + if (ret) { + ath12k_err(ar->ab, "ath12k regd update failed: %d\n", ret); + goto err_cleanup_if_combs; + } + } + ret = ieee80211_register_hw(hw); if (ret) { ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); @@ -15111,13 +15119,6 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) for_each_ar(ah, ar, i) { struct ath12k_base *this_ab = ar->ab; - /* Apply the regd received during initialization */ - ret = ath12k_regd_update(ar, true); - if (ret) { - ath12k_err(this_ab, "ath12k regd update failed: %d\n", ret); - goto err_unregister_hw; - } - if (this_ab->hw_params->current_cc_support) { struct wmi_set_current_country_arg current_cc = {}; struct ieee80211_regdomain *default_regd; @@ -15158,12 +15159,6 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) return 0; -err_unregister_hw: - for_each_ar(ah, ar, i) - ath12k_debugfs_unregister(ar); - - ieee80211_unregister_hw(hw); - err_cleanup_if_combs: ath12k_mac_cleanup_iface_combinations(ah); -- 2.56.0 From: Johannes Berg This reverts commit f81aa834bfa9 ("wifi: iwlwifi: mld: Move regulatory domain initialization"), a custom regdomain must be registered before the wiphy is, otherwise a warning in nl80211 can be hit if userspace queries quickly enough. Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mld/fw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index c33a553488ee..92e519bbc977 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -347,6 +347,10 @@ int iwl_mld_load_fw(struct iwl_mld *mld) if (ret) goto err; + ret = iwl_mld_init_mcc(mld); + if (ret) + goto err; + mld->fw_status.running = true; return 0; @@ -544,10 +548,6 @@ int iwl_mld_start_fw(struct iwl_mld *mld) if (ret) goto error; - ret = iwl_mld_init_mcc(mld); - if (ret) - goto error; - iwl_mld_tx_gp2_start(mld); return 0; -- 2.56.0 From: Johannes Berg Setting the driver's self-managed regulatory domain is currently applied immediately, even if the wiphy isn't actually ever registered, and (for some broken drivers like iwlmld) might not update channels correctly since the regdomain is set before the channels are linked to the wiphy. Regardless of broken drivers though, it doesn't really make sense to apply the regdomain on the spot, if the wiphy never registers we don't need to do this work, nor does it make sense to send a regdomain event for a wiphy userspace doesn't know about. Change it so that a regdomain set before the wiphy is registered doesn't cause any action yet and is just remembered and then apply it correctly when the wiphy is registered. Also WARN if a driver registers a self-managed wiphy without a regdomain, that just leads to confusion in userspace, and a later WARN in nl80211 can be hit if it queries for it quickly enough. Due to locking changes this also removes processing of self-managed hints for all wiphys when one registers, but that never really made much sense anyway. Reviewed-by: Miriam Rachel Korenblit Signed-off-by: Johannes Berg --- net/wireless/core.c | 5 ++++- net/wireless/reg.c | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/net/wireless/core.c b/net/wireless/core.c index f4153c249599..9d586a3e2b44 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1259,10 +1259,13 @@ int wiphy_register(struct wiphy *wiphy) rdev->wiphy.registered = true; nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); - wiphy_unlock(&rdev->wiphy); /* set up regulatory info */ wiphy_regulatory_register(wiphy); + /* TODO: make this a hard failure when drivers are fixed? */ + WARN_ON(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && + !get_wiphy_regdom(wiphy)); + wiphy_unlock(&rdev->wiphy); if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) { struct regulatory_request request = { diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 87eb581aee34..2ac6a0f312ad 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3235,6 +3235,10 @@ static void reg_process_self_managed_hint(struct wiphy *wiphy) lockdep_assert_wiphy(wiphy); + /* not registered yet, apply later during registration */ + if (!rdev->wiphy.registered) + return; + spin_lock(®_requests_lock); regd = rdev->requested_regd; rdev->requested_regd = NULL; @@ -4144,7 +4148,8 @@ int regulatory_set_wiphy_regd(struct wiphy *wiphy, if (ret) return ret; - schedule_work(®_work); + if (wiphy->registered) + schedule_work(®_work); return 0; } EXPORT_SYMBOL(regulatory_set_wiphy_regd); @@ -4172,30 +4177,28 @@ void wiphy_regulatory_register(struct wiphy *wiphy) struct regulatory_request *lr = get_last_request(); lockdep_assert_held(&cfg80211_mutex); + lockdep_assert_wiphy(wiphy); - scoped_guard(wiphy, wiphy) { - /* self-managed devices ignore beacon hints and country IE */ - if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { - wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | - REGULATORY_COUNTRY_IE_IGNORE; + /* self-managed devices ignore beacon hints and country IE */ + if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | + REGULATORY_COUNTRY_IE_IGNORE; - /* - * The last request may have been received before this - * registration call. Call the driver notifier if - * initiator is USER. - */ - if (lr->initiator == NL80211_REGDOM_SET_BY_USER) - reg_call_notifier(wiphy, lr); - } - - if (!reg_dev_ignore_cell_hint(wiphy)) - reg_update_cell_hint_num(wiphy, 1); - - wiphy_update_regulatory(wiphy, lr->initiator); - wiphy_all_share_dfs_chan_state(wiphy); + /* + * The last request may have been received before this + * registration call. Call the driver notifier if + * initiator is USER. + */ + if (lr->initiator == NL80211_REGDOM_SET_BY_USER) + reg_call_notifier(wiphy, lr); } - reg_process_self_managed_hints(); + if (!reg_dev_ignore_cell_hint(wiphy)) + reg_update_cell_hint_num(wiphy, 1); + + wiphy_update_regulatory(wiphy, lr->initiator); + wiphy_all_share_dfs_chan_state(wiphy); + reg_process_self_managed_hint(wiphy); } void wiphy_regulatory_deregister(struct wiphy *wiphy) -- 2.56.0