xref: /freebsd/sys/contrib/dev/rtw89/acpi.c (revision 5036d9652a5701d00e9e40ea942c278e9f77d33d)
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