Commit 0da00e45 authored by Sriram R's avatar Sriram R Committed by Kalle Valo

wifi: ath12k: modify regulatory support for single wiphy architecture

With all the radios being combined and registered as a single
mac80211 hw/wiphy, separate regd built from firmware rules need
not be updated to cfg80211. Rather we can pick one of the regd
built from the rules to update to cfg80211 for the whole
registered device. We prefer 6 GHz pdev based rules since it has
the rules for all bands. If the hw doesn't support 6 GHz, then update
rules from one of the pdevs.

Also, when regulatory notification is received, update to all the
underlying radios/ar so that it becomes aware of the change and as
well us it updates its local regd with the new country rules. Later
pick the appropriate pdev's regd(6 GHz if available) and apply to
cfg80211.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
Signed-off-by: default avatarSriram R <quic_srirrama@quicinc.com>
Signed-off-by: default avatarRameshkumar Sundaram <quic_ramess@quicinc.com>
Acked-by: default avatarJeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240405194519.1337906-10-quic_ramess@quicinc.com
parent cec77a25
......@@ -633,6 +633,8 @@ struct ath12k {
struct ath12k_hw {
struct ieee80211_hw *hw;
bool regd_updated;
bool use_6ghz_regd;
u8 num_radio;
struct ath12k radio[] __aligned(sizeof(void *));
......
......@@ -8106,6 +8106,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
{
struct ieee80211_supported_band *band;
struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap;
struct ath12k_hw *ah = ar->ah;
void *channels;
u32 phy_id;
......@@ -8160,6 +8161,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
ath12k_mac_update_ch_list(ar, band,
reg_cap->low_5ghz_chan,
reg_cap->high_5ghz_chan);
ah->use_6ghz_regd = true;
}
if (reg_cap->low_5ghz_chan < ATH12K_MIN_6G_FREQ) {
......
......@@ -50,7 +50,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
struct ath12k_wmi_init_country_arg arg;
struct ath12k_hw *ah = ath12k_hw_to_ah(hw);
struct ath12k *ar = ath12k_ah_to_ar(ah, 0);
int ret;
int ret, i;
ath12k_dbg(ar->ab, ATH12K_DBG_REG,
"Regulatory Notification received for %s\n", wiphy_name(wiphy));
......@@ -85,10 +85,16 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
arg.cc_info.alpha2[2] = 0;
ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
if (ret)
ath12k_warn(ar->ab,
"INIT Country code set to fw failed : %d\n", ret);
/* Allow fresh updates to wiphy regd */
ah->regd_updated = false;
/* Send the reg change request to all the radios */
for_each_ar(ah, ar, i) {
ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
if (ret)
ath12k_warn(ar->ab,
"INIT Country code set to fw failed : %d\n", ret);
}
}
int ath12k_reg_update_chan_list(struct ath12k *ar)
......@@ -202,10 +208,32 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
{
struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
struct ieee80211_regdomain *regd, *regd_copy = NULL;
struct ath12k_hw *ah = ar->ah;
int ret, regd_len, pdev_id;
struct ath12k_base *ab;
int i;
ab = ar->ab;
/* If one of the radios within ah has already updated the regd for
* the wiphy, then avoid setting regd again
*/
if (ah->regd_updated)
return 0;
/* firmware provides reg rules which are similar for 2 GHz and 5 GHz
* pdev but 6 GHz pdev has superset of all rules including rules for
* all bands, we prefer 6 GHz pdev's rules to be used for setup of
* the wiphy regd.
* If 6 GHz pdev was part of the ath12k_hw, wait for the 6 GHz pdev,
* else pick the first pdev which calls this function and use its
* regd to update global hw regd.
* The regd_updated flag set at the end will not allow any further
* updates.
*/
if (ah->use_6ghz_regd && !ar->supports_6ghz)
return 0;
pdev_id = ar->pdev_idx;
spin_lock_bh(&ab->base_lock);
......@@ -258,10 +286,17 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
if (ret)
goto err;
if (ar->state == ATH12K_STATE_ON) {
ret = ath12k_reg_update_chan_list(ar);
if (ret)
goto err;
ah->regd_updated = true;
/* Apply the new regd to all the radios, this is expected to be received only once
* since we check for ah->regd_updated and allow here only once.
*/
for_each_ar(ah, ar, i) {
if (ar->state == ATH12K_STATE_ON) {
ab = ar->ab;
ret = ath12k_reg_update_chan_list(ar);
if (ret)
goto err;
}
}
return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment