wifi: ath12k: refactor ath12k_reg_chan_list_event()

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>
This commit is contained in:
Baochen Qiang 2025-04-18 10:55:35 +08:00 committed by Jeff Johnson
parent ef115c265a
commit 9e8e55c583
3 changed files with 123 additions and 97 deletions

View 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;

View 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

View 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 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
*/
/* 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;
}