git: 354a030185c6 - main - rtw89: update Realtek's rtw89 driver

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Thu, 23 Oct 2025 21:28:27 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=354a030185c650d1465ed2035a83636b8f825d72

commit 354a030185c650d1465ed2035a83636b8f825d72
Merge: eb15fdb1b72d b35044b38f74
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-10-17 20:46:45 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-10-23 21:26:04 +0000

    rtw89: update Realtek's rtw89 driver
    
    This version is based on
    git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
    e5f0a698b34ed76002dc5cff3804a61c80233a7a ( tag: v6.17 ).
    
    MFC after:      3 days

 sys/contrib/dev/rtw89/Kconfig              |   28 +-
 sys/contrib/dev/rtw89/Makefile             |    9 +
 sys/contrib/dev/rtw89/acpi.c               | 1140 +++++++-
 sys/contrib/dev/rtw89/acpi.h               |  223 +-
 sys/contrib/dev/rtw89/cam.c                |   13 +
 sys/contrib/dev/rtw89/chan.c               |  993 +++++--
 sys/contrib/dev/rtw89/chan.h               |   92 +-
 sys/contrib/dev/rtw89/coex.c               | 4128 +++++++++++++++++-----------
 sys/contrib/dev/rtw89/coex.h               |   25 +-
 sys/contrib/dev/rtw89/core.c               | 1019 +++++--
 sys/contrib/dev/rtw89/core.h               |  572 +++-
 sys/contrib/dev/rtw89/debug.c              | 2232 ++++++++-------
 sys/contrib/dev/rtw89/fw.c                 | 1464 ++++++++--
 sys/contrib/dev/rtw89/fw.h                 |  305 +-
 sys/contrib/dev/rtw89/mac.c                |  316 ++-
 sys/contrib/dev/rtw89/mac.h                |   63 +-
 sys/contrib/dev/rtw89/mac80211.c           |  420 +--
 sys/contrib/dev/rtw89/mac_be.c             |   12 +-
 sys/contrib/dev/rtw89/pci.c                |   78 +-
 sys/contrib/dev/rtw89/pci.h                |   57 +-
 sys/contrib/dev/rtw89/pci_be.c             |    2 +-
 sys/contrib/dev/rtw89/phy.c                | 1209 +++++---
 sys/contrib/dev/rtw89/phy.h                |   40 +-
 sys/contrib/dev/rtw89/phy_be.c             |    2 +-
 sys/contrib/dev/rtw89/ps.c                 |  207 +-
 sys/contrib/dev/rtw89/ps.h                 |    6 +
 sys/contrib/dev/rtw89/reg.h                |   95 +-
 sys/contrib/dev/rtw89/regd.c               |  780 ++++--
 sys/contrib/dev/rtw89/rtw8851b.c           |  199 +-
 sys/contrib/dev/rtw89/rtw8851b_rfk.c       |  156 +-
 sys/contrib/dev/rtw89/rtw8851b_rfk_table.c |   77 +-
 sys/contrib/dev/rtw89/rtw8851b_rfk_table.h |    2 +-
 sys/contrib/dev/rtw89/rtw8851b_table.c     |  501 ++--
 sys/contrib/dev/rtw89/rtw8851be.c          |    1 +
 sys/contrib/dev/rtw89/rtw8851bu.c          |   39 +
 sys/contrib/dev/rtw89/rtw8852a.c           |   35 +-
 sys/contrib/dev/rtw89/rtw8852ae.c          |    1 +
 sys/contrib/dev/rtw89/rtw8852b.c           |  128 +-
 sys/contrib/dev/rtw89/rtw8852b_common.c    |   46 +-
 sys/contrib/dev/rtw89/rtw8852b_rfk.c       |   95 +-
 sys/contrib/dev/rtw89/rtw8852b_rfk.h       |    3 +
 sys/contrib/dev/rtw89/rtw8852be.c          |    1 +
 sys/contrib/dev/rtw89/rtw8852bt.c          |   47 +-
 sys/contrib/dev/rtw89/rtw8852bt_rfk.c      |   87 +-
 sys/contrib/dev/rtw89/rtw8852bt_rfk.h      |    3 +
 sys/contrib/dev/rtw89/rtw8852bte.c         |    1 +
 sys/contrib/dev/rtw89/rtw8852bu.c          |   55 +
 sys/contrib/dev/rtw89/rtw8852c.c           |   65 +-
 sys/contrib/dev/rtw89/rtw8852ce.c          |    1 +
 sys/contrib/dev/rtw89/rtw8922a.c           |  157 +-
 sys/contrib/dev/rtw89/rtw8922a_rfk.c       |   57 +-
 sys/contrib/dev/rtw89/rtw8922ae.c          |    1 +
 sys/contrib/dev/rtw89/sar.c                |  677 ++++-
 sys/contrib/dev/rtw89/sar.h                |   27 +-
 sys/contrib/dev/rtw89/ser.c                |   34 +-
 sys/contrib/dev/rtw89/txrx.h               |   32 +
 sys/contrib/dev/rtw89/usb.c                | 1042 +++++++
 sys/contrib/dev/rtw89/usb.h                |   65 +
 sys/contrib/dev/rtw89/util.c               |  220 +-
 sys/contrib/dev/rtw89/util.h               |   13 +-
 sys/contrib/dev/rtw89/wow.c                |   28 +-
 sys/contrib/dev/rtw89/wow.h                |   14 +-
 sys/modules/rtw89/Makefile                 |    8 +-
 63 files changed, 14320 insertions(+), 5128 deletions(-)

