mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-08 00:29:36 -04:00
wifi: ath12k: add support to select 6 GHz regulatory type
For 6 GHz band, firmware offers 3 types of regulatory rules for AP mode and 6 for station mode in WMI_REG_CHAN_LIST_CC_EXT_EVENTID event. In ath12k_reg_build_regd() current code by default chooses WMI_REG_INDOOR_AP type rules from AP mode reg list to build regdomain, regardless of the interface mode and power type, hence is not correct. Pass interface mode (wmi_vdev_type) and AP power type (ieee80211_ap_reg_power) as new arguments to ath12k_reg_build_regd() such that we can choose correct rules based on them. Currently ath12k_reg_build_regd() is called only by ath12k_reg_chan_list_event() when driver boots, at that time these two arguments are not determined yet, hence by default pass WMI_VDEV_TYPE_UNSPEC and IEEE80211_REG_UNSET_AP, this results in WMI_REG_INDOOR_AP being chosen at last. In upcoming patches the rules would be updated when these two arguments could be determined. 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-4-c869c86cad60@quicinc.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
committed by
Jeff Johnson
parent
c96bce15c5
commit
fafa6ff082
@@ -716,26 +716,67 @@ static bool ath12k_reg_is_world_alpha(char *alpha)
|
||||
(alpha[0] == 'n' && alpha[1] == 'a');
|
||||
}
|
||||
|
||||
enum wmi_reg_6g_ap_type
|
||||
ath12k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type)
|
||||
{
|
||||
switch (power_type) {
|
||||
case IEEE80211_REG_LPI_AP:
|
||||
return WMI_REG_INDOOR_AP;
|
||||
case IEEE80211_REG_SP_AP:
|
||||
return WMI_REG_STD_POWER_AP;
|
||||
case IEEE80211_REG_VLP_AP:
|
||||
return WMI_REG_VLP_AP;
|
||||
default:
|
||||
return WMI_REG_MAX_AP_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_regdomain *
|
||||
ath12k_reg_build_regd(struct ath12k_base *ab,
|
||||
struct ath12k_reg_info *reg_info)
|
||||
struct ath12k_reg_info *reg_info,
|
||||
enum wmi_vdev_type vdev_type,
|
||||
enum ieee80211_ap_reg_power power_type)
|
||||
{
|
||||
struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
|
||||
struct ath12k_reg_rule *reg_rule;
|
||||
struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
|
||||
u32 flags, reg_6ghz_number, max_bw_6ghz;
|
||||
u8 i = 0, j = 0, k = 0;
|
||||
u8 num_rules;
|
||||
u16 max_bw;
|
||||
u32 flags;
|
||||
char alpha2[3];
|
||||
|
||||
num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
|
||||
|
||||
/* FIXME: Currently taking reg rules for 6G only from Indoor AP mode list.
|
||||
* This can be updated to choose the combination dynamically based on AP
|
||||
* type and client type, after complete 6G regulatory support is added.
|
||||
*/
|
||||
if (reg_info->is_ext_reg_event)
|
||||
num_rules += reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP];
|
||||
if (reg_info->is_ext_reg_event) {
|
||||
if (vdev_type == WMI_VDEV_TYPE_STA) {
|
||||
enum wmi_reg_6g_ap_type ap_type;
|
||||
|
||||
ap_type = ath12k_reg_ap_pwr_convert(power_type);
|
||||
if (ap_type == WMI_REG_MAX_AP_TYPE)
|
||||
ap_type = WMI_REG_INDOOR_AP;
|
||||
|
||||
reg_6ghz_number = reg_info->num_6g_reg_rules_cl
|
||||
[ap_type][WMI_REG_DEFAULT_CLIENT];
|
||||
if (reg_6ghz_number == 0) {
|
||||
ap_type = WMI_REG_INDOOR_AP;
|
||||
reg_6ghz_number = reg_info->num_6g_reg_rules_cl
|
||||
[ap_type][WMI_REG_DEFAULT_CLIENT];
|
||||
}
|
||||
|
||||
reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
|
||||
[ap_type][WMI_REG_DEFAULT_CLIENT];
|
||||
max_bw_6ghz = reg_info->max_bw_6g_client
|
||||
[ap_type][WMI_REG_DEFAULT_CLIENT];
|
||||
} else {
|
||||
reg_6ghz_number = reg_info->num_6g_reg_rules_ap
|
||||
[WMI_REG_INDOOR_AP];
|
||||
reg_rule_6ghz =
|
||||
reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
|
||||
max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
|
||||
}
|
||||
|
||||
num_rules += reg_6ghz_number;
|
||||
}
|
||||
|
||||
if (!num_rules)
|
||||
goto ret;
|
||||
@@ -794,12 +835,10 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
|
||||
*/
|
||||
flags = NL80211_RRF_AUTO_BW;
|
||||
ath12k_reg_update_freq_range(&ab->reg_freq_5ghz, reg_rule);
|
||||
} else if (reg_info->is_ext_reg_event &&
|
||||
reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] &&
|
||||
(k < reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP])) {
|
||||
reg_rule = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP] + k++;
|
||||
max_bw = min_t(u16, reg_rule->max_bw,
|
||||
reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP]);
|
||||
} else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
|
||||
(k < reg_6ghz_number)) {
|
||||
reg_rule = reg_rule_6ghz + k++;
|
||||
max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
|
||||
flags = NL80211_RRF_AUTO_BW;
|
||||
ath12k_reg_update_freq_range(&ab->reg_freq_6ghz, reg_rule);
|
||||
} else {
|
||||
@@ -911,7 +950,9 @@ 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)
|
||||
struct ath12k_reg_info *reg_info,
|
||||
enum wmi_vdev_type vdev_type,
|
||||
enum ieee80211_ap_reg_power power_type)
|
||||
{
|
||||
struct ieee80211_regdomain *regd = NULL;
|
||||
struct ath12k *ar;
|
||||
@@ -947,7 +988,7 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
|
||||
reg_info->alpha2, 2))
|
||||
return 0;
|
||||
|
||||
regd = ath12k_reg_build_regd(ab, reg_info);
|
||||
regd = ath12k_reg_build_regd(ab, reg_info, vdev_type, power_type);
|
||||
if (!regd)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -96,11 +96,17 @@ 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);
|
||||
struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
|
||||
struct ath12k_reg_info *reg_info);
|
||||
struct ath12k_reg_info *reg_info,
|
||||
enum wmi_vdev_type vdev_type,
|
||||
enum ieee80211_ap_reg_power power_type);
|
||||
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);
|
||||
struct ath12k_reg_info *reg_info,
|
||||
enum wmi_vdev_type vdev_type,
|
||||
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);
|
||||
#endif
|
||||
|
||||
@@ -6132,7 +6132,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
ret = ath12k_reg_handle_chan_list(ab, reg_info);
|
||||
ret = ath12k_reg_handle_chan_list(ab, reg_info, WMI_VDEV_TYPE_UNSPEC,
|
||||
IEEE80211_REG_UNSET_AP);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to handle chan list %d\n", ret);
|
||||
goto fallback;
|
||||
|
||||
@@ -4507,6 +4507,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,
|
||||
|
||||
Reference in New Issue
Block a user