@@ -563,6 +563,17 @@ struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id)
return NULL;
}
+enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar)
+{
+ struct ath12k_vif *arvif;
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ return arvif->vdev_type;
+ }
+
+ return WMI_VDEV_TYPE_UNSPEC;
+}
+
struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
{
int i;
@@ -66,6 +66,7 @@ struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
u32 vdev_id);
struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id);
struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
+enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar);
void ath12k_mac_drain_tx(struct ath12k *ar);
void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
@@ -5299,26 +5299,15 @@ static bool ath12k_reg_is_world_alpha(char *alpha)
return alpha[0] == '0' && alpha[1] == '0';
}
-static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
+static int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
+ struct ath12k_reg_info *reg_info,
+ enum ieee80211_ap_reg_power power_type)
{
- struct ath12k_reg_info *reg_info = NULL;
- struct ieee80211_regdomain *regd = NULL;
+ struct ieee80211_regdomain *regd;
bool intersect = false;
- int ret = 0, pdev_idx, i, j;
+ int pdev_idx;
struct ath12k *ar;
-
- reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
- if (!reg_info) {
- ret = -ENOMEM;
- goto fallback;
- }
-
- 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;
- }
+ enum wmi_vdev_type vdev_type;
if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
/* In case of failure to set the requested ctry,
@@ -5326,7 +5315,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
* and return from here.
*/
ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");
- goto mem_free;
+ return -EINVAL;
}
pdev_idx = reg_info->phy_id;
@@ -5338,9 +5327,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
*/
if (ab->hw_params->single_pdev_only &&
pdev_idx < ab->hw_params->num_rxmda_per_pdev)
- goto mem_free;
- else
- goto fallback;
+ return -EINVAL;
+ goto fallback;
}
/* Avoid multiple overwrites to default regd, during core
@@ -5349,7 +5337,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
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;
+ return -EINVAL;
/* Intersect new rules with default regd if a new country setting was
* requested, i.e a default regd was already set during initialization
@@ -5361,8 +5349,13 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
!ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
intersect = true;
- regd = ath12k_reg_build_regd(ab, reg_info, intersect,
- WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
+ ar = ab->pdevs[pdev_idx].ar;
+ vdev_type = ath12k_mac_get_ar_vdev_type(ar);
+ ath12k_dbg(ab, ATH12K_DBG_WMI,
+ "wmi handle chan list power type %d vdev type %d intersect %d\n",
+ power_type, vdev_type, intersect);
+
+ regd = ath12k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type);
if (!regd) {
ath12k_warn(ab, "failed to build regd from reg_info\n");
goto fallback;
@@ -5394,7 +5387,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
ab->dfs_region = reg_info->dfs_region;
spin_unlock(&ab->base_lock);
- goto mem_free;
+ return 0;
fallback:
/* Fallback to older reg (by sending previous country setting
@@ -5406,17 +5399,39 @@ 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);
+ return -EINVAL;
+}
+
+static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+ struct ath12k_reg_info *reg_info;
+ int ret, i, j;
+
+ reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
+ if (!reg_info)
+ return -ENOMEM;
+
+ 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 mem_free;
+ }
+
+ ret = ath12k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP);
+ if (ret)
+ ath12k_warn(ab, "failed to process regulatory info from received event\n");
+
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++)
+ 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]);
+ for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++)
+ kfree(reg_info->reg_rules_6g_client_ptr[i][j]);
+ }
}
kfree(reg_info);
}
@@ -4161,6 +4161,7 @@ struct ath12k_wmi_target_cap_arg {
};
enum wmi_vdev_type {
+ WMI_VDEV_TYPE_UNSPEC = 0,
WMI_VDEV_TYPE_AP = 1,
WMI_VDEV_TYPE_STA = 2,
WMI_VDEV_TYPE_IBSS = 3,
During bootup, WMI_REG_CHAN_LIST_CC_EXT_EVENTID event sent from firmware at an early stage and it expects the 6 GHz power type for 6 GHz reg rules. As power mode is not defined at this point host selects IEEE80211_REG_UNSET_AP as default mode. When interface is created, it updates regd rules accordingly. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Aishwarya R <quic_aisr@quicinc.com> --- drivers/net/wireless/ath/ath12k/mac.c | 11 ++++ drivers/net/wireless/ath/ath12k/mac.h | 1 + drivers/net/wireless/ath/ath12k/wmi.c | 75 ++++++++++++++++----------- drivers/net/wireless/ath/ath12k/wmi.h | 1 + 4 files changed, 58 insertions(+), 30 deletions(-)