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