aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath12k/reg.c31
-rw-r--r--drivers/net/wireless/ath/ath12k/reg.h8
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c33
3 files changed, 52 insertions, 20 deletions
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 3bed5f68cd6b..e3ad47532852 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -949,14 +949,10 @@ void ath12k_reg_reset_reg_info(struct ath12k_reg_info *reg_info)
}
}
-int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
- struct ath12k_reg_info *reg_info,
- enum wmi_vdev_type vdev_type,
- enum ieee80211_ap_reg_power power_type)
+enum ath12k_reg_status ath12k_reg_validate_reg_info(struct ath12k_base *ab,
+ struct ath12k_reg_info *reg_info)
{
- struct ieee80211_regdomain *regd = NULL;
- struct ath12k *ar;
- int pdev_idx;
+ int pdev_idx = reg_info->phy_id;
if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
/* In case of failure to set the requested country,
@@ -964,10 +960,9 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
* and return from here.
*/
ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");
- return 0;
+ return ATH12K_REG_STATUS_DROP;
}
- pdev_idx = reg_info->phy_id;
if (pdev_idx >= ab->num_radios) {
/* Process the event for phy0 only if single_pdev_only
* is true. If pdev_idx is valid but not 0, discard the
@@ -975,9 +970,9 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
*/
if (ab->hw_params->single_pdev_only &&
pdev_idx < ab->hw_params->num_rxdma_per_pdev)
- return 0;
+ return ATH12K_REG_STATUS_DROP;
else
- return -EINVAL;
+ return ATH12K_REG_STATUS_FALLBACK;
}
/* Avoid multiple overwrites to default regd, during core
@@ -986,7 +981,19 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
!memcmp(ab->default_regd[pdev_idx]->alpha2,
reg_info->alpha2, 2))
- return 0;
+ return ATH12K_REG_STATUS_DROP;
+
+ return ATH12K_REG_STATUS_VALID;
+}
+
+int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
+ struct ath12k_reg_info *reg_info,
+ enum wmi_vdev_type vdev_type,
+ enum ieee80211_ap_reg_power power_type)
+{
+ struct ieee80211_regdomain *regd = NULL;
+ int pdev_idx = reg_info->phy_id;
+ struct ath12k *ar;
regd = ath12k_reg_build_regd(ab, reg_info, vdev_type, power_type);
if (!regd)
diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
index 9868daf3f1e5..8af8e9ba462e 100644
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -92,6 +92,12 @@ enum ath12k_reg_phy_bitmap {
ATH12K_REG_PHY_BITMAP_NO11BE = BIT(6),
};
+enum ath12k_reg_status {
+ ATH12K_REG_STATUS_VALID,
+ ATH12K_REG_STATUS_DROP,
+ ATH12K_REG_STATUS_FALLBACK,
+};
+
void ath12k_reg_init(struct ieee80211_hw *hw);
void ath12k_reg_free(struct ath12k_base *ab);
void ath12k_regd_update_work(struct work_struct *work);
@@ -109,4 +115,6 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
enum ieee80211_ap_reg_power power_type);
enum wmi_reg_6g_ap_type
ath12k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type);
+enum ath12k_reg_status ath12k_reg_validate_reg_info(struct ath12k_base *ab,
+ struct ath12k_reg_info *reg_info);
#endif
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index be66e88fb65a..42e275762563 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6129,7 +6129,22 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
if (ret) {
ath12k_warn(ab, "failed to extract regulatory info from received event\n");
- goto fallback;
+ goto mem_free;
+ }
+
+ ret = ath12k_reg_validate_reg_info(ab, reg_info);
+ if (ret == ATH12K_REG_STATUS_FALLBACK) {
+ ath12k_warn(ab, "failed to validate reg info %d\n", ret);
+ /* firmware has successfully switches to new regd but host can not
+ * continue, so free reginfo and fallback to old regd
+ */
+ goto mem_free;
+ } else if (ret == ATH12K_REG_STATUS_DROP) {
+ /* reg info is valid but we will not store it and
+ * not going to create new regd for it
+ */
+ ret = ATH12K_REG_STATUS_VALID;
+ goto mem_free;
}
ret = ath12k_reg_handle_chan_list(ab, reg_info, WMI_VDEV_TYPE_UNSPEC,
@@ -6139,7 +6154,14 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
goto fallback;
}
- goto mem_free;
+ goto out;
+
+mem_free:
+ ath12k_reg_reset_reg_info(reg_info);
+ kfree(reg_info);
+
+ if (ret == ATH12K_REG_STATUS_VALID)
+ return ret;
fallback:
/* Fallback to older reg (by sending previous country setting
@@ -6152,12 +6174,7 @@ fallback:
/* TODO: This is rare, but still should also be handled */
WARN_ON(1);
-mem_free:
- if (reg_info) {
- ath12k_reg_reset_reg_info(reg_info);
- kfree(reg_info);
- }
-
+out:
return ret;
}