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
11static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
12					   0x82, 0xBD, 0xFE, 0x86,
13					   0x07, 0x80, 0x3A, 0xA7);
14
15static
16int 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
29static 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
36static
37int 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
80int 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