The branch stable/15 has been updated by bz:

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

commit a13158f451cffe04a723a71144e614ebb6821a58
Author:     Bjoern A. Zeeb <[email protected]>
AuthorDate: 2025-10-17 20:46:45 +0000
Commit:     Bjoern A. Zeeb <[email protected]>
CommitDate: 2025-10-27 00:18:21 +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 ).
    
    (cherry picked from commit 354a030185c650d1465ed2035a83636b8f825d72)
---
 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 --git a/sys/contrib/dev/rtw89/Kconfig b/sys/contrib/dev/rtw89/Kconfig
index b1c86cdd9c0e..4288c30b400a 100644
--- a/sys/contrib/dev/rtw89/Kconfig
+++ b/sys/contrib/dev/rtw89/Kconfig
@@ -17,6 +17,9 @@ config RTW89_CORE
 config RTW89_PCI
        tristate
 
+config RTW89_USB
+       tristate
+
 config RTW89_8851B
        tristate
 
@@ -49,6 +52,17 @@ config RTW89_8851BE
 
          802.11ax PCIe wireless network (Wi-Fi 6) adapter
 
+config RTW89_8851BU
+       tristate "Realtek 8851BU USB wireless network (Wi-Fi 6) adapter"
+       depends on USB
+       select RTW89_CORE
+       select RTW89_USB
+       select RTW89_8851B
+       help
+         Select this option will enable support for 8851BU chipset
+
+         802.11ax USB wireless network (Wi-Fi 6) adapter
+
 config RTW89_8852AE
        tristate "Realtek 8852AE PCI wireless network (Wi-Fi 6) adapter"
        depends on PCI
@@ -72,6 +86,18 @@ config RTW89_8852BE
 
          802.11ax PCIe wireless network (Wi-Fi 6) adapter
 
+config RTW89_8852BU
+       tristate "Realtek 8852BU USB wireless network (Wi-Fi 6) adapter"
+       depends on USB
+       select RTW89_CORE
+       select RTW89_USB
+       select RTW89_8852B
+       select RTW89_8852B_COMMON
+       help
+         Select this option will enable support for 8852BU chipset
+
+         802.11ax USB wireless network (Wi-Fi 6) adapter
+
 config RTW89_8852BTE
        tristate "Realtek 8852BE-VT PCI wireless network (Wi-Fi 6) adapter"
        depends on PCI
@@ -123,7 +149,7 @@ config RTW89_DEBUGMSG
 
 config RTW89_DEBUGFS
        bool "Realtek rtw89 debugfs support"
-       depends on RTW89_CORE
+       depends on RTW89_CORE && CFG80211_DEBUGFS
        select RTW89_DEBUG
        help
          Enable debugfs support
diff --git a/sys/contrib/dev/rtw89/Makefile b/sys/contrib/dev/rtw89/Makefile
index c751013e811e..23e43c444f69 100644
--- a/sys/contrib/dev/rtw89/Makefile
+++ b/sys/contrib/dev/rtw89/Makefile
@@ -31,6 +31,9 @@ rtw89_8851b-objs := rtw8851b.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 \
@@ -52,6 +55,9 @@ rtw89_8852b-objs := rtw8852b.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 \
@@ -81,3 +87,6 @@ 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 --git a/sys/contrib/dev/rtw89/acpi.c b/sys/contrib/dev/rtw89/acpi.c
index f5dedb12c129..fdba1ea46ec6 100644
--- a/sys/contrib/dev/rtw89/acpi.c
+++ b/sys/contrib/dev/rtw89/acpi.c
@@ -12,6 +12,125 @@ 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)
@@ -121,6 +240,138 @@ int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev 
*rtwdev,
        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)
@@ -142,6 +393,14 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
        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);
 
@@ -152,46 +411,879 @@ 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;
+#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 =
+               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;
+               case RTW89_BAND_6G:
+                       ptr_ent_val = &ptr_ent->val_6ghz;
+                       break;
+               default:
+                       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_rt_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_rt_legacy *ptr = content;
+       const struct rtw89_acpi_geo_sar_rt_legacy_entry *ptr_ent;
+       const struct rtw89_acpi_geo_sar_rt_val *ptr_ent_val;
+       enum rtw89_acpi_geo_sar_regd_rt geo_idx =
+               rtw89_acpi_geo_sar_regd_convert_rt_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_rt(rtwdev, ptr_ent_val,
+                                                     &ent->v[subband][path]);
+       }
+}
+
+static
+void rtw89_acpi_geo_sar_load_rt_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_rt_has_6ghz *ptr = content;
+       const struct rtw89_acpi_geo_sar_rt_has_6ghz_entry *ptr_ent;
+       const struct rtw89_acpi_geo_sar_rt_val *ptr_ent_val;
+       enum rtw89_acpi_geo_sar_regd_rt geo_idx =
+               rtw89_acpi_geo_sar_regd_convert_rt_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;
+               case RTW89_BAND_6G:
+                       ptr_ent_val = &ptr_ent->val_6ghz;
+                       break;
+               default:
+                       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_rt(rtwdev, ptr_ent_val,
+                                                     &ent->v[subband][path]);
+       }
+}
+
+#define RTW89_ACPI_GEO_SAR_DECL_HANDLER(type) \
+static const struct rtw89_acpi_geo_sar_handler \
+rtw89_acpi_geo_sar_handler_ ## type = { \
+       .data_size = RTW89_ACPI_GEO_SAR_SIZE_OF(type), \
+       .load = rtw89_acpi_geo_sar_load_ ## type, \
+}
+
+RTW89_ACPI_GEO_SAR_DECL_HANDLER(hp_legacy);
+RTW89_ACPI_GEO_SAR_DECL_HANDLER(hp_has_6ghz);
+RTW89_ACPI_GEO_SAR_DECL_HANDLER(rt_legacy);
+RTW89_ACPI_GEO_SAR_DECL_HANDLER(rt_has_6ghz);
+
+static const struct rtw89_acpi_sar_recognition rtw89_acpi_sar_recs[] = {
+       {
+               .id = {
+                       .cid = RTW89_ACPI_SAR_CID_HP,
+                       .rev = RTW89_ACPI_SAR_REV_LEGACY,
+                       .size = RTW89_ACPI_SAR_SIZE_OF(std_legacy),
+               },
+               .geo = &rtw89_acpi_geo_sar_handler_hp_legacy,
+
+               .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_hp_antidx,
*** 30297 LINES SKIPPED ***

Reply via email to