git: df279a26d331 - main - rtw89: merge Realtek's rtw89 driver based on Linux v6.14
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 27 Apr 2025 23:38:07 UTC
The branch main has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=df279a26d3315e7abc9e6f0744137959a4c2fb86
commit df279a26d3315e7abc9e6f0744137959a4c2fb86
Merge: b989c1dd1e2e 690f81f0b86a
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-24 08:58:54 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-27 23:36:12 +0000
rtw89: merge Realtek's rtw89 driver based on Linux v6.14
This version is based on
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
38fec10eb60d687e30c8c6b5420d86e8149f7557 ( tag: v6.14 ).
Sponsored by: The FreeBSD Foundation
sys/contrib/dev/rtw89/Kconfig | 22 +-
sys/contrib/dev/rtw89/Makefile | 8 +
sys/contrib/dev/rtw89/acpi.c | 64 ++
sys/contrib/dev/rtw89/acpi.h | 9 +
sys/contrib/dev/rtw89/cam.c | 350 +++++--
sys/contrib/dev/rtw89/cam.h | 53 +-
sys/contrib/dev/rtw89/chan.c | 579 ++++++++---
sys/contrib/dev/rtw89/chan.h | 38 +-
sys/contrib/dev/rtw89/coex.c | 899 +++++++++++++---
sys/contrib/dev/rtw89/coex.h | 18 +-
sys/contrib/dev/rtw89/core.c | 1496 +++++++++++++++++++--------
sys/contrib/dev/rtw89/core.h | 841 ++++++++++++---
sys/contrib/dev/rtw89/debug.c | 344 ++++---
sys/contrib/dev/rtw89/debug.h | 2 +
sys/contrib/dev/rtw89/efuse.c | 150 +++
sys/contrib/dev/rtw89/efuse.h | 2 +
sys/contrib/dev/rtw89/efuse_be.c | 52 +-
sys/contrib/dev/rtw89/fw.c | 1689 +++++++++++++++++++++++--------
sys/contrib/dev/rtw89/fw.h | 508 ++++++++--
sys/contrib/dev/rtw89/mac.c | 981 ++++++++++++------
sys/contrib/dev/rtw89/mac.h | 179 +++-
sys/contrib/dev/rtw89/mac80211.c | 969 +++++++++++++++---
sys/contrib/dev/rtw89/mac_be.c | 89 +-
sys/contrib/dev/rtw89/pci.c | 193 +++-
sys/contrib/dev/rtw89/pci.h | 52 +-
sys/contrib/dev/rtw89/pci_be.c | 78 ++
sys/contrib/dev/rtw89/phy.c | 1061 ++++++++++++++-----
sys/contrib/dev/rtw89/phy.h | 58 +-
sys/contrib/dev/rtw89/phy_be.c | 12 +-
sys/contrib/dev/rtw89/ps.c | 120 ++-
sys/contrib/dev/rtw89/ps.h | 12 +-
sys/contrib/dev/rtw89/reg.h | 95 +-
sys/contrib/dev/rtw89/regd.c | 168 +--
sys/contrib/dev/rtw89/rtw8851b.c | 60 +-
sys/contrib/dev/rtw89/rtw8851b_rfk.c | 140 +--
sys/contrib/dev/rtw89/rtw8851b_rfk.h | 18 +-
sys/contrib/dev/rtw89/rtw8851be.c | 4 +
sys/contrib/dev/rtw89/rtw8852a.c | 65 +-
sys/contrib/dev/rtw89/rtw8852a.h | 4 +-
sys/contrib/dev/rtw89/rtw8852a_rfk.c | 292 +++---
sys/contrib/dev/rtw89/rtw8852a_rfk.h | 17 +-
sys/contrib/dev/rtw89/rtw8852ae.c | 4 +
sys/contrib/dev/rtw89/rtw8852b.c | 53 +-
sys/contrib/dev/rtw89/rtw8852b_common.c | 87 +-
sys/contrib/dev/rtw89/rtw8852b_common.h | 24 +-
sys/contrib/dev/rtw89/rtw8852b_rfk.c | 211 ++--
sys/contrib/dev/rtw89/rtw8852b_rfk.h | 20 +-
sys/contrib/dev/rtw89/rtw8852be.c | 4 +
sys/contrib/dev/rtw89/rtw8852bt.c | 855 ++++++++++++++++
sys/contrib/dev/rtw89/rtw8852bt.h | 2 +
sys/contrib/dev/rtw89/rtw8852bt_rfk.c | 418 ++++++--
sys/contrib/dev/rtw89/rtw8852bt_rfk.h | 23 +-
sys/contrib/dev/rtw89/rtw8852bte.c | 103 ++
sys/contrib/dev/rtw89/rtw8852c.c | 113 ++-
sys/contrib/dev/rtw89/rtw8852c_rfk.c | 278 ++---
sys/contrib/dev/rtw89/rtw8852c_rfk.h | 17 +-
sys/contrib/dev/rtw89/rtw8852ce.c | 4 +
sys/contrib/dev/rtw89/rtw8922a.c | 275 ++++-
sys/contrib/dev/rtw89/rtw8922a.h | 1 +
sys/contrib/dev/rtw89/rtw8922a_rfk.c | 61 +-
sys/contrib/dev/rtw89/rtw8922ae.c | 25 +-
sys/contrib/dev/rtw89/sar.c | 65 +-
sys/contrib/dev/rtw89/ser.c | 38 +-
sys/contrib/dev/rtw89/txrx.h | 70 +-
sys/contrib/dev/rtw89/util.h | 18 +
sys/contrib/dev/rtw89/wow.c | 486 ++++++---
sys/contrib/dev/rtw89/wow.h | 21 +
sys/modules/rtw89/Makefile | 4 +-
68 files changed, 11551 insertions(+), 3520 deletions(-)
diff --cc sys/contrib/dev/rtw89/Makefile
index 1f1050a7a89d,000000000000..c751013e811e
mode 100644,000000..100644
--- a/sys/contrib/dev/rtw89/Makefile
+++ b/sys/contrib/dev/rtw89/Makefile
@@@ -1,75 -1,0 +1,83 @@@
+# 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_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_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
+
diff --cc sys/contrib/dev/rtw89/acpi.c
index 272795188f99,000000000000..02d4526c1538
mode 100644,000000..100644
--- a/sys/contrib/dev/rtw89/acpi.c
+++ b/sys/contrib/dev/rtw89/acpi.c
@@@ -1,159 -1,0 +1,223 @@@
+// 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"
+
+#if defined(__linux__)
+static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
+ 0x82, 0xBD, 0xFE, 0x86,
+ 0x07, 0x80, 0x3A, 0xA7);
+
+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;
+}
+
+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
+ ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
+
+ ACPI_FREE(obj);
+ return ret;
+}
+#elif defined(__FreeBSD__)
+int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
+ enum rtw89_acpi_dsm_func func,
+ struct rtw89_acpi_dsm_result *res)
+{
+ return -ENOENT;
+}
+#endif
++
++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;
++ 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))
++ return -EIO;
++
++#if defined(__linux__)
++ obj = buf.pointer;
++ if (obj->type != ACPI_TYPE_BUFFER) {
++#elif defined(__FreeBSD__)
++ obj = buf.Pointer;
++ if (obj->Type != ACPI_TYPE_BUFFER) {
++#endif
++ rtw89_debug(rtwdev, RTW89_DBG_ACPI,
++#if defined(__linux__)
++ "acpi: expect buffer but type: %d\n", obj->type);
++#elif defined(__FreeBSD__)
++ "acpi: expect buffer but type: %d\n", obj->Type);
++#endif
++ ret = -EINVAL;
++ goto out;
++ }
++
++#if defined(__linux__)
++ buf_len = obj->buffer.length;
++#elif defined(__FreeBSD__)
++ buf_len = obj->Buffer.Length;
++#endif
++ if (buf_len != sizeof(*res)) {
++ rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
++ __func__, buf_len);
++ ret = -EINVAL;
++ goto out;
++ }
++
++#if defined(__linux__)
++ *res = *(struct rtw89_acpi_rtag_result *)obj->buffer.pointer;
++#elif defined(__FreeBSD__)
++ *res = *(struct rtw89_acpi_rtag_result *)obj->Buffer.Pointer;
++#endif
++
++ rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "antenna_gain: ", res, sizeof(*res));
++
++out:
++ ACPI_FREE(obj);
++ return ret;
++}
diff --cc sys/contrib/dev/rtw89/core.c
index 85d8dee4e85d,000000000000..e002af84f1d1
mode 100644,000000..100644
--- a/sys/contrib/dev/rtw89/core.c
+++ b/sys/contrib/dev/rtw89/core.c
@@@ -1,4809 -1,0 +1,5509 @@@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2019-2020 Realtek Corporation
+ */
+
+#if defined(__FreeBSD__)
+#define LINUXKPI_PARAM_PREFIX rtw89_
+#endif
+
+#include <linux/ip.h>
+#include <linux/udp.h>
+
+#include "cam.h"
+#include "chan.h"
+#include "coex.h"
+#include "core.h"
+#include "efuse.h"
+#include "fw.h"
+#include "mac.h"
+#include "phy.h"
+#include "ps.h"
+#include "reg.h"
+#include "sar.h"
+#include "ser.h"
+#include "txrx.h"
+#include "util.h"
+#include "wow.h"
+
+static bool rtw89_disable_ps_mode;
+module_param_named(disable_ps_mode, rtw89_disable_ps_mode, bool, 0644);
+MODULE_PARM_DESC(disable_ps_mode, "Set Y to disable low power mode");
+
+#if defined(__FreeBSD__)
+static bool rtw_ht_support = false;
+module_param_named(support_ht, rtw_ht_support, bool, 0644);
+MODULE_PARM_DESC(support_ht, "Set to Y to enable HT support");
+
+static bool rtw_vht_support = false;
+module_param_named(support_vht, rtw_vht_support, bool, 0644);
+MODULE_PARM_DESC(support_vht, "Set to Y to enable VHT support");
+
+static bool rtw_eht_support = false;
+module_param_named(support_eht, rtw_eht_support, bool, 0644);
+MODULE_PARM_DESC(support_eht, "Set to Y to enable EHT support");
+#endif
+
+
+#define RTW89_DEF_CHAN(_freq, _hw_val, _flags, _band) \
+ { .center_freq = _freq, .hw_value = _hw_val, .flags = _flags, .band = _band, }
+#define RTW89_DEF_CHAN_2G(_freq, _hw_val) \
+ RTW89_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_2GHZ)
+#define RTW89_DEF_CHAN_5G(_freq, _hw_val) \
+ RTW89_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_5GHZ)
+#define RTW89_DEF_CHAN_5G_NO_HT40MINUS(_freq, _hw_val) \
+ RTW89_DEF_CHAN(_freq, _hw_val, IEEE80211_CHAN_NO_HT40MINUS, NL80211_BAND_5GHZ)
+#define RTW89_DEF_CHAN_6G(_freq, _hw_val) \
+ RTW89_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_6GHZ)
+
+static struct ieee80211_channel rtw89_channels_2ghz[] = {
+ RTW89_DEF_CHAN_2G(2412, 1),
+ RTW89_DEF_CHAN_2G(2417, 2),
+ RTW89_DEF_CHAN_2G(2422, 3),
+ RTW89_DEF_CHAN_2G(2427, 4),
+ RTW89_DEF_CHAN_2G(2432, 5),
+ RTW89_DEF_CHAN_2G(2437, 6),
+ RTW89_DEF_CHAN_2G(2442, 7),
+ RTW89_DEF_CHAN_2G(2447, 8),
+ RTW89_DEF_CHAN_2G(2452, 9),
+ RTW89_DEF_CHAN_2G(2457, 10),
+ RTW89_DEF_CHAN_2G(2462, 11),
+ RTW89_DEF_CHAN_2G(2467, 12),
+ RTW89_DEF_CHAN_2G(2472, 13),
+ RTW89_DEF_CHAN_2G(2484, 14),
+};
+
+static struct ieee80211_channel rtw89_channels_5ghz[] = {
+ RTW89_DEF_CHAN_5G(5180, 36),
+ RTW89_DEF_CHAN_5G(5200, 40),
+ RTW89_DEF_CHAN_5G(5220, 44),
+ RTW89_DEF_CHAN_5G(5240, 48),
+ RTW89_DEF_CHAN_5G(5260, 52),
+ RTW89_DEF_CHAN_5G(5280, 56),
+ RTW89_DEF_CHAN_5G(5300, 60),
+ RTW89_DEF_CHAN_5G(5320, 64),
+ RTW89_DEF_CHAN_5G(5500, 100),
+ RTW89_DEF_CHAN_5G(5520, 104),
+ RTW89_DEF_CHAN_5G(5540, 108),
+ RTW89_DEF_CHAN_5G(5560, 112),
+ RTW89_DEF_CHAN_5G(5580, 116),
+ RTW89_DEF_CHAN_5G(5600, 120),
+ RTW89_DEF_CHAN_5G(5620, 124),
+ RTW89_DEF_CHAN_5G(5640, 128),
+ RTW89_DEF_CHAN_5G(5660, 132),
+ RTW89_DEF_CHAN_5G(5680, 136),
+ RTW89_DEF_CHAN_5G(5700, 140),
+ RTW89_DEF_CHAN_5G(5720, 144),
+ RTW89_DEF_CHAN_5G(5745, 149),
+ RTW89_DEF_CHAN_5G(5765, 153),
+ RTW89_DEF_CHAN_5G(5785, 157),
+ RTW89_DEF_CHAN_5G(5805, 161),
+ RTW89_DEF_CHAN_5G_NO_HT40MINUS(5825, 165),
+ RTW89_DEF_CHAN_5G(5845, 169),
+ RTW89_DEF_CHAN_5G(5865, 173),
+ RTW89_DEF_CHAN_5G(5885, 177),
+};
+
+static_assert(RTW89_5GHZ_UNII4_START_INDEX + RTW89_5GHZ_UNII4_CHANNEL_NUM ==
+ ARRAY_SIZE(rtw89_channels_5ghz));
+
+static struct ieee80211_channel rtw89_channels_6ghz[] = {
+ RTW89_DEF_CHAN_6G(5955, 1),
+ RTW89_DEF_CHAN_6G(5975, 5),
+ RTW89_DEF_CHAN_6G(5995, 9),
+ RTW89_DEF_CHAN_6G(6015, 13),
+ RTW89_DEF_CHAN_6G(6035, 17),
+ RTW89_DEF_CHAN_6G(6055, 21),
+ RTW89_DEF_CHAN_6G(6075, 25),
+ RTW89_DEF_CHAN_6G(6095, 29),
+ RTW89_DEF_CHAN_6G(6115, 33),
+ RTW89_DEF_CHAN_6G(6135, 37),
+ RTW89_DEF_CHAN_6G(6155, 41),
+ RTW89_DEF_CHAN_6G(6175, 45),
+ RTW89_DEF_CHAN_6G(6195, 49),
+ RTW89_DEF_CHAN_6G(6215, 53),
+ RTW89_DEF_CHAN_6G(6235, 57),
+ RTW89_DEF_CHAN_6G(6255, 61),
+ RTW89_DEF_CHAN_6G(6275, 65),
+ RTW89_DEF_CHAN_6G(6295, 69),
+ RTW89_DEF_CHAN_6G(6315, 73),
+ RTW89_DEF_CHAN_6G(6335, 77),
+ RTW89_DEF_CHAN_6G(6355, 81),
+ RTW89_DEF_CHAN_6G(6375, 85),
+ RTW89_DEF_CHAN_6G(6395, 89),
+ RTW89_DEF_CHAN_6G(6415, 93),
+ RTW89_DEF_CHAN_6G(6435, 97),
+ RTW89_DEF_CHAN_6G(6455, 101),
+ RTW89_DEF_CHAN_6G(6475, 105),
+ RTW89_DEF_CHAN_6G(6495, 109),
+ RTW89_DEF_CHAN_6G(6515, 113),
+ RTW89_DEF_CHAN_6G(6535, 117),
+ RTW89_DEF_CHAN_6G(6555, 121),
+ RTW89_DEF_CHAN_6G(6575, 125),
+ RTW89_DEF_CHAN_6G(6595, 129),
+ RTW89_DEF_CHAN_6G(6615, 133),
+ RTW89_DEF_CHAN_6G(6635, 137),
+ RTW89_DEF_CHAN_6G(6655, 141),
+ RTW89_DEF_CHAN_6G(6675, 145),
+ RTW89_DEF_CHAN_6G(6695, 149),
+ RTW89_DEF_CHAN_6G(6715, 153),
+ RTW89_DEF_CHAN_6G(6735, 157),
+ RTW89_DEF_CHAN_6G(6755, 161),
+ RTW89_DEF_CHAN_6G(6775, 165),
+ RTW89_DEF_CHAN_6G(6795, 169),
+ RTW89_DEF_CHAN_6G(6815, 173),
+ RTW89_DEF_CHAN_6G(6835, 177),
+ RTW89_DEF_CHAN_6G(6855, 181),
+ RTW89_DEF_CHAN_6G(6875, 185),
+ RTW89_DEF_CHAN_6G(6895, 189),
+ RTW89_DEF_CHAN_6G(6915, 193),
+ RTW89_DEF_CHAN_6G(6935, 197),
+ RTW89_DEF_CHAN_6G(6955, 201),
+ RTW89_DEF_CHAN_6G(6975, 205),
+ RTW89_DEF_CHAN_6G(6995, 209),
+ RTW89_DEF_CHAN_6G(7015, 213),
+ RTW89_DEF_CHAN_6G(7035, 217),
+ RTW89_DEF_CHAN_6G(7055, 221),
+ RTW89_DEF_CHAN_6G(7075, 225),
+ RTW89_DEF_CHAN_6G(7095, 229),
+ RTW89_DEF_CHAN_6G(7115, 233),
+};
+
+static struct ieee80211_rate rtw89_bitrates[] = {
+ { .bitrate = 10, .hw_value = 0x00, },
+ { .bitrate = 20, .hw_value = 0x01, },
+ { .bitrate = 55, .hw_value = 0x02, },
+ { .bitrate = 110, .hw_value = 0x03, },
+ { .bitrate = 60, .hw_value = 0x04, },
+ { .bitrate = 90, .hw_value = 0x05, },
+ { .bitrate = 120, .hw_value = 0x06, },
+ { .bitrate = 180, .hw_value = 0x07, },
+ { .bitrate = 240, .hw_value = 0x08, },
+ { .bitrate = 360, .hw_value = 0x09, },
+ { .bitrate = 480, .hw_value = 0x0a, },
+ { .bitrate = 540, .hw_value = 0x0b, },
+};
+
+static const struct ieee80211_iface_limit rtw89_iface_limits[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_AP),
+ },
+};
+
+static const struct ieee80211_iface_limit rtw89_iface_limits_mcc[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO),
+ },
+};
+
+static const struct ieee80211_iface_combination rtw89_iface_combs[] = {
+ {
+ .limits = rtw89_iface_limits,
+ .n_limits = ARRAY_SIZE(rtw89_iface_limits),
- .max_interfaces = 2,
++ .max_interfaces = RTW89_MAX_INTERFACE_NUM,
+ .num_different_channels = 1,
+ },
+ {
+ .limits = rtw89_iface_limits_mcc,
+ .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc),
- .max_interfaces = 2,
++ .max_interfaces = RTW89_MAX_INTERFACE_NUM,
+ .num_different_channels = 2,
+ },
+};
+
++#define RTW89_6GHZ_SPAN_HEAD 6145
++#define RTW89_6GHZ_SPAN_IDX(center_freq) \
++ ((((int)(center_freq) - RTW89_6GHZ_SPAN_HEAD) / 5) / 2)
++
++#define RTW89_DECL_6GHZ_SPAN(center_freq, subband_l, subband_h) \
++ [RTW89_6GHZ_SPAN_IDX(center_freq)] = { \
++ .sar_subband_low = RTW89_SAR_6GHZ_ ## subband_l, \
++ .sar_subband_high = RTW89_SAR_6GHZ_ ## subband_h, \
++ .ant_gain_subband_low = RTW89_ANT_GAIN_6GHZ_ ## subband_l, \
++ .ant_gain_subband_high = RTW89_ANT_GAIN_6GHZ_ ## subband_h, \
++ }
++
++/* Since 6GHz subbands are not edge aligned, some cases span two subbands.
++ * In the following, we describe each of them with rtw89_6ghz_span.
++ */
++static const struct rtw89_6ghz_span rtw89_overlapping_6ghz[] = {
++ RTW89_DECL_6GHZ_SPAN(6145, SUBBAND_5_L, SUBBAND_5_H),
++ RTW89_DECL_6GHZ_SPAN(6165, SUBBAND_5_L, SUBBAND_5_H),
++ RTW89_DECL_6GHZ_SPAN(6185, SUBBAND_5_L, SUBBAND_5_H),
++ RTW89_DECL_6GHZ_SPAN(6505, SUBBAND_6, SUBBAND_7_L),
++ RTW89_DECL_6GHZ_SPAN(6525, SUBBAND_6, SUBBAND_7_L),
++ RTW89_DECL_6GHZ_SPAN(6545, SUBBAND_6, SUBBAND_7_L),
++ RTW89_DECL_6GHZ_SPAN(6665, SUBBAND_7_L, SUBBAND_7_H),
++ RTW89_DECL_6GHZ_SPAN(6705, SUBBAND_7_L, SUBBAND_7_H),
++ RTW89_DECL_6GHZ_SPAN(6825, SUBBAND_7_H, SUBBAND_8),
++ RTW89_DECL_6GHZ_SPAN(6865, SUBBAND_7_H, SUBBAND_8),
++ RTW89_DECL_6GHZ_SPAN(6875, SUBBAND_7_H, SUBBAND_8),
++ RTW89_DECL_6GHZ_SPAN(6885, SUBBAND_7_H, SUBBAND_8),
++};
++
++const struct rtw89_6ghz_span *
++rtw89_get_6ghz_span(struct rtw89_dev *rtwdev, u32 center_freq)
++{
++ int idx;
++
++ if (center_freq >= RTW89_6GHZ_SPAN_HEAD) {
++ idx = RTW89_6GHZ_SPAN_IDX(center_freq);
++ /* To decrease size of rtw89_overlapping_6ghz[],
++ * RTW89_6GHZ_SPAN_IDX() truncates the leading NULLs
++ * to make first span as index 0 of the table. So, if center
++ * frequency is less than the first one, it will get netative.
++ */
++ if (idx >= 0 && idx < ARRAY_SIZE(rtw89_overlapping_6ghz))
++ return &rtw89_overlapping_6ghz[idx];
++ }
++
++ return NULL;
++}
++
+bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate)
+{
+ struct ieee80211_rate rate;
+
+ if (unlikely(rpt_rate >= ARRAY_SIZE(rtw89_bitrates))) {
+ rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rpt rate %d\n", rpt_rate);
+ return false;
+ }
+
+ rate = rtw89_bitrates[rpt_rate];
+ *bitrate = rate.bitrate;
+
+ return true;
+}
+
+static const struct ieee80211_supported_band rtw89_sband_2ghz = {
+ .band = NL80211_BAND_2GHZ,
+ .channels = rtw89_channels_2ghz,
+ .n_channels = ARRAY_SIZE(rtw89_channels_2ghz),
+ .bitrates = rtw89_bitrates,
+ .n_bitrates = ARRAY_SIZE(rtw89_bitrates),
+ .ht_cap = {0},
+ .vht_cap = {0},
+};
+
+static const struct ieee80211_supported_band rtw89_sband_5ghz = {
+ .band = NL80211_BAND_5GHZ,
+ .channels = rtw89_channels_5ghz,
+ .n_channels = ARRAY_SIZE(rtw89_channels_5ghz),
+
+ /* 5G has no CCK rates, 1M/2M/5.5M/11M */
+ .bitrates = rtw89_bitrates + 4,
+ .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4,
+ .ht_cap = {0},
+ .vht_cap = {0},
+};
+
+static const struct ieee80211_supported_band rtw89_sband_6ghz = {
+ .band = NL80211_BAND_6GHZ,
+ .channels = rtw89_channels_6ghz,
+ .n_channels = ARRAY_SIZE(rtw89_channels_6ghz),
+
+ /* 6G has no CCK rates, 1M/2M/5.5M/11M */
+ .bitrates = rtw89_bitrates + 4,
+ .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4,
+};
+
+static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev,
+ struct rtw89_traffic_stats *stats,
+ struct sk_buff *skb, bool tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (tx && ieee80211_is_assoc_req(hdr->frame_control))
+ rtw89_wow_parse_akm(rtwdev, skb);
+
+ if (!ieee80211_is_data(hdr->frame_control))
+ return;
+
+ if (is_broadcast_ether_addr(hdr->addr1) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return;
+
+ if (tx) {
+ stats->tx_cnt++;
+ stats->tx_unicast += skb->len;
+ } else {
+ stats->rx_cnt++;
+ stats->rx_unicast += skb->len;
+ }
+}
+
+void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef)
+{
+ cfg80211_chandef_create(chandef, &rtw89_channels_2ghz[0],
+ NL80211_CHAN_NO_HT);
+}
+
+void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
+ struct rtw89_chan *chan)
+{
+ struct ieee80211_channel *channel = chandef->chan;
+ enum nl80211_chan_width width = chandef->width;
+ u32 primary_freq, center_freq;
+ u8 center_chan;
+ u8 bandwidth = RTW89_CHANNEL_WIDTH_20;
+ u32 offset;
+ u8 band;
+
+ center_chan = channel->hw_value;
+ primary_freq = channel->center_freq;
+ center_freq = chandef->center_freq1;
+
+ switch (width) {
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ bandwidth = RTW89_CHANNEL_WIDTH_20;
+ break;
+ case NL80211_CHAN_WIDTH_40:
+ bandwidth = RTW89_CHANNEL_WIDTH_40;
+ if (primary_freq > center_freq) {
+ center_chan -= 2;
+ } else {
+ center_chan += 2;
+ }
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ case NL80211_CHAN_WIDTH_160:
+ bandwidth = nl_to_rtw89_bandwidth(width);
+ if (primary_freq > center_freq) {
+ offset = (primary_freq - center_freq - 10) / 20;
+ center_chan -= 2 + offset * 4;
+ } else {
+ offset = (center_freq - primary_freq - 10) / 20;
+ center_chan += 2 + offset * 4;
+ }
+ break;
+ default:
+ center_chan = 0;
+ break;
+ }
+
+ switch (channel->band) {
+ default:
+ case NL80211_BAND_2GHZ:
+ band = RTW89_BAND_2G;
+ break;
+ case NL80211_BAND_5GHZ:
+ band = RTW89_BAND_5G;
+ break;
+ case NL80211_BAND_6GHZ:
+ band = RTW89_BAND_6G;
+ break;
+ }
+
+ rtw89_chan_create(chan, center_chan, channel->hw_value, band, bandwidth);
+}
+
- void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
++static void __rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev,
++ const struct rtw89_chan *chan,
++ enum rtw89_phy_idx phy_idx)
+{
- struct rtw89_hal *hal = &rtwdev->hal;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct rtw89_chan *chan;
- enum rtw89_sub_entity_idx sub_entity_idx;
- enum rtw89_sub_entity_idx roc_idx;
- enum rtw89_phy_idx phy_idx;
- enum rtw89_entity_mode mode;
+ bool entity_active;
+
- entity_active = rtw89_get_entity_state(rtwdev);
++ entity_active = rtw89_get_entity_state(rtwdev, phy_idx);
+ if (!entity_active)
+ return;
+
- mode = rtw89_get_entity_mode(rtwdev);
- switch (mode) {
- case RTW89_ENTITY_MODE_SCC:
- case RTW89_ENTITY_MODE_MCC:
- sub_entity_idx = RTW89_SUB_ENTITY_0;
- break;
- case RTW89_ENTITY_MODE_MCC_PREPARE:
- sub_entity_idx = RTW89_SUB_ENTITY_1;
- break;
- default:
- WARN(1, "Invalid ent mode: %d\n", mode);
- return;
- }
++ chip->ops->set_txpwr(rtwdev, chan, phy_idx);
++}
++
++void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
++{
++ const struct rtw89_chan *chan;
+
- roc_idx = atomic_read(&hal->roc_entity_idx);
- if (roc_idx != RTW89_SUB_ENTITY_IDLE)
- sub_entity_idx = roc_idx;
++ chan = rtw89_mgnt_chan_get(rtwdev, 0);
++ __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_0);
+
- phy_idx = RTW89_PHY_0;
- chan = rtw89_chan_get(rtwdev, sub_entity_idx);
- chip->ops->set_txpwr(rtwdev, chan, phy_idx);
++ if (!rtwdev->support_mlo)
++ return;
++
++ chan = rtw89_mgnt_chan_get(rtwdev, 1);
++ __rtw89_core_set_chip_txpwr(rtwdev, chan, RTW89_PHY_1);
+}
+
- int rtw89_set_channel(struct rtw89_dev *rtwdev)
++static void __rtw89_set_channel(struct rtw89_dev *rtwdev,
++ const struct rtw89_chan *chan,
++ enum rtw89_mac_idx mac_idx,
++ enum rtw89_phy_idx phy_idx)
+{
- struct rtw89_hal *hal = &rtwdev->hal;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_chan_rcd *chan_rcd;
- const struct rtw89_chan *chan;
- enum rtw89_sub_entity_idx sub_entity_idx;
- enum rtw89_sub_entity_idx roc_idx;
- enum rtw89_mac_idx mac_idx;
- enum rtw89_phy_idx phy_idx;
+ struct rtw89_channel_help_params bak;
- enum rtw89_entity_mode mode;
+ bool entity_active;
+
- entity_active = rtw89_get_entity_state(rtwdev);
++ entity_active = rtw89_get_entity_state(rtwdev, phy_idx);
+
- mode = rtw89_entity_recalc(rtwdev);
- switch (mode) {
- case RTW89_ENTITY_MODE_SCC:
- case RTW89_ENTITY_MODE_MCC:
- sub_entity_idx = RTW89_SUB_ENTITY_0;
- break;
- case RTW89_ENTITY_MODE_MCC_PREPARE:
- sub_entity_idx = RTW89_SUB_ENTITY_1;
- break;
- default:
- WARN(1, "Invalid ent mode: %d\n", mode);
- return -EINVAL;
- }
-
- roc_idx = atomic_read(&hal->roc_entity_idx);
- if (roc_idx != RTW89_SUB_ENTITY_IDLE)
- sub_entity_idx = roc_idx;
-
- mac_idx = RTW89_MAC_0;
- phy_idx = RTW89_PHY_0;
-
- chan = rtw89_chan_get(rtwdev, sub_entity_idx);
- chan_rcd = rtw89_chan_rcd_get(rtwdev, sub_entity_idx);
++ chan_rcd = rtw89_chan_rcd_get_by_chan(chan);
+
+ rtw89_chip_set_channel_prepare(rtwdev, &bak, chan, mac_idx, phy_idx);
+
+ chip->ops->set_channel(rtwdev, chan, mac_idx, phy_idx);
+
+ chip->ops->set_txpwr(rtwdev, chan, phy_idx);
+
+ rtw89_chip_set_channel_done(rtwdev, &bak, chan, mac_idx, phy_idx);
+
+ if (!entity_active || chan_rcd->band_changed) {
+ rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan->band_type);
- rtw89_chip_rfk_band_changed(rtwdev, phy_idx);
++ rtw89_chip_rfk_band_changed(rtwdev, phy_idx, chan);
+ }
+
- rtw89_set_entity_state(rtwdev, true);
- return 0;
++ rtw89_set_entity_state(rtwdev, phy_idx, true);
+}
+
- void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
- struct rtw89_chan *chan)
++int rtw89_set_channel(struct rtw89_dev *rtwdev)
+{
- const struct cfg80211_chan_def *chandef;
++ const struct rtw89_chan *chan;
++ enum rtw89_entity_mode mode;
++
++ mode = rtw89_entity_recalc(rtwdev);
++ if (mode < 0 || mode >= NUM_OF_RTW89_ENTITY_MODE) {
++ WARN(1, "Invalid ent mode: %d\n", mode);
++ return -EINVAL;
++ }
++
++ chan = rtw89_mgnt_chan_get(rtwdev, 0);
++ __rtw89_set_channel(rtwdev, chan, RTW89_MAC_0, RTW89_PHY_0);
+
- chandef = rtw89_chandef_get(rtwdev, rtwvif->sub_entity_idx);
- rtw89_get_channel_params(chandef, chan);
++ if (!rtwdev->support_mlo)
++ return 0;
++
++ chan = rtw89_mgnt_chan_get(rtwdev, 1);
++ __rtw89_set_channel(rtwdev, chan, RTW89_MAC_1, RTW89_PHY_1);
++
++ return 0;
+}
+
+static enum rtw89_core_tx_type
+rtw89_core_get_tx_type(struct rtw89_dev *rtwdev,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (void *)skb->data;
+ __le16 fc = hdr->frame_control;
+
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc))
+ return RTW89_CORE_TX_TYPE_MGMT;
+
+ return RTW89_CORE_TX_TYPE_DATA;
*** 56936 LINES SKIPPED ***