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 ***