xref: /linux/drivers/net/wireless/realtek/rtw89/acpi.c (revision af8e51644a70f612974a6e767fa7d896d3c23f88)
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 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
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 
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