wifi: rtw89: regd/acpi: support regulatory rules via ACPI DSM and parse rule of regd_UK

ACPI DSM function 10 is defined for the enablement for Realtek regulatory
rules. The first rule is whether to allow regd_UK regulatory settings or
not. If not, the strict one, i.e. regd_ETSI, regulatory settings will be
used on country GB.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://patch.msgid.link/20250709065006.32028-4-pkshih@realtek.com
This commit is contained in:
Zong-Zhe Yang 2025-07-09 14:50:05 +08:00 committed by Ping-Ke Shih
parent 01186c303b
commit 08fbc2b688
3 changed files with 87 additions and 1 deletions

View File

@ -279,6 +279,51 @@ static int rtw89_acpi_dsm_get_policy_tas(struct rtw89_dev *rtwdev,
return 0;
}
static
bool chk_acpi_policy_reg_rules_sig(const struct rtw89_acpi_policy_reg_rules *p)
{
return p->signature[0] == 0x52 &&
p->signature[1] == 0x54 &&
p->signature[2] == 0x4B &&
p->signature[3] == 0x0A;
}
static
int rtw89_acpi_dsm_get_policy_reg_rules(struct rtw89_dev *rtwdev,
union acpi_object *obj,
struct rtw89_acpi_policy_reg_rules **policy)
{
const struct rtw89_acpi_policy_reg_rules *ptr;
u32 buf_len;
if (obj->type != ACPI_TYPE_BUFFER) {
rtw89_debug(rtwdev, RTW89_DBG_ACPI,
"acpi: expect buffer but type: %d\n", obj->type);
return -EINVAL;
}
buf_len = obj->buffer.length;
if (buf_len < sizeof(*ptr)) {
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
__func__, buf_len);
return -EINVAL;
}
ptr = (typeof(ptr))obj->buffer.pointer;
if (!chk_acpi_policy_reg_rules_sig(ptr)) {
rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
return -EINVAL;
}
*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
if (!*policy)
return -ENOMEM;
rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_reg_rules: ", *policy,
sizeof(*ptr));
return 0;
}
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
enum rtw89_acpi_dsm_func func,
struct rtw89_acpi_dsm_result *res)
@ -302,6 +347,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
&res->u.policy_6ghz_sp);
else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN)
ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas);
else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN)
ret = rtw89_acpi_dsm_get_policy_reg_rules(rtwdev, obj,
&res->u.policy_reg_rules);
else
ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);

View File

@ -19,6 +19,7 @@ enum rtw89_acpi_dsm_func {
RTW89_ACPI_DSM_FUNC_TAS_EN = 5,
RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6,
RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7,
RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10,
};
enum rtw89_acpi_conf_unii4 {
@ -75,6 +76,17 @@ struct rtw89_acpi_policy_tas {
u8 rsvd[3];
} __packed;
enum rtw89_acpi_conf_reg_rules {
RTW89_ACPI_CONF_REG_RULE_REGD_UK = BIT(0),
};
struct rtw89_acpi_policy_reg_rules {
u8 signature[4];
u8 revision;
u8 conf;
u8 rsvd[3];
} __packed;
struct rtw89_acpi_dsm_result {
union {
u8 value;
@ -82,6 +94,7 @@ struct rtw89_acpi_dsm_result {
struct rtw89_acpi_policy_6ghz *policy_6ghz;
struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp;
struct rtw89_acpi_policy_tas *policy_tas;
struct rtw89_acpi_policy_reg_rules *policy_reg_rules;
} u;
};

View File

@ -608,6 +608,30 @@ const char *rtw89_regd_get_string(enum rtw89_regulation_type regd)
return rtw89_regd_string[regd];
}
static void rtw89_regd_setup_reg_rules(struct rtw89_dev *rtwdev)
{
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
const struct rtw89_acpi_policy_reg_rules *ptr;
struct rtw89_acpi_dsm_result res = {};
int ret;
regulatory->txpwr_uk_follow_etsi = true;
ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_REG_RULES_EN, &res);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_REGD,
"acpi: cannot eval policy reg-rules: %d\n", ret);
return;
}
ptr = res.u.policy_reg_rules;
regulatory->txpwr_uk_follow_etsi =
!u8_get_bits(ptr->conf, RTW89_ACPI_CONF_REG_RULE_REGD_UK);
kfree(ptr);
}
int rtw89_regd_setup(struct rtw89_dev *rtwdev)
{
struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
@ -624,7 +648,8 @@ int rtw89_regd_setup(struct rtw89_dev *rtwdev)
}
regulatory->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT;
regulatory->txpwr_uk_follow_etsi = true;
rtw89_regd_setup_reg_rules(rtwdev);
if (!wiphy)
return -EINVAL;