]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: refactor ath12k_reg_chan_list_event()
authorBaochen Qiang <quic_bqiang@quicinc.com>
Fri, 18 Apr 2025 02:55:35 +0000 (10:55 +0800)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Fri, 16 May 2025 19:38:52 +0000 (12:38 -0700)
ath12k_reg_chan_list_event() is doing quite some work: allocate/free
reg_info, parse chan list event and store required info in reg_info,
process reg_info, build regd and queue work item for later processing
etc, which makes it hard to read.

Refactor this function:

1. extract reg_info processing and regd building into a new helper
   ath12k_reg_handle_chan_list().
2. extract reg_info free into a new helper ath12k_reg_reset_reg_info().

Note the refactor also benefit some upcoming patches where these helpers
are getting called.

Also relocate these two helpers and the existing
ath12k_reg_is_world_alpha() to reg.c to reflect what they are doing.
And update fw to firmware while relocating.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250418-ath12k-6g-lp-vlp-v1-2-c869c86cad60@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/reg.c
drivers/net/wireless/ath/ath12k/reg.h
drivers/net/wireless/ath/ath12k/wmi.c

index 7048834e0d14f0c125dcae5f3c30d8070a9ada4f..21c5a8312a9e55a458aab5151ff9c017808659d7 100644 (file)
@@ -879,6 +879,118 @@ void ath12k_regd_update_work(struct work_struct *work)
        }
 }
 
+void ath12k_reg_reset_reg_info(struct ath12k_reg_info *reg_info)
+{
+       u8 i, j;
+
+       if (!reg_info)
+               return;
+
+       kfree(reg_info->reg_rules_2g_ptr);
+       kfree(reg_info->reg_rules_5g_ptr);
+
+       if (reg_info->is_ext_reg_event) {
+               for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
+                       kfree(reg_info->reg_rules_6g_ap_ptr[i]);
+
+                       for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++)
+                               kfree(reg_info->reg_rules_6g_client_ptr[i][j]);
+               }
+       }
+}
+
+static bool ath12k_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;
+}
+
+int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
+                               struct ath12k_reg_info *reg_info)
+{
+       struct ieee80211_regdomain *regd = NULL;
+       bool intersect = false;
+       struct ath12k *ar;
+       int pdev_idx;
+
+       if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
+               /* In case of failure to set the requested country,
+                * firmware retains the current regd. We print a failure info
+                * and return from here.
+                */
+               ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");
+               return 0;
+       }
+
+       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
+                * event. Otherwise, it goes to fallback.
+                */
+               if (ab->hw_params->single_pdev_only &&
+                   pdev_idx < ab->hw_params->num_rxdma_per_pdev)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+
+       /* Avoid multiple overwrites to default regd, during core
+        * stop-start after mac registration.
+        */
+       if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
+           !memcmp(ab->default_regd[pdev_idx]->alpha2,
+                   reg_info->alpha2, 2))
+               return 0;
+
+       /* 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] &&
+           !ath12k_reg_is_world_alpha((char *)
+               ab->default_regd[pdev_idx]->alpha2) &&
+           !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
+               intersect = true;
+
+       regd = ath12k_reg_build_regd(ab, reg_info, intersect);
+       if (!regd)
+               return -EINVAL;
+
+       spin_lock_bh(&ab->base_lock);
+       if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {
+               /* Once mac is registered, ar is valid and all CC events from
+                * firmware is considered to be received due to user requests
+                * currently.
+                * Free previously built regd before assigning the newly
+                * generated regd to ar. NULL pointer handling will be
+                * taken care by kfree itself.
+                */
+               ar = ab->pdevs[pdev_idx].ar;
+               kfree(ab->new_regd[pdev_idx]);
+               ab->new_regd[pdev_idx] = regd;
+               queue_work(ab->workqueue, &ar->regd_update_work);
+       } else {
+               /* Multiple events for the same *ar is not expected. But we
+                * can still clear any previously stored default_regd if we
+                * are receiving this event for the same radio by mistake.
+                * NULL pointer handling will be taken care by kfree itself.
+                */
+               kfree(ab->default_regd[pdev_idx]);
+               /* This regd would be applied during mac registration */
+               ab->default_regd[pdev_idx] = regd;
+       }
+       ab->dfs_region = reg_info->dfs_region;
+       spin_unlock_bh(&ab->base_lock);
+
+       return 0;
+}
+
 void ath12k_reg_init(struct ieee80211_hw *hw)
 {
        hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
index b1eb584ff34c4c068195ae3aa660520be19e8243..f65cfaca7404cd72a9978c0ae6ca98be9d5f6b70 100644 (file)
@@ -101,4 +101,7 @@ struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
 int ath12k_regd_update(struct ath12k *ar, bool init);
 int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait);
 