diff --cc sys/contrib/dev/rtw89/Makefile
index c751013e811e,000000000000..23e43c444f69
mode 100644,000000..100644
--- a/sys/contrib/dev/rtw89/Makefile
+++ b/sys/contrib/dev/rtw89/Makefile
@@@ -1,83 -1,0 +1,92 @@@
 +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 +
 +obj-$(CONFIG_RTW89_CORE) += rtw89_core.o
 +rtw89_core-y += core.o \
 +		mac80211.o \
 +		mac.o \
 +		mac_be.o \
 +		phy.o \
 +		phy_be.o \
 +		fw.o \
 +		cam.o \
 +		efuse.o \
 +		efuse_be.o \
 +		regd.o \
 +		sar.o \
 +		coex.o \
 +		ps.o \
 +		chan.o \
 +		ser.o \
 +		acpi.o \
 +		util.o
 +
 +rtw89_core-$(CONFIG_PM) += wow.o
 +
 +obj-$(CONFIG_RTW89_8851B) += rtw89_8851b.o
 +rtw89_8851b-objs := rtw8851b.o \
 +		    rtw8851b_table.o \
 +		    rtw8851b_rfk.o \
 +		    rtw8851b_rfk_table.o
 +
 +obj-$(CONFIG_RTW89_8851BE) += rtw89_8851be.o
 +rtw89_8851be-objs := rtw8851be.o
 +
++obj-$(CONFIG_RTW89_8851BU) += rtw89_8851bu.o
++rtw89_8851bu-objs := rtw8851bu.o
++
 +obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o
 +rtw89_8852a-objs := rtw8852a.o \
 +		    rtw8852a_table.o \
 +		    rtw8852a_rfk.o \
 +		    rtw8852a_rfk_table.o
 +
 +obj-$(CONFIG_RTW89_8852AE) += rtw89_8852ae.o
 +rtw89_8852ae-objs := rtw8852ae.o
 +
 +obj-$(CONFIG_RTW89_8852B_COMMON) += rtw89_8852b_common.o
 +rtw89_8852b_common-objs := rtw8852b_common.o
 +
 +obj-$(CONFIG_RTW89_8852B) += rtw89_8852b.o
 +rtw89_8852b-objs := rtw8852b.o \
 +		    rtw8852b_table.o \
 +		    rtw8852b_rfk.o \
 +		    rtw8852b_rfk_table.o
 +
 +obj-$(CONFIG_RTW89_8852BE) += rtw89_8852be.o
 +rtw89_8852be-objs := rtw8852be.o
 +
