From 5ee5f848469f584adb7010acb8ac656a544f5654 Mon Sep 17 00:00:00 2001 From: Zong-Zhe Yang Date: Wed, 26 Mar 2025 10:06:36 +0800 Subject: [PATCH] wifi: rtw89: acpi: introduce method evaluation function for reuse The following implementations will evaluate different ACPI methods, but the pre-process flow of them are the same. So, introduce a function for these pre-process things. Besides, also change ACPI RTAG method to call this function. Signed-off-by: Zong-Zhe Yang Signed-off-by: Ping-Ke Shih Link: https://patch.msgid.link/20250326020643.14487-6-pkshih@realtek.com --- drivers/net/wireless/realtek/rtw89/acpi.c | 146 ++++++++++++++++++---- drivers/net/wireless/realtek/rtw89/acpi.h | 5 + 2 files changed, 126 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index b870a3df4072..97b069062ec8 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -12,6 +12,121 @@ static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00, 0x82, 0xBD, 0xFE, 0x86, 0x07, 0x80, 0x3A, 0xA7); +static u32 rtw89_acpi_traversal_object(struct rtw89_dev *rtwdev, + const union acpi_object *obj, u8 *pos) +{ + const union acpi_object *elm; + unsigned int i; + u32 sub_len; + u32 len = 0; + u8 *tmp; + + switch (obj->type) { + case ACPI_TYPE_INTEGER: + if (pos) + pos[len] = obj->integer.value; + + len++; + break; + case ACPI_TYPE_BUFFER: + if (unlikely(obj->buffer.length == 0)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "%s: invalid buffer type\n", __func__); + goto err; + } + + if (pos) + memcpy(pos, obj->buffer.pointer, obj->buffer.length); + + len += obj->buffer.length; + break; + case ACPI_TYPE_PACKAGE: + if (unlikely(obj->package.count == 0)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "%s: invalid package type\n", __func__); + goto err; + } + + for (i = 0; i < obj->package.count; i++) { + elm = &obj->package.elements[i]; + tmp = pos ? pos + len : NULL; + + sub_len = rtw89_acpi_traversal_object(rtwdev, elm, tmp); + if (unlikely(sub_len == 0)) + goto err; + + len += sub_len; + } + break; + default: + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: unhandled type: %d\n", + __func__, obj->type); + goto err; + } + + return len; + +err: + return 0; +} + +static u32 rtw89_acpi_calculate_object_length(struct rtw89_dev *rtwdev, + const union acpi_object *obj) +{ + return rtw89_acpi_traversal_object(rtwdev, obj, NULL); +} + +static struct rtw89_acpi_data * +rtw89_acpi_evaluate_method(struct rtw89_dev *rtwdev, const char *method) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + struct rtw89_acpi_data *data = NULL; + acpi_handle root, handle; + union acpi_object *obj; + acpi_status status; + u32 len; + + root = ACPI_HANDLE(rtwdev->dev); + if (!root) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi (%s): failed to get root\n", method); + return NULL; + } + + status = acpi_get_handle(root, (acpi_string)method, &handle); + if (ACPI_FAILURE(status)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi (%s): failed to get handle\n", method); + return NULL; + } + + status = acpi_evaluate_object(handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi (%s): failed to evaluate object\n", method); + return NULL; + } + + obj = buf.pointer; + len = rtw89_acpi_calculate_object_length(rtwdev, obj); + if (unlikely(len == 0)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi (%s): failed to traversal obj len\n", method); + goto out; + } + + data = kzalloc(struct_size(data, buf, len), GFP_KERNEL); + if (!data) + goto out; + + data->len = len; + rtw89_acpi_traversal_object(rtwdev, obj, data->buf); + +out: + ACPI_FREE(obj); + return data; +} + static int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj, u8 *value) @@ -152,34 +267,15 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev, struct rtw89_acpi_rtag_result *res) { - struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_handle root, handle; - union acpi_object *obj; - acpi_status status; + const struct rtw89_acpi_data *data; u32 buf_len; int ret = 0; - root = ACPI_HANDLE(rtwdev->dev); - if (!root) - return -EOPNOTSUPP; - - status = acpi_get_handle(root, (acpi_string)"RTAG", &handle); - if (ACPI_FAILURE(status)) - return -EIO; - - status = acpi_evaluate_object(handle, NULL, NULL, &buf); - if (ACPI_FAILURE(status)) + data = rtw89_acpi_evaluate_method(rtwdev, "RTAG"); + if (!data) return -EIO; - obj = buf.pointer; - if (obj->type != ACPI_TYPE_BUFFER) { - rtw89_debug(rtwdev, RTW89_DBG_ACPI, - "acpi: expect buffer but type: %d\n", obj->type); - ret = -EINVAL; - goto out; - } - - buf_len = obj->buffer.length; + buf_len = data->len; if (buf_len != sizeof(*res)) { rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", __func__, buf_len); @@ -187,12 +283,12 @@ int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev, goto out; } - *res = *(struct rtw89_acpi_rtag_result *)obj->buffer.pointer; + *res = *(struct rtw89_acpi_rtag_result *)data->buf; rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "antenna_gain: ", res, sizeof(*res)); out: - ACPI_FREE(obj); + kfree(data); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index a7f583a2164f..1f5d732c33c0 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -7,6 +7,11 @@ #include "core.h" +struct rtw89_acpi_data { + u32 len; + u8 buf[] __counted_by(len); +}; + enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_IDN_BAND_SUP = 2, RTW89_ACPI_DSM_FUNC_6G_DIS = 3, -- 2.50.1