+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);
 #endif
index 256e05e28afdbee8267bd2ab25bb47cba4530e96..9bb6d99e7c16f327f5cb73777af9c545803420be 100644 (file)
@@ -6115,24 +6115,10 @@ static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
        dev_kfree_skb(skb);
 }
 
-static bool ath12k_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 ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
 {
-       struct ath12k_reg_info *reg_info = NULL;
-       struct ieee80211_regdomain *regd = NULL;
-       bool intersect = false;
-       int ret = 0, pdev_idx, i, j;
-       struct ath12k *ar;
+       struct ath12k_reg_info *reg_info;
+       int ret;
 
        reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
        if (!reg_info) {
@@ -6141,85 +6127,17 @@ 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;
        }
 
-       if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
-               /* In case of failure to set the requested ctry,
-                * fw retains the current regd. We print a failure info
-                * and return from here.
-                */
-               ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");
-               goto mem_free;
-       }
-
-       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
-                * event. Otherwise, it goes to fallback.
-                */
-               if (ab->hw_params->single_pdev_only &&
-                   pdev_idx < ab->hw_params->num_rxdma_per_pdev)
-                       goto mem_free;
-               else
-                       goto fallback;
-       }
-
-       /* Avoid multiple overwrites to default regd, during core
-        * stop-start after mac registration.
-        */
-       if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
-           !memcmp(ab->default_regd[pdev_idx]->alpha2,
-                   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] &&
-           !ath12k_reg_is_world_alpha((char *)
-               ab->default_regd[pdev_idx]->alpha2) &&
-           !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
-               intersect = true;
-
-       regd = ath12k_reg_build_regd(ab, reg_info, intersect);
-       if (!regd) {
-               ath12k_warn(ab, "failed to build regd from reg_info\n");
+       ret = ath12k_reg_handle_chan_list(ab, reg_info);
+       if (ret) {
+               ath12k_warn(ab, "failed to handle chan list %d\n", ret);
                goto fallback;
        }
 
-       spin_lock_bh(&ab->base_lock);
-       if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {
-               /* Once mac is registered, ar is valid and all CC events from
-                * fw is considered to be received due to user requests
-                * currently.
-                * Free previously built regd before assigning the newly
-                * generated regd to ar. NULL pointer handling will be
-                * taken care by kfree itself.
-                */
-               ar = ab->pdevs[pdev_idx].ar;
-               kfree(ab->new_regd[pdev_idx]);
-               ab->new_regd[pdev_idx] = regd;
-               queue_work(ab->workqueue, &ar->regd_update_work);
-       } else {
-               /* Multiple events for the same *ar is not expected. But we
-                * can still clear any previously stored default_regd if we
-                * are receiving this event for the same radio by mistake.
-                * NULL pointer handling will be taken care by kfree itself.
-                */
-               kfree(ab->default_regd[pdev_idx]);
-               /* This regd would be applied during mac registration */
-               ab->default_regd[pdev_idx] = regd;
-       }
-       ab->dfs_region = reg_info->dfs_region;
-       spin_unlock_bh(&ab->base_lock);
-
        goto mem_free;
 
 fallback:
@@ -6232,20 +6150,13 @@ fallback:
         */
        /* TODO: This is rare, but still should also be handled */
        WARN_ON(1);
+
 mem_free:
        if (reg_info) {
-               kfree(reg_info->reg_rules_2g_ptr);
-               kfree(reg_info->reg_rules_5g_ptr);
-               if (reg_info->is_ext_reg_event) {
-                       for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
-                               kfree(reg_info->reg_rules_6g_ap_ptr[i]);
-
-                       for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
-                               for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)
-                                       kfree(reg_info->reg_rules_6g_client_ptr[j][i]);
-               }
+               ath12k_reg_reset_reg_info(reg_info);
                kfree(reg_info);
        }
+
        return ret;
 }