--- /dev/null
+From abdd0985a36189ef2cc0e393b027276e86137ace Mon Sep 17 00:00:00 2001
+From: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Date: Tue, 11 Apr 2023 20:08:49 +0200
+Subject: [PATCH] ath11k: remove intersection support for regulatory rules
+
+Currently, regulatory rules from new country settings is intersected with
+rules from default country settings(during initialisation) in order to prevent
+users to bypass their default country settings such as power limits, channel
+flags, etc.
+
+However, the country setting in the BDF will take higher higher precendence
+and FW will protect it. Therefore, there is no need to handle intersection
+on the driver side now.
+
+Remove regulatory rules intersection logic support.
+
+Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+---
+ drivers/net/wireless/ath/ath11k/reg.c | 168 +++-----------------------
+ drivers/net/wireless/ath/ath11k/reg.h | 2 +-
+ drivers/net/wireless/ath/ath11k/wmi.c | 24 +---
+ 3 files changed, 16 insertions(+), 178 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/reg.c
++++ b/drivers/net/wireless/ath/ath11k/reg.c
+@@ -352,129 +352,6 @@ static u32 ath11k_map_fw_reg_flags(u16 r
+ return flags;
+ }
+
+-static bool
+-ath11k_reg_can_intersect(struct ieee80211_reg_rule *rule1,
+- struct ieee80211_reg_rule *rule2)
+-{
+- u32 start_freq1, end_freq1;
+- u32 start_freq2, end_freq2;
+-
+- start_freq1 = rule1->freq_range.start_freq_khz;
+- start_freq2 = rule2->freq_range.start_freq_khz;
+-
+- end_freq1 = rule1->freq_range.end_freq_khz;
+- end_freq2 = rule2->freq_range.end_freq_khz;
+-
+- if ((start_freq1 >= start_freq2 &&
+- start_freq1 < end_freq2) ||
+- (start_freq2 > start_freq1 &&
+- start_freq2 < end_freq1))
+- return true;
+-
+- /* TODO: Should we restrict intersection feasibility
+- * based on min bandwidth of the intersected region also,
+- * say the intersected rule should have a min bandwidth
+- * of 20MHz?
+- */
+-
+- return false;
+-}
+-
+-static void ath11k_reg_intersect_rules(struct ieee80211_reg_rule *rule1,
+- struct ieee80211_reg_rule *rule2,
+- struct ieee80211_reg_rule *new_rule)
+-{
+- u32 start_freq1, end_freq1;
+- u32 start_freq2, end_freq2;
+- u32 freq_diff, max_bw;
+-
+- start_freq1 = rule1->freq_range.start_freq_khz;
+- start_freq2 = rule2->freq_range.start_freq_khz;
+-
+- end_freq1 = rule1->freq_range.end_freq_khz;
+- end_freq2 = rule2->freq_range.end_freq_khz;
+-
+- new_rule->freq_range.start_freq_khz = max_t(u32, start_freq1,
+- start_freq2);
+- new_rule->freq_range.end_freq_khz = min_t(u32, end_freq1, end_freq2);
+-
+- freq_diff = new_rule->freq_range.end_freq_khz -
+- new_rule->freq_range.start_freq_khz;
+- max_bw = min_t(u32, rule1->freq_range.max_bandwidth_khz,
+- rule2->freq_range.max_bandwidth_khz);
+- new_rule->freq_range.max_bandwidth_khz = min_t(u32, max_bw, freq_diff);
+-
+- new_rule->power_rule.max_antenna_gain =
+- min_t(u32, rule1->power_rule.max_antenna_gain,
+- rule2->power_rule.max_antenna_gain);
+-
+- new_rule->power_rule.max_eirp = min_t(u32, rule1->power_rule.max_eirp,
+- rule2->power_rule.max_eirp);
+-
+- /* Use the flags of both the rules */
+- new_rule->flags = rule1->flags | rule2->flags;
+-
+- /* To be safe, lts use the max cac timeout of both rules */
+- new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms,
+- rule2->dfs_cac_ms);
+-}
+-
+-static struct ieee80211_regdomain *
+-ath11k_regd_intersect(struct ieee80211_regdomain *default_regd,
+- struct ieee80211_regdomain *curr_regd)
+-{
+- u8 num_old_regd_rules, num_curr_regd_rules, num_new_regd_rules;
+- struct ieee80211_reg_rule *old_rule, *curr_rule, *new_rule;
+- struct ieee80211_regdomain *new_regd = NULL;
+- u8 i, j, k;
+-
+- num_old_regd_rules = default_regd->n_reg_rules;
+- num_curr_regd_rules = curr_regd->n_reg_rules;
+- num_new_regd_rules = 0;
+-
+- /* Find the number of intersecting rules to allocate new regd memory */
+- for (i = 0; i < num_old_regd_rules; i++) {
+- old_rule = default_regd->reg_rules + i;
+- for (j = 0; j < num_curr_regd_rules; j++) {
+- curr_rule = curr_regd->reg_rules + j;
+-
+- if (ath11k_reg_can_intersect(old_rule, curr_rule))
+- num_new_regd_rules++;
+- }
+- }
+-
+- if (!num_new_regd_rules)
+- return NULL;
+-
+- new_regd = kzalloc(sizeof(*new_regd) + (num_new_regd_rules *
+- sizeof(struct ieee80211_reg_rule)),
+- GFP_ATOMIC);
+-
+- if (!new_regd)
+- return NULL;
+-
+- /* We set the new country and dfs region directly and only trim
+- * the freq, power, antenna gain by intersecting with the
+- * default regdomain. Also MAX of the dfs cac timeout is selected.
+- */
+- new_regd->n_reg_rules = num_new_regd_rules;
+- memcpy(new_regd->alpha2, curr_regd->alpha2, sizeof(new_regd->alpha2));
+- new_regd->dfs_region = curr_regd->dfs_region;
+- new_rule = new_regd->reg_rules;
+-
+- for (i = 0, k = 0; i < num_old_regd_rules; i++) {
+- old_rule = default_regd->reg_rules + i;
+- for (j = 0; j < num_curr_regd_rules; j++) {
+- curr_rule = curr_regd->reg_rules + j;
+-
+- if (ath11k_reg_can_intersect(old_rule, curr_rule))
+- ath11k_reg_intersect_rules(old_rule, curr_rule,
+- (new_rule + k++));
+- }
+- }
+- return new_regd;
+-}
+-
+ static const char *
+ ath11k_reg_get_regdom_str(enum nl80211_dfs_regions dfs_region)
+ {
+@@ -609,9 +486,9 @@ ath11k_reg_update_weather_radar_band(str
+
+ struct ieee80211_regdomain *
+ ath11k_reg_build_regd(struct ath11k_base *ab,
+- struct cur_regulatory_info *reg_info, bool intersect)
++ struct cur_regulatory_info *reg_info)
+ {
+- struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
++ struct ieee80211_regdomain *new_regd = NULL;
+ struct cur_reg_rule *reg_rule;
+ u8 i = 0, j = 0, k = 0;
+ u8 num_rules;
+@@ -628,26 +505,26 @@ ath11k_reg_build_regd(struct ath11k_base
+ num_rules += reg_info->num_6ghz_rules_ap[WMI_REG_INDOOR_AP];
+
+ if (!num_rules)
+- goto ret;
++ return new_regd;
+
+ /* Add max additional rules to accommodate weather radar band */
+ if (reg_info->dfs_region == ATH11K_DFS_REG_ETSI)
+ num_rules += 2;
+
+- tmp_regd = kzalloc(sizeof(*tmp_regd) +
++ new_regd = kzalloc(sizeof(*new_regd) +
+ (num_rules * sizeof(struct ieee80211_reg_rule)),
+ GFP_ATOMIC);
+- if (!tmp_regd)
+- goto ret;
++ if (!new_regd)
++ return new_regd;
+
+- memcpy(tmp_regd->alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1);
++ memcpy(new_regd->alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1);
+ memcpy(alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1);
+ alpha2[2] = '\0';
+- tmp_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region);
++ new_regd->dfs_region = ath11k_map_fw_dfs_region(reg_info->dfs_region);
+
+ ath11k_dbg(ab, ATH11K_DBG_REG,
+ "Country %s, CFG Regdomain %s FW Regdomain %d, num_reg_rules %d\n",
+- alpha2, ath11k_reg_get_regdom_str(tmp_regd->dfs_region),
++ alpha2, ath11k_reg_get_regdom_str(new_regd->dfs_region),
+ reg_info->dfs_region, num_rules);
+ /* Update reg_rules[] below. Firmware is expected to
+ * send these rules in order(2 GHz rules first and then 5 GHz)
+@@ -686,7 +563,7 @@ ath11k_reg_build_regd(struct ath11k_base
+
+ flags |= ath11k_map_fw_reg_flags(reg_rule->flags);
+
+- ath11k_reg_update_rule(tmp_regd->reg_rules + i,
++ ath11k_reg_update_rule(new_regd->reg_rules + i,
+ reg_rule->start_freq,
+ reg_rule->end_freq, max_bw,
+ reg_rule->ant_gain, reg_rule->reg_power,
+@@ -701,7 +578,7 @@ ath11k_reg_build_regd(struct ath11k_base
+ reg_info->dfs_region == ATH11K_DFS_REG_ETSI &&
+ (reg_rule->end_freq > ETSI_WEATHER_RADAR_BAND_LOW &&
+ reg_rule->start_freq < ETSI_WEATHER_RADAR_BAND_HIGH)){
+- ath11k_reg_update_weather_radar_band(ab, tmp_regd,
++ ath11k_reg_update_weather_radar_band(ab, new_regd,
+ reg_rule, &i,
+ flags, max_bw);
+ continue;
+@@ -712,37 +589,20 @@ ath11k_reg_build_regd(struct ath11k_base
+ "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d) (%d, %d)\n",
+ i + 1, reg_rule->start_freq, reg_rule->end_freq,
+ max_bw, reg_rule->ant_gain, reg_rule->reg_power,
+- tmp_regd->reg_rules[i].dfs_cac_ms, flags,
++ new_regd->reg_rules[i].dfs_cac_ms, flags,
+ reg_rule->psd_flag, reg_rule->psd_eirp);
+ } else {
+ ath11k_dbg(ab, ATH11K_DBG_REG,
+ "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
+ i + 1, reg_rule->start_freq, reg_rule->end_freq,
+ max_bw, reg_rule->ant_gain, reg_rule->reg_power,
+- tmp_regd->reg_rules[i].dfs_cac_ms,
++ new_regd->reg_rules[i].dfs_cac_ms,
+ flags);
+ }
+ }
+
+- tmp_regd->n_reg_rules = i;
+-
+- if (intersect) {
+- default_regd = ab->default_regd[reg_info->phy_id];
+-
+- /* Get a new regd by intersecting the received regd with
+- * our default regd.
+- */
+- new_regd = ath11k_regd_intersect(default_regd, tmp_regd);
+- kfree(tmp_regd);
+- if (!new_regd) {
+- ath11k_warn(ab, "Unable to create intersected regdomain\n");
+- goto ret;
+- }
+- } else {
+- new_regd = tmp_regd;
+- }
++ new_regd->n_reg_rules = i;
+
+-ret:
+ return new_regd;
+ }
+
+--- a/drivers/net/wireless/ath/ath11k/reg.h
++++ b/drivers/net/wireless/ath/ath11k/reg.h
+@@ -30,7 +30,7 @@ void ath11k_reg_free(struct ath11k_base
+ void ath11k_regd_update_work(struct work_struct *work);
+ struct ieee80211_regdomain *
+ ath11k_reg_build_regd(struct ath11k_base *ab,
+- struct cur_regulatory_info *reg_info, bool intersect);
++ struct cur_regulatory_info *reg_info);
+ int ath11k_regd_update(struct ath11k *ar);
+ int ath11k_reg_update_chan_list(struct ath11k *ar, bool wait);
+ #endif
+--- a/drivers/net/wireless/ath/ath11k/wmi.c
++++ b/drivers/net/wireless/ath/ath11k/wmi.c
+@@ -6979,24 +6979,12 @@ static void ath11k_wmi_htc_tx_complete(s
+ wake_up(&wmi->tx_ce_desc_wq);
+ }
+
+-static bool ath11k_reg_is_world_alpha(char *alpha)
+-{
+- if (alpha[0] == '0' && alpha[1] == '0')
+- return true;
+-
+- if (alpha[0] == 'n' && alpha[1] == 'a')
+- return true;
+-
+- return false;
+-}
+-
+ static int ath11k_reg_chan_list_event(struct ath11k_base *ab,
+ struct sk_buff *skb,
+ enum wmi_reg_chan_list_cmd_type id)
+ {
+ struct cur_regulatory_info *reg_info = NULL;
+ struct ieee80211_regdomain *regd = NULL;
+- bool intersect = false;
+ int ret = 0, pdev_idx, i, j;
+ struct ath11k *ar;
+
+@@ -7058,17 +7046,7 @@ static int ath11k_reg_chan_list_event(st
+ (char *)reg_info->alpha2, 2))
+ goto mem_free;
+
+- /* Intersect new rules with default regd if a new country setting was
+- * requested, i.e a default regd was already set during initialization
+- * and the regd coming from this event has a valid country info.
+- */
+- if (ab->default_regd[pdev_idx] &&
+- !ath11k_reg_is_world_alpha((char *)
+- ab->default_regd[pdev_idx]->alpha2) &&
+- !ath11k_reg_is_world_alpha((char *)reg_info->alpha2))
+- intersect = true;
+-
+- regd = ath11k_reg_build_regd(ab, reg_info, intersect);
++ regd = ath11k_reg_build_regd(ab, reg_info);
+ if (!regd) {
+ ath11k_warn(ab, "failed to build regd from reg_info\n");
+ goto fallback;