xref: /freebsd/sys/contrib/dev/rtw89/acpi.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
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 #if defined(__linux__)
12 static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
13 					   0x82, 0xBD, 0xFE, 0x86,
14 					   0x07, 0x80, 0x3A, 0xA7);
15 
16 static
17 int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj,
18 			     u8 *value)
19 {
20 	if (obj->type != ACPI_TYPE_INTEGER) {
21 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
22 			    "acpi: expect integer but type: %d\n", obj->type);
23 		return -EINVAL;
24 	}
25 
26 	*value = (u8)obj->integer.value;
27 	return 0;
28 }
29 
30 static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p)
31 {
32 	return p->signature[0] == 0x00 &&
33 	       p->signature[1] == 0xE0 &&
34 	       p->signature[2] == 0x4C;
35 }
36 
37 static
38 int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
39 				   union acpi_object *obj,
40 				   struct rtw89_acpi_policy_6ghz **policy_6ghz)
41 {
42 	const struct rtw89_acpi_policy_6ghz *ptr;
43 	u32 expect_len;
44 	u32 len;
45 
46 	if (obj->type != ACPI_TYPE_BUFFER) {
47 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
48 			    "acpi: expect buffer but type: %d\n", obj->type);
49 		return -EINVAL;
50 	}
51 
52 	len = obj->buffer.length;
53 	if (len < sizeof(*ptr)) {
54 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
55 			    __func__, len);
56 		return -EINVAL;
57 	}
58 
59 	ptr = (typeof(ptr))obj->buffer.pointer;
60 	if (!chk_acpi_policy_6ghz_sig(ptr)) {
61 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
62 		return -EINVAL;
63 	}
64 
65 	expect_len = struct_size(ptr, country_list, ptr->country_count);
66 	if (len < expect_len) {
67 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n",
68 			    __func__, expect_len, len);
69 		return -EINVAL;
70 	}
71 
72 	*policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL);
73 	if (!*policy_6ghz)
74 		return -ENOMEM;
75 
76 	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz,
77 		       expect_len);
78 	return 0;
79 }
80 
81 static bool chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp *p)
82 {
83 	return p->signature[0] == 0x52 &&
84 	       p->signature[1] == 0x54 &&
85 	       p->signature[2] == 0x4B &&
86 	       p->signature[3] == 0x07;
87 }
88 
89 static
90 int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev,
91 				      union acpi_object *obj,
92 				      struct rtw89_acpi_policy_6ghz_sp **policy)
93 {
94 	const struct rtw89_acpi_policy_6ghz_sp *ptr;
95 	u32 buf_len;
96 
97 	if (obj->type != ACPI_TYPE_BUFFER) {
98 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
99 			    "acpi: expect buffer but type: %d\n", obj->type);
100 		return -EINVAL;
101 	}
102 
103 	buf_len = obj->buffer.length;
104 	if (buf_len < sizeof(*ptr)) {
105 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
106 			    __func__, buf_len);
107 		return -EINVAL;
108 	}
109 
110 	ptr = (typeof(ptr))obj->buffer.pointer;
111 	if (!chk_acpi_policy_6ghz_sp_sig(ptr)) {
112 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
113 		return -EINVAL;
114 	}
115 
116 	*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
117 	if (!*policy)
118 		return -ENOMEM;
119 
120 	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_sp: ", *policy,
121 		       sizeof(*ptr));
122 	return 0;
123 }
124 
125 int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
126 			    enum rtw89_acpi_dsm_func func,
127 			    struct rtw89_acpi_dsm_result *res)
128 {
129 	union acpi_object *obj;
130 	int ret;
131 
132 	obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
133 				0, func, NULL);
134 	if (!obj) {
135 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
136 			    "acpi dsm fail to evaluate func: %d\n", func);
137 		return -ENOENT;
138 	}
139 
140 	if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
141 		ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
142 						     &res->u.policy_6ghz);
143 	else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP)
144 		ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj,
145 							&res->u.policy_6ghz_sp);
146 	else
147 		ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
148 
149 	ACPI_FREE(obj);
150 	return ret;
151 }
152 #elif defined(__FreeBSD__)
153 int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
154 			    enum rtw89_acpi_dsm_func func,
155 			    struct rtw89_acpi_dsm_result *res)
156 {
157 	return -ENOENT;
158 }
159 #endif
160 
161 int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev,
162 			     struct rtw89_acpi_rtag_result *res)
163 {
164 	struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
165 	acpi_handle root, handle;
166 	union acpi_object *obj;
167 	acpi_status status;
168 	u32 buf_len;
169 	int ret = 0;
170 
171 	root = ACPI_HANDLE(rtwdev->dev);
172 	if (!root)
173 		return -EOPNOTSUPP;
174 
175 	status = acpi_get_handle(root, (acpi_string)"RTAG", &handle);
176 	if (ACPI_FAILURE(status))
177 		return -EIO;
178 
179 	status = acpi_evaluate_object(handle, NULL, NULL, &buf);
180 	if (ACPI_FAILURE(status))
181 		return -EIO;
182 
183 #if defined(__linux__)
184 	obj = buf.pointer;
185 	if (obj->type != ACPI_TYPE_BUFFER) {
186 #elif defined(__FreeBSD__)
187 	obj = buf.Pointer;
188 	if (obj->Type != ACPI_TYPE_BUFFER) {
189 #endif
190 		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
191 #if defined(__linux__)
192 			    "acpi: expect buffer but type: %d\n", obj->type);
193 #elif defined(__FreeBSD__)
194 			    "acpi: expect buffer but type: %d\n", obj->Type);
195 #endif
196 		ret = -EINVAL;
197 		goto out;
198 	}
199 
200 #if defined(__linux__)
201 	buf_len = obj->buffer.length;
202 #elif defined(__FreeBSD__)
203 	buf_len = obj->Buffer.Length;
204 #endif
205 	if (buf_len != sizeof(*res)) {
206 		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
207 			    __func__, buf_len);
208 		ret = -EINVAL;
209 		goto out;
210 	}
211 
212 #if defined(__linux__)
213 	*res = *(struct rtw89_acpi_rtag_result *)obj->buffer.pointer;
214 #elif defined(__FreeBSD__)
215 	*res = *(struct rtw89_acpi_rtag_result *)obj->Buffer.Pointer;
216 #endif
217 
218 	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "antenna_gain: ", res, sizeof(*res));
219 
220 out:
221 	ACPI_FREE(obj);
222 	return ret;
223 }
224