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