]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: rtw89: regd/acpi: support regulatory rules via ACPI DSM and parse rule of regd_UK
authorZong-Zhe Yang <kevin_yang@realtek.com>
Wed, 9 Jul 2025 06:50:05 +0000 (14:50 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Tue, 15 Jul 2025 01:13:17 +0000 (09:13 +0800)
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
drivers/net/wireless/realtek/rtw89/acpi.c
drivers/net/wireless/realtek/rtw89/acpi.h
drivers/net/wireless/realtek/rtw89/regd.c

index 581d6d4154d338d8ff3fcfdbe67f602e41901b30..c35a36e0f4d91fc418eae4b6301e765c7720df9b 100644 (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);
 
index 8cf2615055392cf2a11d895a20bc6aafa2df1f87..5811afebc2e6f014ab9487dd48c0edb6ae772f70 100644 (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;
 };
 
index ea44b8311cb233e57838ea0646f0a8aff09ab089..42678ff2a0452abfbd168d1e9c4d6378e69a4881 100644 (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;