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
rtw89_acpi_dsm_get_value(struct rtw89_dev * rtwdev,union acpi_object * obj,u8 * value)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
chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz * p)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
rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev * rtwdev,union acpi_object * obj,struct rtw89_acpi_policy_6ghz ** policy_6ghz)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
chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp * p)80 static bool chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp *p)
81 {
82 return p->signature[0] == 0x52 &&
83 p->signature[1] == 0x54 &&
84 p->signature[2] == 0x4B &&
85 p->signature[3] == 0x07;
86 }
87
88 static
rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev * rtwdev,union acpi_object * obj,struct rtw89_acpi_policy_6ghz_sp ** policy)89 int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev,
90 union acpi_object *obj,
91 struct rtw89_acpi_policy_6ghz_sp **policy)
92 {
93 const struct rtw89_acpi_policy_6ghz_sp *ptr;
94 u32 buf_len;
95
96 if (obj->type != ACPI_TYPE_BUFFER) {
97 rtw89_debug(rtwdev, RTW89_DBG_ACPI,
98 "acpi: expect buffer but type: %d\n", obj->type);
99 return -EINVAL;
100 }
101
102 buf_len = obj->buffer.length;
103 if (buf_len < sizeof(*ptr)) {
104 rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
105 __func__, buf_len);
106 return -EINVAL;
107 }
108
109 ptr = (typeof(ptr))obj->buffer.pointer;
110 if (!chk_acpi_policy_6ghz_sp_sig(ptr)) {
111 rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
112 return -EINVAL;
113 }
114
115 *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
116 if (!*policy)
117 return -ENOMEM;
118
119 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_sp: ", *policy,
120 sizeof(*ptr));
121 return 0;
122 }
123
rtw89_acpi_evaluate_dsm(struct rtw89_dev * rtwdev,enum rtw89_acpi_dsm_func func,struct rtw89_acpi_dsm_result * res)124 int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
125 enum rtw89_acpi_dsm_func func,
126 struct rtw89_acpi_dsm_result *res)
127 {
128 union acpi_object *obj;
129 int ret;
130
131 obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
132 0, func, NULL);
133 if (!obj) {
134 rtw89_debug(rtwdev, RTW89_DBG_ACPI,
135 "acpi dsm fail to evaluate func: %d\n", func);
136 return -ENOENT;
137 }
138
139 if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
140 ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
141 &res->u.policy_6ghz);
142 else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP)
143 ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj,
144 &res->u.policy_6ghz_sp);
145 else
146 ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
147
148 ACPI_FREE(obj);
149 return ret;
150 }
151