++obj-$(CONFIG_RTW89_8852BU) += rtw89_8852bu.o
++rtw89_8852bu-objs := rtw8852bu.o
++
 +obj-$(CONFIG_RTW89_8852BT) += rtw89_8852bt.o
 +rtw89_8852bt-objs := rtw8852bt.o \
 +		    rtw8852bt_rfk.o \
 +		    rtw8852bt_rfk_table.o
 +
 +obj-$(CONFIG_RTW89_8852BTE) += rtw89_8852bte.o
 +rtw89_8852bte-objs := rtw8852bte.o
 +
 +obj-$(CONFIG_RTW89_8852C) += rtw89_8852c.o
 +rtw89_8852c-objs := rtw8852c.o \
 +		    rtw8852c_table.o \
 +		    rtw8852c_rfk.o \
 +		    rtw8852c_rfk_table.o
 +
 +obj-$(CONFIG_RTW89_8852CE) += rtw89_8852ce.o
 +rtw89_8852ce-objs := rtw8852ce.o
 +
 +obj-$(CONFIG_RTW89_8922A) += rtw89_8922a.o
 +rtw89_8922a-objs := rtw8922a.o \
 +		    rtw8922a_rfk.o
 +
 +obj-$(CONFIG_RTW89_8922AE) += rtw89_8922ae.o
 +rtw89_8922ae-objs := rtw8922ae.o
 +
 +rtw89_core-$(CONFIG_RTW89_DEBUG) += debug.o
 +
 +obj-$(CONFIG_RTW89_PCI) += rtw89_pci.o
 +rtw89_pci-y := pci.o pci_be.o
 +
++obj-$(CONFIG_RTW89_USB) += rtw89_usb.o
++rtw89_usb-y := usb.o
++
diff --cc sys/contrib/dev/rtw89/acpi.c
index f5dedb12c129,000000000000..fdba1ea46ec6
mode 100644,000000..100644
--- a/sys/contrib/dev/rtw89/acpi.c
+++ b/sys/contrib/dev/rtw89/acpi.c
@@@ -1,197 -1,0 +1,1289 @@@
 +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 +/* Copyright(c) 2021-2023  Realtek Corporation
 + */
 +
 +#include <linux/acpi.h>
 +#include <linux/uuid.h>
 +
 +#include "acpi.h"
 +#include "debug.h"
 +
 +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;
++	}
++
++#if defined(__linux__)
++	status = acpi_get_handle(root, (acpi_string)method, &handle);
++#elif defined(__FreeBSD__)
++	status = acpi_get_handle(root, method, &handle);
++#endif
++	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)
 +{
 +	if (obj->type != ACPI_TYPE_INTEGER) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
 +			    "acpi: expect integer but type: %d\n", obj->type);
 +		return -EINVAL;
 +	}
 +
 +	*value = (u8)obj->integer.value;
 +	return 0;
 +}
 +
 +static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p)
 +{
 +	return p->signature[0] == 0x00 &&
 +	       p->signature[1] == 0xE0 &&
 +	       p->signature[2] == 0x4C;
 +}
 +
 +static
 +int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
 +				   union acpi_object *obj,
 +				   struct rtw89_acpi_policy_6ghz **policy_6ghz)
 +{
 +	const struct rtw89_acpi_policy_6ghz *ptr;
 +	u32 expect_len;
 +	u32 len;
 +
 +	if (obj->type != ACPI_TYPE_BUFFER) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
 +			    "acpi: expect buffer but type: %d\n", obj->type);
 +		return -EINVAL;
 +	}
 +
 +	len = obj->buffer.length;
 +	if (len < sizeof(*ptr)) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
 +			    __func__, len);
 +		return -EINVAL;
 +	}
 +
 +	ptr = (typeof(ptr))obj->buffer.pointer;
 +	if (!chk_acpi_policy_6ghz_sig(ptr)) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
 +		return -EINVAL;
 +	}
 +
 +	expect_len = struct_size(ptr, country_list, ptr->country_count);
 +	if (len < expect_len) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n",
 +			    __func__, expect_len, len);
 +		return -EINVAL;
 +	}
 +
 +	*policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL);
 +	if (!*policy_6ghz)
 +		return -ENOMEM;
 +
 +	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz,
 +		       expect_len);
 +	return 0;
 +}
 +
 +static bool chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp *p)
 +{
 +	return p->signature[0] == 0x52 &&
 +	       p->signature[1] == 0x54 &&
 +	       p->signature[2] == 0x4B &&
 +	       p->signature[3] == 0x07;
 +}
 +
 +static
 +int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev,
 +				      union acpi_object *obj,
 +				      struct rtw89_acpi_policy_6ghz_sp **policy)
 +{
 +	const struct rtw89_acpi_policy_6ghz_sp *ptr;
 +	u32 buf_len;
 +
 +	if (obj->type != ACPI_TYPE_BUFFER) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
 +			    "acpi: expect buffer but type: %d\n", obj->type);
 +		return -EINVAL;
 +	}
 +
 +	buf_len = obj->buffer.length;
 +	if (buf_len < sizeof(*ptr)) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
 +			    __func__, buf_len);
 +		return -EINVAL;
 +	}
 +
 +	ptr = (typeof(ptr))obj->buffer.pointer;
 +	if (!chk_acpi_policy_6ghz_sp_sig(ptr)) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
 +		return -EINVAL;
 +	}
 +
 +	*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
 +	if (!*policy)
 +		return -ENOMEM;
 +
 +	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_sp: ", *policy,
 +		       sizeof(*ptr));
 +	return 0;
 +}
 +
