xref: /linux/drivers/net/wireless/realtek/rtw89/acpi.c (revision a23e1966932464e1c5226cb9ac4ce1d5fc10ba22)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2021-2023  Realtek Corporation
3  */
4 
5 #include <linux/acpi.h>
6 #include <linux/uuid.h>
7 
8 #include "acpi.h"
9 #include "debug.h"
10 
11 static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
12 					   0x82, 0xBD, 0xFE, 0x86,
13 					   0x07, 0x80, 0x3A, 0xA7);
14 
15 static
16 int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj,
17 			     u8 *value)
18 {
19 	if (obj->type != ACPI_TYPE_INTEGER) {
20 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
21 			    "acpi: expect integer but type: %d\n", obj->type);
22 		return -EINVAL;
23 	}
24 
25 	*value = (u8)obj->integer.value;
26 	return 0;
27 }
28 
29 static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p)
30 {
31 	return p->signature[0] == 0x00 &&
32 	       p->signature[1] == 0xE0 &&
33 	       p->signature[2] == 0x4C;
34 }
35 
36 static
37 int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
38 				   union acpi_object *obj,
39 				   struct rtw89_acpi_policy_6ghz **policy_6ghz)
40 {
41 	const struct rtw89_acpi_policy_6ghz *ptr;
42 	u32 expect_len;
43 	u32 len;
44 
45 	if (obj->type != ACPI_TYPE_BUFFER) {
46 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
47 			    "acpi: expect buffer but type: %d\n", obj->type);
48 		return -EINVAL;
49 	}
50 
51 	len = obj->buffer.length;
52 	if (len < sizeof(*ptr)) {
53 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
54 			    __func__, len);
55 		return -EINVAL;
56 	}
57 
58 	ptr = (typeof(ptr))obj->buffer.pointer;
59 	if (!chk_acpi_policy_6ghz_sig(ptr)) {
60 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
61 		return -EINVAL;
62 	}
63 
64 	expect_len = struct_size(ptr, country_list, ptr->country_count);
65 	if (len < expect_len) {
66 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n",
67 			    __func__, expect_len, len);
68 		return -EINVAL;
69 	}
70 
71 	*policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL);
72 	if (!*policy_6ghz)
73 		return -ENOMEM;
74 
75 	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz,
76 		       expect_len);
77 	return 0;
78 }
79 
80 int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
81 			    enum rtw89_acpi_dsm_func func,
82 			    struct rtw89_acpi_dsm_result *res)
83 {
84 	union acpi_object *obj;
85 	int ret;
86 
87 	obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
88 				0, func, NULL);
89 	if (!obj) {
90 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
91 			    "acpi dsm fail to evaluate func: %d\n", func);
92 		return -ENOENT;
93 	}
94 
95 	if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
96 		ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
97 						     &res->u.policy_6ghz);
98 	else
99 		ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
100 
101 	ACPI_FREE(obj);
102 	return ret;
103 }
104