wifi: rtw89: acpi: process 6 GHz SP policy from ACPI DSM
authorZong-Zhe Yang <kevin_yang@realtek.com>
Fri, 12 Apr 2024 11:57:28 +0000 (19:57 +0800)
committerPing-Ke Shih <pkshih@realtek.com>
Thu, 18 Apr 2024 01:11:10 +0000 (09:11 +0800)
Realtek ACPI DSM func 7, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP, accepts a format
via ACPI buffer as below.

| index | description                      |
--------------------------------------------
| [0-3] | signature                        |
| [4]   | revision                         |
| [5]   | override driver settings, or not |
| [6]   | configuration if override        |
| [7]   | reserved                         |

where field of [6] is a bitmap by country,
and for now, only define BIT(0) is for US.

Through this function with overriding, BIOS can indicate to allow/block
6 GHz SP power by country.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Link: https://msgid.link/20240412115729.8316-8-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/acpi.c
drivers/net/wireless/realtek/rtw89/acpi.h

index 2e7326a8e3e47b597653b58061f46df6f6ac60ef..908e980a4b72bd51c43e9445f046ee1ab309f4ce 100644 (file)
@@ -77,6 +77,50 @@ int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
        return 0;
 }
 
+static bool chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp *p)
+{
+       return p->signature[0] == 0x52 &&
+              p->signature[1] == 0x54 &&
+              p->signature[2] == 0x4B &&
+              p->signature[3] == 0x07;
+}
+
+static
+int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev,
+                                     union acpi_object *obj,
+                                     struct rtw89_acpi_policy_6ghz_sp **policy)
+{
+       const struct rtw89_acpi_policy_6ghz_sp *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_6ghz_sp_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_6ghz_sp: ", *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)
@@ -95,6 +139,9 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
        if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
                ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
                                                     &res->u.policy_6ghz);
+       else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP)
+               ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj,
+                                                       &res->u.policy_6ghz_sp);
        else
                ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
 
index 5182797e68b6d40e4fd27364f802c0a7b0a9111f..d274be1775bf3f60a4dfff677beb9a233d49a739 100644 (file)
@@ -13,6 +13,7 @@ enum rtw89_acpi_dsm_func {
        RTW89_ACPI_DSM_FUNC_6G_BP = 4,
        RTW89_ACPI_DSM_FUNC_TAS_EN = 5,
        RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6,
+       RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7,
 };
 
 enum rtw89_acpi_conf_unii4 {
@@ -41,11 +42,24 @@ struct rtw89_acpi_policy_6ghz {
        struct rtw89_acpi_country_code country_list[] __counted_by(country_count);
 } __packed;
 
+enum rtw89_acpi_conf_6ghz_sp {
+       RTW89_ACPI_CONF_6GHZ_SP_US = BIT(0),
+};
+
+struct rtw89_acpi_policy_6ghz_sp {
+       u8 signature[4];
+       u8 revision;
+       u8 override;
+       u8 conf;
+       u8 rsvd;
+} __packed;
+
 struct rtw89_acpi_dsm_result {
        union {
                u8 value;
                /* caller needs to free it after using */
                struct rtw89_acpi_policy_6ghz *policy_6ghz;
+               struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp;
        } u;
 };