++static bool chk_acpi_policy_6ghz_vlp_sig(const struct rtw89_acpi_policy_6ghz_vlp *p)
++{
++	return p->signature[0] == 0x52 &&
++	       p->signature[1] == 0x54 &&
++	       p->signature[2] == 0x4B &&
++	       p->signature[3] == 0x0B;
++}
++
++static
++int rtw89_acpi_dsm_get_policy_6ghz_vlp(struct rtw89_dev *rtwdev,
++				       union acpi_object *obj,
++				       struct rtw89_acpi_policy_6ghz_vlp **policy)
++{
++	const struct rtw89_acpi_policy_6ghz_vlp *ptr;
++	u32 buf_len;
++
++	if (obj->type != ACPI_TYPE_BUFFER) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
++			    "acpi: expect buffer but type: %d\n", obj->type);
++		return -EINVAL;
++	}
++
++	buf_len = obj->buffer.length;
++	if (buf_len < sizeof(*ptr)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
++			    __func__, buf_len);
++		return -EINVAL;
++	}
++
++	ptr = (typeof(ptr))obj->buffer.pointer;
++	if (!chk_acpi_policy_6ghz_vlp_sig(ptr)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
++		return -EINVAL;
++	}
++
++	*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
++	if (!*policy)
++		return -ENOMEM;
++
++	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_vlp: ", *policy,
++		       sizeof(*ptr));
++	return 0;
++}
++
++static bool chk_acpi_policy_tas_sig(const struct rtw89_acpi_policy_tas *p)
++{
++	return p->signature[0] == 0x52 &&
++	       p->signature[1] == 0x54 &&
++	       p->signature[2] == 0x4B &&
++	       p->signature[3] == 0x05;
++}
++
++static int rtw89_acpi_dsm_get_policy_tas(struct rtw89_dev *rtwdev,
++					 union acpi_object *obj,
++					 struct rtw89_acpi_policy_tas **policy)
++{
++	const struct rtw89_acpi_policy_tas *ptr;
++	u32 buf_len;
++
++	if (obj->type != ACPI_TYPE_BUFFER) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
++			    "acpi: expect buffer but type: %d\n", obj->type);
++		return -EINVAL;
++	}
++
++	buf_len = obj->buffer.length;
++	if (buf_len < sizeof(*ptr)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
++			    __func__, buf_len);
++		return -EINVAL;
++	}
++
++	ptr = (typeof(ptr))obj->buffer.pointer;
++	if (!chk_acpi_policy_tas_sig(ptr)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
++		return -EINVAL;
++	}
++
++	*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
++	if (!*policy)
++		return -ENOMEM;
++
++	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_tas: ", *policy,
++		       sizeof(*ptr));
++	return 0;
++}
++
++static
++bool chk_acpi_policy_reg_rules_sig(const struct rtw89_acpi_policy_reg_rules *p)
++{
++	return p->signature[0] == 0x52 &&
++	       p->signature[1] == 0x54 &&
++	       p->signature[2] == 0x4B &&
++	       p->signature[3] == 0x0A;
++}
++
++static
++int rtw89_acpi_dsm_get_policy_reg_rules(struct rtw89_dev *rtwdev,
++					union acpi_object *obj,
++					struct rtw89_acpi_policy_reg_rules **policy)
++{
++	const struct rtw89_acpi_policy_reg_rules *ptr;
++	u32 buf_len;
++
++	if (obj->type != ACPI_TYPE_BUFFER) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
++			    "acpi: expect buffer but type: %d\n", obj->type);
++		return -EINVAL;
++	}
++
++	buf_len = obj->buffer.length;
++	if (buf_len < sizeof(*ptr)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
++			    __func__, buf_len);
++		return -EINVAL;
++	}
++
++	ptr = (typeof(ptr))obj->buffer.pointer;
++	if (!chk_acpi_policy_reg_rules_sig(ptr)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
++		return -EINVAL;
++	}
++
++	*policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
++	if (!*policy)
++		return -ENOMEM;
++
++	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_reg_rules: ", *policy,
++		       sizeof(*ptr));
++	return 0;
++}
++
 +int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
 +			    enum rtw89_acpi_dsm_func func,
 +			    struct rtw89_acpi_dsm_result *res)
 +{
 +	union acpi_object *obj;
 +	int ret;
 +
 +	obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
 +				0, func, NULL);
 +	if (!obj) {
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
 +			    "acpi dsm fail to evaluate func: %d\n", func);
 +		return -ENOENT;
 +	}
 +
 +	if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
 +		ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
 +						     &res->u.policy_6ghz);
 +	else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP)
 +		ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj,
 +							&res->u.policy_6ghz_sp);
++	else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP)
++		ret = rtw89_acpi_dsm_get_policy_6ghz_vlp(rtwdev, obj,
++							 &res->u.policy_6ghz_vlp);
++	else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN)
++		ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas);
++	else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN)
++		ret = rtw89_acpi_dsm_get_policy_reg_rules(rtwdev, obj,
++							  &res->u.policy_reg_rules);
 +	else
 +		ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
 +
 +	ACPI_FREE(obj);
 +	return ret;
 +}
 +
 +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;
++#if defined(__linux__)
++	const struct rtw89_acpi_data *data;
++#elif defined(__FreeBSD__)
++	struct rtw89_acpi_data *data;
++#endif
 +	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))
++	data = rtw89_acpi_evaluate_method(rtwdev, "RTAG");
++	if (!data)
 +		return -EIO;
 +
- 	status = acpi_evaluate_object(handle, NULL, NULL, &buf);
- 	if (ACPI_FAILURE(status))
- 		return -EIO;
++	buf_len = data->len;
++	if (buf_len != sizeof(*res)) {
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
++			    __func__, buf_len);
++		ret = -EINVAL;
++		goto out;
++	}
 +
- 	obj = buf.pointer;
- 	if (obj->type != ACPI_TYPE_BUFFER) {
++	*res = *(struct rtw89_acpi_rtag_result *)data->buf;
++
++	rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "antenna_gain: ", res, sizeof(*res));
++
++out:
++	kfree(data);
++	return ret;
++}
++
++enum rtw89_acpi_sar_subband rtw89_acpi_sar_get_subband(struct rtw89_dev *rtwdev,
++						       u32 center_freq)
++{
++	switch (center_freq) {
++	default:
 +		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
- 			    "acpi: expect buffer but type: %d\n", obj->type);
- 		ret = -EINVAL;
++			    "center freq %u to ACPI SAR subband is unhandled\n",
++			    center_freq);
++		fallthrough;
++	case 2412 ... 2484:
++		return RTW89_ACPI_SAR_2GHZ_SUBBAND;
++	case 5180 ... 5240:
++		return RTW89_ACPI_SAR_5GHZ_SUBBAND_1;
++	case 5250 ... 5320:
++		return RTW89_ACPI_SAR_5GHZ_SUBBAND_2;
++	case 5500 ... 5720:
++		return RTW89_ACPI_SAR_5GHZ_SUBBAND_2E;
++	case 5745 ... 5885:
++		return RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4;
++	case 5955 ... 6155:
++		return RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L;
++	case 6175 ... 6415:
++		return RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H;
++	case 6435 ... 6515:
++		return RTW89_ACPI_SAR_6GHZ_SUBBAND_6;
++	case 6535 ... 6695:
++		return RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L;
++	case 6715 ... 6855:
++		return RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H;
++
++	/* freq 6875 (ch 185, 20MHz) spans RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H
++	 * and RTW89_ACPI_SAR_6GHZ_SUBBAND_8, so directly describe it with
++	 * struct rtw89_6ghz_span.
++	 */
++
++	case 6895 ... 7115:
++		return RTW89_ACPI_SAR_6GHZ_SUBBAND_8;
++	}
++}
++
++enum rtw89_band rtw89_acpi_sar_subband_to_band(struct rtw89_dev *rtwdev,
++					       enum rtw89_acpi_sar_subband subband)
++{
++	switch (subband) {
++	default:
++		rtw89_debug(rtwdev, RTW89_DBG_ACPI,
++			    "ACPI SAR subband %u to band is unhandled\n", subband);
++		fallthrough;
++	case RTW89_ACPI_SAR_2GHZ_SUBBAND:
++		return RTW89_BAND_2G;
++	case RTW89_ACPI_SAR_5GHZ_SUBBAND_1:
++		return RTW89_BAND_5G;
++	case RTW89_ACPI_SAR_5GHZ_SUBBAND_2:
++		return RTW89_BAND_5G;
++	case RTW89_ACPI_SAR_5GHZ_SUBBAND_2E:
++		return RTW89_BAND_5G;
++	case RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4:
++		return RTW89_BAND_5G;
++	case RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L:
++		return RTW89_BAND_6G;
++	case RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H:
++		return RTW89_BAND_6G;
++	case RTW89_ACPI_SAR_6GHZ_SUBBAND_6:
++		return RTW89_BAND_6G;
++	case RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L:
++		return RTW89_BAND_6G;
++	case RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H:
++		return RTW89_BAND_6G;
++	case RTW89_ACPI_SAR_6GHZ_SUBBAND_8:
++		return RTW89_BAND_6G;
++	}
++}
++
++static u8 rtw89_acpi_sar_rfpath_to_hp_antidx(enum rtw89_rf_path rfpath)
++{
++	switch (rfpath) {
++	default:
++	case RF_PATH_B:
++		return 0;
++	case RF_PATH_A:
++		return 1;
++	}
++}
++
++static u8 rtw89_acpi_sar_rfpath_to_rt_antidx(enum rtw89_rf_path rfpath)
++{
++	switch (rfpath) {
++	default:
++	case RF_PATH_A:
++		return 0;
++	case RF_PATH_B:
++		return 1;
++	}
++}
++
++static s16 rtw89_acpi_sar_normalize_hp_val(u8 v)
++{
++	static const u8 bias = 10;
++	static const u8 fct = 1;
++	u16 res;
++
++	BUILD_BUG_ON(fct > TXPWR_FACTOR_OF_RTW89_ACPI_SAR);
++
++	res = (bias << TXPWR_FACTOR_OF_RTW89_ACPI_SAR) +
++	      (v << (TXPWR_FACTOR_OF_RTW89_ACPI_SAR - fct));
++
++	return min_t(s32, res, MAX_VAL_OF_RTW89_ACPI_SAR);
++}
++
++static s16 rtw89_acpi_sar_normalize_rt_val(u8 v)
++{
++	static const u8 fct = 3;
++	u16 res;
++
++	BUILD_BUG_ON(fct > TXPWR_FACTOR_OF_RTW89_ACPI_SAR);
++
++	res = v << (TXPWR_FACTOR_OF_RTW89_ACPI_SAR - fct);
++
++	return min_t(s32, res, MAX_VAL_OF_RTW89_ACPI_SAR);
++}
++
++static
++void rtw89_acpi_sar_load_std_legacy(struct rtw89_dev *rtwdev,
++				    const struct rtw89_acpi_sar_recognition *rec,
++				    const void *content,
++				    struct rtw89_sar_entry_from_acpi *ent)
++{
++	const struct rtw89_acpi_sar_std_legacy *ptr = content;
++	enum rtw89_acpi_sar_subband subband;
++	enum rtw89_rf_path path;
++
++	for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
++		for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
++			u8 antidx = rec->rfpath_to_antidx(path);
++
++			if (subband < RTW89_ACPI_SAR_SUBBAND_NR_LEGACY)
++				ent->v[subband][path] =
++					rec->normalize(ptr->v[antidx][subband]);
++			else
++				ent->v[subband][path] = MAX_VAL_OF_RTW89_ACPI_SAR;
++		}
++	}
++}
++
++static
++void rtw89_acpi_sar_load_std_has_6ghz(struct rtw89_dev *rtwdev,
++				      const struct rtw89_acpi_sar_recognition *rec,
++				      const void *content,
++				      struct rtw89_sar_entry_from_acpi *ent)
++{
++	const struct rtw89_acpi_sar_std_has_6ghz *ptr = content;
++	enum rtw89_acpi_sar_subband subband;
++	enum rtw89_rf_path path;
++
++	BUILD_BUG_ON(RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ != NUM_OF_RTW89_ACPI_SAR_SUBBAND);
++
++	for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
++		for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
++			u8 antidx = rec->rfpath_to_antidx(path);
++
++			ent->v[subband][path] = rec->normalize(ptr->v[antidx][subband]);
++		}
++	}
++}
++
++static
++void rtw89_acpi_sar_load_sml_legacy(struct rtw89_dev *rtwdev,
++				    const struct rtw89_acpi_sar_recognition *rec,
++				    const void *content,
++				    struct rtw89_sar_entry_from_acpi *ent)
++{
++	const struct rtw89_acpi_sar_sml_legacy *ptr = content;
++	enum rtw89_acpi_sar_subband subband;
++	enum rtw89_rf_path path;
++
++	for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
++		for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
++			u8 antidx = rec->rfpath_to_antidx(path);
++
++			if (subband < RTW89_ACPI_SAR_SUBBAND_NR_LEGACY)
++				ent->v[subband][path] =
++					rec->normalize(ptr->v[antidx][subband]);
++			else
++				ent->v[subband][path] = MAX_VAL_OF_RTW89_ACPI_SAR;
++		}
++	}
++}
++
++static
++void rtw89_acpi_sar_load_sml_has_6ghz(struct rtw89_dev *rtwdev,
++				      const struct rtw89_acpi_sar_recognition *rec,
++				      const void *content,
++				      struct rtw89_sar_entry_from_acpi *ent)
++{
++	const struct rtw89_acpi_sar_sml_has_6ghz *ptr = content;
++	enum rtw89_acpi_sar_subband subband;
++	enum rtw89_rf_path path;
++
++	BUILD_BUG_ON(RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ != NUM_OF_RTW89_ACPI_SAR_SUBBAND);
++
++	for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
++		for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
++			u8 antidx = rec->rfpath_to_antidx(path);
++
++			ent->v[subband][path] = rec->normalize(ptr->v[antidx][subband]);
++		}
++	}
++}
++
++static s16 rtw89_acpi_geo_sar_normalize_delta(s8 delta)
++{
++	static const u8 fct = 1;
++
++	BUILD_BUG_ON(fct > TXPWR_FACTOR_OF_RTW89_ACPI_SAR);
++
++	return delta << (TXPWR_FACTOR_OF_RTW89_ACPI_SAR - fct);
++}
++
++static enum rtw89_acpi_geo_sar_regd_hp
++rtw89_acpi_geo_sar_regd_convert_hp_idx(enum rtw89_regulation_type regd)
++{
++	switch (regd) {
++	case RTW89_FCC:
++	case RTW89_IC:
++	case RTW89_NCC:
++	case RTW89_CHILE:
++	case RTW89_MEXICO:
++		return RTW89_ACPI_GEO_SAR_REGD_HP_FCC;
++	case RTW89_ETSI:
++	case RTW89_MKK:
++	case RTW89_ACMA:
++		return RTW89_ACPI_GEO_SAR_REGD_HP_ETSI;
++	default:
++	case RTW89_WW:
++	case RTW89_NA:
++	case RTW89_KCC:
++		return RTW89_ACPI_GEO_SAR_REGD_HP_WW;
++	}
++}
++
++static enum rtw89_acpi_geo_sar_regd_rt
++rtw89_acpi_geo_sar_regd_convert_rt_idx(enum rtw89_regulation_type regd)
++{
++	switch (regd) {
++	case RTW89_FCC:
++	case RTW89_NCC:
++	case RTW89_CHILE:
++	case RTW89_MEXICO:
++		return RTW89_ACPI_GEO_SAR_REGD_RT_FCC;
++	case RTW89_ETSI:
++	case RTW89_ACMA:
++		return RTW89_ACPI_GEO_SAR_REGD_RT_ETSI;
++	case RTW89_MKK:
++		return RTW89_ACPI_GEO_SAR_REGD_RT_MKK;
++	case RTW89_IC:
++		return RTW89_ACPI_GEO_SAR_REGD_RT_IC;
++	case RTW89_KCC:
++		return RTW89_ACPI_GEO_SAR_REGD_RT_KCC;
++	default:
++	case RTW89_WW:
++	case RTW89_NA:
++		return RTW89_ACPI_GEO_SAR_REGD_RT_WW;
++	}
++}
++
++static
++void rtw89_acpi_geo_sar_load_by_hp(struct rtw89_dev *rtwdev,
++				   const struct rtw89_acpi_geo_sar_hp_val *ptr,
++				   enum rtw89_rf_path path, s16 *val)
++{
++	u8 antidx = rtw89_acpi_sar_rfpath_to_hp_antidx(path);
++	s16 delta = rtw89_acpi_geo_sar_normalize_delta(ptr->delta[antidx]);
++	s16 max = rtw89_acpi_sar_normalize_hp_val(ptr->max);
++
++	*val = clamp_t(s32, (*val) + delta, MIN_VAL_OF_RTW89_ACPI_SAR, max);
++}
++
++static
++void rtw89_acpi_geo_sar_load_by_rt(struct rtw89_dev *rtwdev,
++				   const struct rtw89_acpi_geo_sar_rt_val *ptr,
++				   s16 *val)
++{
++	s16 delta = rtw89_acpi_geo_sar_normalize_delta(ptr->delta);
++	s16 max = rtw89_acpi_sar_normalize_rt_val(ptr->max);
++
++	*val = clamp_t(s32, (*val) + delta, MIN_VAL_OF_RTW89_ACPI_SAR, max);
++}
++
++static
++void rtw89_acpi_geo_sar_load_hp_legacy(struct rtw89_dev *rtwdev,
++				       const void *content,
++				       enum rtw89_regulation_type regd,
++				       struct rtw89_sar_entry_from_acpi *ent)
++{
++	const struct rtw89_acpi_geo_sar_hp_legacy *ptr = content;
++	const struct rtw89_acpi_geo_sar_hp_legacy_entry *ptr_ent;
++	const struct rtw89_acpi_geo_sar_hp_val *ptr_ent_val;
++	enum rtw89_acpi_geo_sar_regd_hp geo_idx =
++		rtw89_acpi_geo_sar_regd_convert_hp_idx(regd);
++	enum rtw89_acpi_sar_subband subband;
++	enum rtw89_rf_path path;
++	enum rtw89_band band;
++
++	ptr_ent = &ptr->entries[geo_idx];
++
++	for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
++		band = rtw89_acpi_sar_subband_to_band(rtwdev, subband);
++		switch (band) {
++		case RTW89_BAND_2G:
++			ptr_ent_val = &ptr_ent->val_2ghz;
++			break;
++		case RTW89_BAND_5G:
++			ptr_ent_val = &ptr_ent->val_5ghz;
++			break;
++		default:
++		case RTW89_BAND_6G:
++			ptr_ent_val = NULL;
++			break;
++		}
++
++		if (!ptr_ent_val)
++			continue;
++
++		for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++)
++			rtw89_acpi_geo_sar_load_by_hp(rtwdev, ptr_ent_val, path,
++						      &ent->v[subband][path]);
++	}
++}
++
++static
++void rtw89_acpi_geo_sar_load_hp_has_6ghz(struct rtw89_dev *rtwdev,
++					 const void *content,
++					 enum rtw89_regulation_type regd,
++					 struct rtw89_sar_entry_from_acpi *ent)
++{
++	const struct rtw89_acpi_geo_sar_hp_has_6ghz *ptr = content;
++	const struct rtw89_acpi_geo_sar_hp_has_6ghz_entry *ptr_ent;
++	const struct rtw89_acpi_geo_sar_hp_val *ptr_ent_val;
++	enum rtw89_acpi_geo_sar_regd_hp geo_idx =
*** 60416 LINES SKIPPED ***