aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2024-10-04 00:00:23 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2024-10-28 14:42:36 +0000
commit6d67aabd63555ab62a2f2b7f52a75ef100a2fe75 (patch)
tree66e6efd2cf35a0e3f3723520d140411632f6a7af
parent11c53278a8a3e86e14377f09bbaa7bad193d3713 (diff)
parent5b760eaecd6c3977aeacfe1654940f6ecd1d4d3e (diff)
downloadsrc-6d67aabd6355.tar.gz
src-6d67aabd6355.zip
rtw89: update Realtek's rtw89 driver.
This adds support for the Realtek 8922AE PCI wireless network (Wi-Fi 7) adapter. This version is based on git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 98f7e32f20d28ec452afb208f9cffc08448a2652 ( tag: v6.11 ). Sponsored by: The FreeBSD Foundation MFC after: 14 days
-rw-r--r--share/man/man4/rtw89.411
-rw-r--r--sys/contrib/dev/rtw89/Kconfig19
-rw-r--r--sys/contrib/dev/rtw89/Makefile18
-rw-r--r--sys/contrib/dev/rtw89/acpi.c131
-rw-r--r--sys/contrib/dev/rtw89/acpi.h53
-rw-r--r--sys/contrib/dev/rtw89/cam.c277
-rw-r--r--sys/contrib/dev/rtw89/cam.h180
-rw-r--r--sys/contrib/dev/rtw89/chan.c2261
-rw-r--r--sys/contrib/dev/rtw89/chan.h48
-rw-r--r--sys/contrib/dev/rtw89/coex.c2978
-rw-r--r--sys/contrib/dev/rtw89/coex.h176
-rw-r--r--sys/contrib/dev/rtw89/core.c1233
-rw-r--r--sys/contrib/dev/rtw89/core.h1468
-rw-r--r--sys/contrib/dev/rtw89/debug.c440
-rw-r--r--sys/contrib/dev/rtw89/debug.h19
-rw-r--r--sys/contrib/dev/rtw89/efuse.c11
-rw-r--r--sys/contrib/dev/rtw89/efuse.h18
-rw-r--r--sys/contrib/dev/rtw89/efuse_be.c562
-rw-r--r--sys/contrib/dev/rtw89/fw.c4030
-rw-r--r--sys/contrib/dev/rtw89/fw.h2329
-rw-r--r--sys/contrib/dev/rtw89/mac.c1738
-rw-r--r--sys/contrib/dev/rtw89/mac.h377
-rw-r--r--sys/contrib/dev/rtw89/mac80211.c138
-rw-r--r--sys/contrib/dev/rtw89/mac_be.c2606
-rw-r--r--sys/contrib/dev/rtw89/pci.c794
-rw-r--r--sys/contrib/dev/rtw89/pci.h623
-rw-r--r--sys/contrib/dev/rtw89/pci_be.c618
-rw-r--r--sys/contrib/dev/rtw89/phy.c2518
-rw-r--r--sys/contrib/dev/rtw89/phy.h429
-rw-r--r--sys/contrib/dev/rtw89/phy_be.c1002
-rw-r--r--sys/contrib/dev/rtw89/ps.c97
-rw-r--r--sys/contrib/dev/rtw89/ps.h8
-rw-r--r--sys/contrib/dev/rtw89/reg.h4292
-rw-r--r--sys/contrib/dev/rtw89/regd.c522
-rw-r--r--sys/contrib/dev/rtw89/rtw8851b.c243
-rw-r--r--sys/contrib/dev/rtw89/rtw8851b_table.c1409
-rw-r--r--sys/contrib/dev/rtw89/rtw8851b_table.h3
-rw-r--r--sys/contrib/dev/rtw89/rtw8851be.c7
-rw-r--r--sys/contrib/dev/rtw89/rtw8852a.c158
-rw-r--r--sys/contrib/dev/rtw89/rtw8852a_table.c2
-rw-r--r--sys/contrib/dev/rtw89/rtw8852a_table.h1
-rw-r--r--sys/contrib/dev/rtw89/rtw8852ae.c7
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b.c1988
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b.h122
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b_common.c2053
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b_common.h388
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b_rfk.c25
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b_table.c459
-rw-r--r--sys/contrib/dev/rtw89/rtw8852b_table.h3
-rw-r--r--sys/contrib/dev/rtw89/rtw8852be.c7
-rw-r--r--sys/contrib/dev/rtw89/rtw8852bt.h13
-rw-r--r--sys/contrib/dev/rtw89/rtw8852bt_rfk.c4019
-rw-r--r--sys/contrib/dev/rtw89/rtw8852bt_rfk.h22
-rw-r--r--sys/contrib/dev/rtw89/rtw8852bt_rfk_table.c490
-rw-r--r--sys/contrib/dev/rtw89/rtw8852bt_rfk_table.h38
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c.c231
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c.h20
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c_rfk.c93
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c_rfk.h3
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c_rfk_table.c42
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c_table.c4488
-rw-r--r--sys/contrib/dev/rtw89/rtw8852c_table.h3
-rw-r--r--sys/contrib/dev/rtw89/rtw8852ce.c29
-rw-r--r--sys/contrib/dev/rtw89/rtw8922a.c2639
-rw-r--r--sys/contrib/dev/rtw89/rtw8922a.h73
-rw-r--r--sys/contrib/dev/rtw89/rtw8922a_rfk.c391
-rw-r--r--sys/contrib/dev/rtw89/rtw8922a_rfk.h18
-rw-r--r--sys/contrib/dev/rtw89/rtw8922ae.c94
-rw-r--r--sys/contrib/dev/rtw89/sar.c222
-rw-r--r--sys/contrib/dev/rtw89/sar.h14
-rw-r--r--sys/contrib/dev/rtw89/ser.c44
-rw-r--r--sys/contrib/dev/rtw89/txrx.h279
-rw-r--r--sys/contrib/dev/rtw89/util.c106
-rw-r--r--sys/contrib/dev/rtw89/util.h5
-rw-r--r--sys/contrib/dev/rtw89/wow.c787
-rw-r--r--sys/contrib/dev/rtw89/wow.h87
-rw-r--r--sys/modules/rtw89/Makefile11
77 files changed, 45031 insertions, 8129 deletions
diff --git a/share/man/man4/rtw89.4 b/share/man/man4/rtw89.4
index 2e1f2676eb8e..14259ae5e077 100644
--- a/share/man/man4/rtw89.4
+++ b/share/man/man4/rtw89.4
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 10, 2024
+.Dd October 12, 2024
.Dt RTW89 4
.Os
.Sh NAME
@@ -101,10 +101,11 @@ The
driver supports PCIe devices with the following chipsets:
.Pp
.Bl -tag -width Ds -offset indent -compact
-.It Realtek 802.11ax wireless 8851be (RTL8851BE)
-.It Realtek 802.11ax wireless 8852ae (RTL8852AE)
-.It Realtek 802.11ax wireless 8852be (RTL8852BE)
-.It Realtek 802.11ax wireless 8852ce (RTL8852CE)
+.It Realtek 8851BE Wi-Fi 6 (RTL8851BE)
+.It Realtek 8852AE Wi-Fi 6 (RTL8852AE)
+.It Realtek 8852BE Wi-Fi 6 (RTL8852BE)
+.It Realtek 8852CE Wi-Fi 6E (RTL8852CE)
+.It Realtek 8922AE Wi-Fi 7 (RTL8922AE)
.El
.Sh BUGS
Certainly.
diff --git a/sys/contrib/dev/rtw89/Kconfig b/sys/contrib/dev/rtw89/Kconfig
index 90ffbab7cc4c..3c9f864805b1 100644
--- a/sys/contrib/dev/rtw89/Kconfig
+++ b/sys/contrib/dev/rtw89/Kconfig
@@ -22,12 +22,18 @@ config RTW89_8851B
config RTW89_8852A
tristate
+config RTW89_8852B_COMMON
+ tristate
+
config RTW89_8852B
tristate
config RTW89_8852C
tristate
+config RTW89_8922A
+ tristate
+
config RTW89_8851BE
tristate "Realtek 8851BE PCI wireless network (Wi-Fi 6) adapter"
depends on PCI
@@ -56,6 +62,7 @@ config RTW89_8852BE
select RTW89_CORE
select RTW89_PCI
select RTW89_8852B
+ select RTW89_8852B_COMMON
help
Select this option will enable support for 8852BE chipset
@@ -72,6 +79,18 @@ config RTW89_8852CE
802.11ax PCIe wireless network (Wi-Fi 6E) adapter
+config RTW89_8922AE
+ tristate "Realtek 8922AE PCI wireless network (Wi-Fi 7) adapter"
+ depends on PCI
+ select RTW89_CORE
+ select RTW89_PCI
+ select RTW89_8922A
+ help
+ Select this option will enable support for 8922AE chipset
+
+ 802.11be PCIe wireless network (Wi-Fi 7) adapter
+ supporting 2x2 2GHz/5GHz/6GHz 4096-QAM 160MHz channels.
+
config RTW89_DEBUG
bool
diff --git a/sys/contrib/dev/rtw89/Makefile b/sys/contrib/dev/rtw89/Makefile
index 41940099af1b..1f1050a7a89d 100644
--- a/sys/contrib/dev/rtw89/Makefile
+++ b/sys/contrib/dev/rtw89/Makefile
@@ -4,17 +4,21 @@ 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
+ acpi.o \
+ util.o
rtw89_core-$(CONFIG_PM) += wow.o
@@ -36,6 +40,9 @@ rtw89_8852a-objs := rtw8852a.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 \
@@ -54,8 +61,15 @@ rtw89_8852c-objs := rtw8852c.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
+rtw89_pci-y := pci.o pci_be.o
diff --git a/sys/contrib/dev/rtw89/acpi.c b/sys/contrib/dev/rtw89/acpi.c
index 83252c861c82..272795188f99 100644
--- a/sys/contrib/dev/rtw89/acpi.c
+++ b/sys/contrib/dev/rtw89/acpi.c
@@ -13,27 +13,118 @@ 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(struct rtw89_dev *rtwdev, union acpi_object *obj,
- u8 *value)
+static
+int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj,
+ u8 *value)
{
- switch (obj->type) {
- case ACPI_TYPE_INTEGER:
- *value = (u8)obj->integer.value;
- break;
- case ACPI_TYPE_BUFFER:
- *value = obj->buffer.pointer[0];
- break;
- default:
- rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
- "acpi dsm return unhandled type: %d\n", obj->type);
+ 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, u8 *value)
+ enum rtw89_acpi_dsm_func func,
+ struct rtw89_acpi_dsm_result *res)
{
union acpi_object *obj;
int ret;
@@ -41,19 +132,27 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
0, func, NULL);
if (!obj) {
- rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI,
"acpi dsm fail to evaluate func: %d\n", func);
return -ENOENT;
}
- ret = rtw89_acpi_dsm_get(rtwdev, obj, value);
+ 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, u8 *value)
+ enum rtw89_acpi_dsm_func func,
+ struct rtw89_acpi_dsm_result *res)
{
return -ENOENT;
}
diff --git a/sys/contrib/dev/rtw89/acpi.h b/sys/contrib/dev/rtw89/acpi.h
index ed74d8ceb733..d274be1775bf 100644
--- a/sys/contrib/dev/rtw89/acpi.h
+++ b/sys/contrib/dev/rtw89/acpi.h
@@ -12,10 +12,59 @@ enum rtw89_acpi_dsm_func {
RTW89_ACPI_DSM_FUNC_6G_DIS = 3,
RTW89_ACPI_DSM_FUNC_6G_BP = 4,
RTW89_ACPI_DSM_FUNC_TAS_EN = 5,
- RTW89_ACPI_DSM_FUNC_59G_EN = 6,
+ RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6,
+ RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7,
+};
+
+enum rtw89_acpi_conf_unii4 {
+ RTW89_ACPI_CONF_UNII4_FCC = BIT(0),
+ RTW89_ACPI_CONF_UNII4_IC = BIT(1),
+};
+
+enum rtw89_acpi_policy_mode {
+ RTW89_ACPI_POLICY_BLOCK = 0,
+ RTW89_ACPI_POLICY_ALLOW = 1,
+};
+
+struct rtw89_acpi_country_code {
+ /* below are allowed:
+ * * ISO alpha2 country code
+ * * EU for countries in Europe
+ */
+ char alpha2[2];
+} __packed;
+
+struct rtw89_acpi_policy_6ghz {
+ u8 signature[3];
+ u8 rsvd;
+ u8 policy_mode;
+ u8 country_count;
+ struct rtw89_acpi_country_code country_list[] __counted_by(country_count);
+} __packed;
+
+enum rtw89_acpi_conf_6ghz_sp {
+ RTW89_ACPI_CONF_6GHZ_SP_US = BIT(0),
+};
+
+struct rtw89_acpi_policy_6ghz_sp {
+ u8 signature[4];
+ u8 revision;
+ u8 override;
+ u8 conf;
+ u8 rsvd;
+} __packed;
+
+struct rtw89_acpi_dsm_result {
+ union {
+ u8 value;
+ /* caller needs to free it after using */
+ struct rtw89_acpi_policy_6ghz *policy_6ghz;
+ struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp;
+ } u;
};
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
- enum rtw89_acpi_dsm_func func, u8 *value);
+ enum rtw89_acpi_dsm_func func,
+ struct rtw89_acpi_dsm_result *res);
#endif
diff --git a/sys/contrib/dev/rtw89/cam.c b/sys/contrib/dev/rtw89/cam.c
index f5301c2bbf13..4557c6e035a9 100644
--- a/sys/contrib/dev/rtw89/cam.c
+++ b/sys/contrib/dev/rtw89/cam.c
@@ -150,8 +150,6 @@ static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam,
case RTW89_ADDR_CAM_SEC_NONE:
return -EINVAL;
case RTW89_ADDR_CAM_SEC_ALL_UNI:
- if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
- return -EINVAL;
idx = find_first_zero_bit(addr_cam->sec_cam_map,
RTW89_SEC_CAM_IN_ADDR_CAM);
if (idx >= RTW89_SEC_CAM_IN_ADDR_CAM)
@@ -213,6 +211,46 @@ static int rtw89_cam_get_addr_cam_key_idx(struct rtw89_addr_cam_entry *addr_cam,
return 0;
}
+static int rtw89_cam_detach_sec_cam(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ const struct rtw89_sec_cam_entry *sec_cam,
+ bool inform_fw)
+{
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ struct rtw89_vif *rtwvif;
+ struct rtw89_addr_cam_entry *addr_cam;
+ unsigned int i;
+ int ret = 0;
+
+ if (!vif) {
+ rtw89_err(rtwdev, "No iface for deleting sec cam\n");
+ return -EINVAL;
+ }
+
+ rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+
+ for_each_set_bit(i, addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM) {
+ if (addr_cam->sec_ent[i] != sec_cam->sec_cam_idx)
+ continue;
+
+ clear_bit(i, addr_cam->sec_cam_map);
+ }
+
+ if (inform_fw) {
+ ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
+ if (ret)
+ rtw89_err(rtwdev,
+ "failed to update dctl cam del key: %d\n", ret);
+ ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
+ if (ret)
+ rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret);
+ }
+
+ return ret;
+}
+
static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -232,6 +270,11 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
rtwvif = (struct rtw89_vif *)vif->drv_priv;
addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+
+ if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+ key->cipher == WLAN_CIPHER_SUITE_WEP104)
+ addr_cam->sec_ent_mode = RTW89_ADDR_CAM_SEC_ALL_UNI;
+
ret = rtw89_cam_get_addr_cam_key_idx(addr_cam, sec_cam, key, &key_idx);
if (ret) {
rtw89_err(rtwdev, "failed to get addr cam key idx %d, %d\n",
@@ -239,10 +282,8 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
return ret;
}
- key->hw_key_idx = key_idx;
addr_cam->sec_ent_keyid[key_idx] = key->keyidx;
addr_cam->sec_ent[key_idx] = sec_cam->sec_cam_idx;
- addr_cam->sec_entries[key_idx] = sec_cam;
set_bit(key_idx, addr_cam->sec_cam_map);
ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
if (ret) {
@@ -255,7 +296,6 @@ static int rtw89_cam_attach_sec_cam(struct rtw89_dev *rtwdev,
rtw89_err(rtwdev, "failed to update addr cam sec entry: %d\n",
ret);
clear_bit(key_idx, addr_cam->sec_cam_map);
- addr_cam->sec_entries[key_idx] = NULL;
return ret;
}
@@ -292,6 +332,9 @@ static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev,
goto err_release_cam;
}
+ key->hw_key_idx = sec_cam_idx;
+ cam_info->sec_entries[sec_cam_idx] = sec_cam;
+
sec_cam->sec_cam_idx = sec_cam_idx;
sec_cam->type = hw_key_type;
sec_cam->len = RTW89_SEC_CAM_LEN;
@@ -313,6 +356,7 @@ static int rtw89_cam_sec_key_install(struct rtw89_dev *rtwdev,
return 0;
err_release_cam:
+ cam_info->sec_entries[sec_cam_idx] = NULL;
kfree(sec_cam);
clear_bit(sec_cam_idx, cam_info->sec_cam_map);
if (ext_key)
@@ -356,6 +400,9 @@ int rtw89_cam_sec_key_add(struct rtw89_dev *rtwdev,
key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
ext_key = true;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ hw_key_type = RTW89_SEC_KEY_TYPE_BIP_CCMP128;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -380,42 +427,22 @@ int rtw89_cam_sec_key_del(struct rtw89_dev *rtwdev,
struct ieee80211_key_conf *key,
bool inform_fw)
{
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
- struct rtw89_vif *rtwvif;
- struct rtw89_addr_cam_entry *addr_cam;
- struct rtw89_sec_cam_entry *sec_cam;
- u8 key_idx = key->hw_key_idx;
+ const struct rtw89_sec_cam_entry *sec_cam;
u8 sec_cam_idx;
- int ret = 0;
-
- if (!vif) {
- rtw89_err(rtwdev, "No iface for deleting sec cam\n");
- return -EINVAL;
- }
+ int ret;
- rtwvif = (struct rtw89_vif *)vif->drv_priv;
- addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
- sec_cam = addr_cam->sec_entries[key_idx];
+ sec_cam_idx = key->hw_key_idx;
+ sec_cam = cam_info->sec_entries[sec_cam_idx];
if (!sec_cam)
return -EINVAL;
- /* detach sec cam from addr cam */
- clear_bit(key_idx, addr_cam->sec_cam_map);
- addr_cam->sec_entries[key_idx] = NULL;
- if (inform_fw) {
- ret = rtw89_chip_h2c_dctl_sec_cam(rtwdev, rtwvif, rtwsta);
- if (ret)
- rtw89_err(rtwdev, "failed to update dctl cam del key: %d\n", ret);
- ret = rtw89_fw_h2c_cam(rtwdev, rtwvif, rtwsta, NULL);
- if (ret)
- rtw89_err(rtwdev, "failed to update cam del key: %d\n", ret);
- }
+ ret = rtw89_cam_detach_sec_cam(rtwdev, vif, sta, sec_cam, inform_fw);
/* clear valid bit in addr cam will disable sec cam,
* so we don't need to send H2C command again
*/
- sec_cam_idx = sec_cam->sec_cam_idx;
+ cam_info->sec_entries[sec_cam_idx] = NULL;
clear_bit(sec_cam_idx, cam_info->sec_cam_map);
if (sec_cam->ext_key)
clear_bit(sec_cam_idx + 1, cam_info->sec_cam_map);
@@ -488,6 +515,21 @@ static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev,
return 0;
}
+static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ switch (chip->chip_id) {
+ case RTL8852A:
+ case RTL8852B:
+ case RTL8851B:
+ case RTL8852BT:
+ return ADDR_CAM_ENT_SIZE;
+ default:
+ return ADDR_CAM_ENT_SHORT_SIZE;
+ }
+}
+
int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
struct rtw89_addr_cam_entry *addr_cam,
const struct rtw89_bssid_cam_entry *bssid_cam)
@@ -509,7 +551,7 @@ int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
}
addr_cam->addr_cam_idx = addr_cam_idx;
- addr_cam->len = ADDR_CAM_ENT_SIZE;
+ addr_cam->len = rtw89_get_addr_cam_entry_size(rtwdev);
addr_cam->offset = 0;
addr_cam->valid = true;
addr_cam->addr_mask = 0;
@@ -739,27 +781,158 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta,
- u8 *cmd)
+ struct rtw89_h2c_dctlinfo_ud_v1 *h2c)
{
struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+ struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv;
+
+ h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id,
+ DCTLINFO_V1_C0_MACID) |
+ le32_encode_bits(1, DCTLINFO_V1_C0_OP);
+
+ h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0],
+ DCTLINFO_V1_W4_SEC_ENT0_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[1],
+ DCTLINFO_V1_W4_SEC_ENT1_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[2],
+ DCTLINFO_V1_W4_SEC_ENT2_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[3],
+ DCTLINFO_V1_W4_SEC_ENT3_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[4],
+ DCTLINFO_V1_W4_SEC_ENT4_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[5],
+ DCTLINFO_V1_W4_SEC_ENT5_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[6],
+ DCTLINFO_V1_W4_SEC_ENT6_KEYID);
+ h2c->m4 = cpu_to_le32(DCTLINFO_V1_W4_SEC_ENT0_KEYID |
+ DCTLINFO_V1_W4_SEC_ENT1_KEYID |
+ DCTLINFO_V1_W4_SEC_ENT2_KEYID |
+ DCTLINFO_V1_W4_SEC_ENT3_KEYID |
+ DCTLINFO_V1_W4_SEC_ENT4_KEYID |
+ DCTLINFO_V1_W4_SEC_ENT5_KEYID |
+ DCTLINFO_V1_W4_SEC_ENT6_KEYID);
+
+ h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0] & 0xff,
+ DCTLINFO_V1_W5_SEC_ENT_VALID) |
+ le32_encode_bits(addr_cam->sec_ent[0],
+ DCTLINFO_V1_W5_SEC_ENT0) |
+ le32_encode_bits(addr_cam->sec_ent[1],
+ DCTLINFO_V1_W5_SEC_ENT1) |
+ le32_encode_bits(addr_cam->sec_ent[2],
+ DCTLINFO_V1_W5_SEC_ENT2);
+ h2c->m5 = cpu_to_le32(DCTLINFO_V1_W5_SEC_ENT_VALID |
+ DCTLINFO_V1_W5_SEC_ENT0 |
+ DCTLINFO_V1_W5_SEC_ENT1 |
+ DCTLINFO_V1_W5_SEC_ENT2);
+
+ h2c->w6 = le32_encode_bits(addr_cam->sec_ent[3],
+ DCTLINFO_V1_W6_SEC_ENT3) |
+ le32_encode_bits(addr_cam->sec_ent[4],
+ DCTLINFO_V1_W6_SEC_ENT4) |
+ le32_encode_bits(addr_cam->sec_ent[5],
+ DCTLINFO_V1_W6_SEC_ENT5) |
+ le32_encode_bits(addr_cam->sec_ent[6],
+ DCTLINFO_V1_W6_SEC_ENT6);
+ h2c->m6 = cpu_to_le32(DCTLINFO_V1_W6_SEC_ENT3 |
+ DCTLINFO_V1_W6_SEC_ENT4 |
+ DCTLINFO_V1_W6_SEC_ENT5 |
+ DCTLINFO_V1_W6_SEC_ENT6);
+
+ if (rtw_wow->ptk_alg) {
+ h2c->w0 = le32_encode_bits(ptk_tx_iv[0] | ptk_tx_iv[1] << 8,
+ DCTLINFO_V1_W0_AES_IV_L);
+ h2c->m0 = cpu_to_le32(DCTLINFO_V1_W0_AES_IV_L);
+
+ h2c->w1 = le32_encode_bits(ptk_tx_iv[4] |
+ ptk_tx_iv[5] << 8 |
+ ptk_tx_iv[6] << 16 |
+ ptk_tx_iv[7] << 24,
+ DCTLINFO_V1_W1_AES_IV_H);
+ h2c->m1 = cpu_to_le32(DCTLINFO_V1_W1_AES_IV_H);
+
+ h2c->w4 |= le32_encode_bits(rtw_wow->ptk_keyidx,
+ DCTLINFO_V1_W4_SEC_KEY_ID);
+ h2c->m4 |= cpu_to_le32(DCTLINFO_V1_W4_SEC_KEY_ID);
+ }
+}
- SET_DCTL_MACID_V1(cmd, rtwsta ? rtwsta->mac_id : rtwvif->mac_id);
- SET_DCTL_OPERATION_V1(cmd, 1);
-
- SET_DCTL_SEC_ENT0_KEYID_V1(cmd, addr_cam->sec_ent_keyid[0]);
- SET_DCTL_SEC_ENT1_KEYID_V1(cmd, addr_cam->sec_ent_keyid[1]);
- SET_DCTL_SEC_ENT2_KEYID_V1(cmd, addr_cam->sec_ent_keyid[2]);
- SET_DCTL_SEC_ENT3_KEYID_V1(cmd, addr_cam->sec_ent_keyid[3]);
- SET_DCTL_SEC_ENT4_KEYID_V1(cmd, addr_cam->sec_ent_keyid[4]);
- SET_DCTL_SEC_ENT5_KEYID_V1(cmd, addr_cam->sec_ent_keyid[5]);
- SET_DCTL_SEC_ENT6_KEYID_V1(cmd, addr_cam->sec_ent_keyid[6]);
-
- SET_DCTL_SEC_ENT_VALID_V1(cmd, addr_cam->sec_cam_map[0] & 0xff);
- SET_DCTL_SEC_ENT0_V1(cmd, addr_cam->sec_ent[0]);
- SET_DCTL_SEC_ENT1_V1(cmd, addr_cam->sec_ent[1]);
- SET_DCTL_SEC_ENT2_V1(cmd, addr_cam->sec_ent[2]);
- SET_DCTL_SEC_ENT3_V1(cmd, addr_cam->sec_ent[3]);
- SET_DCTL_SEC_ENT4_V1(cmd, addr_cam->sec_ent[4]);
- SET_DCTL_SEC_ENT5_V1(cmd, addr_cam->sec_ent[5]);
- SET_DCTL_SEC_ENT6_V1(cmd, addr_cam->sec_ent[6]);
+void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta,
+ struct rtw89_h2c_dctlinfo_ud_v2 *h2c)
+{
+ struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
+ struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ u8 *ptk_tx_iv = rtw_wow->key_info.ptk_tx_iv;
+
+ h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id,
+ DCTLINFO_V2_C0_MACID) |
+ le32_encode_bits(1, DCTLINFO_V2_C0_OP);
+
+ h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0],
+ DCTLINFO_V2_W4_SEC_ENT0_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[1],
+ DCTLINFO_V2_W4_SEC_ENT1_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[2],
+ DCTLINFO_V2_W4_SEC_ENT2_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[3],
+ DCTLINFO_V2_W4_SEC_ENT3_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[4],
+ DCTLINFO_V2_W4_SEC_ENT4_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[5],
+ DCTLINFO_V2_W4_SEC_ENT5_KEYID) |
+ le32_encode_bits(addr_cam->sec_ent_keyid[6],
+ DCTLINFO_V2_W4_SEC_ENT6_KEYID);
+ h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_SEC_ENT0_KEYID |
+ DCTLINFO_V2_W4_SEC_ENT1_KEYID |
+ DCTLINFO_V2_W4_SEC_ENT2_KEYID |
+ DCTLINFO_V2_W4_SEC_ENT3_KEYID |
+ DCTLINFO_V2_W4_SEC_ENT4_KEYID |
+ DCTLINFO_V2_W4_SEC_ENT5_KEYID |
+ DCTLINFO_V2_W4_SEC_ENT6_KEYID);
+
+ h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0],
+ DCTLINFO_V2_W5_SEC_ENT_VALID_V1) |
+ le32_encode_bits(addr_cam->sec_ent[0],
+ DCTLINFO_V2_W5_SEC_ENT0_V1);
+ h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_SEC_ENT_VALID_V1 |
+ DCTLINFO_V2_W5_SEC_ENT0_V1);
+
+ h2c->w6 = le32_encode_bits(addr_cam->sec_ent[1],
+ DCTLINFO_V2_W6_SEC_ENT1_V1) |
+ le32_encode_bits(addr_cam->sec_ent[2],
+ DCTLINFO_V2_W6_SEC_ENT2_V1) |
+ le32_encode_bits(addr_cam->sec_ent[3],
+ DCTLINFO_V2_W6_SEC_ENT3_V1) |
+ le32_encode_bits(addr_cam->sec_ent[4],
+ DCTLINFO_V2_W6_SEC_ENT4_V1);
+ h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_SEC_ENT1_V1 |
+ DCTLINFO_V2_W6_SEC_ENT2_V1 |
+ DCTLINFO_V2_W6_SEC_ENT3_V1 |
+ DCTLINFO_V2_W6_SEC_ENT4_V1);
+
+ h2c->w7 = le32_encode_bits(addr_cam->sec_ent[5],
+ DCTLINFO_V2_W7_SEC_ENT5_V1) |
+ le32_encode_bits(addr_cam->sec_ent[6],
+ DCTLINFO_V2_W7_SEC_ENT6_V1);
+ h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_SEC_ENT5_V1 |
+ DCTLINFO_V2_W7_SEC_ENT6_V1);
+
+ if (rtw_wow->ptk_alg) {
+ h2c->w0 = le32_encode_bits(ptk_tx_iv[0] | ptk_tx_iv[1] << 8,
+ DCTLINFO_V2_W0_AES_IV_L);
+ h2c->m0 = cpu_to_le32(DCTLINFO_V2_W0_AES_IV_L);
+
+ h2c->w1 = le32_encode_bits(ptk_tx_iv[4] |
+ ptk_tx_iv[5] << 8 |
+ ptk_tx_iv[6] << 16 |
+ ptk_tx_iv[7] << 24,
+ DCTLINFO_V2_W1_AES_IV_H);
+ h2c->m1 = cpu_to_le32(DCTLINFO_V2_W1_AES_IV_H);
+
+ h2c->w4 |= le32_encode_bits(rtw_wow->ptk_keyidx,
+ DCTLINFO_V2_W4_SEC_KEY_ID);
+ h2c->m4 |= cpu_to_le32(DCTLINFO_V2_W4_SEC_KEY_ID);
+ }
}
diff --git a/sys/contrib/dev/rtw89/cam.h b/sys/contrib/dev/rtw89/cam.h
index 83c160a614e6..5d7b624c2dd4 100644
--- a/sys/contrib/dev/rtw89/cam.h
+++ b/sys/contrib/dev/rtw89/cam.h
@@ -352,6 +352,180 @@ static inline void FWCMD_SET_ADDR_BSSID_BSSID5(void *cmd, u32 value)
le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(31, 24));
}
+struct rtw89_h2c_dctlinfo_ud_v1 {
+ __le32 c0;
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+ __le32 w4;
+ __le32 w5;
+ __le32 w6;
+ __le32 w7;
+ __le32 m0;
+ __le32 m1;
+ __le32 m2;
+ __le32 m3;
+ __le32 m4;
+ __le32 m5;
+ __le32 m6;
+ __le32 m7;
+} __packed;
+
+#define DCTLINFO_V1_C0_MACID GENMASK(6, 0)
+#define DCTLINFO_V1_C0_OP BIT(7)
+
+#define DCTLINFO_V1_W0_QOS_FIELD_H GENMASK(7, 0)
+#define DCTLINFO_V1_W0_HW_EXSEQ_MACID GENMASK(14, 8)
+#define DCTLINFO_V1_W0_QOS_DATA BIT(15)
+#define DCTLINFO_V1_W0_AES_IV_L GENMASK(31, 16)
+#define DCTLINFO_V1_W0_ALL GENMASK(31, 0)
+#define DCTLINFO_V1_W1_AES_IV_H GENMASK(31, 0)
+#define DCTLINFO_V1_W1_ALL GENMASK(31, 0)
+#define DCTLINFO_V1_W2_SEQ0 GENMASK(11, 0)
+#define DCTLINFO_V1_W2_SEQ1 GENMASK(23, 12)
+#define DCTLINFO_V1_W2_AMSDU_MAX_LEN GENMASK(26, 24)
+#define DCTLINFO_V1_W2_STA_AMSDU_EN BIT(27)
+#define DCTLINFO_V1_W2_CHKSUM_OFLD_EN BIT(28)
+#define DCTLINFO_V1_W2_WITH_LLC BIT(29)
+#define DCTLINFO_V1_W2_ALL GENMASK(29, 0)
+#define DCTLINFO_V1_W3_SEQ2 GENMASK(11, 0)
+#define DCTLINFO_V1_W3_SEQ3 GENMASK(23, 12)
+#define DCTLINFO_V1_W3_TGT_IND GENMASK(27, 24)
+#define DCTLINFO_V1_W3_TGT_IND_EN BIT(28)
+#define DCTLINFO_V1_W3_HTC_LB GENMASK(31, 29)
+#define DCTLINFO_V1_W3_ALL GENMASK(31, 0)
+#define DCTLINFO_V1_W4_MHDR_LEN GENMASK(4, 0)
+#define DCTLINFO_V1_W4_VLAN_TAG_VALID BIT(5)
+#define DCTLINFO_V1_W4_VLAN_TAG_SEL GENMASK(7, 6)
+#define DCTLINFO_V1_W4_HTC_ORDER BIT(8)
+#define DCTLINFO_V1_W4_SEC_KEY_ID GENMASK(10, 9)
+#define DCTLINFO_V1_W4_WAPI BIT(15)
+#define DCTLINFO_V1_W4_SEC_ENT_MODE GENMASK(17, 16)
+#define DCTLINFO_V1_W4_SEC_ENT0_KEYID GENMASK(19, 18)
+#define DCTLINFO_V1_W4_SEC_ENT1_KEYID GENMASK(21, 20)
+#define DCTLINFO_V1_W4_SEC_ENT2_KEYID GENMASK(23, 22)
+#define DCTLINFO_V1_W4_SEC_ENT3_KEYID GENMASK(25, 24)
+#define DCTLINFO_V1_W4_SEC_ENT4_KEYID GENMASK(27, 26)
+#define DCTLINFO_V1_W4_SEC_ENT5_KEYID GENMASK(29, 28)
+#define DCTLINFO_V1_W4_SEC_ENT6_KEYID GENMASK(31, 30)
+#define DCTLINFO_V1_W4_ALL (GENMASK(31, 15) | GENMASK(10, 0))
+#define DCTLINFO_V1_W5_SEC_ENT_VALID GENMASK(7, 0)
+#define DCTLINFO_V1_W5_SEC_ENT0 GENMASK(15, 8)
+#define DCTLINFO_V1_W5_SEC_ENT1 GENMASK(23, 16)
+#define DCTLINFO_V1_W5_SEC_ENT2 GENMASK(31, 24)
+#define DCTLINFO_V1_W5_ALL GENMASK(31, 0)
+#define DCTLINFO_V1_W6_SEC_ENT3 GENMASK(7, 0)
+#define DCTLINFO_V1_W6_SEC_ENT4 GENMASK(15, 8)
+#define DCTLINFO_V1_W6_SEC_ENT5 GENMASK(23, 16)
+#define DCTLINFO_V1_W6_SEC_ENT6 GENMASK(31, 24)
+#define DCTLINFO_V1_W6_ALL GENMASK(31, 0)
+
+struct rtw89_h2c_dctlinfo_ud_v2 {
+ __le32 c0;
+ __le32 w0;
+ __le32 w1;
+ __le32 w2;
+ __le32 w3;
+ __le32 w4;
+ __le32 w5;
+ __le32 w6;
+ __le32 w7;
+ __le32 w8;
+ __le32 w9;
+ __le32 w10;
+ __le32 w11;
+ __le32 w12;
+ __le32 w13;
+ __le32 w14;
+ __le32 w15;
+ __le32 m0;
+ __le32 m1;
+ __le32 m2;
+ __le32 m3;
+ __le32 m4;
+ __le32 m5;
+ __le32 m6;
+ __le32 m7;
+ __le32 m8;
+ __le32 m9;
+ __le32 m10;
+ __le32 m11;
+ __le32 m12;
+ __le32 m13;
+ __le32 m14;
+ __le32 m15;
+} __packed;
+
+#define DCTLINFO_V2_C0_MACID GENMASK(6, 0)
+#define DCTLINFO_V2_C0_OP BIT(7)
+
+#define DCTLINFO_V2_W0_QOS_FIELD_H GENMASK(7, 0)
+#define DCTLINFO_V2_W0_HW_EXSEQ_MACID GENMASK(14, 8)
+#define DCTLINFO_V2_W0_QOS_DATA BIT(15)
+#define DCTLINFO_V2_W0_AES_IV_L GENMASK(31, 16)
+#define DCTLINFO_V2_W0_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W1_AES_IV_H GENMASK(31, 0)
+#define DCTLINFO_V2_W1_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W2_SEQ0 GENMASK(11, 0)
+#define DCTLINFO_V2_W2_SEQ1 GENMASK(23, 12)
+#define DCTLINFO_V2_W2_AMSDU_MAX_LEN GENMASK(26, 24)
+#define DCTLINFO_V2_W2_STA_AMSDU_EN BIT(27)
+#define DCTLINFO_V2_W2_CHKSUM_OFLD_EN BIT(28)
+#define DCTLINFO_V2_W2_WITH_LLC BIT(29)
+#define DCTLINFO_V2_W2_NAT25_EN BIT(30)
+#define DCTLINFO_V2_W2_IS_MLD BIT(31)
+#define DCTLINFO_V2_W2_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W3_SEQ2 GENMASK(11, 0)
+#define DCTLINFO_V2_W3_SEQ3 GENMASK(23, 12)
+#define DCTLINFO_V2_W3_TGT_IND GENMASK(27, 24)
+#define DCTLINFO_V2_W3_TGT_IND_EN BIT(28)
+#define DCTLINFO_V2_W3_HTC_LB GENMASK(31, 29)
+#define DCTLINFO_V2_W3_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W4_VLAN_TAG_SEL GENMASK(7, 5)
+#define DCTLINFO_V2_W4_HTC_ORDER BIT(8)
+#define DCTLINFO_V2_W4_SEC_KEY_ID GENMASK(10, 9)
+#define DCTLINFO_V2_W4_VLAN_RX_DYNAMIC_PCP_EN BIT(11)
+#define DCTLINFO_V2_W4_VLAN_RX_PKT_DROP BIT(12)
+#define DCTLINFO_V2_W4_VLAN_RX_VALID BIT(13)
+#define DCTLINFO_V2_W4_VLAN_TX_VALID BIT(14)
+#define DCTLINFO_V2_W4_WAPI BIT(15)
+#define DCTLINFO_V2_W4_SEC_ENT_MODE GENMASK(17, 16)
+#define DCTLINFO_V2_W4_SEC_ENT0_KEYID GENMASK(19, 18)
+#define DCTLINFO_V2_W4_SEC_ENT1_KEYID GENMASK(21, 20)
+#define DCTLINFO_V2_W4_SEC_ENT2_KEYID GENMASK(23, 22)
+#define DCTLINFO_V2_W4_SEC_ENT3_KEYID GENMASK(25, 24)
+#define DCTLINFO_V2_W4_SEC_ENT4_KEYID GENMASK(27, 26)
+#define DCTLINFO_V2_W4_SEC_ENT5_KEYID GENMASK(29, 28)
+#define DCTLINFO_V2_W4_SEC_ENT6_KEYID GENMASK(31, 30)
+#define DCTLINFO_V2_W4_ALL GENMASK(31, 5)
+#define DCTLINFO_V2_W5_SEC_ENT7_KEYID GENMASK(1, 0)
+#define DCTLINFO_V2_W5_SEC_ENT8_KEYID GENMASK(3, 2)
+#define DCTLINFO_V2_W5_SEC_ENT_VALID_V1 GENMASK(23, 8)
+#define DCTLINFO_V2_W5_SEC_ENT0_V1 GENMASK(31, 24)
+#define DCTLINFO_V2_W5_ALL (GENMASK(31, 8) | GENMASK(3, 0))
+#define DCTLINFO_V2_W6_SEC_ENT1_V1 GENMASK(7, 0)
+#define DCTLINFO_V2_W6_SEC_ENT2_V1 GENMASK(15, 8)
+#define DCTLINFO_V2_W6_SEC_ENT3_V1 GENMASK(23, 16)
+#define DCTLINFO_V2_W6_SEC_ENT4_V1 GENMASK(31, 24)
+#define DCTLINFO_V2_W6_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W7_SEC_ENT5_V1 GENMASK(7, 0)
+#define DCTLINFO_V2_W7_SEC_ENT6_V1 GENMASK(15, 8)
+#define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16)
+#define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24)
+#define DCTLINFO_V2_W7_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0)
+#define DCTLINFO_V2_W8_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0)
+#define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16)
+#define DCTLINFO_V2_W9_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0)
+#define DCTLINFO_V2_W10_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0)
+#define DCTLINFO_V2_W11_ALL GENMASK(31, 0)
+#define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0)
+#define DCTLINFO_V2_W12_ALL GENMASK(15, 0)
+
int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
@@ -372,7 +546,11 @@ void rtw89_cam_fill_addr_cam_info(struct rtw89_dev *rtwdev,
void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta,
- u8 *cmd);
+ struct rtw89_h2c_dctlinfo_ud_v1 *h2c);
+void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta,
+ struct rtw89_h2c_dctlinfo_ud_v2 *h2c);
int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta, u8 *cmd);
diff --git a/sys/contrib/dev/rtw89/chan.c b/sys/contrib/dev/rtw89/chan.c
index 4663db4ce2f6..7f90d93dcdc0 100644
--- a/sys/contrib/dev/rtw89/chan.c
+++ b/sys/contrib/dev/rtw89/chan.c
@@ -3,7 +3,11 @@
*/
#include "chan.h"
+#include "coex.h"
#include "debug.h"
+#include "fw.h"
+#include "mac.h"
+#include "ps.h"
#include "util.h"
static enum rtw89_subband rtw89_get_subband_type(enum rtw89_band band,
@@ -83,6 +87,19 @@ static enum rtw89_sc_offset rtw89_get_primary_chan_idx(enum rtw89_bandwidth bw,
return primary_chan_idx;
}
+static u8 rtw89_get_primary_sb_idx(u8 central_ch, u8 pri_ch,
+ enum rtw89_bandwidth bw)
+{
+ static const u8 prisb_cal_ofst[RTW89_CHANNEL_WIDTH_ORDINARY_NUM] = {
+ 0, 2, 6, 14, 30
+ };
+
+ if (bw >= RTW89_CHANNEL_WIDTH_ORDINARY_NUM)
+ return 0;
+
+ return (prisb_cal_ofst[bw] + pri_ch - central_ch) / 4;
+}
+
void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
enum rtw89_band band, enum rtw89_bandwidth bandwidth)
{
@@ -102,6 +119,8 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
chan->subband_type = rtw89_get_subband_type(band, center_chan);
chan->pri_ch_idx = rtw89_get_primary_chan_idx(bandwidth, center_freq,
primary_freq);
+ chan->pri_sb_idx = rtw89_get_primary_sb_idx(center_chan, primary_chan,
+ bandwidth);
}
bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
@@ -116,11 +135,34 @@ bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
rcd->prev_primary_channel = chan->primary_channel;
rcd->prev_band_type = chan->band_type;
band_changed = new->band_type != chan->band_type;
+ rcd->band_changed = band_changed;
*chan = *new;
return band_changed;
}
+int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev,
+ int (*iterator)(const struct rtw89_chan *chan,
+ void *data),
+ void *data)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ const struct rtw89_chan *chan;
+ int ret;
+ u8 idx;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY) {
+ chan = rtw89_chan_get(rtwdev, idx);
+ ret = iterator(chan, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
enum rtw89_sub_entity_idx idx,
const struct cfg80211_chan_def *chandef,
@@ -185,35 +227,2150 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
+ hal->entity_pause = false;
bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
+ bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES);
atomic_set(&hal->roc_entity_idx, RTW89_SUB_ENTITY_IDLE);
rtw89_config_default_chandef(rtwdev);
}
+static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev,
+ struct rtw89_entity_weight *w)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ const struct rtw89_chanctx_cfg *cfg;
+ struct rtw89_vif *rtwvif;
+ int idx;
+
+ for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY) {
+ cfg = hal->sub[idx].cfg;
+ if (!cfg) {
+ /* doesn't run with chanctx ops; one channel at most */
+ w->active_chanctxs = 1;
+ break;
+ }
+
+ if (cfg->ref_count > 0)
+ w->active_chanctxs++;
+ }
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ if (rtwvif->chanctx_assigned)
+ w->active_roles++;
+ }
+}
+
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev)
{
+ DECLARE_BITMAP(recalc_map, NUM_OF_RTW89_SUB_ENTITY) = {};
struct rtw89_hal *hal = &rtwdev->hal;
+ const struct cfg80211_chan_def *chandef;
+ struct rtw89_entity_weight w = {};
enum rtw89_entity_mode mode;
- u8 weight;
+ struct rtw89_chan chan;
+ u8 idx;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ bitmap_copy(recalc_map, hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
- weight = bitmap_weight(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
- switch (weight) {
+ rtw89_entity_calculate_weight(rtwdev, &w);
+ switch (w.active_chanctxs) {
default:
- rtw89_warn(rtwdev, "unknown ent chan weight: %d\n", weight);
- bitmap_zero(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY);
+ rtw89_warn(rtwdev, "unknown ent chanctxs weight: %d\n",
+ w.active_chanctxs);
+ bitmap_zero(recalc_map, NUM_OF_RTW89_SUB_ENTITY);
fallthrough;
case 0:
rtw89_config_default_chandef(rtwdev);
+ set_bit(RTW89_SUB_ENTITY_0, recalc_map);
fallthrough;
case 1:
mode = RTW89_ENTITY_MODE_SCC;
break;
+ case 2 ... NUM_OF_RTW89_SUB_ENTITY:
+ if (w.active_roles != NUM_OF_RTW89_MCC_ROLES) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "unhandled ent: %d chanctxs %d roles\n",
+ w.active_chanctxs, w.active_roles);
+ return RTW89_ENTITY_MODE_UNHANDLED;
+ }
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ break;
+
+ mode = RTW89_ENTITY_MODE_MCC_PREPARE;
+ break;
}
+ for_each_set_bit(idx, recalc_map, NUM_OF_RTW89_SUB_ENTITY) {
+ chandef = rtw89_chandef_get(rtwdev, idx);
+ rtw89_get_channel_params(chandef, &chan);
+ if (chan.channel == 0) {
+ WARN(1, "Invalid channel on chanctx %d\n", idx);
+ return RTW89_ENTITY_MODE_INVALID;
+ }
+
+ rtw89_assign_entity_chan(rtwdev, idx, &chan);
+ }
+
+ if (hal->entity_pause)
+ return rtw89_get_entity_mode(rtwdev);
+
rtw89_set_entity_mode(rtwdev, mode);
return mode;
}
+static void rtw89_chanctx_notify(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_state state)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_chanctx_listener *listener = chip->chanctx_listener;
+ int i;
+
+ if (!listener)
+ return;
+
+ for (i = 0; i < NUM_OF_RTW89_CHANCTX_CALLBACKS; i++) {
+ if (!listener->callbacks[i])
+ continue;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "chanctx notify listener: cb %d, state %d\n",
+ i, state);
+
+ listener->callbacks[i](rtwdev, state);
+ }
+}
+
+static bool rtw89_concurrent_via_mrc(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+
+ return chip_gen == RTW89_CHIP_BE;
+}
+
+/* This function centrally manages how MCC roles are sorted and iterated.
+ * And, it guarantees that ordered_idx is less than NUM_OF_RTW89_MCC_ROLES.
+ * So, if data needs to pass an array for ordered_idx, the array can declare
+ * with NUM_OF_RTW89_MCC_ROLES. Besides, the entire iteration will stop
+ * immediately as long as iterator returns a non-zero value.
+ */
+static
+int rtw89_iterate_mcc_roles(struct rtw89_dev *rtwdev,
+ int (*iterator)(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role,
+ unsigned int ordered_idx,
+ void *data),
+ void *data)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role * const roles[] = {
+ &mcc->role_ref,
+ &mcc->role_aux,
+ };
+ unsigned int idx;
+ int ret;
+
+ BUILD_BUG_ON(ARRAY_SIZE(roles) != NUM_OF_RTW89_MCC_ROLES);
+
+ for (idx = 0; idx < NUM_OF_RTW89_MCC_ROLES; idx++) {
+ ret = iterator(rtwdev, roles[idx], idx, data);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static u32 rtw89_mcc_get_tbtt_ofst(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *role, u64 tsf)
+{
+ struct rtw89_vif *rtwvif = role->rtwvif;
+ u32 bcn_intvl_us = ieee80211_tu_to_usec(role->beacon_interval);
+ u64 sync_tsf = READ_ONCE(rtwvif->sync_bcn_tsf);
+ u32 remainder;
+
+ if (tsf < sync_tsf) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC get tbtt ofst: tsf might not update yet\n");
+ sync_tsf = 0;
+ }
+
+ div_u64_rem(tsf - sync_tsf, bcn_intvl_us, &remainder);
+
+ return remainder;
+}
+
+static int __mcc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mac_mcc_tsf_rpt rpt = {};
+ struct rtw89_fw_mcc_tsf_req req = {};
+ int ret;
+
+ req.group = mcc->group;
+ req.macid_x = ref->rtwvif->mac_id;
+ req.macid_y = aux->rtwvif->mac_id;
+ ret = rtw89_fw_h2c_mcc_req_tsf(rtwdev, &req, &rpt);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to request tsf: %d\n", ret);
+ return ret;
+ }
+
+ *tsf_ref = (u64)rpt.tsf_x_high << 32 | rpt.tsf_x_low;
+ *tsf_aux = (u64)rpt.tsf_y_high << 32 | rpt.tsf_y_low;
+
+ return 0;
+}
+
+static int __mrc_fw_req_tsf(struct rtw89_dev *rtwdev, u64 *tsf_ref, u64 *tsf_aux)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_fw_mrc_req_tsf_arg arg = {};
+ struct rtw89_mac_mrc_tsf_rpt rpt = {};
+ int ret;
+
+ BUILD_BUG_ON(RTW89_MAC_MRC_MAX_REQ_TSF_NUM < NUM_OF_RTW89_MCC_ROLES);
+
+ arg.num = 2;
+ arg.infos[0].band = ref->rtwvif->mac_idx;
+ arg.infos[0].port = ref->rtwvif->port;
+ arg.infos[1].band = aux->rtwvif->mac_idx;
+ arg.infos[1].port = aux->rtwvif->port;
+
+ ret = rtw89_fw_h2c_mrc_req_tsf(rtwdev, &arg, &rpt);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to request tsf: %d\n", ret);
+ return ret;
+ }
+
+ *tsf_ref = rpt.tsfs[0];
+ *tsf_aux = rpt.tsfs[1];
+
+ return 0;
+}
+
+static u16 rtw89_mcc_get_bcn_ofst(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
+ u32 tbtt_ofst_ref, tbtt_ofst_aux;
+ u64 tsf_ref, tsf_aux;
+ int ret;
+
+ if (rtw89_concurrent_via_mrc(rtwdev))
+ ret = __mrc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
+ else
+ ret = __mcc_fw_req_tsf(rtwdev, &tsf_ref, &tsf_aux);
+
+ if (ret)
+ return RTW89_MCC_DFLT_BCN_OFST_TIME;
+
+ tbtt_ofst_ref = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf_ref);
+ tbtt_ofst_aux = rtw89_mcc_get_tbtt_ofst(rtwdev, aux, tsf_aux);
+
+ while (tbtt_ofst_ref < tbtt_ofst_aux)
+ tbtt_ofst_ref += bcn_intvl_ref_us;
+
+ return (tbtt_ofst_ref - tbtt_ofst_aux) / 1024;
+}
+
+static
+void rtw89_mcc_role_fw_macid_bitmap_set_bit(struct rtw89_mcc_role *mcc_role,
+ unsigned int bit)
+{
+ unsigned int idx = bit / 8;
+ unsigned int pos = bit % 8;
+
+ if (idx >= ARRAY_SIZE(mcc_role->macid_bitmap))
+ return;
+
+ mcc_role->macid_bitmap[idx] |= BIT(pos);
+}
+
+static
+u32 rtw89_mcc_role_fw_macid_bitmap_to_u32(struct rtw89_mcc_role *mcc_role)
+{
+ unsigned int macid;
+ unsigned int i, j;
+ u32 bitmap = 0;
+
+ for (i = 0; i < ARRAY_SIZE(mcc_role->macid_bitmap); i++) {
+ for (j = 0; j < 8; j++) {
+ macid = i * 8 + j;
+ if (macid >= 32)
+ goto out;
+
+ if (mcc_role->macid_bitmap[i] & BIT(j))
+ bitmap |= BIT(macid);
+ }
+ }
+
+out:
+ return bitmap;
+}
+
+static void rtw89_mcc_role_macid_sta_iter(void *data, struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct rtw89_mcc_role *mcc_role = data;
+ struct rtw89_vif *target = mcc_role->rtwvif;
+
+ if (rtwvif != target)
+ return;
+
+ rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwsta->mac_id);
+}
+
+static void rtw89_mcc_fill_role_macid_bitmap(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role)
+{
+ struct rtw89_vif *rtwvif = mcc_role->rtwvif;
+
+ rtw89_mcc_role_fw_macid_bitmap_set_bit(mcc_role, rtwvif->mac_id);
+ ieee80211_iterate_stations_atomic(rtwdev->hw,
+ rtw89_mcc_role_macid_sta_iter,
+ mcc_role);
+}
+
+static void rtw89_mcc_fill_role_policy(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role)
+{
+ struct rtw89_mcc_policy *policy = &mcc_role->policy;
+
+ policy->c2h_rpt = RTW89_FW_MCC_C2H_RPT_ALL;
+ policy->tx_null_early = RTW89_MCC_DFLT_TX_NULL_EARLY;
+ policy->in_curr_ch = false;
+ policy->dis_sw_retry = true;
+ policy->sw_retry_count = false;
+
+ if (mcc_role->is_go)
+ policy->dis_tx_null = true;
+ else
+ policy->dis_tx_null = false;
+}
+
+static void rtw89_mcc_fill_role_limit(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(mcc_role->rtwvif);
+ struct ieee80211_p2p_noa_desc *noa_desc;
+ u32 bcn_intvl_us = ieee80211_tu_to_usec(mcc_role->beacon_interval);
+ u32 max_toa_us, max_tob_us, max_dur_us;
+ u32 start_time, interval, duration;
+ u64 tsf, tsf_lmt;
+ int ret;
+ int i;
+
+ if (!mcc_role->is_go && !mcc_role->is_gc)
+ return;
+
+ /* find the first periodic NoA */
+ for (i = 0; i < RTW89_P2P_MAX_NOA_NUM; i++) {
+ noa_desc = &vif->bss_conf.p2p_noa_attr.desc[i];
+ if (noa_desc->count == 255)
+ goto fill;
+ }
+
+ return;
+
+fill:
+ start_time = le32_to_cpu(noa_desc->start_time);
+ interval = le32_to_cpu(noa_desc->interval);
+ duration = le32_to_cpu(noa_desc->duration);
+
+ if (interval != bcn_intvl_us) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC role limit: mismatch interval: %d vs. %d\n",
+ interval, bcn_intvl_us);
+ return;
+ }
+
+ ret = rtw89_mac_port_get_tsf(rtwdev, mcc_role->rtwvif, &tsf);
+ if (ret) {
+ rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
+ return;
+ }
+
+ tsf_lmt = (tsf & GENMASK_ULL(63, 32)) | start_time;
+ max_toa_us = rtw89_mcc_get_tbtt_ofst(rtwdev, mcc_role, tsf_lmt);
+ max_dur_us = interval - duration;
+ max_tob_us = max_dur_us - max_toa_us;
+
+ if (!max_toa_us || !max_tob_us) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC role limit: hit boundary\n");
+ return;
+ }
+
+ if (max_dur_us < max_toa_us) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC role limit: insufficient duration\n");
+ return;
+ }
+
+ mcc_role->limit.max_toa = max_toa_us / 1024;
+ mcc_role->limit.max_tob = max_tob_us / 1024;
+ mcc_role->limit.max_dur = max_dur_us / 1024;
+ mcc_role->limit.enable = true;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC role limit: max_toa %d, max_tob %d, max_dur %d\n",
+ mcc_role->limit.max_toa, mcc_role->limit.max_tob,
+ mcc_role->limit.max_dur);
+}
+
+static int rtw89_mcc_fill_role(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_mcc_role *role)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ const struct rtw89_chan *chan;
+
+ memset(role, 0, sizeof(*role));
+ role->rtwvif = rtwvif;
+ role->beacon_interval = vif->bss_conf.beacon_int;
+
+ if (!role->beacon_interval) {
+ rtw89_warn(rtwdev,
+ "cannot handle MCC role without beacon interval\n");
+ return -EINVAL;
+ }
+
+ role->duration = role->beacon_interval / 2;
+
+ chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx);
+ role->is_2ghz = chan->band_type == RTW89_BAND_2G;
+ role->is_go = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_GO;
+ role->is_gc = rtwvif->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT;
+
+ rtw89_mcc_fill_role_macid_bitmap(rtwdev, role);
+ rtw89_mcc_fill_role_policy(rtwdev, role);
+ rtw89_mcc_fill_role_limit(rtwdev, role);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC role: bcn_intvl %d, is_2ghz %d, is_go %d, is_gc %d\n",
+ role->beacon_interval, role->is_2ghz, role->is_go, role->is_gc);
+ return 0;
+}
+
+static void rtw89_mcc_fill_bt_role(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
+
+ memset(bt_role, 0, sizeof(*bt_role));
+ bt_role->duration = rtw89_coex_query_bt_req_len(rtwdev, RTW89_PHY_0);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC bt role: dur %d\n",
+ bt_role->duration);
+}
+
+struct rtw89_mcc_fill_role_selector {
+ struct rtw89_vif *bind_vif[NUM_OF_RTW89_SUB_ENTITY];
+};
+
+static_assert((u8)NUM_OF_RTW89_SUB_ENTITY >= NUM_OF_RTW89_MCC_ROLES);
+
+static int rtw89_mcc_fill_role_iterator(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role,
+ unsigned int ordered_idx,
+ void *data)
+{
+ struct rtw89_mcc_fill_role_selector *sel = data;
+ struct rtw89_vif *role_vif = sel->bind_vif[ordered_idx];
+ int ret;
+
+ if (!role_vif) {
+ rtw89_warn(rtwdev, "cannot handle MCC without role[%d]\n",
+ ordered_idx);
+ return -EINVAL;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC fill role[%d] with vif <macid %d>\n",
+ ordered_idx, role_vif->mac_id);
+
+ ret = rtw89_mcc_fill_role(rtwdev, role_vif, mcc_role);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_fill_role_selector sel = {};
+ struct rtw89_vif *rtwvif;
+ int ret;
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ if (!rtwvif->chanctx_assigned)
+ continue;
+
+ if (sel.bind_vif[rtwvif->sub_entity_idx]) {
+ rtw89_warn(rtwdev,
+ "MCC skip extra vif <macid %d> on chanctx[%d]\n",
+ rtwvif->mac_id, rtwvif->sub_entity_idx);
+ continue;
+ }
+
+ sel.bind_vif[rtwvif->sub_entity_idx] = rtwvif;
+ }
+
+ ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel);
+ if (ret)
+ return ret;
+
+ rtw89_mcc_fill_bt_role(rtwdev);
+ return 0;
+}
+
+static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev,
+ const struct rtw89_mcc_pattern *new)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC assign pattern: ref {%d | %d}, aux {%d | %d}\n",
+ new->tob_ref, new->toa_ref, new->tob_aux, new->toa_aux);
+
+ *pattern = *new;
+ memset(&pattern->courtesy, 0, sizeof(pattern->courtesy));
+
+ if (pattern->tob_aux <= 0 || pattern->toa_aux <= 0) {
+ pattern->courtesy.macid_tgt = aux->rtwvif->mac_id;
+ pattern->courtesy.macid_src = ref->rtwvif->mac_id;
+ pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
+ pattern->courtesy.enable = true;
+ } else if (pattern->tob_ref <= 0 || pattern->toa_ref <= 0) {
+ pattern->courtesy.macid_tgt = ref->rtwvif->mac_id;
+ pattern->courtesy.macid_src = aux->rtwvif->mac_id;
+ pattern->courtesy.slot_num = RTW89_MCC_DFLT_COURTESY_SLOT;
+ pattern->courtesy.enable = true;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC pattern flags: plan %d, courtesy_en %d\n",
+ pattern->plan, pattern->courtesy.enable);
+
+ if (!pattern->courtesy.enable)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC pattern courtesy: tgt %d, src %d, slot %d\n",
+ pattern->courtesy.macid_tgt, pattern->courtesy.macid_src,
+ pattern->courtesy.slot_num);
+}
+
+/* The follow-up roughly shows the relationship between the parameters
+ * for pattern calculation.
+ *
+ * |< duration ref >| (if mid bt) |< duration aux >|
+ * |< tob ref >|< toa ref >| ... |< tob aux >|< toa aux >|
+ * V V
+ * tbtt ref tbtt aux
+ * |< beacon offset >|
+ *
+ * In loose pattern calculation, we only ensure at least tob_ref and
+ * toa_ref have positive results. If tob_aux or toa_aux is negative
+ * unfortunately, FW will be notified to handle it with courtesy
+ * mechanism.
+ */
+static void __rtw89_mcc_calc_pattern_loose(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_pattern *ptrn,
+ bool hdl_bt)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u16 bcn_ofst = config->beacon_offset;
+ u16 bt_dur_in_mid = 0;
+ u16 max_bcn_ofst;
+ s16 upper, lower;
+ u16 res;
+
+ *ptrn = (typeof(*ptrn)){
+ .plan = hdl_bt ? RTW89_MCC_PLAN_TAIL_BT : RTW89_MCC_PLAN_NO_BT,
+ };
+
+ if (!hdl_bt)
+ goto calc;
+
+ max_bcn_ofst = ref->duration + aux->duration;
+ if (ref->limit.enable)
+ max_bcn_ofst = min_t(u16, max_bcn_ofst,
+ ref->limit.max_toa + aux->duration);
+ else if (aux->limit.enable)
+ max_bcn_ofst = min_t(u16, max_bcn_ofst,
+ ref->duration + aux->limit.max_tob);
+
+ if (bcn_ofst > max_bcn_ofst && bcn_ofst >= mcc->bt_role.duration) {
+ bt_dur_in_mid = mcc->bt_role.duration;
+ ptrn->plan = RTW89_MCC_PLAN_MID_BT;
+ }
+
+calc:
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_ls: plan %d, bcn_ofst %d\n",
+ ptrn->plan, bcn_ofst);
+
+ res = bcn_ofst - bt_dur_in_mid;
+ upper = min_t(s16, ref->duration, res);
+ lower = 0;
+
+ if (ref->limit.enable) {
+ upper = min_t(s16, upper, ref->limit.max_toa);
+ lower = max_t(s16, lower, ref->duration - ref->limit.max_tob);
+ } else if (aux->limit.enable) {
+ upper = min_t(s16, upper,
+ res - (aux->duration - aux->limit.max_toa));
+ lower = max_t(s16, lower, res - aux->limit.max_tob);
+ }
+
+ if (lower < upper)
+ ptrn->toa_ref = (upper + lower) / 2;
+ else
+ ptrn->toa_ref = lower;
+
+ ptrn->tob_ref = ref->duration - ptrn->toa_ref;
+ ptrn->tob_aux = res - ptrn->toa_ref;
+ ptrn->toa_aux = aux->duration - ptrn->tob_aux;
+}
+
+/* In strict pattern calculation, we consider timing that might need
+ * for HW stuffs, i.e. min_tob and min_toa.
+ */
+static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_pattern *ptrn)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME;
+ u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME;
+ u16 bcn_ofst = config->beacon_offset;
+ s16 upper_toa_ref, lower_toa_ref;
+ s16 upper_tob_aux, lower_tob_aux;
+ u16 bt_dur_in_mid;
+ s16 res;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: plan %d, bcn_ofst %d\n",
+ ptrn->plan, bcn_ofst);
+
+ if (ptrn->plan == RTW89_MCC_PLAN_MID_BT)
+ bt_dur_in_mid = mcc->bt_role.duration;
+ else
+ bt_dur_in_mid = 0;
+
+ if (ref->duration < min_tob + min_toa) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: not meet ref dur cond\n");
+ return -EINVAL;
+ }
+
+ if (aux->duration < min_tob + min_toa) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: not meet aux dur cond\n");
+ return -EINVAL;
+ }
+
+ res = bcn_ofst - min_toa - min_tob - bt_dur_in_mid;
+ if (res < 0) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: not meet bcn_ofst cond\n");
+ return -EINVAL;
+ }
+
+ upper_toa_ref = min_t(s16, min_toa + res, ref->duration - min_tob);
+ lower_toa_ref = min_toa;
+ upper_tob_aux = min_t(s16, min_tob + res, aux->duration - min_toa);
+ lower_tob_aux = min_tob;
+
+ if (ref->limit.enable) {
+ if (min_tob > ref->limit.max_tob || min_toa > ref->limit.max_toa) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: conflict ref limit\n");
+ return -EINVAL;
+ }
+
+ upper_toa_ref = min_t(s16, upper_toa_ref, ref->limit.max_toa);
+ lower_toa_ref = max_t(s16, lower_toa_ref,
+ ref->duration - ref->limit.max_tob);
+ } else if (aux->limit.enable) {
+ if (min_tob > aux->limit.max_tob || min_toa > aux->limit.max_toa) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: conflict aux limit\n");
+ return -EINVAL;
+ }
+
+ upper_tob_aux = min_t(s16, upper_tob_aux, aux->limit.max_tob);
+ lower_tob_aux = max_t(s16, lower_tob_aux,
+ aux->duration - aux->limit.max_toa);
+ }
+
+ upper_toa_ref = min_t(s16, upper_toa_ref,
+ bcn_ofst - bt_dur_in_mid - lower_tob_aux);
+ lower_toa_ref = max_t(s16, lower_toa_ref,
+ bcn_ofst - bt_dur_in_mid - upper_tob_aux);
+ if (lower_toa_ref > upper_toa_ref) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st: conflict boundary\n");
+ return -EINVAL;
+ }
+
+ ptrn->toa_ref = (upper_toa_ref + lower_toa_ref) / 2;
+ ptrn->tob_ref = ref->duration - ptrn->toa_ref;
+ ptrn->tob_aux = bcn_ofst - ptrn->toa_ref - bt_dur_in_mid;
+ ptrn->toa_aux = aux->duration - ptrn->tob_aux;
+ return 0;
+}
+
+static int rtw89_mcc_calc_pattern(struct rtw89_dev *rtwdev, bool hdl_bt)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ bool sel_plan[NUM_OF_RTW89_MCC_PLAN] = {};
+ struct rtw89_mcc_pattern ptrn;
+ int ret;
+ int i;
+
+ if (ref->limit.enable && aux->limit.enable) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn: not support dual limited roles\n");
+ return -EINVAL;
+ }
+
+ if (ref->limit.enable &&
+ ref->duration > ref->limit.max_tob + ref->limit.max_toa) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn: not fit ref limit\n");
+ return -EINVAL;
+ }
+
+ if (aux->limit.enable &&
+ aux->duration > aux->limit.max_tob + aux->limit.max_toa) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn: not fit aux limit\n");
+ return -EINVAL;
+ }
+
+ if (hdl_bt) {
+ sel_plan[RTW89_MCC_PLAN_TAIL_BT] = true;
+ sel_plan[RTW89_MCC_PLAN_MID_BT] = true;
+ } else {
+ sel_plan[RTW89_MCC_PLAN_NO_BT] = true;
+ }
+
+ for (i = 0; i < NUM_OF_RTW89_MCC_PLAN; i++) {
+ if (!sel_plan[i])
+ continue;
+
+ ptrn = (typeof(ptrn)){
+ .plan = i,
+ };
+
+ ret = __rtw89_mcc_calc_pattern_strict(rtwdev, &ptrn);
+ if (ret)
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC calc ptrn_st with plan %d: fail\n", i);
+ else
+ goto done;
+ }
+
+ __rtw89_mcc_calc_pattern_loose(rtwdev, &ptrn, hdl_bt);
+
+done:
+ rtw89_mcc_assign_pattern(rtwdev, &ptrn);
+ return 0;
+}
+
+static void rtw89_mcc_set_default_pattern(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_pattern tmp = {};
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC use default pattern unexpectedly\n");
+
+ tmp.plan = RTW89_MCC_PLAN_NO_BT;
+ tmp.tob_ref = ref->duration / 2;
+ tmp.toa_ref = ref->duration - tmp.tob_ref;
+ tmp.tob_aux = aux->duration / 2;
+ tmp.toa_aux = aux->duration - tmp.tob_aux;
+
+ rtw89_mcc_assign_pattern(rtwdev, &tmp);
+}
+
+static void rtw89_mcc_set_duration_go_sta(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *role_go,
+ struct rtw89_mcc_role *role_sta)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u16 mcc_intvl = config->mcc_interval;
+ u16 dur_go, dur_sta;
+
+ dur_go = clamp_t(u16, role_go->duration, RTW89_MCC_MIN_GO_DURATION,
+ mcc_intvl - RTW89_MCC_MIN_STA_DURATION);
+ if (role_go->limit.enable)
+ dur_go = min(dur_go, role_go->limit.max_dur);
+ dur_sta = mcc_intvl - dur_go;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC set dur: (go, sta) {%d, %d} -> {%d, %d}\n",
+ role_go->duration, role_sta->duration, dur_go, dur_sta);
+
+ role_go->duration = dur_go;
+ role_sta->duration = dur_sta;
+}
+
+static void rtw89_mcc_set_duration_gc_sta(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u16 mcc_intvl = config->mcc_interval;
+ u16 dur_ref, dur_aux;
+
+ if (ref->duration < RTW89_MCC_MIN_STA_DURATION) {
+ dur_ref = RTW89_MCC_MIN_STA_DURATION;
+ dur_aux = mcc_intvl - dur_ref;
+ } else if (aux->duration < RTW89_MCC_MIN_STA_DURATION) {
+ dur_aux = RTW89_MCC_MIN_STA_DURATION;
+ dur_ref = mcc_intvl - dur_aux;
+ } else {
+ dur_ref = ref->duration;
+ dur_aux = mcc_intvl - dur_ref;
+ }
+
+ if (ref->limit.enable) {
+ dur_ref = min(dur_ref, ref->limit.max_dur);
+ dur_aux = mcc_intvl - dur_ref;
+ } else if (aux->limit.enable) {
+ dur_aux = min(dur_aux, aux->limit.max_dur);
+ dur_ref = mcc_intvl - dur_aux;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC set dur: (ref, aux) {%d ~ %d} -> {%d ~ %d}\n",
+ ref->duration, aux->duration, dur_ref, dur_aux);
+
+ ref->duration = dur_ref;
+ aux->duration = dur_aux;
+}
+
+struct rtw89_mcc_mod_dur_data {
+ u16 available;
+ struct {
+ u16 dur;
+ u16 room;
+ } parm[NUM_OF_RTW89_MCC_ROLES];
+};
+
+static int rtw89_mcc_mod_dur_get_iterator(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role,
+ unsigned int ordered_idx,
+ void *data)
+{
+ struct rtw89_mcc_mod_dur_data *p = data;
+ u16 min;
+
+ p->parm[ordered_idx].dur = mcc_role->duration;
+
+ if (mcc_role->is_go)
+ min = RTW89_MCC_MIN_GO_DURATION;
+ else
+ min = RTW89_MCC_MIN_STA_DURATION;
+
+ p->parm[ordered_idx].room = max_t(s32, p->parm[ordered_idx].dur - min, 0);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur: chk role[%u]: dur %u, min %u, room %u\n",
+ ordered_idx, p->parm[ordered_idx].dur, min,
+ p->parm[ordered_idx].room);
+
+ p->available += p->parm[ordered_idx].room;
+ return 0;
+}
+
+static int rtw89_mcc_mod_dur_put_iterator(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role,
+ unsigned int ordered_idx,
+ void *data)
+{
+ struct rtw89_mcc_mod_dur_data *p = data;
+
+ mcc_role->duration = p->parm[ordered_idx].dur;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur: set role[%u]: dur %u\n",
+ ordered_idx, p->parm[ordered_idx].dur);
+ return 0;
+}
+
+static void rtw89_mcc_mod_duration_dual_2ghz_with_bt(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_mod_dur_data data = {};
+ u16 mcc_intvl = config->mcc_interval;
+ u16 bt_dur = mcc->bt_role.duration;
+ u16 wifi_dur;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur (dual 2ghz): mcc_intvl %u, raw bt_dur %u\n",
+ mcc_intvl, bt_dur);
+
+ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_mod_dur_get_iterator, &data);
+
+ bt_dur = clamp_t(u16, bt_dur, 1, data.available / 3);
+ wifi_dur = mcc_intvl - bt_dur;
+
+ if (data.parm[0].room <= data.parm[1].room) {
+ data.parm[0].dur -= min_t(u16, bt_dur / 2, data.parm[0].room);
+ data.parm[1].dur = wifi_dur - data.parm[0].dur;
+ } else {
+ data.parm[1].dur -= min_t(u16, bt_dur / 2, data.parm[1].room);
+ data.parm[0].dur = wifi_dur - data.parm[1].dur;
+ }
+
+ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_mod_dur_put_iterator, &data);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC mod dur: set bt: dur %u\n", bt_dur);
+ mcc->bt_role.duration = bt_dur;
+}
+
+static
+void rtw89_mcc_mod_duration_diff_band_with_bt(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *role_2ghz,
+ struct rtw89_mcc_role *role_non_2ghz)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u16 dur_2ghz, dur_non_2ghz;
+ u16 bt_dur, mcc_intvl;
+
+ dur_2ghz = role_2ghz->duration;
+ dur_non_2ghz = role_non_2ghz->duration;
+ mcc_intvl = config->mcc_interval;
+ bt_dur = mcc->bt_role.duration;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur (diff band): mcc_intvl %u, bt_dur %u\n",
+ mcc_intvl, bt_dur);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur: check dur_2ghz %u, dur_non_2ghz %u\n",
+ dur_2ghz, dur_non_2ghz);
+
+ if (dur_non_2ghz >= bt_dur) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur: dur_non_2ghz is enough for bt\n");
+ return;
+ }
+
+ dur_non_2ghz = bt_dur;
+ dur_2ghz = mcc_intvl - dur_non_2ghz;
+
+ if (role_non_2ghz->limit.enable) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur: dur_non_2ghz is limited with max %u\n",
+ role_non_2ghz->limit.max_dur);
+
+ dur_non_2ghz = min(dur_non_2ghz, role_non_2ghz->limit.max_dur);
+ dur_2ghz = mcc_intvl - dur_non_2ghz;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC mod dur: set dur_2ghz %u, dur_non_2ghz %u\n",
+ dur_2ghz, dur_non_2ghz);
+
+ role_2ghz->duration = dur_2ghz;
+ role_non_2ghz->duration = dur_non_2ghz;
+}
+
+static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
+
+ if (!bt_role->duration)
+ return false;
+
+ if (ref->is_2ghz && aux->is_2ghz) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC dual roles are on 2GHz; consider BT duration\n");
+
+ rtw89_mcc_mod_duration_dual_2ghz_with_bt(rtwdev);
+ return true;
+ }
+
+ if (!ref->is_2ghz && !aux->is_2ghz) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC dual roles are not on 2GHz; ignore BT duration\n");
+ return false;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC one role is on 2GHz; modify another for BT duration\n");
+
+ if (ref->is_2ghz)
+ rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, ref, aux);
+ else
+ rtw89_mcc_mod_duration_diff_band_with_bt(rtwdev, aux, ref);
+
+ return false;
+}
+
+static void rtw89_mcc_sync_tbtt(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *tgt,
+ struct rtw89_mcc_role *src,
+ bool ref_is_src)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u16 beacon_offset_us = ieee80211_tu_to_usec(config->beacon_offset);
+ u32 bcn_intvl_src_us = ieee80211_tu_to_usec(src->beacon_interval);
+ u32 cur_tbtt_ofst_src;
+ u32 tsf_ofst_tgt;
+ u32 remainder;
+ u64 tbtt_tgt;
+ u64 tsf_src;
+ int ret;
+
+ ret = rtw89_mac_port_get_tsf(rtwdev, src->rtwvif, &tsf_src);
+ if (ret) {
+ rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
+ return;
+ }
+
+ cur_tbtt_ofst_src = rtw89_mcc_get_tbtt_ofst(rtwdev, src, tsf_src);
+
+ if (ref_is_src)
+ tbtt_tgt = tsf_src - cur_tbtt_ofst_src + beacon_offset_us;
+ else
+ tbtt_tgt = tsf_src - cur_tbtt_ofst_src +
+ (bcn_intvl_src_us - beacon_offset_us);
+
+ div_u64_rem(tbtt_tgt, bcn_intvl_src_us, &remainder);
+ tsf_ofst_tgt = bcn_intvl_src_us - remainder;
+
+ config->sync.macid_tgt = tgt->rtwvif->mac_id;
+ config->sync.band_tgt = tgt->rtwvif->mac_idx;
+ config->sync.port_tgt = tgt->rtwvif->port;
+ config->sync.macid_src = src->rtwvif->mac_id;
+ config->sync.band_src = src->rtwvif->mac_idx;
+ config->sync.port_src = src->rtwvif->port;
+ config->sync.offset = tsf_ofst_tgt / 1024;
+ config->sync.enable = true;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC sync tbtt: tgt %d, src %d, offset %d\n",
+ config->sync.macid_tgt, config->sync.macid_src,
+ config->sync.offset);
+
+ rtw89_mac_port_tsf_sync(rtwdev, tgt->rtwvif, src->rtwvif,
+ config->sync.offset);
+}
+
+static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_config *config = &mcc->config;
+ u32 bcn_intvl_ref_us = ieee80211_tu_to_usec(ref->beacon_interval);
+ u32 tob_ref_us = ieee80211_tu_to_usec(config->pattern.tob_ref);
+ struct rtw89_vif *rtwvif = ref->rtwvif;
+ u64 tsf, start_tsf;
+ u32 cur_tbtt_ofst;
+ u64 min_time;
+ int ret;
+
+ ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif, &tsf);
+ if (ret) {
+ rtw89_warn(rtwdev, "MCC failed to get port tsf: %d\n", ret);
+ return ret;
+ }
+
+ min_time = tsf;
+ if (ref->is_go)
+ min_time += ieee80211_tu_to_usec(RTW89_MCC_SHORT_TRIGGER_TIME);
+ else
+ min_time += ieee80211_tu_to_usec(RTW89_MCC_LONG_TRIGGER_TIME);
+
+ cur_tbtt_ofst = rtw89_mcc_get_tbtt_ofst(rtwdev, ref, tsf);
+ start_tsf = tsf - cur_tbtt_ofst + bcn_intvl_ref_us - tob_ref_us;
+ while (start_tsf < min_time)
+ start_tsf += bcn_intvl_ref_us;
+
+ config->start_tsf = start_tsf;
+ return 0;
+}
+
+static int rtw89_mcc_fill_config(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ bool hdl_bt;
+ int ret;
+
+ memset(config, 0, sizeof(*config));
+
+ switch (mcc->mode) {
+ case RTW89_MCC_MODE_GO_STA:
+ config->beacon_offset = RTW89_MCC_DFLT_BCN_OFST_TIME;
+ if (ref->is_go) {
+ rtw89_mcc_sync_tbtt(rtwdev, ref, aux, false);
+ config->mcc_interval = ref->beacon_interval;
+ rtw89_mcc_set_duration_go_sta(rtwdev, ref, aux);
+ } else {
+ rtw89_mcc_sync_tbtt(rtwdev, aux, ref, true);
+ config->mcc_interval = aux->beacon_interval;
+ rtw89_mcc_set_duration_go_sta(rtwdev, aux, ref);
+ }
+ break;
+ case RTW89_MCC_MODE_GC_STA:
+ config->beacon_offset = rtw89_mcc_get_bcn_ofst(rtwdev);
+ config->mcc_interval = ref->beacon_interval;
+ rtw89_mcc_set_duration_gc_sta(rtwdev);
+ break;
+ default:
+ rtw89_warn(rtwdev, "MCC unknown mode: %d\n", mcc->mode);
+ return -EFAULT;
+ }
+
+ hdl_bt = rtw89_mcc_duration_decision_on_bt(rtwdev);
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC handle bt: %d\n", hdl_bt);
+
+ ret = rtw89_mcc_calc_pattern(rtwdev, hdl_bt);
+ if (!ret)
+ goto bottom;
+
+ rtw89_mcc_set_default_pattern(rtwdev);
+
+bottom:
+ return rtw89_mcc_fill_start_tsf(rtwdev);
+}
+
+static int __mcc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
+ struct rtw89_mcc_policy *policy = &role->policy;
+ struct rtw89_fw_mcc_add_req req = {};
+ const struct rtw89_chan *chan;
+ int ret;
+
+ chan = rtw89_chan_get(rtwdev, role->rtwvif->sub_entity_idx);
+ req.central_ch_seg0 = chan->channel;
+ req.primary_ch = chan->primary_channel;
+ req.bandwidth = chan->band_width;
+ req.ch_band_type = chan->band_type;
+
+ req.macid = role->rtwvif->mac_id;
+ req.group = mcc->group;
+ req.c2h_rpt = policy->c2h_rpt;
+ req.tx_null_early = policy->tx_null_early;
+ req.dis_tx_null = policy->dis_tx_null;
+ req.in_curr_ch = policy->in_curr_ch;
+ req.sw_retry_count = policy->sw_retry_count;
+ req.dis_sw_retry = policy->dis_sw_retry;
+ req.duration = role->duration;
+ req.btc_in_2g = false;
+
+ if (courtesy->enable && courtesy->macid_src == req.macid) {
+ req.courtesy_target = courtesy->macid_tgt;
+ req.courtesy_num = courtesy->slot_num;
+ req.courtesy_en = true;
+ }
+
+ ret = rtw89_fw_h2c_add_mcc(rtwdev, &req);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to add wifi role: %d\n", ret);
+ return ret;
+ }
+
+ ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
+ role->rtwvif->mac_id,
+ role->macid_bitmap);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to set macid bitmap: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static
+void __mrc_fw_add_role(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role,
+ struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_policy *policy = &role->policy;
+ struct rtw89_fw_mrc_add_slot_arg *slot_arg;
+ const struct rtw89_chan *chan;
+
+ slot_arg = &arg->slots[slot_idx];
+ role->slot_idx = slot_idx;
+
+ slot_arg->duration = role->duration;
+ slot_arg->role_num = 1;
+
+ chan = rtw89_chan_get(rtwdev, role->rtwvif->sub_entity_idx);
+
+ slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_WIFI;
+ slot_arg->roles[0].is_master = role == ref;
+ slot_arg->roles[0].band = chan->band_type;
+ slot_arg->roles[0].bw = chan->band_width;
+ slot_arg->roles[0].central_ch = chan->channel;
+ slot_arg->roles[0].primary_ch = chan->primary_channel;
+ slot_arg->roles[0].en_tx_null = !policy->dis_tx_null;
+ slot_arg->roles[0].null_early = policy->tx_null_early;
+ slot_arg->roles[0].macid = role->rtwvif->mac_id;
+ slot_arg->roles[0].macid_main_bitmap =
+ rtw89_mcc_role_fw_macid_bitmap_to_u32(role);
+}
+
+static int __mcc_fw_add_bt_role(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
+ struct rtw89_fw_mcc_add_req req = {};
+ int ret;
+
+ req.group = mcc->group;
+ req.duration = bt_role->duration;
+ req.btc_in_2g = true;
+
+ ret = rtw89_fw_h2c_add_mcc(rtwdev, &req);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to add bt role: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static
+void __mrc_fw_add_bt_role(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_mrc_add_arg *arg, u8 slot_idx)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_bt_role *bt_role = &mcc->bt_role;
+ struct rtw89_fw_mrc_add_slot_arg *slot_arg = &arg->slots[slot_idx];
+
+ slot_arg->duration = bt_role->duration;
+ slot_arg->role_num = 1;
+
+ slot_arg->roles[0].role_type = RTW89_H2C_MRC_ROLE_BT;
+}
+
+static int __mcc_fw_start(struct rtw89_dev *rtwdev, bool replace)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_sync *sync = &config->sync;
+ struct rtw89_fw_mcc_start_req req = {};
+ int ret;
+
+ if (replace) {
+ req.old_group = mcc->group;
+ req.old_group_action = RTW89_FW_MCC_OLD_GROUP_ACT_REPLACE;
+ mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
+ }
+
+ req.group = mcc->group;
+
+ switch (pattern->plan) {
+ case RTW89_MCC_PLAN_TAIL_BT:
+ ret = __mcc_fw_add_role(rtwdev, ref);
+ if (ret)
+ return ret;
+ ret = __mcc_fw_add_role(rtwdev, aux);
+ if (ret)
+ return ret;
+ ret = __mcc_fw_add_bt_role(rtwdev);
+ if (ret)
+ return ret;
+
+ req.btc_in_group = true;
+ break;
+ case RTW89_MCC_PLAN_MID_BT:
+ ret = __mcc_fw_add_role(rtwdev, ref);
+ if (ret)
+ return ret;
+ ret = __mcc_fw_add_bt_role(rtwdev);
+ if (ret)
+ return ret;
+ ret = __mcc_fw_add_role(rtwdev, aux);
+ if (ret)
+ return ret;
+
+ req.btc_in_group = true;
+ break;
+ case RTW89_MCC_PLAN_NO_BT:
+ ret = __mcc_fw_add_role(rtwdev, ref);
+ if (ret)
+ return ret;
+ ret = __mcc_fw_add_role(rtwdev, aux);
+ if (ret)
+ return ret;
+
+ req.btc_in_group = false;
+ break;
+ default:
+ rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
+ return -EFAULT;
+ }
+
+ if (sync->enable) {
+ ret = rtw89_fw_h2c_mcc_sync(rtwdev, req.group, sync->macid_src,
+ sync->macid_tgt, sync->offset);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to trigger sync: %d\n", ret);
+ return ret;
+ }
+ }
+
+ req.macid = ref->rtwvif->mac_id;
+ req.tsf_high = config->start_tsf >> 32;
+ req.tsf_low = config->start_tsf;
+
+ ret = rtw89_fw_h2c_start_mcc(rtwdev, &req);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to trigger start: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __mrc_fw_add_courtesy(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_mrc_add_arg *arg)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_courtesy *courtesy = &pattern->courtesy;
+ struct rtw89_fw_mrc_add_slot_arg *slot_arg_src;
+ u8 slot_idx_tgt;
+
+ if (!courtesy->enable)
+ return;
+
+ if (courtesy->macid_src == ref->rtwvif->mac_id) {
+ slot_arg_src = &arg->slots[ref->slot_idx];
+ slot_idx_tgt = aux->slot_idx;
+ } else {
+ slot_arg_src = &arg->slots[aux->slot_idx];
+ slot_idx_tgt = ref->slot_idx;
+ }
+
+ slot_arg_src->courtesy_target = slot_idx_tgt;
+ slot_arg_src->courtesy_period = courtesy->slot_num;
+ slot_arg_src->courtesy_en = true;
+}
+
+static int __mrc_fw_start(struct rtw89_dev *rtwdev, bool replace)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_sync *sync = &config->sync;
+ struct rtw89_fw_mrc_start_arg start_arg = {};
+ struct rtw89_fw_mrc_add_arg add_arg = {};
+ int ret;
+
+ BUILD_BUG_ON(RTW89_MAC_MRC_MAX_ADD_SLOT_NUM <
+ NUM_OF_RTW89_MCC_ROLES + 1 /* bt role */);
+
+ if (replace) {
+ start_arg.old_sch_idx = mcc->group;
+ start_arg.action = RTW89_H2C_MRC_START_ACTION_REPLACE_OLD;
+ mcc->group = RTW89_MCC_NEXT_GROUP(mcc->group);
+ }
+
+ add_arg.sch_idx = mcc->group;
+ add_arg.sch_type = RTW89_H2C_MRC_SCH_BAND0_ONLY;
+
+ switch (pattern->plan) {
+ case RTW89_MCC_PLAN_TAIL_BT:
+ __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
+ __mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
+ __mrc_fw_add_bt_role(rtwdev, &add_arg, 2);
+
+ add_arg.slot_num = 3;
+ add_arg.btc_in_sch = true;
+ break;
+ case RTW89_MCC_PLAN_MID_BT:
+ __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
+ __mrc_fw_add_bt_role(rtwdev, &add_arg, 1);
+ __mrc_fw_add_role(rtwdev, aux, &add_arg, 2);
+
+ add_arg.slot_num = 3;
+ add_arg.btc_in_sch = true;
+ break;
+ case RTW89_MCC_PLAN_NO_BT:
+ __mrc_fw_add_role(rtwdev, ref, &add_arg, 0);
+ __mrc_fw_add_role(rtwdev, aux, &add_arg, 1);
+
+ add_arg.slot_num = 2;
+ add_arg.btc_in_sch = false;
+ break;
+ default:
+ rtw89_warn(rtwdev, "MCC unknown plan: %d\n", pattern->plan);
+ return -EFAULT;
+ }
+
+ __mrc_fw_add_courtesy(rtwdev, &add_arg);
+
+ ret = rtw89_fw_h2c_mrc_add(rtwdev, &add_arg);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to trigger add: %d\n", ret);
+ return ret;
+ }
+
+ if (sync->enable) {
+ struct rtw89_fw_mrc_sync_arg sync_arg = {
+ .offset = sync->offset,
+ .src = {
+ .band = sync->band_src,
+ .port = sync->port_src,
+ },
+ .dest = {
+ .band = sync->band_tgt,
+ .port = sync->port_tgt,
+ },
+ };
+
+ ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to trigger sync: %d\n", ret);
+ return ret;
+ }
+ }
+
+ start_arg.sch_idx = mcc->group;
+ start_arg.start_tsf = config->start_tsf;
+
+ ret = rtw89_fw_h2c_mrc_start(rtwdev, &start_arg);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to trigger start: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __mcc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_sync *sync = &config->sync;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_fw_mcc_duration req = {
+ .group = mcc->group,
+ .btc_in_group = false,
+ .start_macid = ref->rtwvif->mac_id,
+ .macid_x = ref->rtwvif->mac_id,
+ .macid_y = aux->rtwvif->mac_id,
+ .duration_x = ref->duration,
+ .duration_y = aux->duration,
+ .start_tsf_high = config->start_tsf >> 32,
+ .start_tsf_low = config->start_tsf,
+ };
+ int ret;
+
+ ret = rtw89_fw_h2c_mcc_set_duration(rtwdev, &req);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to set duration: %d\n", ret);
+ return ret;
+ }
+
+ if (!sync->enable || !sync_changed)
+ return 0;
+
+ ret = rtw89_fw_h2c_mcc_sync(rtwdev, mcc->group, sync->macid_src,
+ sync->macid_tgt, sync->offset);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to trigger sync: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __mrc_fw_set_duration_no_bt(struct rtw89_dev *rtwdev, bool sync_changed)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_sync *sync = &config->sync;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_fw_mrc_upd_duration_arg dur_arg = {
+ .sch_idx = mcc->group,
+ .start_tsf = config->start_tsf,
+ .slot_num = 2,
+ .slots[0] = {
+ .slot_idx = ref->slot_idx,
+ .duration = ref->duration,
+ },
+ .slots[1] = {
+ .slot_idx = aux->slot_idx,
+ .duration = aux->duration,
+ },
+ };
+ struct rtw89_fw_mrc_sync_arg sync_arg = {
+ .offset = sync->offset,
+ .src = {
+ .band = sync->band_src,
+ .port = sync->port_src,
+ },
+ .dest = {
+ .band = sync->band_tgt,
+ .port = sync->port_tgt,
+ },
+
+ };
+ int ret;
+
+ ret = rtw89_fw_h2c_mrc_upd_duration(rtwdev, &dur_arg);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to update duration: %d\n", ret);
+ return ret;
+ }
+
+ if (!sync->enable || !sync_changed)
+ return 0;
+
+ ret = rtw89_fw_h2c_mrc_sync(rtwdev, &sync_arg);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to trigger sync: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+ struct rtw89_mcc_sync *sync = &config->sync;
+ struct ieee80211_p2p_noa_desc noa_desc = {};
+ u64 start_time = config->start_tsf;
+ u32 interval = config->mcc_interval;
+ struct rtw89_vif *rtwvif_go;
+ u32 duration;
+
+ if (mcc->mode != RTW89_MCC_MODE_GO_STA)
+ return;
+
+ if (ref->is_go) {
+ rtwvif_go = ref->rtwvif;
+ start_time += ieee80211_tu_to_usec(ref->duration);
+ duration = config->mcc_interval - ref->duration;
+ } else if (aux->is_go) {
+ rtwvif_go = aux->rtwvif;
+ start_time += ieee80211_tu_to_usec(pattern->tob_ref) +
+ ieee80211_tu_to_usec(config->beacon_offset) +
+ ieee80211_tu_to_usec(pattern->toa_aux);
+ duration = config->mcc_interval - aux->duration;
+
+ /* convert time domain from sta(ref) to GO(aux) */
+ start_time += ieee80211_tu_to_usec(sync->offset);
+ } else {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC find no GO: skip updating beacon NoA\n");
+ return;
+ }
+
+ rtw89_p2p_noa_renew(rtwvif_go);
+
+ if (enable) {
+ noa_desc.start_time = cpu_to_le32(start_time);
+ noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval));
+ noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration));
+ noa_desc.count = 255;
+ rtw89_p2p_noa_append(rtwvif_go, &noa_desc);
+ }
+
+ /* without chanctx, we cannot get beacon from mac80211 stack */
+ if (!rtwvif_go->chanctx_assigned)
+ return;
+
+ rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_go);
+}
+
+static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+
+ if (mcc->mode != RTW89_MCC_MODE_GO_STA)
+ return;
+
+ if (ref->is_go)
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, true);
+ else if (aux->is_go)
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, true);
+
+ rtw89_mcc_handle_beacon_noa(rtwdev, true);
+}
+
+static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+
+ if (mcc->mode != RTW89_MCC_MODE_GO_STA)
+ return;
+
+ if (ref->is_go)
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, ref->rtwvif, false);
+ else if (aux->is_go)
+ rtw89_fw_h2c_tsf32_toggle(rtwdev, aux->rtwvif, false);
+
+ rtw89_mcc_handle_beacon_noa(rtwdev, false);
+}
+
+static int rtw89_mcc_start(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ struct rtw89_mcc_role *aux = &mcc->role_aux;
+ int ret;
+
+ if (rtwdev->scanning)
+ rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+
+ rtw89_leave_lps(rtwdev);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC start\n");
+
+ ret = rtw89_mcc_fill_all_roles(rtwdev);
+ if (ret)
+ return ret;
+
+ if (ref->is_go || aux->is_go)
+ mcc->mode = RTW89_MCC_MODE_GO_STA;
+ else
+ mcc->mode = RTW89_MCC_MODE_GC_STA;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC sel mode: %d\n", mcc->mode);
+
+ mcc->group = RTW89_MCC_DFLT_GROUP;
+
+ ret = rtw89_mcc_fill_config(rtwdev);
+ if (ret)
+ return ret;
+
+ if (rtw89_concurrent_via_mrc(rtwdev))
+ ret = __mrc_fw_start(rtwdev, false);
+ else
+ ret = __mcc_fw_start(rtwdev, false);
+
+ if (ret)
+ return ret;
+
+ rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START);
+
+ rtw89_mcc_start_beacon_noa(rtwdev);
+ return 0;
+}
+
+static void rtw89_mcc_stop(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_role *ref = &mcc->role_ref;
+ int ret;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC stop\n");
+
+ if (rtw89_concurrent_via_mrc(rtwdev)) {
+ ret = rtw89_fw_h2c_mrc_del(rtwdev, mcc->group);
+ if (ret)
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to trigger del: %d\n", ret);
+ } else {
+ ret = rtw89_fw_h2c_stop_mcc(rtwdev, mcc->group,
+ ref->rtwvif->mac_id, true);
+ if (ret)
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to trigger stop: %d\n", ret);
+
+ ret = rtw89_fw_h2c_del_mcc_group(rtwdev, mcc->group, true);
+ if (ret)
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to delete group: %d\n", ret);
+ }
+
+ rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP);
+
+ rtw89_mcc_stop_beacon_noa(rtwdev);
+}
+
+static int rtw89_mcc_update(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_config old_cfg = *config;
+ bool sync_changed;
+ int ret;
+
+ if (rtwdev->scanning)
+ rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "MCC update\n");
+
+ ret = rtw89_mcc_fill_config(rtwdev);
+ if (ret)
+ return ret;
+
+ if (old_cfg.pattern.plan != RTW89_MCC_PLAN_NO_BT ||
+ config->pattern.plan != RTW89_MCC_PLAN_NO_BT) {
+ if (rtw89_concurrent_via_mrc(rtwdev))
+ ret = __mrc_fw_start(rtwdev, true);
+ else
+ ret = __mcc_fw_start(rtwdev, true);
+
+ if (ret)
+ return ret;
+ } else {
+ if (memcmp(&old_cfg.sync, &config->sync, sizeof(old_cfg.sync)) == 0)
+ sync_changed = false;
+ else
+ sync_changed = true;
+
+ if (rtw89_concurrent_via_mrc(rtwdev))
+ ret = __mrc_fw_set_duration_no_bt(rtwdev, sync_changed);
+ else
+ ret = __mcc_fw_set_duration_no_bt(rtwdev, sync_changed);
+
+ if (ret)
+ return ret;
+ }
+
+ rtw89_mcc_handle_beacon_noa(rtwdev, true);
+ return 0;
+}
+
+static void rtw89_mcc_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_mcc_config *config = &mcc->config;
+ struct rtw89_mcc_pattern *pattern = &config->pattern;
+ s16 tolerance;
+ u16 bcn_ofst;
+ u16 diff;
+
+ if (mcc->mode != RTW89_MCC_MODE_GC_STA)
+ return;
+
+ bcn_ofst = rtw89_mcc_get_bcn_ofst(rtwdev);
+ if (bcn_ofst > config->beacon_offset) {
+ diff = bcn_ofst - config->beacon_offset;
+ if (pattern->tob_aux < 0)
+ tolerance = -pattern->tob_aux;
+ else
+ tolerance = pattern->toa_aux;
+ } else {
+ diff = config->beacon_offset - bcn_ofst;
+ if (pattern->toa_aux < 0)
+ tolerance = -pattern->toa_aux;
+ else
+ tolerance = pattern->tob_aux;
+ }
+
+ if (diff <= tolerance)
+ return;
+
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BCN_OFFSET_CHANGE);
+}
+
+static int __mcc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *upd)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ int ret;
+
+ ret = rtw89_fw_h2c_mcc_macid_bitmap(rtwdev, mcc->group,
+ upd->rtwvif->mac_id,
+ upd->macid_bitmap);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MCC h2c failed to update macid bitmap: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __mrc_fw_upd_macid_bitmap(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *cur,
+ struct rtw89_mcc_role *upd)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+ struct rtw89_fw_mrc_upd_bitmap_arg arg = {};
+ u32 old = rtw89_mcc_role_fw_macid_bitmap_to_u32(cur);
+ u32 new = rtw89_mcc_role_fw_macid_bitmap_to_u32(upd);
+ u32 add = new & ~old;
+ u32 del = old & ~new;
+ int ret;
+ int i;
+
+ arg.sch_idx = mcc->group;
+ arg.macid = upd->rtwvif->mac_id;
+
+ for (i = 0; i < 32; i++) {
+ if (add & BIT(i)) {
+ arg.client_macid = i;
+ arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_ADD;
+
+ ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
+ if (ret)
+ goto err;
+ }
+ }
+
+ for (i = 0; i < 32; i++) {
+ if (del & BIT(i)) {
+ arg.client_macid = i;
+ arg.action = RTW89_H2C_MRC_UPD_BITMAP_ACTION_DEL;
+
+ ret = rtw89_fw_h2c_mrc_upd_bitmap(rtwdev, &arg);
+ if (ret)
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "MRC h2c failed to update bitmap: %d\n", ret);
+ return ret;
+}
+
+static int rtw89_mcc_upd_map_iterator(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role,
+ unsigned int ordered_idx,
+ void *data)
+{
+ struct rtw89_mcc_role upd = {
+ .rtwvif = mcc_role->rtwvif,
+ };
+ int ret;
+
+ if (!mcc_role->is_go)
+ return 0;
+
+ rtw89_mcc_fill_role_macid_bitmap(rtwdev, &upd);
+ if (memcmp(mcc_role->macid_bitmap, upd.macid_bitmap,
+ sizeof(mcc_role->macid_bitmap)) == 0)
+ return 0;
+
+ if (rtw89_concurrent_via_mrc(rtwdev))
+ ret = __mrc_fw_upd_macid_bitmap(rtwdev, mcc_role, &upd);
+ else
+ ret = __mcc_fw_upd_macid_bitmap(rtwdev, &upd);
+
+ if (ret)
+ return ret;
+
+ memcpy(mcc_role->macid_bitmap, upd.macid_bitmap,
+ sizeof(mcc_role->macid_bitmap));
+ return 0;
+}
+
+static void rtw89_mcc_update_macid_bitmap(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+
+ if (mcc->mode != RTW89_MCC_MODE_GO_STA)
+ return;
+
+ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_map_iterator, NULL);
+}
+
+static int rtw89_mcc_upd_lmt_iterator(struct rtw89_dev *rtwdev,
+ struct rtw89_mcc_role *mcc_role,
+ unsigned int ordered_idx,
+ void *data)
+{
+ memset(&mcc_role->limit, 0, sizeof(mcc_role->limit));
+ rtw89_mcc_fill_role_limit(rtwdev, mcc_role);
+ return 0;
+}
+
+static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mcc_info *mcc = &rtwdev->mcc;
+
+ if (mcc->mode != RTW89_MCC_MODE_GC_STA)
+ return;
+
+ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL);
+}
+
+void rtw89_chanctx_work(struct work_struct *work)
+{
+ struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
+ chanctx_work.work);
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool update_mcc_pattern = false;
+ enum rtw89_entity_mode mode;
+ u32 changed = 0;
+ int ret;
+ int i;
+
+ mutex_lock(&rtwdev->mutex);
+
+ if (hal->entity_pause) {
+ mutex_unlock(&rtwdev->mutex);
+ return;
+ }
+
+ for (i = 0; i < NUM_OF_RTW89_CHANCTX_CHANGES; i++) {
+ if (test_and_clear_bit(i, hal->changes))
+ changed |= BIT(i);
+ }
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ rtw89_set_entity_mode(rtwdev, RTW89_ENTITY_MODE_MCC);
+ rtw89_set_channel(rtwdev);
+
+ ret = rtw89_mcc_start(rtwdev);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
+ break;
+ case RTW89_ENTITY_MODE_MCC:
+ if (changed & BIT(RTW89_CHANCTX_BCN_OFFSET_CHANGE) ||
+ changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE) ||
+ changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE) ||
+ changed & BIT(RTW89_CHANCTX_TSF32_TOGGLE_CHANGE))
+ update_mcc_pattern = true;
+ if (changed & BIT(RTW89_CHANCTX_REMOTE_STA_CHANGE))
+ rtw89_mcc_update_macid_bitmap(rtwdev);
+ if (changed & BIT(RTW89_CHANCTX_P2P_PS_CHANGE))
+ rtw89_mcc_update_limit(rtwdev);
+ if (changed & BIT(RTW89_CHANCTX_BT_SLOT_CHANGE))
+ rtw89_mcc_fill_bt_role(rtwdev);
+ if (update_mcc_pattern) {
+ ret = rtw89_mcc_update(rtwdev);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to update MCC: %d\n",
+ ret);
+ }
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&rtwdev->mutex);
+}
+
+void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_changes change)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_entity_mode mode;
+ u32 delay;
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ default:
+ return;
+ case RTW89_ENTITY_MODE_MCC_PREPARE:
+ delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE);
+ break;
+ case RTW89_ENTITY_MODE_MCC:
+ delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC);
+ break;
+ }
+
+ if (change != RTW89_CHANCTX_CHANGE_DFLT) {
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "set chanctx change %d\n",
+ change);
+ set_bit(change, hal->changes);
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN,
+ "queue chanctx work for mode %d with delay %d us\n",
+ mode, delay);
+ ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->chanctx_work,
+ usecs_to_jiffies(delay));
+}
+
+void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev)
+{
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT);
+}
+
+void rtw89_chanctx_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_entity_mode mode;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (hal->entity_pause)
+ return;
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC:
+ rtw89_mcc_track(rtwdev);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_pause_reasons rsn)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_entity_mode mode;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (hal->entity_pause)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx pause (rsn: %d)\n", rsn);
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC:
+ rtw89_mcc_stop(rtwdev);
+ break;
+ default:
+ break;
+ }
+
+ hal->entity_pause = true;
+}
+
+void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ enum rtw89_entity_mode mode;
+ int ret;
+
+ lockdep_assert_held(&rtwdev->mutex);
+
+ if (!hal->entity_pause)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_CHAN, "chanctx proceed\n");
+
+ hal->entity_pause = false;
+ rtw89_set_channel(rtwdev);
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ switch (mode) {
+ case RTW89_ENTITY_MODE_MCC:
+ ret = rtw89_mcc_start(rtwdev);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to start MCC: %d\n", ret);
+ break;
+ default:
+ break;
+ }
+
+ rtw89_queue_chanctx_work(rtwdev);
+}
+
+static void rtw89_swap_sub_entity(struct rtw89_dev *rtwdev,
+ enum rtw89_sub_entity_idx idx1,
+ enum rtw89_sub_entity_idx idx2)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_vif *rtwvif;
+ u8 cur;
+
+ if (idx1 == idx2)
+ return;
+
+ hal->sub[idx1].cfg->idx = idx2;
+ hal->sub[idx2].cfg->idx = idx1;
+
+ swap(hal->sub[idx1], hal->sub[idx2]);
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ if (!rtwvif->chanctx_assigned)
+ continue;
+ if (rtwvif->sub_entity_idx == idx1)
+ rtwvif->sub_entity_idx = idx2;
+ else if (rtwvif->sub_entity_idx == idx2)
+ rtwvif->sub_entity_idx = idx1;
+ }
+
+ cur = atomic_read(&hal->roc_entity_idx);
+ if (cur == idx1)
+ atomic_set(&hal->roc_entity_idx, idx2);
+ else if (cur == idx2)
+ atomic_set(&hal->roc_entity_idx, idx1);
+}
+
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx)
{
@@ -227,8 +2384,8 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
return -ENOENT;
rtw89_config_entity_chandef(rtwdev, idx, &ctx->def);
- rtw89_set_channel(rtwdev);
cfg->idx = idx;
+ cfg->ref_count = 0;
hal->sub[idx].cfg = cfg;
return 0;
}
@@ -238,37 +2395,8 @@ void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
{
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
- struct rtw89_vif *rtwvif;
- u8 drop, roll;
-
- drop = cfg->idx;
- if (drop != RTW89_SUB_ENTITY_0)
- goto out;
-
- roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY, drop + 1);
-
- /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
- if (roll == NUM_OF_RTW89_SUB_ENTITY)
- goto out;
-
- /* RTW89_SUB_ENTITY_0 is going to release, and another exists.
- * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
- */
- hal->sub[roll].cfg->idx = RTW89_SUB_ENTITY_0;
- hal->sub[RTW89_SUB_ENTITY_0] = hal->sub[roll];
-
- rtw89_for_each_rtwvif(rtwdev, rtwvif) {
- if (rtwvif->sub_entity_idx == roll)
- rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
- }
-
- atomic_cmpxchg(&hal->roc_entity_idx, roll, RTW89_SUB_ENTITY_0);
-
- drop = roll;
-out:
- clear_bit(drop, hal->entity_map);
- rtw89_set_channel(rtwdev);
+ clear_bit(cfg->idx, hal->entity_map);
}
void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev,
@@ -289,14 +2417,73 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx)
{
struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ struct rtw89_entity_weight w = {};
rtwvif->sub_entity_idx = cfg->idx;
- return 0;
+ rtwvif->chanctx_assigned = true;
+ cfg->ref_count++;
+
+ if (cfg->idx == RTW89_SUB_ENTITY_0)
+ goto out;
+
+ rtw89_entity_calculate_weight(rtwdev, &w);
+ if (w.active_chanctxs != 1)
+ goto out;
+
+ /* put the first active chanctx at RTW89_SUB_ENTITY_0 */
+ rtw89_swap_sub_entity(rtwdev, cfg->idx, RTW89_SUB_ENTITY_0);
+
+out:
+ return rtw89_set_channel(rtwdev);
}
void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct ieee80211_chanctx_conf *ctx)
{
+ struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_entity_weight w = {};
+ enum rtw89_sub_entity_idx roll;
+ enum rtw89_entity_mode cur;
+
rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0;
+ rtwvif->chanctx_assigned = false;
+ cfg->ref_count--;
+
+ if (cfg->ref_count != 0)
+ goto out;
+
+ if (cfg->idx != RTW89_SUB_ENTITY_0)
+ goto out;
+
+ roll = find_next_bit(hal->entity_map, NUM_OF_RTW89_SUB_ENTITY,
+ cfg->idx + 1);
+ /* Follow rtw89_config_default_chandef() when rtw89_entity_recalc(). */
+ if (roll == NUM_OF_RTW89_SUB_ENTITY)
+ goto out;
+
+ /* RTW89_SUB_ENTITY_0 is going to release, and another exists.
+ * Make another roll down to RTW89_SUB_ENTITY_0 to replace.
+ */
+ rtw89_swap_sub_entity(rtwdev, cfg->idx, roll);
+
+out:
+ rtw89_entity_calculate_weight(rtwdev, &w);
+
+ cur = rtw89_get_entity_mode(rtwdev);
+ switch (cur) {
+ case RTW89_ENTITY_MODE_MCC:
+ /* If still multi-roles, re-plan MCC for chanctx changes.
+ * Otherwise, just stop MCC.
+ */
+ rtw89_mcc_stop(rtwdev);
+ if (w.active_roles == NUM_OF_RTW89_MCC_ROLES)
+ rtw89_mcc_start(rtwdev);
+ break;
+ default:
+ break;
+ }
+
+ rtw89_set_channel(rtwdev);
}
diff --git a/sys/contrib/dev/rtw89/chan.h b/sys/contrib/dev/rtw89/chan.h
index bdf369db5041..5278ff8c513b 100644
--- a/sys/contrib/dev/rtw89/chan.h
+++ b/sys/contrib/dev/rtw89/chan.h
@@ -7,6 +7,42 @@
#include "core.h"
+/* The dwell time in TU before doing rtw89_chanctx_work(). */
+#define RTW89_CHANCTX_TIME_MCC_PREPARE 100
+#define RTW89_CHANCTX_TIME_MCC 100
+
+/* various MCC setting time in TU */
+#define RTW89_MCC_LONG_TRIGGER_TIME 300
+#define RTW89_MCC_SHORT_TRIGGER_TIME 100
+#define RTW89_MCC_EARLY_TX_BCN_TIME 10
+#define RTW89_MCC_EARLY_RX_BCN_TIME 5
+#define RTW89_MCC_MIN_RX_BCN_TIME 10
+#define RTW89_MCC_DFLT_BCN_OFST_TIME 40
+
+#define RTW89_MCC_MIN_GO_DURATION \
+ (RTW89_MCC_EARLY_TX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME)
+
+#define RTW89_MCC_MIN_STA_DURATION \
+ (RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME)
+
+#define RTW89_MCC_DFLT_GROUP 0
+#define RTW89_MCC_NEXT_GROUP(cur) (((cur) + 1) % 4)
+
+#define RTW89_MCC_DFLT_TX_NULL_EARLY 3
+#define RTW89_MCC_DFLT_COURTESY_SLOT 3
+
+#define NUM_OF_RTW89_MCC_ROLES 2
+
+enum rtw89_chanctx_pause_reasons {
+ RTW89_CHANCTX_PAUSE_REASON_HW_SCAN,
+ RTW89_CHANCTX_PAUSE_REASON_ROC,
+};
+
+struct rtw89_entity_weight {
+ unsigned int active_chanctxs;
+ unsigned int active_roles;
+};
+
static inline bool rtw89_get_entity_state(struct rtw89_dev *rtwdev)
{
struct rtw89_hal *hal = &rtwdev->hal;
@@ -42,6 +78,10 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan,
bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev,
enum rtw89_sub_entity_idx idx,
const struct rtw89_chan *new);
+int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev,
+ int (*iterator)(const struct rtw89_chan *chan,
+ void *data),
+ void *data);
void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev,
enum rtw89_sub_entity_idx idx,
const struct cfg80211_chan_def *chandef);
@@ -50,6 +90,14 @@ void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev,
const struct cfg80211_chan_def *chandef);
void rtw89_entity_init(struct rtw89_dev *rtwdev);
enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev);
+void rtw89_chanctx_work(struct work_struct *work);
+void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev);
+void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_changes change);
+void rtw89_chanctx_track(struct rtw89_dev *rtwdev);
+void rtw89_chanctx_pause(struct rtw89_dev *rtwdev,
+ enum rtw89_chanctx_pause_reasons rsn);
+void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev);
int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev,
struct ieee80211_chanctx_conf *ctx);
void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev,
diff --git a/sys/contrib/dev/rtw89/coex.c b/sys/contrib/dev/rtw89/coex.c
index bda0e1e99a8c..24929ef534e0 100644
--- a/sys/contrib/dev/rtw89/coex.c
+++ b/sys/contrib/dev/rtw89/coex.c
@@ -6,11 +6,13 @@
#include "debug.h"
#include "fw.h"
#include "mac.h"
+#include "phy.h"
#include "ps.h"
#include "reg.h"
#define RTW89_COEX_VERSION 0x07000113
#define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/
+#define BTC_E2G_LIMIT_DEF 80
enum btc_fbtc_tdma_template {
CXTD_OFF = 0x0,
@@ -53,7 +55,6 @@ enum btc_mlme_state {
MLME_LINKED,
};
-#define FCXONESLOT_VER 1
struct btc_fbtc_1slot {
u8 fver;
u8 sid; /* slot id */
@@ -90,7 +91,7 @@ static const struct rtw89_btc_fbtc_slot s_def[] = {
[CXST_BLK] = __DEF_FBTC_SLOT(500, 0x55555555, SLOT_MIX),
[CXST_E2G] = __DEF_FBTC_SLOT(0, 0xea5a5a5a, SLOT_MIX),
[CXST_E5G] = __DEF_FBTC_SLOT(0, 0xffffffff, SLOT_ISO),
- [CXST_EBT] = __DEF_FBTC_SLOT(0, 0xe5555555, SLOT_MIX),
+ [CXST_EBT] = __DEF_FBTC_SLOT(5, 0xe5555555, SLOT_MIX),
[CXST_ENULL] = __DEF_FBTC_SLOT(0, 0xaaaaaaaa, SLOT_ISO),
[CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX),
[CXST_W1FDD] = __DEF_FBTC_SLOT(50, 0xffffffff, SLOT_ISO),
@@ -122,73 +123,81 @@ static const u32 cxtbl[] = {
0xea55556a, /* 21 */
0xaafafafa, /* 22 */
0xfafaaafa, /* 23 */
- 0xfafffaff /* 24 */
+ 0xfafffaff, /* 24 */
+ 0xea6a5a5a, /* 25 */
};
static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
/* firmware version must be in decreasing order for each chip */
+ {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0),
+ .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7,
+ .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7,
+ .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7,
+ .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7,
+ .fwevntrptl = 1, .drvinfo_type = 1, .info_buf = 1800, .max_role_num = 6,
+ },
{RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
.fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
- .info_buf = 1800, .max_role_num = 6,
+ .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
- .info_buf = 1280, .max_role_num = 5,
+ .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 2, .fcxctrl = 1,
- .info_buf = 1280, .max_role_num = 5,
+ .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 2, .fcxctrl = 1,
- .info_buf = 1280, .max_role_num = 5,
+ .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0),
.fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
- .info_buf = 1800, .max_role_num = 6,
+ .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0),
.fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
- .info_buf = 1800, .max_role_num = 6,
+ .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1800, .max_role_num = 6,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 1, .fcxctrl = 1,
- .info_buf = 1280, .max_role_num = 5,
+ .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
},
{RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0),
.fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
- .info_buf = 1280, .max_role_num = 5,
+ .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1280, .max_role_num = 5,
},
{RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0),
.fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2,
.fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
- .fwlrole = 0, .frptmap = 0, .fcxctrl = 0,
- .info_buf = 1024, .max_role_num = 5,
+ .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5,
},
/* keep it to be the last as default entry */
@@ -196,19 +205,53 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2,
.fcxstep = 2, .fcxnullsta = 1, .fcxmreg = 1, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1,
- .fwlrole = 0, .frptmap = 0, .fcxctrl = 0,
- .info_buf = 1024, .max_role_num = 5,
+ .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0,
+ .fwevntrptl = 0, .drvinfo_type = 0, .info_buf = 1024, .max_role_num = 5,
},
};
#define RTW89_DEFAULT_BTC_VER_IDX (ARRAY_SIZE(rtw89_btc_ver_defs) - 1)
+static const union rtw89_btc_wl_state_map btc_scanning_map = {
+ .map = {
+ .scan = 1,
+ .connecting = 1,
+ .roaming = 1,
+ .transacting = 1,
+ ._4way = 1,
+ },
+};
+
+static u32 chip_id_to_bt_rom_code_id(u32 id)
+{
+ switch (id) {
+ case RTL8852A:
+ case RTL8852B:
+ case RTL8852C:
+ case RTL8852BT:
+ return 0x8852;
+ case RTL8851B:
+ return 0x8851;
+ case RTL8922A:
+ return 0x8922;
+ default:
+ return 0;
+ }
+}
+
struct rtw89_btc_btf_tlv {
u8 type;
u8 len;
u8 val[];
} __packed;
+struct rtw89_btc_btf_tlv_v7 {
+ u8 type;
+ u8 ver;
+ u8 len;
+ u8 val[];
+} __packed;
+
enum btc_btf_set_report_en {
RPT_EN_TDMA,
RPT_EN_CYCLE,
@@ -226,26 +269,61 @@ enum btc_btf_set_report_en {
RPT_EN_MONITER,
};
-#define BTF_SET_REPORT_VER 1
-struct rtw89_btc_btf_set_report {
+struct rtw89_btc_btf_set_report_v1 {
u8 fver;
__le32 enable;
__le32 para;
} __packed;
+struct rtw89_btc_btf_set_report_v8 {
+ u8 type;
+ u8 fver;
+ u8 len;
+ __le32 map;
+} __packed;
+
+union rtw89_fbtc_rtp_ctrl {
+ struct rtw89_btc_btf_set_report_v1 v1;
+ struct rtw89_btc_btf_set_report_v8 v8;
+};
+
#define BTF_SET_SLOT_TABLE_VER 1
struct rtw89_btc_btf_set_slot_table {
u8 fver;
u8 tbl_num;
- u8 buf[];
+ struct rtw89_btc_fbtc_slot tbls[] __counted_by(tbl_num);
+} __packed;
+
+struct rtw89_btc_btf_set_slot_table_v7 {
+ u8 type;
+ u8 ver;
+ u8 len;
+ struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX];
} __packed;
-struct rtw89_btc_btf_set_mon_reg {
+struct rtw89_btc_btf_set_mon_reg_v1 {
u8 fver;
u8 reg_num;
- u8 buf[];
+ struct rtw89_btc_fbtc_mreg regs[] __counted_by(reg_num);
+} __packed;
+
+struct rtw89_btc_btf_set_mon_reg_v7 {
+ u8 type;
+ u8 fver;
+ u8 len;
+ struct rtw89_btc_fbtc_mreg regs[] __counted_by(len);
+} __packed;
+
+union rtw89_fbtc_set_mon_reg {
+ struct rtw89_btc_btf_set_mon_reg_v1 v1;
+ struct rtw89_btc_btf_set_mon_reg_v7 v7;
} __packed;
+struct _wl_rinfo_now {
+ u8 link_mode;
+ u32 dbcc_2g_phy: 2;
+};
+
enum btc_btf_set_cx_policy {
CXPOLICY_TDMA = 0x0,
CXPOLICY_SLOT = 0x1,
@@ -262,6 +340,8 @@ enum btc_b2w_scoreboard {
BTC_BSCB_RFK_RUN = BIT(5),
BTC_BSCB_RFK_REQ = BIT(6),
BTC_BSCB_LPS = BIT(7),
+ BTC_BSCB_BT_LNAB0 = BIT(8),
+ BTC_BSCB_BT_LNAB1 = BIT(10),
BTC_BSCB_WLRFK = BIT(11),
BTC_BSCB_BT_HILNA = BIT(13),
BTC_BSCB_BT_CONNECT = BIT(16),
@@ -294,6 +374,7 @@ enum btc_ant_phase {
BTC_ANT_W25G,
BTC_ANT_FREERUN,
BTC_ANT_WRFK,
+ BTC_ANT_WRFK2,
BTC_ANT_BRFK,
BTC_ANT_MAX
};
@@ -342,17 +423,26 @@ enum btc_cx_poicy_type {
/* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
BTC_CXP_OFF_EQ3 = (BTC_CXP_OFF << 8) | 5,
+ /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
+ BTC_CXP_OFF_EQ4 = (BTC_CXP_OFF << 8) | 6,
+
+ /* TDMA off + pri: WL_Rx = BT, BT_HI > WL_Tx > BT_Lo */
+ BTC_CXP_OFF_EQ5 = (BTC_CXP_OFF << 8) | 7,
+
/* TDMA off + pri: BT_Hi > WL > BT_Lo */
- BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 6,
+ BTC_CXP_OFF_BWB0 = (BTC_CXP_OFF << 8) | 8,
/* TDMA off + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo */
- BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 7,
+ BTC_CXP_OFF_BWB1 = (BTC_CXP_OFF << 8) | 9,
/* TDMA off + pri: WL_Hi-Tx > BT, BT_Hi > other-WL > BT_Lo */
- BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 8,
+ BTC_CXP_OFF_BWB2 = (BTC_CXP_OFF << 8) | 10,
/* TDMA off + pri: WL_Hi-Tx = BT */
- BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 9,
+ BTC_CXP_OFF_BWB3 = (BTC_CXP_OFF << 8) | 11,
+
+ /* TDMA off + pri: WL > BT, Block-BT*/
+ BTC_CXP_OFF_WL2 = (BTC_CXP_OFF << 8) | 12,
/* TDMA off+Bcn-Protect + pri: WL_Hi-Tx > BT_Hi_Rx, BT_Hi > WL > BT_Lo*/
BTC_CXP_OFFB_BWB0 = (BTC_CXP_OFFB << 8) | 0,
@@ -405,11 +495,14 @@ enum btc_cx_poicy_type {
/* TDMA Fix slot-8: W1:B1 = user-define */
BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,
- /* TDMA Fix slot-9: W1:B1 = 40:20 */
- BTC_CXP_FIX_TD4020 = (BTC_CXP_FIX << 8) | 9,
-
/* TDMA Fix slot-9: W1:B1 = 40:10 */
- BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 10,
+ BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 9,
+
+ /* TDMA Fix slot-10: W1:B1 = 40:10 */
+ BTC_CXP_FIX_TD4010ISO_DL = (BTC_CXP_FIX << 8) | 10,
+
+ /* TDMA Fix slot-11: W1:B1 = 40:10 */
+ BTC_CXP_FIX_TD4010ISO_UL = (BTC_CXP_FIX << 8) | 11,
/* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
@@ -586,6 +679,13 @@ enum btc_ctr_path {
BTC_CTRL_BY_WL
};
+enum btc_wlact_state {
+ BTC_WLACT_HW = 0,
+ BTC_WLACT_SW_LO,
+ BTC_WLACT_SW_HI,
+ BTC_WLACT_MAX,
+};
+
enum btc_wl_max_tx_time {
BTC_MAX_TX_TIME_L1 = 500,
BTC_MAX_TX_TIME_L2 = 1000,
@@ -664,20 +764,25 @@ static void _run_coex(struct rtw89_dev *rtwdev,
static void _write_scbd(struct rtw89_dev *rtwdev, u32 val, bool state);
static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update);
-static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
- void *param, u16 len)
+static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
+ void *param, u16 len)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_dm *dm = &btc->dm;
int ret;
- if (!wl->status.map.init_ok) {
+ if (len > BTC_H2C_MAXLEN || len == 0) {
+ btc->fwinfo.cnt_h2c_fail++;
+ dm->error.map.h2c_buffer_over = true;
+ return -EINVAL;
+ } else if (!wl->status.map.init_ok) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): return by btc not init!!\n", __func__);
pfwinfo->cnt_h2c_fail++;
- return;
+ return -EINVAL;
} else if ((wl->status.map.rf_off_pre == BTC_LPS_RF_OFF &&
wl->status.map.rf_off == BTC_LPS_RF_OFF) ||
(wl->status.map.lps_pre == BTC_LPS_RF_OFF &&
@@ -685,53 +790,74 @@ static void _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func,
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): return by wl off!!\n", __func__);
pfwinfo->cnt_h2c_fail++;
- return;
+ return -EINVAL;
}
- pfwinfo->cnt_h2c++;
-
ret = rtw89_fw_h2c_raw_with_hdr(rtwdev, h2c_class, h2c_func, param, len,
false, true);
- if (ret != 0)
+ if (ret)
pfwinfo->cnt_h2c_fail++;
+ else
+ pfwinfo->cnt_h2c++;
+
+ return ret;
}
static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
- struct rtw89_btc_wl_link_info *wl_linfo = wl->link_info;
+ struct rtw89_btc_wl_link_info *wl_linfo;
u8 i;
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s\n", __func__);
if (type & BTC_RESET_CX)
memset(cx, 0, sizeof(*cx));
- else if (type & BTC_RESET_BTINFO) /* only for BT enable */
+
+ if (type & BTC_RESET_BTINFO) /* only for BT enable */
memset(bt, 0, sizeof(*bt));
if (type & BTC_RESET_CTRL) {
memset(&btc->ctrl, 0, sizeof(btc->ctrl));
- btc->ctrl.trace_step = FCXDEF_STEP;
+ btc->manual_ctrl = false;
+ if (ver->fcxctrl != 7)
+ btc->ctrl.ctrl.trace_step = FCXDEF_STEP;
}
/* Init Coex variables that are not zero */
if (type & BTC_RESET_DM) {
memset(&btc->dm, 0, sizeof(btc->dm));
memset(bt_linfo->rssi_state, 0, sizeof(bt_linfo->rssi_state));
-
- for (i = 0; i < RTW89_PORT_NUM; i++)
- memset(wl_linfo[i].rssi_state, 0,
- sizeof(wl_linfo[i].rssi_state));
+ for (i = 0; i < RTW89_PORT_NUM; i++) {
+ if (btc->ver->fwlrole == 8)
+ wl_linfo = &wl->rlink_info[i][0];
+ else
+ wl_linfo = &wl->link_info[i];
+ memset(wl_linfo->rssi_state, 0, sizeof(wl_linfo->rssi_state));
+ }
/* set the slot_now table to original */
btc->dm.tdma_now = t_def[CXTD_OFF];
btc->dm.tdma = t_def[CXTD_OFF];
- memcpy(&btc->dm.slot_now, s_def, sizeof(btc->dm.slot_now));
- memcpy(&btc->dm.slot, s_def, sizeof(btc->dm.slot));
+ if (ver->fcxslots >= 7) {
+ for (i = 0; i < ARRAY_SIZE(s_def); i++) {
+ btc->dm.slot.v7[i].dur = s_def[i].dur;
+ btc->dm.slot.v7[i].cxtype = s_def[i].cxtype;
+ btc->dm.slot.v7[i].cxtbl = s_def[i].cxtbl;
+ }
+ memcpy(&btc->dm.slot_now.v7, &btc->dm.slot.v7,
+ sizeof(btc->dm.slot_now.v7));
+ } else {
+ memcpy(&btc->dm.slot_now.v1, s_def,
+ sizeof(btc->dm.slot_now.v1));
+ memcpy(&btc->dm.slot.v1, s_def,
+ sizeof(btc->dm.slot.v1));
+ }
btc->policy_len = 0;
btc->bt_req_len = 0;
@@ -739,12 +865,120 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
+ btc->dm.wl_pre_agc_rb = BTC_PREAGC_NOTFOUND;
+ btc->dm.wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_NOTFOUND;
}
if (type & BTC_RESET_MDINFO)
memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
}
+static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 i;
+
+ for (i = 0; i < mreg_num; i++)
+ if (le16_to_cpu(chip->mon_reg[i].type) == reg_type &&
+ le32_to_cpu(chip->mon_reg[i].offset) == target) {
+ return i;
+ }
+ return BTC_REG_NOTFOUND;
+}
+
+static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ union rtw89_btc_module_info *md = &btc->mdinfo;
+ union rtw89_btc_fbtc_mreg_val *pmreg;
+ u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1;
+ u32 reg_val;
+ u8 idx, switch_type;
+
+ if (ver->fcxinit == 7)
+ switch_type = md->md_v7.switch_type;
+ else
+ switch_type = md->md.switch_type;
+
+ if (btc->btg_pos == RF_PATH_A)
+ pre_agc_addr = R_BTC_BB_PRE_AGC_S0;
+
+ switch (type) {
+ case BTC_CSTATUS_TXDIV_POS:
+ if (switch_type == BTC_SWITCH_INTERNAL)
+ *val = BTC_ANT_DIV_MAIN;
+ break;
+ case BTC_CSTATUS_RXDIV_POS:
+ if (switch_type == BTC_SWITCH_INTERNAL)
+ *val = BTC_ANT_DIV_MAIN;
+ break;
+ case BTC_CSTATUS_BB_GNT_MUX:
+ reg_val = rtw89_phy_read32(rtwdev, R_BTC_BB_BTG_RX);
+ *val = !(reg_val & B_BTC_BB_GNT_MUX);
+ break;
+ case BTC_CSTATUS_BB_GNT_MUX_MON:
+ if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
+ return;
+
+ pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
+ if (ver->fcxmreg == 1) {
+ idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
+ REG_BB, R_BTC_BB_BTG_RX);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]);
+ *val = !(reg_val & B_BTC_BB_GNT_MUX);
+ }
+ } else if (ver->fcxmreg == 2) {
+ idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
+ REG_BB, R_BTC_BB_BTG_RX);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]);
+ *val = !(reg_val & B_BTC_BB_GNT_MUX);
+ }
+ }
+ break;
+ case BTC_CSTATUS_BB_PRE_AGC:
+ reg_val = rtw89_phy_read32(rtwdev, pre_agc_addr);
+ reg_val &= B_BTC_BB_PRE_AGC_MASK;
+ *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
+ break;
+ case BTC_CSTATUS_BB_PRE_AGC_MON:
+ if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
+ return;
+
+ pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
+ if (ver->fcxmreg == 1) {
+ idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
+ REG_BB, pre_agc_addr);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_PREAGC_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]) &
+ B_BTC_BB_PRE_AGC_MASK;
+ *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
+ }
+ } else if (ver->fcxmreg == 2) {
+ idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
+ REG_BB, pre_agc_addr);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_PREAGC_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]) &
+ B_BTC_BB_PRE_AGC_MASK;
+ *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
#define BTC_RPT_HDR_SIZE 3
#define BTC_CHK_WLSLOT_DRIFT_MAX 15
#define BTC_CHK_BTSLOT_DRIFT_MAX 15
@@ -754,14 +988,25 @@ static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_cx *cx = &btc->cx;
- struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_bt_info *bt = &cx->bt;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_dm *dm = &btc->dm;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): type:%d cnt:%d\n",
__func__, type, cnt);
switch (type) {
+ case BTC_DCNT_WL_FW_VER_MATCH:
+ if ((wl->ver_info.fw_coex & 0xffff0000) !=
+ rtwdev->chip->wlcx_desired) {
+ wl->fw_ver_mismatch = true;
+ dm->error.map.wl_ver_mismatch = true;
+ } else {
+ wl->fw_ver_mismatch = false;
+ dm->error.map.wl_ver_mismatch = false;
+ }
+ break;
case BTC_DCNT_RPT_HANG:
if (dm->cnt_dm[BTC_DCNT_RPT] == cnt && btc->fwinfo.rpt_en_map)
dm->cnt_dm[BTC_DCNT_RPT_HANG]++;
@@ -854,6 +1099,19 @@ static void _chk_btc_err(struct rtw89_dev *rtwdev, u8 type, u32 cnt)
else
dm->error.map.slot_no_sync = false;
break;
+ case BTC_DCNT_BTTX_HANG:
+ cnt = cx->cnt_bt[BTC_BCNT_LOPRI_TX];
+
+ if (cnt == 0 && bt->link_info.slave_role)
+ dm->cnt_dm[BTC_DCNT_BTTX_HANG]++;
+ else
+ dm->cnt_dm[BTC_DCNT_BTTX_HANG] = 0;
+
+ if (dm->cnt_dm[BTC_DCNT_BTTX_HANG] >= BTC_CHK_HANG_MAX)
+ dm->error.map.bt_tx_hang = true;
+ else
+ dm->error.map.bt_tx_hang = false;
+ break;
case BTC_DCNT_BTCNT_HANG:
cnt = cx->cnt_bt[BTC_BCNT_HIPRI_RX] +
cx->cnt_bt[BTC_BCNT_HIPRI_TX] +
@@ -903,27 +1161,36 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
struct rtw89_btc_bt_a2dp_desc *a2dp = &bt_linfo->a2dp_desc;
- struct rtw89_btc_fbtc_btver *pver = NULL;
- struct rtw89_btc_fbtc_btscan_v1 *pscan_v1;
- struct rtw89_btc_fbtc_btscan_v2 *pscan_v2;
- struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL;
+ union rtw89_btc_fbtc_btver *pver = &btc->fwinfo.rpt_fbtc_btver.finfo;
struct rtw89_btc_fbtc_btafh_v2 *pafh_v2 = NULL;
+ struct rtw89_btc_fbtc_btafh_v7 *pafh_v7 = NULL;
struct rtw89_btc_fbtc_btdevinfo *pdev = NULL;
+ struct rtw89_btc_fbtc_btafh *pafh_v1 = NULL;
+ struct rtw89_btc_fbtc_btscan_v1 *pscan_v1;
+ struct rtw89_btc_fbtc_btscan_v2 *pscan_v2;
+ struct rtw89_btc_fbtc_btscan_v7 *pscan_v7;
bool scan_update = true;
int i;
- pver = (struct rtw89_btc_fbtc_btver *)pfinfo;
- pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
-
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): rpt_type:%d\n",
__func__, rpt_type);
switch (rpt_type) {
case BTC_RPT_TYPE_BT_VER:
- bt->ver_info.fw = le32_to_cpu(pver->fw_ver);
- bt->ver_info.fw_coex = le32_get_bits(pver->coex_ver, GENMASK(7, 0));
- bt->feature = le32_to_cpu(pver->feature);
+ if (ver->fcxbtver == 7) {
+ pver->v7 = *(struct rtw89_btc_fbtc_btver_v7 *)pfinfo;
+ bt->ver_info.fw = le32_to_cpu(pver->v7.fw_ver);
+ bt->ver_info.fw_coex = le32_get_bits(pver->v7.coex_ver,
+ GENMASK(7, 0));
+ bt->feature = le32_to_cpu(pver->v7.feature);
+ } else {
+ pver->v1 = *(struct rtw89_btc_fbtc_btver_v1 *)pfinfo;
+ bt->ver_info.fw = le32_to_cpu(pver->v1.fw_ver);
+ bt->ver_info.fw_coex = le32_get_bits(pver->v1.coex_ver,
+ GENMASK(7, 0));
+ bt->feature = le32_to_cpu(pver->v1.feature);
+ }
break;
case BTC_RPT_TYPE_BT_SCAN:
if (ver->fcxbtscan == 1) {
@@ -943,6 +1210,15 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
pscan_v2->para[i].intvl == 0)
scan_update = false;
}
+ } else if (ver->fcxbtscan == 7) {
+ pscan_v7 = (struct rtw89_btc_fbtc_btscan_v7 *)pfinfo;
+ for (i = 0; i < CXSCAN_MAX; i++) {
+ bt->scan_info_v2[i] = pscan_v7->para[i];
+ if ((pscan_v7->type & BIT(i)) &&
+ pscan_v7->para[i].win == 0 &&
+ pscan_v7->para[i].intvl == 0)
+ scan_update = false;
+ }
}
if (scan_update)
bt->scan_info_update = 1;
@@ -959,6 +1235,17 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
memcpy(&bt_linfo->afh_map_le[0], pafh_v2->afh_le_a, 4);
memcpy(&bt_linfo->afh_map_le[4], pafh_v2->afh_le_b, 1);
}
+ } else if (ver->fcxbtafh == 7) {
+ pafh_v7 = (struct rtw89_btc_fbtc_btafh_v7 *)pfinfo;
+ if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LEGACY) {
+ memcpy(&bt_linfo->afh_map[0], pafh_v7->afh_l, 4);
+ memcpy(&bt_linfo->afh_map[4], pafh_v7->afh_m, 4);
+ memcpy(&bt_linfo->afh_map[8], pafh_v7->afh_h, 2);
+ }
+ if (pafh_v7->map_type & RPT_BT_AFH_SEQ_LE) {
+ memcpy(&bt_linfo->afh_map_le[0], pafh_v7->afh_le_a, 4);
+ memcpy(&bt_linfo->afh_map_le[4], pafh_v7->afh_le_b, 1);
+ }
} else if (ver->fcxbtafh == 1) {
pafh_v1 = (struct rtw89_btc_fbtc_btafh *)pfinfo;
memcpy(&bt_linfo->afh_map[0], pafh_v1->afh_l, 4);
@@ -967,6 +1254,7 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
}
break;
case BTC_RPT_TYPE_BT_DEVICE:
+ pdev = (struct rtw89_btc_fbtc_btdevinfo *)pfinfo;
a2dp->device_name = le32_to_cpu(pdev->dev_name);
a2dp->vendor_id = le16_to_cpu(pdev->vendor_id);
a2dp->flush_time = le32_to_cpu(pdev->flush_time);
@@ -976,6 +1264,22 @@ static void _update_bt_report(struct rtw89_dev *rtwdev, u8 rpt_type, u8 *pfinfo)
}
}
+static void rtw89_btc_fw_rpt_evnt_ver(struct rtw89_dev *rtwdev, u8 *index)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
+
+ if (ver->fwevntrptl == 1)
+ return;
+
+ if (*index <= __BTC_RPT_TYPE_V0_SAME)
+ return;
+ else if (*index <= __BTC_RPT_TYPE_V0_MAX)
+ (*index)++;
+ else
+ *index = BTC_RPT_TYPE_MAX;
+}
+
#define BTC_LEAK_AP_TH 10
#define BTC_CYSTA_CHK_PERIOD 100
@@ -1000,10 +1304,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
struct rtw89_btc_prpt *btc_prpt = NULL;
void *rpt_content = NULL, *pfinfo = NULL;
u8 rpt_type = 0;
- u16 wl_slot_set = 0, wl_slot_real = 0;
- u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t = 0;
+ u16 wl_slot_set = 0, wl_slot_real = 0, val16;
+ u32 trace_step = 0, rpt_len = 0, diff_t = 0;
u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr;
- u8 i;
+ u8 i, val = 0, val1, val2;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): index:%d\n",
@@ -1023,6 +1327,8 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
"[BTC], %s(): rpt_type:%d\n",
__func__, rpt_type);
+ rtw89_btc_fw_rpt_evnt_ver(rtwdev, &rpt_type);
+
switch (rpt_type) {
case BTC_RPT_TYPE_CTRL:
pcinfo = &pfwinfo->rpt_ctrl.cinfo;
@@ -1041,6 +1347,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v105);
pcinfo->req_fver = 5;
break;
+ } else if (ver->fcxbtcrpt == 8) {
+ pfinfo = &pfwinfo->rpt_ctrl.finfo.v8;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8);
+ break;
} else {
goto err;
}
@@ -1051,7 +1361,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
if (ver->fcxtdma == 1) {
pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1);
- } else if (ver->fcxtdma == 3) {
+ } else if (ver->fcxtdma == 3 || ver->fcxtdma == 7) {
pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3);
} else {
@@ -1061,8 +1371,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
break;
case BTC_RPT_TYPE_SLOT:
pcinfo = &pfwinfo->rpt_fbtc_slots.cinfo;
- pfinfo = &pfwinfo->rpt_fbtc_slots.finfo;
- pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo);
+ if (ver->fcxslots == 1) {
+ pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1);
+ } else if (ver->fcxslots == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7);
+ } else {
+ goto err;
+ }
pcinfo->req_fver = ver->fcxslots;
break;
case BTC_RPT_TYPE_CYSTA:
@@ -1084,6 +1401,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v5;
pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5);
+ } else if (ver->fcxcysta == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
+ pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v7);
} else {
goto err;
}
@@ -1091,6 +1412,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
break;
case BTC_RPT_TYPE_STEP:
pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
+ if (ver->fcxctrl != 7)
+ trace_step = btc->ctrl.ctrl.trace_step;
+
if (ver->fcxstep == 2) {
pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v2;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) *
@@ -1114,6 +1438,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
} else if (ver->fcxnullsta == 2) {
pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2);
+ } else if (ver->fcxnullsta == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v7);
} else {
goto err;
}
@@ -1127,6 +1454,9 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
} else if (ver->fcxmreg == 2) {
pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v2;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v2);
+ } else if (ver->fcxmreg == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v7);
} else {
goto err;
}
@@ -1134,14 +1464,24 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
break;
case BTC_RPT_TYPE_GPIO_DBG:
pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
- pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo;
- pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo);
+ if (ver->fcxgpiodbg == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7);
+ } else {
+ pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1);
+ }
pcinfo->req_fver = ver->fcxgpiodbg;
break;
case BTC_RPT_TYPE_BT_VER:
pcinfo = &pfwinfo->rpt_fbtc_btver.cinfo;
- pfinfo = &pfwinfo->rpt_fbtc_btver.finfo;
- pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo);
+ if (ver->fcxbtver == 1) {
+ pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v1;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v1);
+ } else if (ver->fcxbtver == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7);
+ }
pcinfo->req_fver = ver->fcxbtver;
break;
case BTC_RPT_TYPE_BT_SCAN:
@@ -1152,6 +1492,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
} else if (ver->fcxbtscan == 2) {
pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v2;
pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v2);
+ } else if (ver->fcxbtscan == 7) {
+ pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7;
+ pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7);
+ } else {
+ goto err;
}
pcinfo->req_fver = ver->fcxbtscan;
break;
@@ -1310,6 +1655,44 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
pfwinfo->event[BTF_EVNT_RPT]);
dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
+ } else if (ver->fcxbtcrpt == 8) {
+ prpt->v8 = pfwinfo->rpt_ctrl.finfo.v8;
+ pfwinfo->rpt_en_map = le32_to_cpu(prpt->v8.rpt_info.en);
+ wl->ver_info.fw_coex = le32_to_cpu(prpt->v8.rpt_info.cx_ver);
+ wl->ver_info.fw = le32_to_cpu(prpt->v8.rpt_info.fw_ver);
+
+ for (i = RTW89_PHY_0; i < RTW89_PHY_MAX; i++)
+ memcpy(&dm->gnt.band[i], &prpt->v8.gnt_val[i][0],
+ sizeof(dm->gnt.band[i]));
+
+ btc->cx.cnt_bt[BTC_BCNT_HIPRI_TX] =
+ le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_TX_V105]);
+ btc->cx.cnt_bt[BTC_BCNT_HIPRI_RX] =
+ le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_HI_RX_V105]);
+ btc->cx.cnt_bt[BTC_BCNT_LOPRI_TX] =
+ le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_TX_V105]);
+ btc->cx.cnt_bt[BTC_BCNT_LOPRI_RX] =
+ le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_LO_RX_V105]);
+
+ val1 = le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
+ if (val1 > btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW])
+ val1 -= btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW]; /* diff */
+
+ btc->cx.cnt_bt[BTC_BCNT_POLUT_DIFF] = val1;
+ btc->cx.cnt_bt[BTC_BCNT_POLUT_NOW] =
+ le16_to_cpu(prpt->v8.bt_cnt[BTC_BCNT_POLLUTED_V105]);
+
+ val1 = pfwinfo->event[BTF_EVNT_RPT];
+ if (((prpt->v8.rpt_len_max_h << 8) +
+ prpt->v8.rpt_len_max_l) != ver->info_buf)
+ dm->error.map.h2c_c2h_buffer_mismatch = true;
+ else
+ dm->error.map.h2c_c2h_buffer_mismatch = false;
+
+ _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
+ _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG, val1);
+ _chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
+ _chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
} else {
goto err;
}
@@ -1324,7 +1707,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
memcmp(&dm->tdma_now,
&pfwinfo->rpt_fbtc_tdma.finfo.v1,
sizeof(dm->tdma_now)));
- else if (ver->fcxtdma == 3)
+ else if (ver->fcxtdma == 3 || ver->fcxtdma == 7)
_chk_btc_err(rtwdev, BTC_DCNT_TDMA_NONSYNC,
memcmp(&dm->tdma_now,
&pfwinfo->rpt_fbtc_tdma.finfo.v3.tdma,
@@ -1333,14 +1716,25 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
goto err;
break;
case BTC_RPT_TYPE_SLOT:
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): check %d %zu\n",
- __func__, BTC_DCNT_SLOT_NONSYNC,
- sizeof(dm->slot_now));
- _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
- memcmp(dm->slot_now,
- pfwinfo->rpt_fbtc_slots.finfo.slot,
- sizeof(dm->slot_now)));
+ if (ver->fcxslots == 7) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): check %d %zu\n",
+ __func__, BTC_DCNT_SLOT_NONSYNC,
+ sizeof(dm->slot_now.v7));
+ _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
+ memcmp(dm->slot_now.v7,
+ pfwinfo->rpt_fbtc_slots.finfo.v7.slot,
+ sizeof(dm->slot_now.v7)));
+ } else if (ver->fcxslots == 1) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): check %d %zu\n",
+ __func__, BTC_DCNT_SLOT_NONSYNC,
+ sizeof(dm->slot_now.v1));
+ _chk_btc_err(rtwdev, BTC_DCNT_SLOT_NONSYNC,
+ memcmp(dm->slot_now.v1,
+ pfwinfo->rpt_fbtc_slots.finfo.v1.slot,
+ sizeof(dm->slot_now.v1)));
+ }
break;
case BTC_RPT_TYPE_CYSTA:
if (ver->fcxcysta == 2) {
@@ -1356,10 +1750,17 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
/* Check diff time between WL slot and W1/E2G slot */
if (dm->tdma_now.type == CXTDMA_OFF &&
- dm->tdma_now.ext_ctrl == CXECTL_EXT)
- wl_slot_set = le16_to_cpu(dm->slot_now[CXST_E2G].dur);
- else
- wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
+ dm->tdma_now.ext_ctrl == CXECTL_EXT) {
+ if (ver->fcxslots == 1)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_E2G].dur);
+ else if (ver->fcxslots == 7)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_E2G].dur);
+ } else {
+ if (ver->fcxslots == 1)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
+ else if (ver->fcxslots == 7)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
+ }
if (le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) > wl_slot_set) {
diff_t = le16_to_cpu(pcysta->v2.tavg_cycle[CXT_WL]) - wl_slot_set;
@@ -1389,7 +1790,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
/* Check diff time between real WL slot and W1 slot */
if (dm->tdma_now.type == CXTDMA_OFF) {
- wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
+ if (ver->fcxslots == 1)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
+ else if (ver->fcxslots == 7)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
wl_slot_real = le16_to_cpu(pcysta->v3.cycle_time.tavg[CXT_WL]);
if (wl_slot_real > wl_slot_set) {
diff_t = wl_slot_real - wl_slot_set;
@@ -1430,7 +1834,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
/* Check diff time between real WL slot and W1 slot */
if (dm->tdma_now.type == CXTDMA_OFF) {
- wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
+ if (ver->fcxslots == 1)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
+ else if (ver->fcxslots == 7)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
wl_slot_real = le16_to_cpu(pcysta->v4.cycle_time.tavg[CXT_WL]);
if (wl_slot_real > wl_slot_set) {
diff_t = wl_slot_real - wl_slot_set;
@@ -1472,7 +1879,10 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
/* Check diff time between real WL slot and W1 slot */
if (dm->tdma_now.type == CXTDMA_OFF) {
- wl_slot_set = le16_to_cpu(dm->slot_now[CXST_W1].dur);
+ if (ver->fcxslots == 1)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v1[CXST_W1].dur);
+ else if (ver->fcxslots == 7)
+ wl_slot_set = le16_to_cpu(dm->slot_now.v7[CXST_W1].dur);
wl_slot_real = le16_to_cpu(pcysta->v5.cycle_time.tavg[CXT_WL]);
if (wl_slot_real > wl_slot_set)
@@ -1504,10 +1914,74 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
le16_to_cpu(pcysta->v5.slot_cnt[CXST_B1]));
_chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
le16_to_cpu(pcysta->v5.cycles));
+ } else if (ver->fcxcysta == 7) {
+ if (dm->fddt_train == BTC_FDDT_ENABLE)
+ break;
+
+ pcysta = &pfwinfo->rpt_fbtc_cysta.finfo;
+
+ if (dm->tdma_now.type != CXTDMA_OFF) {
+ /* Check diff time between real WL slot and W1 slot */
+ val16 = le16_to_cpu(pcysta->v7.cycle_time.tavg[CXT_WL]);
+ _chk_btc_err(rtwdev, BTC_DCNT_WL_SLOT_DRIFT, val16);
+
+ /* Check Leak-AP */
+ val1 = le32_to_cpu(pcysta->v7.leak_slot.cnt_rximr) *
+ BTC_LEAK_AP_TH;
+ val2 = le16_to_cpu(pcysta->v7.slot_cnt[CXST_LK]);
+
+ val16 = le16_to_cpu(pcysta->v7.cycles);
+ if (dm->tdma_now.rxflctrl &&
+ val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
+ dm->leak_ap = 1;
+ } else if (dm->tdma_now.ext_ctrl == CXECTL_EXT) {
+ val16 = le16_to_cpu(pcysta->v7.cycle_time.tavg[CXT_BT]);
+ /* Check diff between real BT slot and EBT/E5G slot */
+ _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_DRIFT, val16);
+
+ /* Check bt slot length for P2P mode*/
+ val1 = le16_to_cpu(pcysta->v7.a2dp_ept.cnt_timeout) *
+ BTC_SLOT_REQ_TH;
+ val2 = le16_to_cpu(pcysta->v7.a2dp_ept.cnt);
+
+ val16 = le16_to_cpu(pcysta->v7.cycles);
+ if (val16 >= BTC_CYSTA_CHK_PERIOD && val1 > val2)
+ dm->slot_req_more = 1;
+ else if (bt->link_info.status.map.connect == 0)
+ dm->slot_req_more = 0;
+ }
+
+ _chk_btc_err(rtwdev, BTC_DCNT_E2G_HANG,
+ le16_to_cpu(pcysta->v7.slot_cnt[CXST_E2G]));
+ _chk_btc_err(rtwdev, BTC_DCNT_W1_HANG,
+ le16_to_cpu(pcysta->v7.slot_cnt[CXST_W1]));
+ _chk_btc_err(rtwdev, BTC_DCNT_B1_HANG,
+ le16_to_cpu(pcysta->v7.slot_cnt[CXST_B1]));
+
+ /* "BT_SLOT_FLOOD" error-check MUST before "CYCLE_HANG" */
+ _chk_btc_err(rtwdev, BTC_DCNT_BT_SLOT_FLOOD,
+ le16_to_cpu(pcysta->v7.cycles));
+ _chk_btc_err(rtwdev, BTC_DCNT_CYCLE_HANG,
+ le16_to_cpu(pcysta->v7.cycles));
} else {
goto err;
}
break;
+ case BTC_RPT_TYPE_MREG:
+ if (ver->fcxmreg == 7)
+ break;
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX_MON, &val);
+ if (dm->wl_btg_rx == BTC_BTGCTRL_BB_GNT_FWCTRL)
+ dm->wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_FWCTRL;
+ else
+ dm->wl_btg_rx_rb = val;
+
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC_MON, &val);
+ if (dm->wl_pre_agc == BTC_PREAGC_BB_FWCTRL)
+ dm->wl_pre_agc_rb = BTC_PREAGC_BB_FWCTRL;
+ else
+ dm->wl_pre_agc_rb = val;
+ break;
case BTC_RPT_TYPE_BT_VER:
case BTC_RPT_TYPE_BT_SCAN:
case BTC_RPT_TYPE_BT_AFH:
@@ -1552,6 +2026,7 @@ static void _parse_btc_report(struct rtw89_dev *rtwdev,
}
#define BTC_TLV_HDR_LEN 2
+#define BTC_TLV_HDR_LEN_V7 3
static void _append_tdma(struct rtw89_dev *rtwdev)
{
@@ -1559,6 +2034,7 @@ static void _append_tdma(struct rtw89_dev *rtwdev)
const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_btf_tlv *tlv;
+ struct rtw89_btc_btf_tlv_v7 *tlv_v7;
struct rtw89_btc_fbtc_tdma *v;
struct rtw89_btc_fbtc_tdma_v3 *v3;
u16 len = btc->policy_len;
@@ -1576,13 +2052,20 @@ static void _append_tdma(struct rtw89_dev *rtwdev)
if (ver->fcxtdma == 1) {
v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0];
tlv->len = sizeof(*v);
- memcpy(v, &dm->tdma, sizeof(*v));
+ *v = dm->tdma;
btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v);
+ } else if (ver->fcxtdma == 7) {
+ tlv_v7 = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
+ tlv_v7->len = sizeof(dm->tdma);
+ tlv_v7->ver = ver->fcxtdma;
+ tlv_v7->type = CXPOLICY_TDMA;
+ memcpy(tlv_v7->val, &dm->tdma, tlv_v7->len);
+ btc->policy_len += BTC_TLV_HDR_LEN_V7 + tlv_v7->len;
} else {
tlv->len = sizeof(*v3);
v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0];
v3->fver = ver->fcxtdma;
- memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma));
+ v3->tdma = dm->tdma;
btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3);
}
@@ -1593,7 +2076,7 @@ static void _append_tdma(struct rtw89_dev *rtwdev)
dm->tdma.ext_ctrl);
}
-static void _append_slot(struct rtw89_dev *rtwdev)
+static void _append_slot_v1(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
@@ -1608,8 +2091,8 @@ static void _append_slot(struct rtw89_dev *rtwdev)
for (i = 0; i < CXST_MAX; i++) {
if (!btc->update_policy_force &&
- !memcmp(&dm->slot[i], &dm->slot_now[i],
- sizeof(dm->slot[i])))
+ !memcmp(&dm->slot.v1[i], &dm->slot_now.v1[i],
+ sizeof(dm->slot.v1[i])))
continue;
len = btc->policy_len;
@@ -1619,14 +2102,14 @@ static void _append_slot(struct rtw89_dev *rtwdev)
tlv->type = CXPOLICY_SLOT;
tlv->len = sizeof(*v);
- v->fver = FCXONESLOT_VER;
+ v->fver = btc->ver->fcxslots;
v->sid = i;
- v->slot = dm->slot[i];
+ v->slot = dm->slot.v1[i];
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): slot-%d: dur=%d, table=0x%08x, type=%d\n",
- __func__, i, dm->slot[i].dur, dm->slot[i].cxtbl,
- dm->slot[i].cxtype);
+ __func__, i, dm->slot.v1[i].dur, dm->slot.v1[i].cxtbl,
+ dm->slot.v1[i].cxtype);
cnt++;
btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v);
@@ -1638,6 +2121,71 @@ static void _append_slot(struct rtw89_dev *rtwdev)
__func__, cnt);
}
+static void _append_slot_v7(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc_btf_tlv_v7 *tlv = NULL;
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 i, cnt = 0;
+ u16 len;
+
+ for (i = 0; i < CXST_MAX; i++) {
+ if (!btc->update_policy_force &&
+ !memcmp(&dm->slot.v7[i], &dm->slot_now.v7[i],
+ sizeof(dm->slot.v7[i])))
+ continue;
+
+ len = btc->policy_len;
+
+ if (!tlv) {
+ if ((len + BTC_TLV_HDR_LEN_V7) > RTW89_BTC_POLICY_MAXLEN) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): buff overflow!\n", __func__);
+ break;
+ }
+
+ tlv = (struct rtw89_btc_btf_tlv_v7 *)&btc->policy[len];
+ tlv->type = CXPOLICY_SLOT;
+ tlv->ver = btc->ver->fcxslots;
+ tlv->len = sizeof(dm->slot.v7[0]) + BTC_TLV_SLOT_ID_LEN_V7;
+ len += BTC_TLV_HDR_LEN_V7;
+ }
+
+ if ((len + (u16)tlv->len) > RTW89_BTC_POLICY_MAXLEN) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): buff overflow!\n", __func__);
+ break;
+ }
+
+ btc->policy[len] = i; /* slot-id */
+ memcpy(&btc->policy[len + 1], &dm->slot.v7[i],
+ sizeof(dm->slot.v7[0]));
+ len += tlv->len;
+
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s: policy_len=%d, slot-%d: dur=%d, type=%d, table=0x%08x\n",
+ __func__, btc->policy_len, i, dm->slot.v7[i].dur,
+ dm->slot.v7[i].cxtype, dm->slot.v7[i].cxtbl);
+ cnt++;
+ btc->policy_len = len; /* update total length */
+ }
+
+ if (cnt > 0)
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s: slot update (cnt=%d, len=%d)!!\n",
+ __func__, cnt, btc->policy_len);
+}
+
+static void _append_slot(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+
+ if (btc->ver->fcxslots == 7)
+ _append_slot_v7(rtwdev);
+ else
+ _append_slot_v1(rtwdev);
+}
+
static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -1783,14 +2331,54 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map)
return bit_map;
}
+static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_btc_btf_tlv_v7 *tlv_v7 = NULL;
+ struct rtw89_btc_btf_set_slot_table *tbl;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u16 n, len;
+
+ if (ver->fcxslots == 7) {
+ len = sizeof(*tlv_v7) + sizeof(dm->slot.v7);
+ tlv_v7 = kmalloc(len, GFP_KERNEL);
+ if (!tlv_v7)
+ return;
+
+ tlv_v7->type = SET_SLOT_TABLE;
+ tlv_v7->ver = ver->fcxslots;
+ tlv_v7->len = ARRAY_SIZE(dm->slot.v7);
+ memcpy(tlv_v7->val, dm->slot.v7, sizeof(dm->slot.v7));
+
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, (u8 *)tlv_v7, len);
+
+ kfree(tlv_v7);
+ } else {
+ n = struct_size(tbl, tbls, CXST_MAX);
+ tbl = kmalloc(n, GFP_KERNEL);
+ if (!tbl)
+ return;
+
+ tbl->fver = BTF_SET_SLOT_TABLE_VER;
+ tbl->tbl_num = CXST_MAX;
+ memcpy(tbl->tbls, dm->slot.v1, flex_array_size(tbl, tbls, CXST_MAX));
+
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, tbl, n);
+
+ kfree(tbl);
+ }
+}
+
static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
u32 rpt_map, bool rpt_state)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_smap *wl_smap = &btc->cx.wl.status.map;
struct rtw89_btc_btf_fwinfo *fwinfo = &btc->fwinfo;
- struct rtw89_btc_btf_set_report r = {0};
+ union rtw89_fbtc_rtp_ctrl r;
u32 val, bit_map;
+ int ret;
if ((wl_smap->rf_off || wl_smap->lps != BTC_LPS_OFF) && rpt_state != 0)
return;
@@ -1809,43 +2397,35 @@ static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
if (val == fwinfo->rpt_en_map)
return;
- fwinfo->rpt_en_map = val;
-
- r.fver = BTF_SET_REPORT_VER;
- r.enable = cpu_to_le32(val);
- r.para = cpu_to_le32(rpt_state);
-
- _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r, sizeof(r));
-}
-
-static void rtw89_btc_fw_set_slots(struct rtw89_dev *rtwdev, u8 num,
- struct rtw89_btc_fbtc_slot *s)
-{
- struct rtw89_btc_btf_set_slot_table *tbl = NULL;
- u8 *ptr = NULL;
- u16 n = 0;
-
- n = sizeof(*s) * num + sizeof(*tbl);
- tbl = kmalloc(n, GFP_KERNEL);
- if (!tbl)
- return;
-
- tbl->fver = BTF_SET_SLOT_TABLE_VER;
- tbl->tbl_num = num;
- ptr = &tbl->buf[0];
- memcpy(ptr, s, num * sizeof(*s));
-
- _send_fw_cmd(rtwdev, BTFC_SET, SET_SLOT_TABLE, tbl, n);
+ if (btc->ver->fcxbtcrpt == 8) {
+ r.v8.type = SET_REPORT_EN;
+ r.v8.fver = btc->ver->fcxbtcrpt;
+ r.v8.len = sizeof(r.v8.map);
+ r.v8.map = cpu_to_le32(val);
+ ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r.v8,
+ sizeof(r.v8));
+ } else {
+ if (btc->ver->fcxbtcrpt == 105)
+ r.v1.fver = 5;
+ else
+ r.v1.fver = btc->ver->fcxbtcrpt;
+ r.v1.enable = cpu_to_le32(val);
+ r.v1.para = cpu_to_le32(rpt_state);
+ ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r.v1,
+ sizeof(r.v1));
+ }
- kfree(tbl);
+ if (!ret)
+ fwinfo->rpt_en_map = val;
}
static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
- struct rtw89_btc_btf_set_mon_reg *monreg = NULL;
- u8 n, *ptr = NULL, ulen, cxmreg_max;
+ struct rtw89_btc_btf_set_mon_reg_v1 *v1 = NULL;
+ struct rtw89_btc_btf_set_mon_reg_v7 *v7 = NULL;
+ u8 i, n, ulen, cxmreg_max;
u16 sz = 0;
n = chip->mon_reg_num;
@@ -1854,10 +2434,8 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
if (ver->fcxmreg == 1)
cxmreg_max = CXMREG_MAX;
- else if (ver->fcxmreg == 2)
- cxmreg_max = CXMREG_MAX_V2;
else
- return;
+ cxmreg_max = CXMREG_MAX_V2;
if (n > cxmreg_max) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -1867,21 +2445,36 @@ static void btc_fw_set_monreg(struct rtw89_dev *rtwdev)
}
ulen = sizeof(struct rtw89_btc_fbtc_mreg);
- sz = (ulen * n) + sizeof(*monreg);
- monreg = kmalloc(sz, GFP_KERNEL);
- if (!monreg)
- return;
- monreg->fver = ver->fcxmreg;
- monreg->reg_num = n;
- ptr = &monreg->buf[0];
- memcpy(ptr, chip->mon_reg, n * ulen);
+ if (ver->fcxmreg == 7) {
+ sz = struct_size(v7, regs, n);
+ v7 = kmalloc(sz, GFP_KERNEL);
+ v7->type = RPT_EN_MREG;
+ v7->fver = ver->fcxmreg;
+ v7->len = n;
+ for (i = 0; i < n; i++) {
+ v7->regs[i].type = chip->mon_reg[i].type;
+ v7->regs[i].bytes = chip->mon_reg[i].bytes;
+ v7->regs[i].offset = chip->mon_reg[i].offset;
+ }
+
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, v7, sz);
+ kfree(v7);
+ } else {
+ sz = struct_size(v1, regs, n);
+ v1 = kmalloc(sz, GFP_KERNEL);
+ v1->fver = ver->fcxmreg;
+ v1->reg_num = n;
+ memcpy(v1->regs, chip->mon_reg, flex_array_size(v1, regs, n));
+
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, v1, sz);
+ kfree(v1);
+ }
+
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): sz=%d ulen=%d n=%d\n",
__func__, sz, ulen, n);
- _send_fw_cmd(rtwdev, BTFC_SET, SET_MREG_TABLE, (u8 *)monreg, sz);
- kfree(monreg);
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, 1);
}
@@ -1906,6 +2499,7 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
+ int ret;
dm->run_action = action;
@@ -1934,11 +2528,15 @@ static void _fw_set_policy(struct rtw89_dev *rtwdev, u16 policy_type,
if (btc->lps == 1)
rtw89_set_coex_ctrl_lps(rtwdev, btc->lps);
- _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY,
- btc->policy, btc->policy_len);
-
- memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now));
- memcpy(&dm->slot_now, &dm->slot, sizeof(dm->slot_now));
+ ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_CX_POLICY,
+ btc->policy, btc->policy_len);
+ if (!ret) {
+ memcpy(&dm->tdma_now, &dm->tdma, sizeof(dm->tdma_now));
+ if (btc->ver->fcxslots == 7)
+ memcpy(&dm->slot_now.v7, &dm->slot.v7, sizeof(dm->slot_now.v7));
+ else
+ memcpy(&dm->slot_now.v1, &dm->slot.v1, sizeof(dm->slot_now.v1));
+ }
if (btc->update_policy_force)
btc->update_policy_force = false;
@@ -1957,20 +2555,32 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type)
switch (type) {
case CXDRVINFO_INIT:
- rtw89_fw_h2c_cxdrv_init(rtwdev);
+ if (ver->fcxinit == 7)
+ rtw89_fw_h2c_cxdrv_init_v7(rtwdev, type);
+ else
+ rtw89_fw_h2c_cxdrv_init(rtwdev, type);
break;
case CXDRVINFO_ROLE:
if (ver->fwlrole == 0)
- rtw89_fw_h2c_cxdrv_role(rtwdev);
+ rtw89_fw_h2c_cxdrv_role(rtwdev, type);
else if (ver->fwlrole == 1)
- rtw89_fw_h2c_cxdrv_role_v1(rtwdev);
+ rtw89_fw_h2c_cxdrv_role_v1(rtwdev, type);
else if (ver->fwlrole == 2)
- rtw89_fw_h2c_cxdrv_role_v2(rtwdev);
+ rtw89_fw_h2c_cxdrv_role_v2(rtwdev, type);
break;
case CXDRVINFO_CTRL:
- rtw89_fw_h2c_cxdrv_ctrl(rtwdev);
+ if (ver->drvinfo_type == 1)
+ type = 2;
+
+ if (ver->fcxctrl == 7)
+ rtw89_fw_h2c_cxdrv_ctrl_v7(rtwdev, type);
+ else
+ rtw89_fw_h2c_cxdrv_ctrl(rtwdev, type);
break;
case CXDRVINFO_TRX:
+ if (ver->drvinfo_type == 1)
+ type = 3;
+
dm->trx_info.tx_power = u32_get_bits(rf_para.wl_tx_power,
RTW89_BTC_WL_DEF_TX_PWR);
dm->trx_info.rx_gain = u32_get_bits(rf_para.wl_rx_gain,
@@ -1981,11 +2591,18 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type)
RTW89_BTC_WL_DEF_TX_PWR);
dm->trx_info.cn = wl->cn_report;
dm->trx_info.nhm = wl->nhm.pwr;
- rtw89_fw_h2c_cxdrv_trx(rtwdev);
+ rtw89_fw_h2c_cxdrv_trx(rtwdev, type);
break;
case CXDRVINFO_RFK:
- rtw89_fw_h2c_cxdrv_rfk(rtwdev);
+ if (ver->drvinfo_type == 1)
+ return;
+
+ rtw89_fw_h2c_cxdrv_rfk(rtwdev, type);
break;
+ case CXDRVINFO_TXPWR:
+ case CXDRVINFO_FDDT:
+ case CXDRVINFO_MLO:
+ case CXDRVINFO_OSI:
default:
break;
}
@@ -2061,6 +2678,76 @@ static void _set_gnt(struct rtw89_dev *rtwdev, u8 phy_map, u8 wl_state, u8 bt_st
rtw89_chip_mac_cfg_gnt(rtwdev, &dm->gnt);
}
+static void _set_gnt_v1(struct rtw89_dev *rtwdev, u8 phy_map,
+ u8 wl_state, u8 bt_state, u8 wlact_state)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_mac_ax_gnt *g = dm->gnt.band;
+ u8 i, bt_idx = dm->bt_select + 1;
+
+ if (phy_map > BTC_PHY_ALL)
+ return;
+
+ for (i = 0; i < RTW89_PHY_MAX; i++) {
+ if (!(phy_map & BIT(i)))
+ continue;
+
+ switch (wl_state) {
+ case BTC_GNT_HW:
+ g[i].gnt_wl_sw_en = 0;
+ g[i].gnt_wl = 0;
+ break;
+ case BTC_GNT_SW_LO:
+ g[i].gnt_wl_sw_en = 1;
+ g[i].gnt_wl = 0;
+ break;
+ case BTC_GNT_SW_HI:
+ g[i].gnt_wl_sw_en = 1;
+ g[i].gnt_wl = 1;
+ break;
+ }
+
+ switch (bt_state) {
+ case BTC_GNT_HW:
+ g[i].gnt_bt_sw_en = 0;
+ g[i].gnt_bt = 0;
+ break;
+ case BTC_GNT_SW_LO:
+ g[i].gnt_bt_sw_en = 1;
+ g[i].gnt_bt = 0;
+ break;
+ case BTC_GNT_SW_HI:
+ g[i].gnt_bt_sw_en = 1;
+ g[i].gnt_bt = 1;
+ break;
+ }
+ }
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_WLAN_ACT_MUX) {
+ for (i = 0; i < 2; i++) {
+ if (!(bt_idx & BIT(i)))
+ continue;
+
+ switch (wlact_state) {
+ case BTC_WLACT_HW:
+ dm->gnt.bt[i].wlan_act_en = 0;
+ dm->gnt.bt[i].wlan_act = 0;
+ break;
+ case BTC_WLACT_SW_LO:
+ dm->gnt.bt[i].wlan_act_en = 1;
+ dm->gnt.bt[i].wlan_act = 0;
+ break;
+ case BTC_WLACT_SW_HI:
+ dm->gnt.bt[i].wlan_act_en = 1;
+ dm->gnt.bt[i].wlan_act = 1;
+ break;
+ }
+ }
+ }
+ rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt);
+}
+
#define BTC_TDMA_WLROLE_MAX 2
static void _set_bt_ignore_wlan_act(struct rtw89_dev *rtwdev, u8 enable)
@@ -2135,20 +2822,25 @@ static void _set_bt_tx_power(struct rtw89_dev *rtwdev, u8 level)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ int ret;
u8 buf;
- if (bt->rf_para.tx_pwr_freerun == level)
+ if (btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE] == 0)
return;
- bt->rf_para.tx_pwr_freerun = level;
- btc->dm.rf_trx_para.bt_tx_power = level;
+ if (bt->rf_para.tx_pwr_freerun == level)
+ return;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): level = %d\n",
__func__, level);
buf = (s8)(-level);
- _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1);
+ ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_TX_PWR, &buf, 1);
+ if (!ret) {
+ bt->rf_para.tx_pwr_freerun = level;
+ btc->dm.rf_trx_para.bt_tx_power = level;
+ }
}
#define BTC_BT_RX_NORMAL_LVL 7
@@ -2158,8 +2850,12 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
- if (bt->rf_para.rx_gain_freerun == level ||
- level > BTC_BT_RX_NORMAL_LVL)
+ if (btc->cx.cnt_bt[BTC_BCNT_INFOUPDATE] == 0)
+ return;
+
+ if ((bt->rf_para.rx_gain_freerun == level ||
+ level > BTC_BT_RX_NORMAL_LVL) &&
+ (!rtwdev->chip->scbd || bt->lna_constrain == level))
return;
bt->rf_para.rx_gain_freerun = level;
@@ -2174,32 +2870,59 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
else
_write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
- _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, 1);
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, sizeof(level));
}
static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_bt_link_info *b = &bt->link_info;
+ struct rtw89_btc_wl_smap *wl_smap = &wl->status.map;
struct rtw89_btc_rf_trx_para para;
u32 wl_stb_chg = 0;
- u8 level_id = 0;
+ u8 level_id = 0, link_mode = 0, i, dbcc_2g_phy = 0;
+
+ if (ver->fwlrole == 0) {
+ link_mode = wl->role_info.link_mode;
+ for (i = 0; i < RTW89_PHY_MAX; i++) {
+ if (wl->dbcc_info.real_band[i] == RTW89_BAND_2G)
+ dbcc_2g_phy = i;
+ }
+ } else if (ver->fwlrole == 1) {
+ link_mode = wl->role_info_v1.link_mode;
+ dbcc_2g_phy = wl->role_info_v1.dbcc_2g_phy;
+ } else if (ver->fwlrole == 2) {
+ link_mode = wl->role_info_v2.link_mode;
+ dbcc_2g_phy = wl->role_info_v2.dbcc_2g_phy;
+ }
- if (!dm->freerun) {
- /* fix LNA2 = level-5 for BT ACI issue at BTG */
+ /* decide trx_para_level */
+ if (btc->ant_type == BTC_ANT_SHARED) {
+ /* fix LNA2 + TIA gain not change by GNT_BT */
if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) ||
dm->bt_only == 1)
- dm->trx_para_level = 1;
+ dm->trx_para_level = 1; /* for better BT ACI issue */
else
dm->trx_para_level = 0;
+ } else { /* non-shared antenna */
+ dm->trx_para_level = 5;
+ /* modify trx_para if WK 2.4G-STA-DL + bt link */
+ if (b->profile_cnt.now != 0 &&
+ link_mode == BTC_WLINK_2G_STA &&
+ wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { /* uplink */
+ if (wl->rssi_level == 4 && bt->rssi_level > 2)
+ dm->trx_para_level = 6;
+ else if (wl->rssi_level == 3 && bt->rssi_level > 3)
+ dm->trx_para_level = 7;
+ }
}
- level_id = (u8)dm->trx_para_level;
-
+ level_id = dm->trx_para_level;
if (level_id >= chip->rf_para_dlink_num ||
level_id >= chip->rf_para_ulink_num) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -2213,25 +2936,26 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
else
para = chip->rf_para_dlink[level_id];
- if (para.wl_tx_power != RTW89_BTC_WL_DEF_TX_PWR)
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): wl_tx_power=%d\n",
- __func__, para.wl_tx_power);
- _set_wl_tx_power(rtwdev, para.wl_tx_power);
- _set_wl_rx_gain(rtwdev, para.wl_rx_gain);
- _set_bt_tx_power(rtwdev, para.bt_tx_power);
- _set_bt_rx_gain(rtwdev, para.bt_rx_gain);
-
- if (bt->enable.now == 0 || wl->status.map.rf_off == 1 ||
- wl->status.map.lps == BTC_LPS_RF_OFF)
+ if (dm->fddt_train) {
+ _set_wl_rx_gain(rtwdev, 1);
+ _write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
+ } else {
+ _set_wl_tx_power(rtwdev, para.wl_tx_power);
+ _set_wl_rx_gain(rtwdev, para.wl_rx_gain);
+ _set_bt_tx_power(rtwdev, para.bt_tx_power);
+ _set_bt_rx_gain(rtwdev, para.bt_rx_gain);
+ }
+
+ if (!bt->enable.now || dm->wl_only || wl_smap->rf_off ||
+ wl_smap->lps == BTC_LPS_RF_OFF ||
+ link_mode == BTC_WLINK_5G ||
+ link_mode == BTC_WLINK_NOLINK ||
+ (rtwdev->dbcc_en && dbcc_2g_phy != RTW89_PHY_1))
wl_stb_chg = 0;
else
wl_stb_chg = 1;
if (wl_stb_chg != dm->wl_stb_chg) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): wl_stb_chg=%d\n",
- __func__, wl_stb_chg);
dm->wl_stb_chg = wl_stb_chg;
chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
}
@@ -2274,13 +2998,15 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
struct rtw89_btc_wl_active_role *r;
struct rtw89_btc_wl_active_role_v1 *r1;
struct rtw89_btc_wl_active_role_v2 *r2;
+ struct rtw89_btc_wl_rlink *rlink;
u8 en = 0, i, ch = 0, bw = 0;
u8 mode, connect_cnt;
- if (btc->ctrl.manual || wl->status.map.scan)
+ if (btc->manual_ctrl || wl->status.map.scan)
return;
if (ver->fwlrole == 0) {
@@ -2292,6 +3018,9 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
} else if (ver->fwlrole == 2) {
mode = wl_rinfo_v2->link_mode;
connect_cnt = wl_rinfo_v2->connect_cnt;
+ } else if (ver->fwlrole == 8) {
+ mode = wl_rinfo_v8->link_mode;
+ connect_cnt = wl_rinfo_v8->connect_cnt;
} else {
return;
}
@@ -2307,6 +3036,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
r = &wl_rinfo->active_role[i];
r1 = &wl_rinfo_v1->active_role_v1[i];
r2 = &wl_rinfo_v2->active_role_v2[i];
+ rlink = &wl_rinfo_v8->rlink[i][0];
if (ver->fwlrole == 0 &&
(r->role == RTW89_WIFI_ROLE_P2P_GO ||
@@ -2326,6 +3056,12 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
ch = r2->ch;
bw = r2->bw;
break;
+ } else if (ver->fwlrole == 8 &&
+ (rlink->role == RTW89_WIFI_ROLE_P2P_GO ||
+ rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) {
+ ch = rlink->ch;
+ bw = rlink->bw;
+ break;
}
}
} else {
@@ -2335,6 +3071,7 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
r = &wl_rinfo->active_role[i];
r1 = &wl_rinfo_v1->active_role_v1[i];
r2 = &wl_rinfo_v2->active_role_v2[i];
+ rlink = &wl_rinfo_v8->rlink[i][0];
if (ver->fwlrole == 0 &&
r->connected && r->band == RTW89_BAND_2G) {
@@ -2351,6 +3088,11 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev)
ch = r2->ch;
bw = r2->bw;
break;
+ } else if (ver->fwlrole == 8 &&
+ rlink->connected && rlink->rf_band == RTW89_BAND_2G) {
+ ch = rlink->ch;
+ bw = rlink->bw;
+ break;
}
}
}
@@ -2403,17 +3145,35 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
+ struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
struct rtw89_btc_bt_hid_desc *hid = &bt_linfo->hid_desc;
+ union rtw89_btc_module_info *md = &btc->mdinfo;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ u8 isolation, connect_cnt = 0;
+
+ if (ver->fcxinit == 7)
+ isolation = md->md_v7.ant.isolation;
+ else
+ isolation = md->md.ant.isolation;
+
+ if (ver->fwlrole == 0)
+ connect_cnt = wl_rinfo->connect_cnt;
+ else if (ver->fwlrole == 1)
+ connect_cnt = wl_rinfo_v1->connect_cnt;
+ else if (ver->fwlrole == 2)
+ connect_cnt = wl_rinfo_v2->connect_cnt;
+ else if (ver->fwlrole == 8)
+ connect_cnt = wl_rinfo_v8->connect_cnt;
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
+ if (btc->ant_type == BTC_ANT_SHARED) {
btc->dm.trx_para_level = 0;
return false;
}
/* The below is dedicated antenna case */
- if (wl_rinfo->connect_cnt > BTC_TDMA_WLROLE_MAX ||
- wl_rinfo_v1->connect_cnt > BTC_TDMA_WLROLE_MAX) {
+ if (connect_cnt > BTC_TDMA_WLROLE_MAX) {
btc->dm.trx_para_level = 5;
return true;
}
@@ -2429,7 +3189,7 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
}
/* TODO get isolation by BT psd */
- if (btc->mdinfo.ant.isolation >= BTC_FREERUN_ANTISO_MIN) {
+ if (isolation >= BTC_FREERUN_ANTISO_MIN) {
btc->dm.trx_para_level = 5;
return true;
}
@@ -2466,19 +3226,6 @@ static bool _check_freerun(struct rtw89_dev *rtwdev)
#define _tdma_set_tog(btc, wtg) ({(btc)->dm.tdma.wtgle_n = wtg; })
#define _tdma_set_lek(btc, lek) ({(btc)->dm.tdma.leak_n = lek; })
-#define _slot_set(btc, sid, dura, tbl, type) \
- do { \
- typeof(sid) _sid = (sid); \
- typeof(btc) _btc = (btc); \
- _btc->dm.slot[_sid].dur = cpu_to_le16(dura);\
- _btc->dm.slot[_sid].cxtbl = cpu_to_le32(tbl); \
- _btc->dm.slot[_sid].cxtype = cpu_to_le16(type); \
- } while (0)
-
-#define _slot_set_dur(btc, sid, dura) (btc)->dm.slot[sid].dur = cpu_to_le16(dura)
-#define _slot_set_tbl(btc, sid, tbl) (btc)->dm.slot[sid].cxtbl = cpu_to_le32(tbl)
-#define _slot_set_type(btc, sid, type) (btc)->dm.slot[sid].cxtype = cpu_to_le16(type)
-
struct btc_btinfo_lb2 {
u8 connect: 1;
u8 sco_busy: 1;
@@ -2553,11 +3300,11 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
- struct rtw89_btc_fbtc_slot *s = dm->slot;
+ struct rtw89_btc_fbtc_slot *s = dm->slot.v1;
u8 type;
u32 tbl_w1, tbl_b1, tbl_b4;
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
+ if (btc->ant_type == BTC_ANT_SHARED) {
if (btc->cx.wl.status.map._4way)
tbl_w1 = cxtbl[1];
else
@@ -2664,9 +3411,17 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
break;
- case BTC_CXP_FIX_TD4020:
- _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX);
- _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX);
+ case BTC_CXP_FIX_TD4010ISO:
+ _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
+ break;
+ case BTC_CXP_FIX_TD4010ISO_DL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
+ break;
+ case BTC_CXP_FIX_TD4010ISO_UL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
break;
case BTC_CXP_FIX_TD7010:
_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
@@ -2856,16 +3611,17 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_fbtc_tdma *t = &dm->tdma;
- struct rtw89_btc_fbtc_slot *s = dm->slot;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo = &btc->cx.wl.role_info_v1;
struct rtw89_btc_bt_hid_desc *hid = &btc->cx.bt.link_info.hid_desc;
struct rtw89_btc_bt_hfp_desc *hfp = &btc->cx.bt.link_info.hfp_desc;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
u8 type, null_role;
u32 tbl_w1, tbl_b1, tbl_b4;
+ u16 dur_2;
type = FIELD_GET(BTC_CXP_MASK, policy_type);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
+ if (btc->ant_type == BTC_ANT_SHARED) {
if (btc->cx.wl.status.map._4way)
tbl_w1 = cxtbl[1];
else if (hid->exist && hid->type == BTC_HID_218)
@@ -2885,9 +3641,16 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
tbl_b4 = cxtbl[2];
}
} else {
- tbl_w1 = cxtbl[16];
tbl_b1 = cxtbl[17];
tbl_b4 = cxtbl[17];
+
+ if (wl->bg_mode)
+ tbl_w1 = cxtbl[8];
+ else if ((wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) &&
+ hid->exist)
+ tbl_w1 = cxtbl[19];
+ else
+ tbl_w1 = cxtbl[16];
}
btc->bt_req_en = false;
@@ -2896,13 +3659,15 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
case BTC_CXP_USERDEF0:
btc->update_policy_force = true;
*t = t_def[CXTD_OFF];
- s[CXST_OFF] = s_def[CXST_OFF];
+ _slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
+ s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
_slot_set_tbl(btc, CXST_OFF, cxtbl[2]);
break;
case BTC_CXP_OFF: /* TDMA off */
_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
*t = t_def[CXTD_OFF];
- s[CXST_OFF] = s_def[CXST_OFF];
+ _slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
+ s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
switch (policy_type) {
case BTC_CXP_OFF_BT:
@@ -2943,7 +3708,8 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
case BTC_CXP_OFFB: /* TDMA off + beacon protect */
_write_scbd(rtwdev, BTC_WSCB_TDMA, false);
*t = t_def[CXTD_OFF_B2];
- s[CXST_OFF] = s_def[CXST_OFF];
+ _slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
+ s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
switch (policy_type) {
case BTC_CXP_OFFB_BWB0:
@@ -2962,23 +3728,54 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
if (hid->exist || hfp->exist)
tbl_w1 = cxtbl[16];
+ dur_2 = dm->e2g_slot_limit;
+
switch (policy_type) {
+ case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */
+ _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_ISO);
+ _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+ s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
+ _slot_set_dur(btc, CXST_EBT, dur_2);
+ break;
+ case BTC_CXP_OFFE_2GISOB: /* for bt no-link */
+ _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_ISO);
+ _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+ s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
+ _slot_set_dur(btc, CXST_EBT, dur_2);
+ break;
case BTC_CXP_OFFE_DEF:
- s[CXST_E2G] = s_def[CXST_E2G];
- s[CXST_E5G] = s_def[CXST_E5G];
- s[CXST_EBT] = s_def[CXST_EBT];
- s[CXST_ENULL] = s_def[CXST_ENULL];
+ _slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur,
+ s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype);
+ _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
+ s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
+ _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+ s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
+ _slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
+ s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
break;
case BTC_CXP_OFFE_DEF2:
_slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO);
- s[CXST_E5G] = s_def[CXST_E5G];
- s[CXST_EBT] = s_def[CXST_EBT];
- s[CXST_ENULL] = s_def[CXST_ENULL];
+ _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur,
+ s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype);
+ _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+ s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype);
+ _slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur,
+ s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype);
+ break;
+ case BTC_CXP_OFFE_2GBWMIXB:
+ _slot_set(btc, CXST_E2G, 0, 0x55555555, SLOT_MIX);
+ _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur,
+ cpu_to_le32(0x55555555), s_def[CXST_EBT].cxtype);
+ break;
+ case BTC_CXP_OFFE_WL: /* for 4-way */
+ _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX);
+ _slot_set(btc, CXST_EBT, 0, cxtbl[1], SLOT_MIX);
break;
default:
break;
}
- s[CXST_OFF] = s_def[CXST_OFF];
+ _slot_set_le(btc, CXST_OFF, s_def[CXST_OFF].dur,
+ s_def[CXST_OFF].cxtbl, s_def[CXST_OFF].cxtype);
break;
case BTC_CXP_FIX: /* TDMA Fix-Slot */
_write_scbd(rtwdev, BTC_WSCB_TDMA, true);
@@ -3005,9 +3802,13 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
break;
- case BTC_CXP_FIX_TD4020:
- _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX);
- _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX);
+ case BTC_CXP_FIX_TD4010ISO_DL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
+ break;
+ case BTC_CXP_FIX_TD4010ISO_UL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
break;
case BTC_CXP_FIX_TD7010:
_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
@@ -3234,25 +4035,36 @@ EXPORT_SYMBOL(rtw89_btc_set_policy_v1);
static void _set_bt_plut(struct rtw89_dev *rtwdev, u8 phy_map,
u8 tx_val, u8 rx_val)
{
+ struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
struct rtw89_mac_ax_plt plt;
- plt.band = RTW89_MAC_0;
plt.tx = tx_val;
plt.rx = rx_val;
- if (phy_map & BTC_PHY_0)
+ if (rtwdev->btc.ver->fwlrole == 8) {
+ plt.band = wl->pta_req_mac;
+ if (wl->bt_polut_type[plt.band] == tx_val)
+ return;
+
+ wl->bt_polut_type[plt.band] = tx_val;
rtw89_mac_cfg_plt(rtwdev, &plt);
+ } else {
+ plt.band = RTW89_MAC_0;
- if (!rtwdev->dbcc_en)
- return;
+ if (phy_map & BTC_PHY_0)
+ rtw89_mac_cfg_plt(rtwdev, &plt);
- plt.band = RTW89_MAC_1;
- if (phy_map & BTC_PHY_1)
- rtw89_mac_cfg_plt(rtwdev, &plt);
+ if (!rtwdev->dbcc_en)
+ return;
+
+ plt.band = RTW89_MAC_1;
+ if (phy_map & BTC_PHY_1)
+ rtw89_mac_cfg_plt(rtwdev, &plt);
+ }
}
-static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
- u8 phy_map, u8 type)
+static void _set_ant_v0(struct rtw89_dev *rtwdev, bool force_exec,
+ u8 phy_map, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
@@ -3261,13 +4073,21 @@ static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
struct rtw89_btc_bt_info *bt = &cx->bt;
struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
u8 gnt_wl_ctrl, gnt_bt_ctrl, plt_ctrl, i, b2g = 0;
+ bool dbcc_chg = false;
u32 ant_path_type;
ant_path_type = ((phy_map << 8) + type);
+ if (btc->ver->fwlrole == 1)
+ dbcc_chg = wl->role_info_v1.dbcc_chg;
+ else if (btc->ver->fwlrole == 2)
+ dbcc_chg = wl->role_info_v2.dbcc_chg;
+ else if (btc->ver->fwlrole == 8)
+ dbcc_chg = wl->role_info_v8.dbcc_chg;
+
if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
- btc->dm.run_reason == BTC_RSN_CMD_SET_COEX)
+ btc->dm.run_reason == BTC_RSN_CMD_SET_COEX || dbcc_chg)
force_exec = FC_EXEC;
if (!force_exec && ant_path_type == dm->set_ant_path) {
@@ -3370,6 +4190,117 @@ static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
}
}
+static void _set_ant_v1(struct rtw89_dev *rtwdev, bool force_exec,
+ u8 phy_map, u8 type)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
+ u32 ant_path_type = rtw89_get_antpath_type(phy_map, type);
+ struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 gwl = BTC_GNT_HW;
+
+ if (btc->dm.run_reason == BTC_RSN_NTFY_POWEROFF ||
+ btc->dm.run_reason == BTC_RSN_NTFY_RADIO_STATE ||
+ btc->dm.run_reason == BTC_RSN_CMD_SET_COEX || wl_rinfo->dbcc_chg)
+ force_exec = FC_EXEC;
+
+ if (wl_rinfo->link_mode != BTC_WLINK_25G_MCC &&
+ btc->dm.wl_btg_rx == 2)
+ force_exec = FC_EXEC;
+
+ if (!force_exec && ant_path_type == dm->set_ant_path) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return by no change!!\n",
+ __func__);
+ return;
+ } else if (bt->rfk_info.map.run) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return by bt rfk!!\n", __func__);
+ return;
+ } else if (btc->dm.run_reason != BTC_RSN_NTFY_WL_RFK &&
+ wl->rfk_info.state != BTC_WRFK_STOP) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return by wl rfk!!\n", __func__);
+ return;
+ }
+
+ dm->set_ant_path = ant_path_type;
+
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): path=0x%x, set_type=0x%x\n",
+ __func__, phy_map, dm->set_ant_path & 0xff);
+
+ switch (type) {
+ case BTC_ANT_WINIT:
+ /* To avoid BT MP driver case (bt_enable but no mailbox) */
+ if (bt->enable.now && bt->run_patch_code)
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI,
+ BTC_WLACT_SW_LO);
+ else
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
+ BTC_WLACT_SW_HI);
+ break;
+ case BTC_ANT_WONLY:
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
+ BTC_WLACT_SW_HI);
+ break;
+ case BTC_ANT_WOFF:
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_LO, BTC_GNT_SW_HI,
+ BTC_WLACT_SW_LO);
+ break;
+ case BTC_ANT_W2G:
+ case BTC_ANT_W25G:
+ if (wl_rinfo->dbcc_en) {
+ if (wl_dinfo->real_band[RTW89_PHY_0] == RTW89_BAND_2G)
+ gwl = BTC_GNT_HW;
+ else
+ gwl = BTC_GNT_SW_HI;
+ _set_gnt_v1(rtwdev, BTC_PHY_0, gwl, BTC_GNT_HW, BTC_WLACT_HW);
+
+ if (wl_dinfo->real_band[RTW89_PHY_1] == RTW89_BAND_2G)
+ gwl = BTC_GNT_HW;
+ else
+ gwl = BTC_GNT_SW_HI;
+ _set_gnt_v1(rtwdev, BTC_PHY_1, gwl, BTC_GNT_HW, BTC_WLACT_HW);
+ } else {
+ gwl = BTC_GNT_HW;
+ _set_gnt_v1(rtwdev, phy_map, gwl, BTC_GNT_HW, BTC_WLACT_HW);
+ }
+ break;
+ case BTC_ANT_W5G:
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_HW, BTC_WLACT_HW);
+ break;
+ case BTC_ANT_FREERUN:
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_HI,
+ BTC_WLACT_SW_LO);
+ break;
+ case BTC_ANT_WRFK:
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
+ BTC_WLACT_HW);
+ break;
+ case BTC_ANT_WRFK2:
+ _set_gnt_v1(rtwdev, phy_map, BTC_GNT_SW_HI, BTC_GNT_SW_LO,
+ BTC_WLACT_SW_HI); /* no BT-Tx */
+ break;
+ default:
+ return;
+ }
+
+ _set_bt_plut(rtwdev, phy_map, BTC_PLT_GNT_WL, BTC_PLT_GNT_WL);
+}
+
+static void _set_ant(struct rtw89_dev *rtwdev, bool force_exec,
+ u8 phy_map, u8 type)
+{
+ if (rtwdev->chip->chip_id == RTL8922A)
+ _set_ant_v1(rtwdev, force_exec, phy_map, type);
+ else
+ _set_ant_v0(rtwdev, force_exec, phy_map, type);
+}
+
static void _action_wl_only(struct rtw89_dev *rtwdev)
{
_set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_WONLY);
@@ -3384,17 +4315,32 @@ static void _action_wl_init(struct rtw89_dev *rtwdev)
_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT);
}
-static void _action_wl_off(struct rtw89_dev *rtwdev)
+static void _action_wl_off(struct rtw89_dev *rtwdev, u8 mode)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
- if (wl->status.map.rf_off || btc->dm.bt_only)
+ if (wl->status.map.rf_off || btc->dm.bt_only) {
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF);
+ } else if (wl->status.map.lps == BTC_LPS_RF_ON) {
+ if (mode == BTC_WLINK_5G)
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W5G);
+ else
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
+ }
- _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
+ if (mode == BTC_WLINK_5G) {
+ _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OFF);
+ } else if (wl->status.map.lps == BTC_LPS_RF_ON) {
+ if (btc->cx.bt.link_info.a2dp_desc.active)
+ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
+ else
+ _set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_WL_OFF);
+ } else {
+ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
+ }
}
static void _action_freerun(struct rtw89_dev *rtwdev)
@@ -3429,31 +4375,25 @@ static void _action_bt_idle(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_link_info *b = &btc->cx.bt.link_info;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
switch (btc->cx.state_map) {
case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/
- if (b->profile_cnt.now > 0)
- _set_policy(rtwdev, BTC_CXP_FIX_TD4010,
- BTC_ACT_BT_IDLE);
+ case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
+ if (b->status.map.connect)
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_IDLE);
+ else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL))
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_DL, BTC_ACT_BT_IDLE);
else
- _set_policy(rtwdev, BTC_CXP_FIX_TD4020,
- BTC_ACT_BT_IDLE);
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_UL, BTC_ACT_BT_IDLE);
break;
case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */
_set_policy(rtwdev, BTC_CXP_PFIX_TD5050,
BTC_ACT_BT_IDLE);
break;
- case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
- if (b->profile_cnt.now > 0)
- _set_policy(rtwdev, BTC_CXP_FIX_TD4010,
- BTC_ACT_BT_IDLE);
- else
- _set_policy(rtwdev, BTC_CXP_FIX_TD4020,
- BTC_ACT_BT_IDLE);
- break;
case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */
_set_policy(rtwdev, BTC_CXP_FIX_TD5050,
BTC_ACT_BT_IDLE);
@@ -3478,7 +4418,7 @@ static void _action_bt_hfp(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
+ if (btc->ant_type == BTC_ANT_SHARED) {
if (btc->cx.wl.status.map._4way) {
_set_policy(rtwdev, BTC_CXP_OFF_WL, BTC_ACT_BT_HFP);
} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
@@ -3488,7 +4428,12 @@ static void _action_bt_hfp(struct rtw89_dev *rtwdev)
_set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
}
} else {
- _set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP);
+ if (wl->bg_mode)
+ _set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_BT_HFP);
+ else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
+ _set_policy(rtwdev, BTC_CXP_OFF_EQ5, BTC_ACT_BT_HFP);
+ else
+ _set_policy(rtwdev, BTC_CXP_OFF_EQ2, BTC_ACT_BT_HFP);
}
}
@@ -3503,7 +4448,7 @@ static void _action_bt_hid(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
if (wl->status.map._4way) {
policy_type = BTC_CXP_OFF_WL;
} else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) {
@@ -3521,7 +4466,12 @@ static void _action_bt_hid(struct rtw89_dev *rtwdev)
policy_type = BTC_CXP_OFF_BWB1;
}
} else { /* dedicated-antenna */
- policy_type = BTC_CXP_OFF_EQ3;
+ if (wl->bg_mode)
+ policy_type = BTC_CXP_OFF_BWB1;
+ else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_UL))
+ policy_type = BTC_CXP_OFF_EQ4;
+ else
+ policy_type = BTC_CXP_OFF_EQ3;
}
_set_policy(rtwdev, policy_type, BTC_ACT_BT_HID);
@@ -3620,7 +4570,7 @@ static void _action_bt_pan(struct rtw89_dev *rtwdev)
_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN);
break;
case BTC_WLINKING: /* wl-connecting + bt-PAN */
- _set_policy(rtwdev, BTC_CXP_FIX_TD4020, BTC_ACT_BT_PAN);
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO, BTC_ACT_BT_PAN);
break;
case BTC_WIDLE: /* wl-idle + bt-pan */
_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN);
@@ -3771,7 +4721,7 @@ static void _action_wl_other(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED)
+ if (btc->ant_type == BTC_ANT_SHARED)
_set_policy(rtwdev, BTC_CXP_OFFB_BWB0, BTC_ACT_WL_OTHER);
else
_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OTHER);
@@ -3801,46 +4751,139 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev)
static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
- const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
+ struct rtw89_btc_wl_role_info *wl_rinfo_v0 = &wl->role_info;
struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
- bool is_btg;
- u8 mode;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct _wl_rinfo_now wl_rinfo;
+ u32 run_reason = btc->dm.run_reason;
+ u32 is_btg;
+ u8 i, val;
- if (btc->ctrl.manual)
+ if (btc->manual_ctrl)
return;
if (ver->fwlrole == 0)
- mode = wl_rinfo->link_mode;
+ wl_rinfo.link_mode = wl_rinfo_v0->link_mode;
else if (ver->fwlrole == 1)
- mode = wl_rinfo_v1->link_mode;
+ wl_rinfo.link_mode = wl_rinfo_v1->link_mode;
else if (ver->fwlrole == 2)
- mode = wl_rinfo_v2->link_mode;
+ wl_rinfo.link_mode = wl_rinfo_v2->link_mode;
+ else if (ver->fwlrole == 8)
+ wl_rinfo.link_mode = wl_rinfo_v8->link_mode;
else
return;
- /* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */
- if (mode == BTC_WLINK_5G) /* always 0 if 5G */
- is_btg = false;
- else if (mode == BTC_WLINK_25G_DBCC &&
- wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
- is_btg = false;
+ if (rtwdev->dbcc_en) {
+ if (ver->fwlrole == 0) {
+ for (i = 0; i < RTW89_PHY_MAX; i++) {
+ if (wl_dinfo->real_band[i] == RTW89_BAND_2G)
+ wl_rinfo.dbcc_2g_phy = i;
+ }
+ } else if (ver->fwlrole == 1) {
+ wl_rinfo.dbcc_2g_phy = wl_rinfo_v1->dbcc_2g_phy;
+ } else if (ver->fwlrole == 2) {
+ wl_rinfo.dbcc_2g_phy = wl_rinfo_v2->dbcc_2g_phy;
+ } else if (ver->fwlrole == 8) {
+ wl_rinfo.dbcc_2g_phy = wl_rinfo_v8->dbcc_2g_phy;
+ } else {
+ return;
+ }
+ }
+
+ if (wl_rinfo.link_mode == BTC_WLINK_25G_MCC)
+ is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL;
+ else if (!(bt->run_patch_code && bt->enable.now))
+ is_btg = BTC_BTGCTRL_DISABLE;
+ else if (wl_rinfo.link_mode == BTC_WLINK_5G)
+ is_btg = BTC_BTGCTRL_DISABLE;
+ else if (dm->freerun)
+ is_btg = BTC_BTGCTRL_DISABLE;
+ else if (rtwdev->dbcc_en && wl_rinfo.dbcc_2g_phy != RTW89_PHY_1)
+ is_btg = BTC_BTGCTRL_DISABLE;
else
- is_btg = true;
+ is_btg = BTC_BTGCTRL_ENABLE;
- if (btc->dm.run_reason != BTC_RSN_NTFY_INIT &&
- is_btg == btc->dm.wl_btg_rx)
- return;
+ if (dm->wl_btg_rx_rb != dm->wl_btg_rx &&
+ dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) {
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX, &val);
+ dm->wl_btg_rx_rb = val;
+ }
+
+ if (run_reason == BTC_RSN_NTFY_INIT ||
+ run_reason == BTC_RSN_NTFY_SWBAND ||
+ dm->wl_btg_rx_rb != dm->wl_btg_rx ||
+ is_btg != dm->wl_btg_rx) {
+
+ dm->wl_btg_rx = is_btg;
- btc->dm.wl_btg_rx = is_btg;
+ if (is_btg > BTC_BTGCTRL_ENABLE)
+ return;
+
+ chip->ops->ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0);
+ }
+}
+
+static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_wl_role_info_v2 *wl_rinfo = &wl->role_info_v2;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 is_preagc, val;
- if (mode == BTC_WLINK_25G_MCC)
+ if (btc->manual_ctrl)
return;
- rtw89_ctrl_btg(rtwdev, is_btg);
+ if (wl_rinfo->link_mode == BTC_WLINK_25G_MCC)
+ is_preagc = BTC_PREAGC_BB_FWCTRL;
+ else if (!(bt->run_patch_code && bt->enable.now))
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (wl_rinfo->link_mode == BTC_WLINK_5G)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (wl_rinfo->link_mode == BTC_WLINK_NOLINK ||
+ btc->cx.bt.link_info.profile_cnt.now == 0)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (dm->tdma_now.type != CXTDMA_OFF &&
+ !bt_linfo->hfp_desc.exist &&
+ !bt_linfo->hid_desc.exist &&
+ dm->fddt_train == BTC_FDDT_DISABLE)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (ver->fwlrole == 2 && wl_rinfo->dbcc_en &&
+ wl_rinfo->dbcc_2g_phy != RTW89_PHY_1)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (btc->ant_type == BTC_ANT_SHARED)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else
+ is_preagc = BTC_PREAGC_ENABLE;
+
+ if (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
+ dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) {
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val);
+ dm->wl_pre_agc_rb = val;
+ }
+
+ if ((wl->coex_mode == BTC_MODE_NORMAL &&
+ (dm->run_reason == BTC_RSN_NTFY_INIT ||
+ dm->run_reason == BTC_RSN_NTFY_SWBAND ||
+ dm->wl_pre_agc_rb != dm->wl_pre_agc)) ||
+ is_preagc != dm->wl_pre_agc) {
+ dm->wl_pre_agc = is_preagc;
+
+ if (is_preagc > BTC_PREAGC_ENABLE)
+ return;
+ chip->ops->ctrl_nbtg_bt_tx(rtwdev, dm->wl_pre_agc, RTW89_PHY_0);
+ }
}
struct rtw89_txtime_data {
@@ -3869,7 +4912,10 @@ static void rtw89_tx_time_iter(void *data, struct ieee80211_sta *sta)
u16 enable = iter_data->enable;
bool reenable = iter_data->reenable;
- plink = &wl->link_info[port];
+ if (btc->ver->fwlrole == 8)
+ plink = &wl->rlink_info[port][0];
+ else
+ plink = &wl->link_info[port];
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): port = %d\n", __func__, port);
@@ -3922,14 +4968,14 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
struct rtw89_txtime_data data = {.rtwdev = rtwdev};
- u8 mode;
- u8 tx_retry;
+ u8 mode, igno_bt, tx_retry;
u32 tx_time;
u16 enable;
bool reenable = false;
- if (btc->ctrl.manual)
+ if (btc->manual_ctrl)
return;
if (ver->fwlrole == 0)
@@ -3938,10 +4984,17 @@ static void _set_wl_tx_limit(struct rtw89_dev *rtwdev)
mode = wl_rinfo_v1->link_mode;
else if (ver->fwlrole == 2)
mode = wl_rinfo_v2->link_mode;
+ else if (ver->fwlrole == 8)
+ mode = wl_rinfo_v8->link_mode;
else
return;
- if (btc->dm.freerun || btc->ctrl.igno_bt || b->profile_cnt.now == 0 ||
+ if (ver->fcxctrl == 7)
+ igno_bt = btc->ctrl.ctrl_v7.igno_bt;
+ else
+ igno_bt = btc->ctrl.ctrl.igno_bt;
+
+ if (btc->dm.freerun || igno_bt || b->profile_cnt.now == 0 ||
mode == BTC_WLINK_5G || mode == BTC_WLINK_NOLINK) {
enable = 0;
tx_time = BTC_MAX_TX_TIME_DEF;
@@ -3990,6 +5043,7 @@ static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
bool bt_hi_lna_rx = false;
u8 mode;
@@ -4000,6 +5054,8 @@ static void _set_bt_rx_agc(struct rtw89_dev *rtwdev)
mode = wl_rinfo_v1->link_mode;
else if (ver->fwlrole == 2)
mode = wl_rinfo_v2->link_mode;
+ else if (ver->fwlrole == 8)
+ mode = wl_rinfo_v8->link_mode;
else
return;
@@ -4020,19 +5076,43 @@ static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev)
_write_scbd(rtwdev, BTC_WSCB_RXSCAN_PRI, (bool)(!!bt->scan_rx_low_pri));
}
-/* TODO add these functions */
static void _action_common(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_wl_smap *wl_smap = &wl->status.map;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u32 bt_rom_code_id, bt_fw_ver;
_set_btg_ctrl(rtwdev);
+ _set_wl_preagc_ctrl(rtwdev);
_set_wl_tx_limit(rtwdev);
_set_bt_afh_info(rtwdev);
_set_bt_rx_agc(rtwdev);
_set_rf_trx_para(rtwdev);
_set_bt_rx_scan_pri(rtwdev);
+ bt_rom_code_id = chip_id_to_bt_rom_code_id(rtwdev->btc.ver->chip_id);
+ bt_fw_ver = bt->ver_info.fw & 0xffff;
+ if (bt->enable.now &&
+ (bt_fw_ver == 0 ||
+ (bt_fw_ver == bt_rom_code_id && bt->run_patch_code && rtwdev->chip->scbd)))
+ rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, 1);
+ else
+ rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, 0);
+
+ if (dm->run_reason == BTC_RSN_NTFY_INIT ||
+ dm->run_reason == BTC_RSN_NTFY_RADIO_STATE ||
+ dm->run_reason == BTC_RSN_NTFY_POWEROFF) {
+ _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
+
+ if (wl_smap->rf_off == 1 || wl_smap->lps != BTC_LPS_OFF)
+ rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, 0);
+ else
+ rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_MREG, 1);
+ }
+
if (wl->scbd_change) {
rtw89_mac_cfg_sb(rtwdev, wl->scbd);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], write scbd: 0x%08x\n",
@@ -4129,6 +5209,30 @@ static void _action_wl_2g_sta(struct rtw89_dev *rtwdev)
_action_by_bt(rtwdev);
}
+static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ u16 policy_type = BTC_CXP_OFF_BT;
+
+ if (btc->ant_type == BTC_ANT_SHARED) {
+ if (btc->cx.wl.status.map._4way)
+ policy_type = BTC_CXP_OFFE_WL;
+ else if (btc->cx.wl.status.val & btc_scanning_map.val)
+ policy_type = BTC_CXP_OFFE_2GBWMIXB;
+ else if (btc->cx.bt.link_info.profile_cnt.now == 0)
+ policy_type = BTC_CXP_OFFE_2GISOB;
+ else
+ policy_type = BTC_CXP_OFFE_2GBWISOB;
+ } else { /* dedicated-antenna */
+ policy_type = BTC_CXP_OFF_EQ0;
+ }
+
+ btc->dm.e2g_slot_limit = BTC_E2G_LIMIT_DEF;
+
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
+ _set_policy(rtwdev, policy_type, BTC_ACT_WL_25G_MCC);
+}
+
static void _action_wl_scan(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -4136,14 +5240,7 @@ static void _action_wl_scan(struct rtw89_dev *rtwdev)
struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
- _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED)
- _set_policy(rtwdev, BTC_CXP_OFFE_DEF,
- BTC_RSN_NTFY_SCAN_START);
- else
- _set_policy(rtwdev, BTC_CXP_OFF_EQ0,
- BTC_RSN_NTFY_SCAN_START);
-
+ _action_wl_25g_mcc(rtwdev);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], Scan offload!\n");
} else if (rtwdev->dbcc_en) {
if (wl_dinfo->real_band[RTW89_PHY_0] != RTW89_BAND_2G &&
@@ -4159,30 +5256,12 @@ static void _action_wl_scan(struct rtw89_dev *rtwdev)
}
}
-static void _action_wl_25g_mcc(struct rtw89_dev *rtwdev)
-{
- struct rtw89_btc *btc = &rtwdev->btc;
-
- _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W25G);
-
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
- if (btc->cx.bt.link_info.profile_cnt.now == 0)
- _set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
- BTC_ACT_WL_25G_MCC);
- else
- _set_policy(rtwdev, BTC_CXP_OFFE_DEF,
- BTC_ACT_WL_25G_MCC);
- } else { /* dedicated-antenna */
- _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_25G_MCC);
- }
-}
-
static void _action_wl_2g_mcc(struct rtw89_dev *rtwdev)
{ struct rtw89_btc *btc = &rtwdev->btc;
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
if (btc->cx.bt.link_info.profile_cnt.now == 0)
_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
BTC_ACT_WL_2G_MCC);
@@ -4200,7 +5279,7 @@ static void _action_wl_2g_scc(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
if (btc->cx.bt.link_info.profile_cnt.now == 0)
_set_policy(rtwdev,
BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_SCC);
@@ -4222,7 +5301,7 @@ static void _action_wl_2g_scc_v1(struct rtw89_dev *rtwdev)
u16 policy_type = BTC_CXP_OFF_BT;
u32 dur;
- if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) {
+ if (btc->ant_type == BTC_ANT_DEDICATED) {
policy_type = BTC_CXP_OFF_EQ0;
} else {
/* shared-antenna */
@@ -4284,7 +5363,7 @@ static void _action_wl_2g_scc_v2(struct rtw89_dev *rtwdev)
u16 policy_type = BTC_CXP_OFF_BT;
u32 dur;
- if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED) {
+ if (btc->ant_type == BTC_ANT_DEDICATED) {
policy_type = BTC_CXP_OFF_EQ0;
} else {
/* shared-antenna */
@@ -4336,13 +5415,38 @@ static void _action_wl_2g_scc_v2(struct rtw89_dev *rtwdev)
_set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
}
+static void _action_wl_2g_scc_v8(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u16 policy_type = BTC_CXP_OFF_BT;
+
+ if (btc->ant_type == BTC_ANT_SHARED) {
+ if (wl->status.map._4way)
+ policy_type = BTC_CXP_OFFE_WL;
+ else if (bt->link_info.status.map.connect == 0)
+ policy_type = BTC_CXP_OFFE_2GISOB;
+ else
+ policy_type = BTC_CXP_OFFE_2GBWISOB;
+ } else {
+ policy_type = BTC_CXP_OFF_EQ0;
+ }
+
+ dm->e2g_slot_limit = BTC_E2G_LIMIT_DEF;
+
+ _set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
+ _set_policy(rtwdev, policy_type, BTC_ACT_WL_2G_SCC);
+}
+
static void _action_wl_2g_ap(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
+ if (btc->ant_type == BTC_ANT_SHARED) {
if (btc->cx.bt.link_info.profile_cnt.now == 0)
_set_policy(rtwdev, BTC_CXP_OFFE_DEF2,
BTC_ACT_WL_2G_AP);
@@ -4359,7 +5463,7 @@ static void _action_wl_2g_go(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
if (btc->cx.bt.link_info.profile_cnt.now == 0)
_set_policy(rtwdev,
BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_GO);
@@ -4377,7 +5481,7 @@ static void _action_wl_2g_gc(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
_action_by_bt(rtwdev);
} else {/* dedicated-antenna */
_set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_2G_GC);
@@ -4390,7 +5494,7 @@ static void _action_wl_2g_nan(struct rtw89_dev *rtwdev)
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
- if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
+ if (btc->ant_type == BTC_ANT_SHARED) { /* shared-antenna */
if (btc->cx.bt.link_info.profile_cnt.now == 0)
_set_policy(rtwdev,
BTC_CXP_OFFE_DEF2, BTC_ACT_WL_2G_NAN);
@@ -4928,6 +6032,312 @@ static void _update_wl_info_v2(struct rtw89_dev *rtwdev)
#define BTC_CHK_HANG_MAX 3
#define BTC_SCB_INV_VALUE GENMASK(31, 0)
+static u8 _get_role_link_mode(u8 role)
+{
+ switch (role) {
+ case RTW89_WIFI_ROLE_STATION:
+ return BTC_WLINK_2G_STA;
+ case RTW89_WIFI_ROLE_P2P_GO:
+ return BTC_WLINK_2G_GO;
+ case RTW89_WIFI_ROLE_P2P_CLIENT:
+ return BTC_WLINK_2G_GC;
+ case RTW89_WIFI_ROLE_AP:
+ return BTC_WLINK_2G_AP;
+ default:
+ return BTC_WLINK_OTHER;
+ }
+}
+
+static bool _chk_role_ch_group(const struct rtw89_btc_chdef *r1,
+ const struct rtw89_btc_chdef *r2)
+{
+ if (r1->chan != r2->chan) { /* primary ch is different */
+ return false;
+ } else if (r1->bw == RTW89_CHANNEL_WIDTH_40 &&
+ r2->bw == RTW89_CHANNEL_WIDTH_40) {
+ if (r1->offset != r2->offset)
+ return false;
+ }
+ return true;
+}
+
+static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch,
+ u8 *phy, u8 *role, u8 *dbcc_2g_phy)
+{
+ struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
+ bool is_2g_ch_exist = false, is_multi_role_in_2g_phy = false;
+ u8 j, k, dbcc_2g_cid, dbcc_2g_cid2;
+
+ /* find out the 2G-PHY by connect-id ->ch */
+ for (j = 0; j < wl_rinfo->connect_cnt; j++) {
+ if (ch[j].center_ch <= 14) {
+ is_2g_ch_exist = true;
+ break;
+ }
+ }
+
+ /* If no any 2G-port exist, it's impossible because 5G-exclude */
+ if (!is_2g_ch_exist)
+ return BTC_WLINK_OTHER;
+
+ dbcc_2g_cid = j;
+ *dbcc_2g_phy = phy[dbcc_2g_cid];
+
+ /* connect_cnt <= 2 */
+ if (wl_rinfo->connect_cnt < BTC_TDMA_WLROLE_MAX)
+ return (_get_role_link_mode((role[dbcc_2g_cid])));
+
+ /* find the other-port in the 2G-PHY, ex: PHY-0:6G, PHY1: mcc/scc */
+ for (k = 0; k < wl_rinfo->connect_cnt; k++) {
+ if (k == dbcc_2g_cid)
+ continue;
+
+ if (phy[k] == *dbcc_2g_phy) {
+ is_multi_role_in_2g_phy = true;
+ dbcc_2g_cid2 = k;
+ break;
+ }
+ }
+
+ /* Single-role in 2G-PHY */
+ if (!is_multi_role_in_2g_phy)
+ return (_get_role_link_mode(role[dbcc_2g_cid]));
+
+ /* 2-role in 2G-PHY */
+ if (ch[dbcc_2g_cid2].center_ch > 14)
+ return BTC_WLINK_25G_MCC;
+ else if (_chk_role_ch_group(&ch[dbcc_2g_cid], &ch[dbcc_2g_cid2]))
+ return BTC_WLINK_2G_SCC;
+ else
+ return BTC_WLINK_2G_MCC;
+}
+
+static void _update_role_link_mode(struct rtw89_dev *rtwdev,
+ bool client_joined, u32 noa)
+{
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &rtwdev->btc.cx.wl.role_info_v8;
+ u32 type = BTC_WLMROLE_NONE, dur = 0;
+ u32 wl_role = wl_rinfo->role_map;
+
+ /* if no client_joined, don't care P2P-GO/AP role */
+ if (((wl_role & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
+ (wl_role & BIT(RTW89_WIFI_ROLE_AP))) && !client_joined) {
+ if (wl_rinfo->link_mode == BTC_WLINK_2G_SCC) {
+ wl_rinfo->link_mode = BTC_WLINK_2G_STA;
+ wl_rinfo->connect_cnt--;
+ } else if (wl_rinfo->link_mode == BTC_WLINK_2G_GO ||
+ wl_rinfo->link_mode == BTC_WLINK_2G_AP) {
+ wl_rinfo->link_mode = BTC_WLINK_NOLINK;
+ wl_rinfo->connect_cnt--;
+ }
+ }
+
+ /* Identify 2-Role type */
+ if (wl_rinfo->connect_cnt >= 2 &&
+ (wl_rinfo->link_mode == BTC_WLINK_2G_SCC ||
+ wl_rinfo->link_mode == BTC_WLINK_2G_MCC ||
+ wl_rinfo->link_mode == BTC_WLINK_25G_MCC ||
+ wl_rinfo->link_mode == BTC_WLINK_5G)) {
+ if ((wl_role & BIT(RTW89_WIFI_ROLE_P2P_GO)) ||
+ (wl_role & BIT(RTW89_WIFI_ROLE_AP)))
+ type = noa ? BTC_WLMROLE_STA_GO_NOA : BTC_WLMROLE_STA_GO;
+ else if (wl_role & BIT(RTW89_WIFI_ROLE_P2P_CLIENT))
+ type = noa ? BTC_WLMROLE_STA_GC_NOA : BTC_WLMROLE_STA_GC;
+ else
+ type = BTC_WLMROLE_STA_STA;
+
+ dur = noa;
+ }
+
+ wl_rinfo->mrole_type = type;
+ wl_rinfo->mrole_noa_duration = dur;
+}
+
+static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id,
+ enum btc_role_state state)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER];
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8;
+ struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
+ bool client_joined = false, b2g = false, b5g = false;
+ u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
+ u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {};
+ u8 dbcc_en = 0, pta_req_band = RTW89_MAC_0;
+ u8 i, j, cnt = 0, cnt_2g = 0, cnt_5g = 0;
+ struct rtw89_btc_wl_link_info *wl_linfo;
+ struct rtw89_btc_wl_rlink *rlink = NULL;
+ u8 dbcc_2g_phy = RTW89_PHY_0;
+ u8 mode = BTC_WLINK_NOLINK;
+ u32 noa_dur = 0;
+
+ if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id > RTW89_MAC_1)
+ return;
+
+ /* Extract wl->link_info[role_id][rlink_id] to wl->role_info
+ * role_id: role index
+ * rlink_id: rlink index (= HW-band index)
+ * pid: port_index
+ */
+
+ wl_linfo = &wl->rlink_info[role_id][rlink_id];
+ if (wl_linfo->connected == MLME_LINKING)
+ return;
+
+ rlink = &wl_rinfo->rlink[role_id][rlink_id];
+ rlink->role = wl_linfo->role;
+ rlink->active = wl_linfo->active; /* Doze or not */
+ rlink->pid = wl_linfo->pid;
+ rlink->phy = wl_linfo->phy;
+ rlink->rf_band = wl_linfo->band;
+ rlink->ch = wl_linfo->ch;
+ rlink->bw = wl_linfo->bw;
+ rlink->noa = wl_linfo->noa;
+ rlink->noa_dur = wl_linfo->noa_duration / 1000;
+ rlink->client_cnt = wl_linfo->client_cnt;
+ rlink->mode = wl_linfo->mode;
+
+ switch (wl_linfo->connected) {
+ case MLME_NO_LINK:
+ rlink->connected = 0;
+ if (rlink->role == RTW89_WIFI_ROLE_STATION)
+ btc->dm.leak_ap = 0;
+ break;
+ case MLME_LINKED:
+ rlink->connected = 1;
+ break;
+ default:
+ return;
+ }
+
+ wl->is_5g_hi_channel = false;
+ wl->bg_mode = false;
+ wl_rinfo->role_map = 0;
+ wl_rinfo->p2p_2g = 0;
+ memset(cid_ch, 0, sizeof(cid_ch));
+
+ for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) {
+ for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) {
+ rlink = &wl_rinfo->rlink[i][j];
+
+ if (!rlink->active || !rlink->connected)
+ continue;
+
+ cnt++;
+ wl_rinfo->role_map |= BIT(rlink->role);
+
+ /* only if client connect for p2p-Go/AP */
+ if ((rlink->role == RTW89_WIFI_ROLE_P2P_GO ||
+ rlink->role == RTW89_WIFI_ROLE_AP) &&
+ rlink->client_cnt > 1)
+ client_joined = true;
+
+ /* Identufy if P2P-Go (GO/GC/AP) exist at 2G band*/
+ if (rlink->rf_band == RTW89_BAND_2G &&
+ (client_joined || rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT))
+ wl_rinfo->p2p_2g = 1;
+
+ /* only one noa-role exist */
+ if (rlink->noa && rlink->noa_dur > 0)
+ noa_dur = rlink->noa_dur;
+
+ /* for WL 5G-Rx interfered with BT issue */
+ if (rlink->rf_band == RTW89_BAND_5G && rlink->ch >= 100)
+ wl->is_5g_hi_channel = 1;
+
+ if ((rlink->mode & BIT(BTC_WL_MODE_11B)) ||
+ (rlink->mode & BIT(BTC_WL_MODE_11G)))
+ wl->bg_mode = 1;
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT)
+ continue;
+
+ cid_ch[cnt - 1] = wl_linfo->chdef;
+ cid_phy[cnt - 1] = rlink->phy;
+ cid_role[cnt - 1] = rlink->role;
+
+ if (rlink->rf_band != RTW89_BAND_2G) {
+ cnt_5g++;
+ b5g = true;
+ } else {
+ cnt_2g++;
+ b2g = true;
+ }
+ }
+ }
+
+ if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC] rlink cnt_2g=%d cnt_5g=%d\n", cnt_2g, cnt_5g);
+ rtw89_warn(rtwdev, "not support MLO feature yet");
+ } else {
+ dbcc_en = rtwdev->dbcc_en;
+
+ /* Be careful to change the following sequence!! */
+ if (cnt == 0) {
+ mode = BTC_WLINK_NOLINK;
+ } else if (!b2g && b5g) {
+ mode = BTC_WLINK_5G;
+ } else if (wl_rinfo->role_map & BIT(RTW89_WIFI_ROLE_NAN)) {
+ mode = BTC_WLINK_2G_NAN;
+ } else if (cnt > BTC_TDMA_WLROLE_MAX) {
+ mode = BTC_WLINK_OTHER;
+ } else if (dbcc_en) {
+ mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role,
+ &dbcc_2g_phy);
+ } else if (b2g && b5g && cnt == 2) {
+ mode = BTC_WLINK_25G_MCC;
+ } else if (!b5g && cnt == 2) { /* cnt_connect = 2 */
+ if (_chk_role_ch_group(&cid_ch[0], &cid_ch[cnt - 1]))
+ mode = BTC_WLINK_2G_SCC;
+ else
+ mode = BTC_WLINK_2G_MCC;
+ } else if (!b5g && cnt == 1) { /* cnt_connect = 1 */
+ mode = _get_role_link_mode(cid_role[0]);
+ }
+ }
+
+ wl_rinfo->link_mode = mode;
+ wl_rinfo->connect_cnt = cnt;
+ if (wl_rinfo->connect_cnt == 0)
+ wl_rinfo->role_map = BIT(RTW89_WIFI_ROLE_NONE);
+ _update_role_link_mode(rtwdev, client_joined, noa_dur);
+
+ wl_rinfo->dbcc_2g_phy = dbcc_2g_phy;
+ if (wl_rinfo->dbcc_en != dbcc_en) {
+ wl_rinfo->dbcc_en = dbcc_en;
+ wl_rinfo->dbcc_chg = 1;
+ btc->cx.cnt_wl[BTC_WCNT_DBCC_CHG]++;
+ } else {
+ wl_rinfo->dbcc_chg = 0;
+ }
+
+ if (wl_rinfo->dbcc_en) {
+ memset(wl_dinfo, 0, sizeof(struct rtw89_btc_wl_dbcc_info));
+
+ if (mode == BTC_WLINK_5G) {
+ pta_req_band = RTW89_PHY_0;
+ wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_5G;
+ wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_2G;
+ } else if (wl_rinfo->dbcc_2g_phy == RTW89_PHY_1) {
+ pta_req_band = RTW89_PHY_1;
+ wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_5G;
+ wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_2G;
+ } else {
+ pta_req_band = RTW89_PHY_0;
+ wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_2G;
+ wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_5G;
+ }
+ _update_dbcc_band(rtwdev, RTW89_PHY_0);
+ _update_dbcc_band(rtwdev, RTW89_PHY_1);
+ }
+
+ wl_rinfo->pta_req_band = pta_req_band;
+ _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE);
+}
+
void rtw89_coex_act1_work(struct work_struct *work)
{
struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev,
@@ -5011,8 +6421,7 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
return;
}
- if (!(val & BTC_BSCB_ON) ||
- btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] >= BTC_CHK_HANG_MAX)
+ if (!(val & BTC_BSCB_ON))
bt->enable.now = 0;
else
bt->enable.now = 1;
@@ -5038,6 +6447,9 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
bt->link_info.a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT);
+ bt->lna_constrain = !!(val & BTC_BSCB_BT_LNAB0) +
+ !!(val & BTC_BSCB_BT_LNAB1) * 2 + 4;
+
/* if rfk run 1->0 */
if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
status_change = true;
@@ -5084,7 +6496,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
- u8 mode;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
+ u8 mode, igno_bt, always_freerun;
lockdep_assert_held(&rtwdev->mutex);
@@ -5098,23 +6511,33 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
mode = wl_rinfo_v1->link_mode;
else if (ver->fwlrole == 2)
mode = wl_rinfo_v2->link_mode;
+ else if (ver->fwlrole == 8)
+ mode = wl_rinfo_v8->link_mode;
else
return;
+ if (ver->fcxctrl == 7) {
+ igno_bt = btc->ctrl.ctrl_v7.igno_bt;
+ always_freerun = btc->ctrl.ctrl_v7.always_freerun;
+ } else {
+ igno_bt = btc->ctrl.ctrl.igno_bt;
+ always_freerun = btc->ctrl.ctrl.always_freerun;
+ }
+
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): reason=%d, mode=%d\n",
__func__, reason, mode);
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): wl_only=%d, bt_only=%d\n",
__func__, dm->wl_only, dm->bt_only);
/* Be careful to change the following function sequence!! */
- if (btc->ctrl.manual) {
+ if (btc->manual_ctrl) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): return for Manual CTRL!!\n",
__func__);
return;
}
- if (btc->ctrl.igno_bt &&
+ if (igno_bt &&
(reason == BTC_RSN_UPDATE_BT_INFO ||
reason == BTC_RSN_UPDATE_BT_SCBD)) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -5131,40 +6554,47 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
}
if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
- wl->status.map.lps_pre == wl->status.map.lps &&
- (reason == BTC_RSN_NTFY_POWEROFF ||
- reason == BTC_RSN_NTFY_RADIO_STATE)) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): return for WL rf off state no change!!\n",
- __func__);
- return;
+ wl->status.map.lps_pre == wl->status.map.lps) {
+ if (reason == BTC_RSN_NTFY_POWEROFF ||
+ reason == BTC_RSN_NTFY_RADIO_STATE) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return for WL rf off state no change!!\n",
+ __func__);
+ return;
+ }
+ if (wl->status.map.rf_off == 1 ||
+ wl->status.map.lps == BTC_LPS_RF_OFF) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return for WL rf off state!!\n",
+ __func__);
+ return;
+ }
}
+ dm->freerun = false;
dm->cnt_dm[BTC_DCNT_RUN]++;
dm->fddt_train = BTC_FDDT_DISABLE;
+ bt->scan_rx_low_pri = false;
+ igno_bt = false;
- if (btc->ctrl.always_freerun) {
+ if (always_freerun) {
_action_freerun(rtwdev);
- btc->ctrl.igno_bt = true;
+ igno_bt = true;
goto exit;
}
if (dm->wl_only) {
_action_wl_only(rtwdev);
- btc->ctrl.igno_bt = true;
+ igno_bt = true;
goto exit;
}
if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) {
- _action_wl_off(rtwdev);
- btc->ctrl.igno_bt = true;
+ _action_wl_off(rtwdev, mode);
+ igno_bt = true;
goto exit;
}
- btc->ctrl.igno_bt = false;
- dm->freerun = false;
- bt->scan_rx_low_pri = false;
-
if (reason == BTC_RSN_NTFY_INIT) {
_action_wl_init(rtwdev);
goto exit;
@@ -5189,12 +6619,14 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA ||
mode == BTC_WLINK_5G) {
_action_wl_scan(rtwdev);
+ bt->scan_rx_low_pri = false;
goto exit;
}
}
if (wl->status.map.scan) {
_action_wl_scan(rtwdev);
+ bt->scan_rx_low_pri = false;
goto exit;
}
@@ -5227,6 +6659,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
_action_wl_2g_scc_v1(rtwdev);
else if (ver->fwlrole == 2)
_action_wl_2g_scc_v2(rtwdev);
+ else if (ver->fwlrole == 8)
+ _action_wl_2g_scc_v8(rtwdev);
break;
case BTC_WLINK_2G_MCC:
bt->scan_rx_low_pri = true;
@@ -5249,6 +6683,10 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
exit:
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): exit\n", __func__);
+ if (ver->fcxctrl == 7)
+ btc->ctrl.ctrl_v7.igno_bt = igno_bt;
+ else
+ btc->ctrl.ctrl.igno_bt = igno_bt;
_action_common(rtwdev);
}
@@ -5284,16 +6722,26 @@ static void _set_init_info(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- dm->init_info.wl_only = (u8)dm->wl_only;
- dm->init_info.bt_only = (u8)dm->bt_only;
- dm->init_info.wl_init_ok = (u8)wl->status.map.init_ok;
- dm->init_info.dbcc_en = rtwdev->dbcc_en;
- dm->init_info.cx_other = btc->cx.other.type;
- dm->init_info.wl_guard_ch = chip->afh_guard_ch;
- dm->init_info.module = btc->mdinfo;
+ if (ver->fcxinit == 7) {
+ dm->init_info.init_v7.wl_only = (u8)dm->wl_only;
+ dm->init_info.init_v7.bt_only = (u8)dm->bt_only;
+ dm->init_info.init_v7.wl_init_ok = (u8)wl->status.map.init_ok;
+ dm->init_info.init_v7.cx_other = btc->cx.other.type;
+ dm->init_info.init_v7.wl_guard_ch = chip->afh_guard_ch;
+ dm->init_info.init_v7.module = btc->mdinfo.md_v7;
+ } else {
+ dm->init_info.init.wl_only = (u8)dm->wl_only;
+ dm->init_info.init.bt_only = (u8)dm->bt_only;
+ dm->init_info.init.wl_init_ok = (u8)wl->status.map.init_ok;
+ dm->init_info.init.dbcc_en = rtwdev->dbcc_en;
+ dm->init_info.init.cx_other = btc->cx.other.type;
+ dm->init_info.init.wl_guard_ch = chip->afh_guard_ch;
+ dm->init_info.init.module = btc->mdinfo.md;
+ }
}
void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
@@ -5302,15 +6750,20 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_btc_ver *ver = btc->ver;
_reset_btc_var(rtwdev, BTC_RESET_ALL);
btc->dm.run_reason = BTC_RSN_NONE;
btc->dm.run_action = BTC_ACT_NONE;
- btc->ctrl.igno_bt = true;
+ if (ver->fcxctrl == 7)
+ btc->ctrl.ctrl_v7.igno_bt = true;
+ else
+ btc->ctrl.ctrl.igno_bt = true;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): mode=%d\n", __func__, mode);
+ wl->coex_mode = mode;
dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
@@ -5339,8 +6792,8 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
_set_init_info(rtwdev);
_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR);
- rtw89_btc_fw_set_slots(rtwdev, CXST_MAX, dm->slot);
btc_fw_set_monreg(rtwdev);
+ rtw89_btc_fw_set_slots(rtwdev);
_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
@@ -5355,6 +6808,10 @@ void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): phy_idx=%d, band=%d\n",
__func__, phy_idx, band);
+
+ if (phy_idx >= RTW89_PHY_MAX)
+ return;
+
btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
wl->status.map.scan = true;
wl->scan_info.band[phy_idx] = band;
@@ -5399,6 +6856,10 @@ void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): phy_idx=%d, band=%d\n",
__func__, phy_idx, band);
+
+ if (phy_idx >= RTW89_PHY_MAX)
+ return;
+
btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
wl->scan_info.band[phy_idx] = band;
@@ -5520,6 +6981,53 @@ void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work)
mutex_unlock(&rtwdev->mutex);
}
+static u8 _update_bt_rssi_level(struct rtw89_dev *rtwdev, u8 rssi)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ u8 *rssi_st, rssi_th, rssi_level = 0;
+ u8 i;
+
+ /* for rssi locate in which {40, 36, 31, 28}
+ * if rssi >= 40% (-60dBm) --> rssi_level = 4
+ * if 36% <= rssi < 40% --> rssi_level = 3
+ * if 31% <= rssi < 36% --> rssi_level = 2
+ * if 28% <= rssi < 31% --> rssi_level = 1
+ * if rssi < 28% --> rssi_level = 0
+ */
+
+ /* check if rssi across bt_rssi_thres boundary */
+ for (i = 0; i < BTC_BT_RSSI_THMAX; i++) {
+ rssi_th = chip->bt_rssi_thres[i];
+ rssi_st = &bt->link_info.rssi_state[i];
+
+ *rssi_st = _update_rssi_state(rtwdev, *rssi_st, rssi, rssi_th);
+
+ if (BTC_RSSI_HIGH(*rssi_st)) {
+ rssi_level = BTC_BT_RSSI_THMAX - i;
+ break;
+ }
+ }
+ return rssi_level;
+}
+
+static void _update_zb_coex_tbl(struct rtw89_dev *rtwdev)
+{
+ u8 mode = rtwdev->btc.cx.wl.role_info.link_mode;
+ u32 zb_tbl0 = 0xda5a5a5a, zb_tbl1 = 0xda5a5a5a;
+
+ if (mode == BTC_WLINK_5G || rtwdev->btc.dm.freerun) {
+ zb_tbl0 = 0xffffffff;
+ zb_tbl1 = 0xffffffff;
+ } else if (mode == BTC_WLINK_25G_MCC) {
+ zb_tbl0 = 0xffffffff; /* for E5G slot */
+ zb_tbl1 = 0xda5a5a5a; /* for E2G slot */
+ }
+ rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_0, zb_tbl0);
+ rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_1, zb_tbl1);
+}
+
#define BT_PROFILE_PROTOCOL_MASK GENMASK(7, 4)
static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
@@ -5595,7 +7103,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
btinfo.val = bt->raw_info[BTC_BTINFO_H0];
/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
- btc->dm.trx_info.bt_rssi = b->rssi;
+ bt->rssi_level = _update_bt_rssi_level(rtwdev, b->rssi);
+ btc->dm.trx_info.bt_rssi = bt->rssi_level;
/* parse raw info high-Byte1 */
btinfo.val = bt->raw_info[BTC_BTINFO_H1];
@@ -5656,17 +7165,11 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
_run_coex(rtwdev, BTC_RSN_UPDATE_BT_INFO);
}
-enum btc_wl_mode {
- BTC_WL_MODE_HT = 0,
- BTC_WL_MODE_VHT = 1,
- BTC_WL_MODE_HE = 2,
- BTC_WL_MODE_NUM,
-};
-
void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta, enum btc_role_state state)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
struct ieee80211_sta *sta = rtwsta_to_sta(rtwsta);
struct rtw89_btc *btc = &rtwdev->btc;
@@ -5674,7 +7177,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_wl_link_info r = {0};
struct rtw89_btc_wl_link_info *wlinfo = NULL;
- u8 mode = 0;
+ u8 mode = 0, rlink_id, link_mode_ori, pta_req_mac_ori, wa_type;
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], state=%d\n", state);
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -5724,6 +7227,10 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
r.band = chan->band_type;
r.ch = chan->channel;
r.bw = chan->band_width;
+ r.chdef.band = chan->band_type;
+ r.chdef.center_ch = chan->channel;
+ r.chdef.bw = chan->band_width;
+ r.chdef.chan = chan->primary_channel;
ether_addr_copy(r.mac_addr, rtwvif->mac_addr);
if (rtwsta && vif->type == NL80211_IFTYPE_STATION)
@@ -5733,13 +7240,37 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif
wlinfo = &wl->link_info[r.pid];
- memcpy(wlinfo, &r, sizeof(*wlinfo));
- if (ver->fwlrole == 0)
+ rlink_id = 0; /* to do */
+ if (ver->fwlrole == 0) {
+ *wlinfo = r;
_update_wl_info(rtwdev);
- else if (ver->fwlrole == 1)
+ } else if (ver->fwlrole == 1) {
+ *wlinfo = r;
_update_wl_info_v1(rtwdev);
- else if (ver->fwlrole == 2)
+ } else if (ver->fwlrole == 2) {
+ *wlinfo = r;
_update_wl_info_v2(rtwdev);
+ } else if (ver->fwlrole == 8) {
+ wlinfo = &wl->rlink_info[r.pid][rlink_id];
+ *wlinfo = r;
+ link_mode_ori = wl->role_info_v8.link_mode;
+ pta_req_mac_ori = wl->pta_req_mac;
+ _update_wl_info_v8(rtwdev, r.pid, rlink_id, state);
+
+ if (wl->role_info_v8.link_mode != link_mode_ori) {
+ wl->role_info_v8.link_mode_chg = 1;
+ if (ver->fcxinit == 7)
+ wa_type = btc->mdinfo.md_v7.wa_type;
+ else
+ wa_type = btc->mdinfo.md.wa_type;
+
+ if (wa_type & BTC_WA_HFP_ZB)
+ _update_zb_coex_tbl(rtwdev);
+ }
+
+ if (wl->pta_req_mac != pta_req_mac_ori)
+ wl->pta_reg_mac_chg = 1;
+ }
if (wlinfo->role == RTW89_WIFI_ROLE_STATION &&
wlinfo->connected == MLME_NO_LINK)
@@ -5798,22 +7329,22 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta
chip->ops->btc_init_cfg(rtwdev);
} else {
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
- if (rf_state == BTC_RFCTRL_WL_OFF)
+ if (rf_state == BTC_RFCTRL_FW_CTRL)
+ _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
+ else if (rf_state == BTC_RFCTRL_WL_OFF)
_write_scbd(rtwdev, BTC_WSCB_ALL, false);
- else if (rf_state == BTC_RFCTRL_LPS_WL_ON &&
- wl->status.map.lps_pre != BTC_LPS_OFF)
+ else
+ _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
+
+ if (rf_state == BTC_RFCTRL_LPS_WL_ON &&
+ wl->status.map.lps_pre != BTC_LPS_OFF)
_update_bt_scbd(rtwdev, true);
}
btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
- if (wl->status.map.lps_pre == BTC_LPS_OFF &&
- wl->status.map.lps_pre != wl->status.map.lps)
- btc->dm.tdma_instant_excute = 1;
- else
- btc->dm.tdma_instant_excute = 0;
+ btc->dm.tdma_instant_excute = 1;
_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
- btc->dm.tdma_instant_excute = 0;
wl->status.map.rf_off_pre = wl->status.map.rf_off;
wl->status.map.lps_pre = wl->status.map.lps;
}
@@ -5980,7 +7511,7 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
if (BTC_RSSI_LOW(link_info->rssi_state[i]))
rssi_map |= BIT(i);
- if (btc->mdinfo.ant.type == BTC_ANT_DEDICATED &&
+ if (btc->ant_type == BTC_ANT_DEDICATED &&
BTC_RSSI_CHANGE(link_info->rssi_state[i]))
is_sta_change = true;
}
@@ -6052,6 +7583,13 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
dm->trx_info.tx_tp = link_info_t->tx_throughput;
dm->trx_info.rx_tp = link_info_t->rx_throughput;
+ /* Trigger coex-run if 0x10980 reg-value is diff with coex setup */
+ if ((dm->wl_btg_rx_rb != dm->wl_btg_rx &&
+ dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) ||
+ (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
+ dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND))
+ iter_data->is_sta_change = true;
+
if (is_sta_change)
iter_data->is_sta_change = true;
@@ -6164,13 +7702,16 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m)
{
+ union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo;
const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
u32 ver_main = 0, ver_sub = 0, ver_hotfix = 0, id_branch = 0;
+ u8 cv, rfe, iso, ant_num, ant_single_pos;
if (!(dm->coex_info_map & BTC_COEX_INFO_CX))
return;
@@ -6220,11 +7761,24 @@ static void _show_cx_info(struct rtw89_dev *rtwdev, struct seq_file *m)
ver_main, ver_sub, ver_hotfix, id_branch,
bt->ver_info.fw, bt->run_patch_code ? "patch" : "ROM");
+ if (ver->fcxinit == 7) {
+ cv = md->md_v7.kt_ver;
+ rfe = md->md_v7.rfe_type;
+ iso = md->md_v7.ant.isolation;
+ ant_num = md->md_v7.ant.num;
+ ant_single_pos = md->md_v7.ant.single_pos;
+ } else {
+ cv = md->md.cv;
+ rfe = md->md.rfe_type;
+ iso = md->md.ant.isolation;
+ ant_num = md->md.ant.num;
+ ant_single_pos = md->md.ant.single_pos;
+ }
+
seq_printf(m, " %-15s : cv:%x, rfe_type:0x%x, ant_iso:%d, ant_pg:%d, %s",
- "[hw_info]", btc->mdinfo.cv, btc->mdinfo.rfe_type,
- btc->mdinfo.ant.isolation, btc->mdinfo.ant.num,
- (btc->mdinfo.ant.num > 1 ? "" : (btc->mdinfo.ant.single_pos ?
- "1Ant_Pos:S1, " : "1Ant_Pos:S0, ")));
+ "[hw_info]", cv, rfe, iso, ant_num,
+ ant_num > 1 ? "" :
+ ant_single_pos ? "1Ant_Pos:S1, " : "1Ant_Pos:S0, ");
seq_printf(m, "3rd_coex:%d, dbcc:%d, tx_num:%d, rx_num:%d\n",
btc->cx.other.type, rtwdev->dbcc_en, hal->tx_nss,
@@ -6254,7 +7808,10 @@ static void _show_wl_role_info(struct rtw89_dev *rtwdev, struct seq_file *m)
}
for (i = 0; i < RTW89_PORT_NUM; i++) {
- plink = &btc->cx.wl.link_info[i];
+ if (btc->ver->fwlrole == 8)
+ plink = &btc->cx.wl.rlink_info[i][0];
+ else
+ plink = &btc->cx.wl.link_info[i];
if (!plink->active)
continue;
@@ -6299,6 +7856,7 @@ static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m)
struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8;
u8 mode;
if (!(btc->dm.coex_info_map & BTC_COEX_INFO_WL))
@@ -6312,6 +7870,8 @@ static void _show_wl_info(struct rtw89_dev *rtwdev, struct seq_file *m)
mode = wl_rinfo_v1->link_mode;
else if (ver->fwlrole == 2)
mode = wl_rinfo_v2->link_mode;
+ else if (ver->fwlrole == 8)
+ mode = wl_rinfo_v8->link_mode;
else
return;
@@ -6397,20 +7957,26 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_bt_info *bt = &cx->bt;
struct rtw89_btc_wl_info *wl = &cx->wl;
- struct rtw89_btc_module *module = &btc->mdinfo;
struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info;
+ union rtw89_btc_module_info *md = &btc->mdinfo;
u8 *afh = bt_linfo->afh_map;
u8 *afh_le = bt_linfo->afh_map_le;
+ u8 bt_pos;
if (!(btc->dm.coex_info_map & BTC_COEX_INFO_BT))
return;
+ if (ver->fcxinit == 7)
+ bt_pos = md->md_v7.bt_pos;
+ else
+ bt_pos = md->md.bt_pos;
+
seq_puts(m, "========== [BT Status] ==========\n");
seq_printf(m, " %-15s : enable:%s, btg:%s%s, connect:%s, ",
"[status]", bt->enable.now ? "Y" : "N",
bt->btg_type ? "Y" : "N",
- (bt->enable.now && (bt->btg_type != module->bt_pos) ?
+ (bt->enable.now && (bt->btg_type != bt_pos) ?
"(efuse-mismatch!!)" : ""),
(bt_linfo->status.map.connect ? "Y" : "N"));
@@ -6437,8 +8003,9 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
bt_linfo->pan_desc.active ? "Y" : "N");
seq_printf(m,
- " %-15s : rssi:%ddBm, tx_rate:%dM, %s%s%s",
+ " %-15s : rssi:%ddBm(lvl:%d), tx_rate:%dM, %s%s%s",
"[link]", bt_linfo->rssi - 100,
+ bt->rssi_level,
bt_linfo->tx_3m ? 3 : 2,
bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
@@ -6517,11 +8084,6 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
seq_puts(m, "\n");
}
- if (bt->enable.now && bt->ver_info.fw == 0)
- rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true);
- else
- rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, false);
-
if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect)
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true);
else
@@ -6547,6 +8109,81 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
#define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e
#define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e
+#define CASE_BTC_INIT(e) case BTC_MODE_## e: return #e
+#define CASE_BTC_ANTPATH_STR(e) case BTC_ANT_##e: return #e
+#define CASE_BTC_POLUT_STR(e) case BTC_PLT_## e: return #e
+#define CASE_BTC_REGTYPE_STR(e) case REG_## e: return #e
+#define CASE_BTC_GDBG_STR(e) case BTC_DBG_## e: return #e
+
+static const char *id_to_polut(u32 id)
+{
+ switch (id) {
+ CASE_BTC_POLUT_STR(NONE);
+ CASE_BTC_POLUT_STR(GNT_BT_TX);
+ CASE_BTC_POLUT_STR(GNT_BT_RX);
+ CASE_BTC_POLUT_STR(GNT_WL);
+ CASE_BTC_POLUT_STR(BT);
+ CASE_BTC_POLUT_STR(ALL);
+ default:
+ return "unknown";
+ }
+}
+
+static const char *id_to_regtype(u32 id)
+{
+ switch (id) {
+ CASE_BTC_REGTYPE_STR(MAC);
+ CASE_BTC_REGTYPE_STR(BB);
+ CASE_BTC_REGTYPE_STR(RF);
+ CASE_BTC_REGTYPE_STR(BT_RF);
+ CASE_BTC_REGTYPE_STR(BT_MODEM);
+ CASE_BTC_REGTYPE_STR(BT_BLUEWIZE);
+ CASE_BTC_REGTYPE_STR(BT_VENDOR);
+ CASE_BTC_REGTYPE_STR(BT_LE);
+ default:
+ return "unknown";
+ }
+}
+
+static const char *id_to_gdbg(u32 id)
+{
+ switch (id) {
+ CASE_BTC_GDBG_STR(GNT_BT);
+ CASE_BTC_GDBG_STR(GNT_WL);
+ CASE_BTC_GDBG_STR(BCN_EARLY);
+ CASE_BTC_GDBG_STR(WL_NULL0);
+ CASE_BTC_GDBG_STR(WL_NULL1);
+ CASE_BTC_GDBG_STR(WL_RXISR);
+ CASE_BTC_GDBG_STR(TDMA_ENTRY);
+ CASE_BTC_GDBG_STR(A2DP_EMPTY);
+ CASE_BTC_GDBG_STR(BT_RETRY);
+ CASE_BTC_GDBG_STR(BT_RELINK);
+ CASE_BTC_GDBG_STR(SLOT_WL);
+ CASE_BTC_GDBG_STR(SLOT_BT);
+ CASE_BTC_GDBG_STR(WL_ERR);
+ CASE_BTC_GDBG_STR(WL_OK);
+ CASE_BTC_GDBG_STR(SLOT_B2W);
+ CASE_BTC_GDBG_STR(SLOT_W1);
+ CASE_BTC_GDBG_STR(SLOT_W2);
+ CASE_BTC_GDBG_STR(SLOT_W2B);
+ CASE_BTC_GDBG_STR(SLOT_B1);
+ CASE_BTC_GDBG_STR(SLOT_B2);
+ CASE_BTC_GDBG_STR(SLOT_B3);
+ CASE_BTC_GDBG_STR(SLOT_B4);
+ CASE_BTC_GDBG_STR(SLOT_LK);
+ CASE_BTC_GDBG_STR(SLOT_E2G);
+ CASE_BTC_GDBG_STR(SLOT_E5G);
+ CASE_BTC_GDBG_STR(SLOT_EBT);
+ CASE_BTC_GDBG_STR(SLOT_WLK);
+ CASE_BTC_GDBG_STR(SLOT_B1FDD);
+ CASE_BTC_GDBG_STR(BT_CHANGE);
+ CASE_BTC_GDBG_STR(WL_CCA);
+ CASE_BTC_GDBG_STR(BT_LEAUDIO);
+ CASE_BTC_GDBG_STR(USER_DEF);
+ default:
+ return "unknown";
+ }
+}
static const char *steps_to_str(u16 step)
{
@@ -6606,10 +8243,13 @@ static const char *steps_to_str(u16 step)
CASE_BTC_POLICY_STR(OFF_EQ1);
CASE_BTC_POLICY_STR(OFF_EQ2);
CASE_BTC_POLICY_STR(OFF_EQ3);
+ CASE_BTC_POLICY_STR(OFF_EQ4);
+ CASE_BTC_POLICY_STR(OFF_EQ5);
CASE_BTC_POLICY_STR(OFF_BWB0);
CASE_BTC_POLICY_STR(OFF_BWB1);
CASE_BTC_POLICY_STR(OFF_BWB2);
CASE_BTC_POLICY_STR(OFF_BWB3);
+ CASE_BTC_POLICY_STR(OFF_WL2);
CASE_BTC_POLICY_STR(OFFB_BWB0);
CASE_BTC_POLICY_STR(OFFE_DEF);
CASE_BTC_POLICY_STR(OFFE_DEF2);
@@ -6627,8 +8267,9 @@ static const char *steps_to_str(u16 step)
CASE_BTC_POLICY_STR(FIX_TD3060);
CASE_BTC_POLICY_STR(FIX_TD2080);
CASE_BTC_POLICY_STR(FIX_TDW1B1);
- CASE_BTC_POLICY_STR(FIX_TD4020);
CASE_BTC_POLICY_STR(FIX_TD4010ISO);
+ CASE_BTC_POLICY_STR(FIX_TD4010ISO_DL);
+ CASE_BTC_POLICY_STR(FIX_TD4010ISO_UL);
CASE_BTC_POLICY_STR(PFIX_TD3030);
CASE_BTC_POLICY_STR(PFIX_TD5050);
CASE_BTC_POLICY_STR(PFIX_TD2030);
@@ -6721,6 +8362,37 @@ static const char *id_to_evt(u32 id)
}
}
+static const char *id_to_mode(u8 id)
+{
+ switch (id) {
+ CASE_BTC_INIT(NORMAL);
+ CASE_BTC_INIT(WL);
+ CASE_BTC_INIT(BT);
+ CASE_BTC_INIT(WLOFF);
+ default:
+ return "unknown";
+ }
+}
+
+static const char *id_to_ant(u32 id)
+{
+ switch (id) {
+ CASE_BTC_ANTPATH_STR(WPOWERON);
+ CASE_BTC_ANTPATH_STR(WINIT);
+ CASE_BTC_ANTPATH_STR(WONLY);
+ CASE_BTC_ANTPATH_STR(WOFF);
+ CASE_BTC_ANTPATH_STR(W2G);
+ CASE_BTC_ANTPATH_STR(W5G);
+ CASE_BTC_ANTPATH_STR(W25G);
+ CASE_BTC_ANTPATH_STR(FREERUN);
+ CASE_BTC_ANTPATH_STR(WRFK);
+ CASE_BTC_ANTPATH_STR(BRFK);
+ CASE_BTC_ANTPATH_STR(MAX);
+ default:
+ return "unknown";
+ }
+}
+
static
void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data,
u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
@@ -6763,30 +8435,37 @@ static void _show_dm_step(struct rtw89_dev *rtwdev, struct seq_file *m)
static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m)
{
struct rtw89_btc *btc = &rtwdev->btc;
- struct rtw89_btc_module *module = &btc->mdinfo;
+ const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ u8 igno_bt;
if (!(dm->coex_info_map & BTC_COEX_INFO_DM))
return;
seq_printf(m, "========== [Mechanism Status %s] ==========\n",
- (btc->ctrl.manual ? "(Manual)" : "(Auto)"));
+ (btc->manual_ctrl ? "(Manual)" : "(Auto)"));
seq_printf(m,
- " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n",
+ " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n",
"[status]",
- module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated",
+ btc->ant_type == BTC_ANT_SHARED ? "shared" : "dedicated",
steps_to_str(dm->run_reason),
steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
- FIELD_GET(GENMASK(7, 0), dm->set_ant_path),
+ id_to_ant(FIELD_GET(GENMASK(7, 0), dm->set_ant_path)),
+ id_to_mode(wl->coex_mode),
dm->cnt_dm[BTC_DCNT_RUN]);
_show_dm_step(rtwdev, m);
+ if (ver->fcxctrl == 7)
+ igno_bt = btc->ctrl.ctrl_v7.igno_bt;
+ else
+ igno_bt = btc->ctrl.ctrl.igno_bt;
+
seq_printf(m, " %-15s : wl_only:%d, bt_only:%d, igno_bt:%d, free_run:%d, wl_ps_ctrl:%d, wl_mimo_ps:%d, ",
- "[dm_flag]", dm->wl_only, dm->bt_only, btc->ctrl.igno_bt,
+ "[dm_flag]", dm->wl_only, dm->bt_only, igno_bt,
dm->freerun, btc->lps, dm->wl_mimo_ps);
seq_printf(m, "leak_ap:%d, fw_offload:%s%s\n", dm->leak_ap,
@@ -6842,6 +8521,10 @@ static void _show_error(struct rtw89_dev *rtwdev, struct seq_file *m)
pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5;
except_cnt = pcysta->v5.except_cnt;
exception_map = le32_to_cpu(pcysta->v5.except_map);
+ } else if (ver->fcxcysta == 7) {
+ pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7;
+ except_cnt = pcysta->v7.except_cnt;
+ exception_map = le32_to_cpu(pcysta->v7.except_map);
} else {
return;
}
@@ -6918,22 +8601,35 @@ static void _show_fbtc_slots(struct rtw89_dev *rtwdev, struct seq_file *m)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
- struct rtw89_btc_fbtc_slot *s;
+ u16 dur, cxtype;
+ u32 tbl;
u8 i = 0;
for (i = 0; i < CXST_MAX; i++) {
- s = &dm->slot_now[i];
+ if (btc->ver->fcxslots == 1) {
+ dur = le16_to_cpu(dm->slot_now.v1[i].dur);
+ tbl = le32_to_cpu(dm->slot_now.v1[i].cxtbl);
+ cxtype = le16_to_cpu(dm->slot_now.v1[i].cxtype);
+ } else if (btc->ver->fcxslots == 7) {
+ dur = le16_to_cpu(dm->slot_now.v7[i].dur);
+ tbl = le32_to_cpu(dm->slot_now.v7[i].cxtbl);
+ cxtype = le16_to_cpu(dm->slot_now.v7[i].cxtype);
+ } else {
+ return;
+ }
+
if (i % 5 == 0)
seq_printf(m,
" %-15s : %5s[%03d/0x%x/%d]",
"[slot_list]",
id_to_slot((u32)i),
- s->dur, s->cxtbl, s->cxtype);
+ dur, tbl, cxtype);
else
seq_printf(m,
", %5s[%03d/0x%x/%d]",
id_to_slot((u32)i),
- s->dur, s->cxtbl, s->cxtype);
+ dur, tbl, cxtype);
+
if (i % 5 == 4)
seq_puts(m, "\n");
}
@@ -7461,6 +9157,136 @@ static void _show_fbtc_cysta_v5(struct rtw89_dev *rtwdev, struct seq_file *m)
}
}
+static void _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, struct seq_file *m)
+{
+ struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt;
+ struct rtw89_btc_bt_a2dp_desc *a2dp = &bt->link_info.a2dp_desc;
+ struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
+ struct rtw89_btc_fbtc_cysta_v7 *pcysta = NULL;
+ struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
+ struct rtw89_btc_rpt_cmn_info *pcinfo;
+ u16 cycle, c_begin, c_end, s_id;
+ u8 i, cnt = 0, divide_cnt;
+ u8 slot_pair;
+
+ pcinfo = &pfwinfo->rpt_fbtc_cysta.cinfo;
+ if (!pcinfo->valid)
+ return;
+
+ pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v7;
+ seq_printf(m, "\n\r %-15s : cycle:%d", "[slot_stat]",
+ le16_to_cpu(pcysta->cycles));
+
+ for (i = 0; i < CXST_MAX; i++) {
+ if (!le16_to_cpu(pcysta->slot_cnt[i]))
+ continue;
+ seq_printf(m, ", %s:%d",
+ id_to_slot(i), le16_to_cpu(pcysta->slot_cnt[i]));
+ }
+
+ if (dm->tdma_now.rxflctrl)
+ seq_printf(m, ", leak_rx:%d",
+ le32_to_cpu(pcysta->leak_slot.cnt_rximr));
+
+ if (pcysta->collision_cnt)
+ seq_printf(m, ", collision:%d", pcysta->collision_cnt);
+
+ if (pcysta->skip_cnt)
+ seq_printf(m, ", skip:%d", le16_to_cpu(pcysta->skip_cnt));
+
+ seq_printf(m, "\n\r %-15s : avg_t[wl:%d/bt:%d/lk:%d.%03d]",
+ "[cycle_stat]",
+ le16_to_cpu(pcysta->cycle_time.tavg[CXT_WL]),
+ le16_to_cpu(pcysta->cycle_time.tavg[CXT_BT]),
+ le16_to_cpu(pcysta->leak_slot.tavg) / 1000,
+ le16_to_cpu(pcysta->leak_slot.tavg) % 1000);
+ seq_printf(m, ", max_t[wl:%d/bt:%d(>%dms:%d)/lk:%d.%03d]",
+ le16_to_cpu(pcysta->cycle_time.tmax[CXT_WL]),
+ le16_to_cpu(pcysta->cycle_time.tmax[CXT_BT]),
+ dm->bt_slot_flood, dm->cnt_dm[BTC_DCNT_BT_SLOT_FLOOD],
+ le16_to_cpu(pcysta->leak_slot.tamx) / 1000,
+ le16_to_cpu(pcysta->leak_slot.tamx) % 1000);
+ seq_printf(m, ", bcn[all:%d/ok:%d/in_bt:%d/in_bt_ok:%d]",
+ le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL]),
+ le16_to_cpu(pcysta->bcn_cnt[CXBCN_ALL_OK]),
+ le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_SLOT]),
+ le16_to_cpu(pcysta->bcn_cnt[CXBCN_BT_OK]));
+
+ if (a2dp->exist) {
+ seq_printf(m,
+ "\n\r %-15s : a2dp_ept:%d, a2dp_late:%d(streak 2S:%d/max:%d)",
+ "[a2dp_stat]",
+ le16_to_cpu(pcysta->a2dp_ept.cnt),
+ le16_to_cpu(pcysta->a2dp_ept.cnt_timeout),
+ a2dp->no_empty_streak_2s, a2dp->no_empty_streak_max);
+
+ seq_printf(m, ", avg_t:%d, max_t:%d",
+ le16_to_cpu(pcysta->a2dp_ept.tavg),
+ le16_to_cpu(pcysta->a2dp_ept.tmax));
+ }
+
+ if (le16_to_cpu(pcysta->cycles) <= 1)
+ return;
+
+ /* 1 cycle = 1 wl-slot + 1 bt-slot */
+ slot_pair = BTC_CYCLE_SLOT_MAX / 2;
+
+ if (le16_to_cpu(pcysta->cycles) <= slot_pair)
+ c_begin = 1;
+ else
+ c_begin = le16_to_cpu(pcysta->cycles) - slot_pair + 1;
+
+ c_end = le16_to_cpu(pcysta->cycles);
+
+ if (a2dp->exist)
+ divide_cnt = 2;
+ else
+ divide_cnt = 6;
+
+ if (c_begin > c_end)
+ return;
+
+ for (cycle = c_begin; cycle <= c_end; cycle++) {
+ cnt++;
+ s_id = ((cycle - 1) % slot_pair) * 2;
+
+ if (cnt % divide_cnt == 1) {
+ if (a2dp->exist)
+ seq_printf(m, "\n\r %-15s : ", "[slotT_wermtan]");
+ else
+ seq_printf(m, "\n\r %-15s : ", "[slotT_rxerr]");
+ }
+
+ seq_printf(m, "->b%d", le16_to_cpu(pcysta->slot_step_time[s_id]));
+
+ if (a2dp->exist)
+ seq_printf(m, "(%d/%d/%d/%dM/%d/%d/%d)",
+ pcysta->wl_rx_err_ratio[s_id],
+ pcysta->a2dp_trx[s_id].empty_cnt,
+ pcysta->a2dp_trx[s_id].retry_cnt,
+ (pcysta->a2dp_trx[s_id].tx_rate ? 3 : 2),
+ pcysta->a2dp_trx[s_id].tx_cnt,
+ pcysta->a2dp_trx[s_id].ack_cnt,
+ pcysta->a2dp_trx[s_id].nack_cnt);
+ else
+ seq_printf(m, "(%d)", pcysta->wl_rx_err_ratio[s_id]);
+
+ seq_printf(m, "->w%d", le16_to_cpu(pcysta->slot_step_time[s_id + 1]));
+
+ if (a2dp->exist)
+ seq_printf(m, "(%d/%d/%d/%dM/%d/%d/%d)",
+ pcysta->wl_rx_err_ratio[s_id + 1],
+ pcysta->a2dp_trx[s_id + 1].empty_cnt,
+ pcysta->a2dp_trx[s_id + 1].retry_cnt,
+ (pcysta->a2dp_trx[s_id + 1].tx_rate ? 3 : 2),
+ pcysta->a2dp_trx[s_id + 1].tx_cnt,
+ pcysta->a2dp_trx[s_id + 1].ack_cnt,
+ pcysta->a2dp_trx[s_id + 1].nack_cnt);
+ else
+ seq_printf(m, "(%d)", pcysta->wl_rx_err_ratio[s_id + 1]);
+ }
+}
+
static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -7497,6 +9323,27 @@ static void _show_fbtc_nullsta(struct rtw89_dev *rtwdev, struct seq_file *m)
le32_to_cpu(ns->v1.max_t[i]) / 1000,
le32_to_cpu(ns->v1.max_t[i]) % 1000);
}
+ } else if (ver->fcxnullsta == 7) {
+ for (i = 0; i < 2; i++) {
+ seq_printf(m, " %-15s : ", "[NULL-STA]");
+ seq_printf(m, "null-%d", i);
+ seq_printf(m, "[Tx:%d/",
+ le32_to_cpu(ns->v7.result[i][4]));
+ seq_printf(m, "[ok:%d/",
+ le32_to_cpu(ns->v7.result[i][1]));
+ seq_printf(m, "fail:%d/",
+ le32_to_cpu(ns->v7.result[i][0]));
+ seq_printf(m, "on_time:%d/",
+ le32_to_cpu(ns->v7.result[i][2]));
+ seq_printf(m, "retry:%d/",
+ le32_to_cpu(ns->v7.result[i][3]));
+ seq_printf(m, "avg_t:%d.%03d/",
+ le32_to_cpu(ns->v7.tavg[i]) / 1000,
+ le32_to_cpu(ns->v7.tavg[i]) % 1000);
+ seq_printf(m, "max_t:%d.%03d]\n",
+ le32_to_cpu(ns->v7.tmax[i]) / 1000,
+ le32_to_cpu(ns->v7.tmax[i]) % 1000);
+ }
} else {
for (i = 0; i < 2; i++) {
seq_printf(m, " %-15s : ", "[NULL-STA]");
@@ -7527,10 +9374,11 @@ static void _show_fbtc_step_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_fbtc_steps_v2 *pstep = NULL;
+ const struct rtw89_btc_ver *ver = btc->ver;
u8 type, val, cnt = 0, state = 0;
bool outloop = false;
u16 i, diff_t, n_start = 0, n_stop = 0;
- u16 pos_old, pos_new;
+ u16 pos_old, pos_new, trace_step;
pcinfo = &pfwinfo->rpt_fbtc_step.cinfo;
if (!pcinfo->valid)
@@ -7547,11 +9395,16 @@ static void _show_fbtc_step_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
do {
switch (state) {
case 0:
+ if (ver->fcxctrl == 7 || ver->fcxctrl == 1)
+ trace_step = 50;
+ else
+ trace_step = btc->ctrl.ctrl.trace_step;
+
n_start = pos_old;
if (pos_new >= pos_old)
n_stop = pos_new;
else
- n_stop = btc->ctrl.trace_step - 1;
+ n_stop = trace_step - 1;
state = 1;
break;
@@ -7667,6 +9520,8 @@ static void _show_fw_dm_msg(struct rtw89_dev *rtwdev, struct seq_file *m)
_show_fbtc_cysta_v4(rtwdev, m);
else if (ver->fcxcysta == 5)
_show_fbtc_cysta_v5(rtwdev, m);
+ else if (ver->fcxcysta == 7)
+ _show_fbtc_cysta_v7(rtwdev, m);
_show_fbtc_nullsta(rtwdev, m);
@@ -7683,7 +9538,8 @@ static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt
struct rtw89_mac_ax_gnt *gnt;
u32 val, status;
- if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) {
+ if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
+ chip->chip_id == RTL8851B || chip->chip_id == RTL8852BT) {
rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status);
@@ -7718,6 +9574,47 @@ static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt
}
}
+static void _show_gpio_dbg(struct rtw89_dev *rtwdev, struct seq_file *m)
+{
+ struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
+ const struct rtw89_btc_ver *ver = rtwdev->btc.ver;
+ struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
+ union rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
+ u8 *gpio_map, i;
+ u32 en_map;
+
+ pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
+ gdbg = &rtwdev->btc.fwinfo.rpt_fbtc_gpio_dbg.finfo;
+ if (!pcinfo->valid) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
+ __func__);
+ seq_puts(m, "\n");
+ return;
+ }
+
+ if (ver->fcxgpiodbg == 7) {
+ en_map = le32_to_cpu(gdbg->v7.en_map);
+ gpio_map = gdbg->v7.gpio_map;
+ } else {
+ en_map = le32_to_cpu(gdbg->v1.en_map);
+ gpio_map = gdbg->v1.gpio_map;
+ }
+
+ if (!en_map)
+ return;
+
+ seq_printf(m, " %-15s : enable_map:0x%08x",
+ "[gpio_dbg]", en_map);
+
+ for (i = 0; i < BTC_DBG_MAX1; i++) {
+ if (!(en_map & BIT(i)))
+ continue;
+ seq_printf(m, ", %s->GPIO%d", id_to_gdbg(i), gpio_map[i]);
+ }
+ seq_puts(m, "\n");
+}
+
static void _show_mreg_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -7725,7 +9622,6 @@ static void _show_mreg_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_fbtc_mreg_val_v1 *pmreg = NULL;
- struct rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
@@ -7745,27 +9641,25 @@ static void _show_mreg_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
- /* To avoid I/O if WL LPS or power-off */
- if (!wl->status.map.lps && !wl->status.map.rf_off) {
- btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ _get_gnt(rtwdev, &gnt_cfg);
+
+ gnt = gnt_cfg.band[0];
+ seq_printf(m,
+ " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
+ "[gnt_status]",
+ chip->chip_id == RTL8852C ? "HW" :
+ btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
+ gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
+
+ gnt = gnt_cfg.band[1];
+ seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
+ gnt.gnt_wl_sw_en ? "SW" : "HW",
+ gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW",
+ gnt.gnt_bt);
- _get_gnt(rtwdev, &gnt_cfg);
- gnt = gnt_cfg.band[0];
- seq_printf(m,
- " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
- "[gnt_status]",
- chip->chip_id == RTL8852C ? "HW" :
- btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
- gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
-
- gnt = gnt_cfg.band[1];
- seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
- gnt.gnt_wl_sw_en ? "SW" : "HW",
- gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW",
- gnt.gnt_bt);
- }
pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
if (!pcinfo->valid) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -7797,29 +9691,6 @@ static void _show_mreg_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
if (i >= pmreg->reg_num)
seq_puts(m, "\n");
}
-
- pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
- if (!pcinfo->valid) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
- __func__);
- seq_puts(m, "\n");
- return;
- }
-
- gdbg = &pfwinfo->rpt_fbtc_gpio_dbg.finfo;
- if (!gdbg->en_map)
- return;
-
- seq_printf(m, " %-15s : enable_map:0x%08x",
- "[gpio_dbg]", gdbg->en_map);
-
- for (i = 0; i < BTC_DBG_MAX1; i++) {
- if (!(gdbg->en_map & BIT(i)))
- continue;
- seq_printf(m, ", %d->GPIO%d", (u32)i, gdbg->gpio_map[i]);
- }
- seq_puts(m, "\n");
}
static void _show_mreg_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
@@ -7829,7 +9700,6 @@ static void _show_mreg_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
struct rtw89_btc_fbtc_mreg_val_v2 *pmreg = NULL;
- struct rtw89_btc_fbtc_gpio_dbg *gdbg = NULL;
struct rtw89_btc_cx *cx = &btc->cx;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
@@ -7849,27 +9719,26 @@ static void _show_mreg_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
- /* To avoid I/O if WL LPS or power-off */
- if (!wl->status.map.lps && !wl->status.map.rf_off) {
- btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ _get_gnt(rtwdev, &gnt_cfg);
+
+ gnt = gnt_cfg.band[0];
+ seq_printf(m,
+ " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], polut_type:%s",
+ "[gnt_status]",
+ chip->chip_id == RTL8852C ? "HW" :
+ btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
+ gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt,
+ id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
+
+ gnt = gnt_cfg.band[1];
+ seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
+ gnt.gnt_wl_sw_en ? "SW" : "HW",
+ gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW",
+ gnt.gnt_bt);
- _get_gnt(rtwdev, &gnt_cfg);
- gnt = gnt_cfg.band[0];
- seq_printf(m,
- " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
- "[gnt_status]",
- chip->chip_id == RTL8852C ? "HW" :
- btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
- gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
-
- gnt = gnt_cfg.band[1];
- seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
- gnt.gnt_wl_sw_en ? "SW" : "HW",
- gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW",
- gnt.gnt_bt);
- }
pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
if (!pcinfo->valid) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -7901,27 +9770,74 @@ static void _show_mreg_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
if (i >= pmreg->reg_num)
seq_puts(m, "\n");
}
+}
- pcinfo = &pfwinfo->rpt_fbtc_gpio_dbg.cinfo;
- if (!pcinfo->valid) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n",
- __func__);
- seq_puts(m, "\n");
+static void _show_mreg_v7(struct rtw89_dev *rtwdev, struct seq_file *m)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
+ struct rtw89_btc_fbtc_mreg_val_v7 *pmreg = NULL;
+ struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_bt_info *bt = &cx->bt;
+ struct rtw89_mac_ax_gnt *gnt = NULL;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 i, type, cnt = 0;
+ u32 val, offset;
+
+ if (!(dm->coex_info_map & BTC_COEX_INFO_MREG))
return;
+
+ seq_puts(m, "\n\r========== [HW Status] ==========");
+
+ seq_printf(m,
+ "\n\r %-15s : WL->BT:0x%08x(cnt:%d), BT->WL:0x%08x(total:%d, bt_update:%d)",
+ "[scoreboard]", wl->scbd, cx->cnt_wl[BTC_WCNT_SCBDUPDATE],
+ bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
+ cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
+
+ /* To avoid I/O if WL LPS or power-off */
+ dm->pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+
+ seq_printf(m,
+ "\n\r %-15s : pta_owner:%s, pta_req_mac:MAC%d, rf_gnt_source: polut_type:%s",
+ "[gnt_status]",
+ rtwdev->chip->para_ver & BTC_FEAT_PTA_ONOFF_CTRL ? "HW" :
+ dm->pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
+ wl->pta_req_mac, id_to_polut(wl->bt_polut_type[wl->pta_req_mac]));
+
+ gnt = &dm->gnt.band[RTW89_PHY_0];
+
+ seq_printf(m, ", phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d]",
+ gnt->gnt_wl_sw_en ? "SW" : "HW", gnt->gnt_wl,
+ gnt->gnt_bt_sw_en ? "SW" : "HW", gnt->gnt_bt);
+
+ if (rtwdev->dbcc_en) {
+ gnt = &dm->gnt.band[RTW89_PHY_1];
+ seq_printf(m, ", phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]",
+ gnt->gnt_wl_sw_en ? "SW" : "HW", gnt->gnt_wl,
+ gnt->gnt_bt_sw_en ? "SW" : "HW", gnt->gnt_bt);
}
- gdbg = &pfwinfo->rpt_fbtc_gpio_dbg.finfo;
- if (!gdbg->en_map)
+ pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
+ if (!pcinfo->valid)
return;
- seq_printf(m, " %-15s : enable_map:0x%08x",
- "[gpio_dbg]", gdbg->en_map);
+ pmreg = &pfwinfo->rpt_fbtc_mregval.finfo.v7;
- for (i = 0; i < BTC_DBG_MAX1; i++) {
- if (!(gdbg->en_map & BIT(i)))
- continue;
- seq_printf(m, ", %d->GPIO%d", (u32)i, gdbg->gpio_map[i]);
+ for (i = 0; i < pmreg->reg_num; i++) {
+ type = (u8)le16_to_cpu(rtwdev->chip->mon_reg[i].type);
+ offset = le32_to_cpu(rtwdev->chip->mon_reg[i].offset);
+ val = le32_to_cpu(pmreg->mreg_val[i]);
+
+ if (cnt % 6 == 0)
+ seq_printf(m, "\n\r %-15s : %s_0x%x=0x%x", "[reg]",
+ id_to_regtype(type), offset, val);
+ else
+ seq_printf(m, ", %s_0x%x=0x%x",
+ id_to_regtype(type), offset, val);
+ cnt++;
}
seq_puts(m, "\n");
}
@@ -8372,6 +10288,108 @@ static void _show_summary_v105(struct rtw89_dev *rtwdev, struct seq_file *m)
cnt[BTC_NCNT_CUSTOMERIZE]);
}
+static void _show_summary_v8(struct rtw89_dev *rtwdev, struct seq_file *m)
+{
+ struct rtw89_btc_btf_fwinfo *pfwinfo = &rtwdev->btc.fwinfo;
+ struct rtw89_btc_rpt_cmn_info *pcinfo = NULL;
+ struct rtw89_btc_fbtc_rpt_ctrl_v8 *prptctrl = NULL;
+ struct rtw89_btc_cx *cx = &rtwdev->btc.cx;
+ struct rtw89_btc_dm *dm = &rtwdev->btc.dm;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ u32 *cnt = rtwdev->btc.dm.cnt_notify;
+ u32 cnt_sum = 0;
+ u8 i;
+
+ if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
+ return;
+
+ seq_printf(m, "%s", "\n\r========== [Statistics] ==========");
+
+ pcinfo = &pfwinfo->rpt_ctrl.cinfo;
+ if (pcinfo->valid && wl->status.map.lps != BTC_LPS_RF_OFF &&
+ !wl->status.map.rf_off) {
+ prptctrl = &pfwinfo->rpt_ctrl.finfo.v8;
+
+ seq_printf(m,
+ "\n\r %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d, len:%d, max:fw-%d/drv-%d), ",
+ "[summary]", pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
+ le16_to_cpu(prptctrl->rpt_info.cnt_h2c), pfwinfo->cnt_c2h,
+ le16_to_cpu(prptctrl->rpt_info.cnt_c2h),
+ le16_to_cpu(prptctrl->rpt_info.len_c2h),
+ (prptctrl->rpt_len_max_h << 8) + prptctrl->rpt_len_max_l,
+ rtwdev->btc.ver->info_buf);
+
+ seq_printf(m, "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x",
+ pfwinfo->event[BTF_EVNT_RPT],
+ le16_to_cpu(prptctrl->rpt_info.cnt),
+ le32_to_cpu(prptctrl->rpt_info.en));
+
+ if (dm->error.map.wl_fw_hang)
+ seq_puts(m, " (WL FW Hang!!)");
+
+ seq_printf(m, "\n\r %-15s : send_ok:%d, send_fail:%d, recv:%d, ",
+ "[mailbox]", le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_ok),
+ le32_to_cpu(prptctrl->bt_mbx_info.cnt_send_fail),
+ le32_to_cpu(prptctrl->bt_mbx_info.cnt_recv));
+
+ seq_printf(m, "A2DP_empty:%d(stop:%d/tx:%d/ack:%d/nack:%d)",
+ le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_empty),
+ le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_flowctrl),
+ le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_tx),
+ le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_ack),
+ le32_to_cpu(prptctrl->bt_mbx_info.a2dp.cnt_nack));
+
+ seq_printf(m,
+ "\n\r %-15s : wl_rfk[req:%d/go:%d/reject:%d/tout:%d/time:%dms]",
+ "[RFK/LPS]", cx->cnt_wl[BTC_WCNT_RFK_REQ],
+ cx->cnt_wl[BTC_WCNT_RFK_GO],
+ cx->cnt_wl[BTC_WCNT_RFK_REJECT],
+ cx->cnt_wl[BTC_WCNT_RFK_TIMEOUT],
+ wl->rfk_info.proc_time);
+
+ seq_printf(m, ", bt_rfk[req:%d]",
+ le16_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]));
+
+ seq_printf(m, ", AOAC[RF_on:%d/RF_off:%d]",
+ le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_on),
+ le16_to_cpu(prptctrl->rpt_info.cnt_aoac_rf_off));
+ } else {
+ seq_printf(m,
+ "\n\r %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d (lps=%d/rf_off=%d)",
+ "[summary]",
+ pfwinfo->cnt_h2c, pfwinfo->cnt_h2c_fail,
+ pfwinfo->cnt_c2h,
+ wl->status.map.lps, wl->status.map.rf_off);
+ }
+
+ for (i = 0; i < BTC_NCNT_NUM; i++)
+ cnt_sum += dm->cnt_notify[i];
+
+ seq_printf(m,
+ "\n\r %-15s : total=%d, show_coex_info=%d, power_on=%d, init_coex=%d, ",
+ "[notify_cnt]",
+ cnt_sum, cnt[BTC_NCNT_SHOW_COEX_INFO],
+ cnt[BTC_NCNT_POWER_ON], cnt[BTC_NCNT_INIT_COEX]);
+
+ seq_printf(m,
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d",
+ cnt[BTC_NCNT_POWER_OFF], cnt[BTC_NCNT_RADIO_STATE],
+ cnt[BTC_NCNT_ROLE_INFO], cnt[BTC_NCNT_WL_RFK],
+ cnt[BTC_NCNT_WL_STA]);
+
+ seq_printf(m,
+ "\n\r %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, switch_chbw=%d, special_pkt=%d, ",
+ "[notify_cnt]",
+ cnt[BTC_NCNT_SCAN_START], cnt[BTC_NCNT_SCAN_FINISH],
+ cnt[BTC_NCNT_SWITCH_BAND], cnt[BTC_NCNT_SWITCH_CHBW],
+ cnt[BTC_NCNT_SPECIAL_PACKET]);
+
+ seq_printf(m, "timer=%d, customerize=%d, hub_msg=%d, chg_fw=%d, send_cc=%d",
+ cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CUSTOMERIZE],
+ rtwdev->btc.hubmsg_cnt, cnt[BTC_NCNT_RESUME_DL_FW],
+ cnt[BTC_NCNT_COUNTRYCODE]);
+}
+
void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
{
struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal;
@@ -8384,7 +10402,7 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
seq_printf(m, "WL FW / BT FW %d.%d.%d.%d / NA\n",
fw_suit->major_ver, fw_suit->minor_ver,
fw_suit->sub_ver, fw_suit->sub_idex);
- seq_printf(m, "manual %d\n", btc->ctrl.manual);
+ seq_printf(m, "manual %d\n", btc->manual_ctrl);
seq_puts(m, "=========================================\n");
@@ -8409,6 +10427,10 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
_show_mreg_v1(rtwdev, m);
else if (ver->fcxmreg == 2)
_show_mreg_v2(rtwdev, m);
+ else if (ver->fcxmreg == 7)
+ _show_mreg_v7(rtwdev, m);
+
+ _show_gpio_dbg(rtwdev, m);
if (ver->fcxbtcrpt == 1)
_show_summary_v1(rtwdev, m);
@@ -8418,6 +10440,8 @@ void rtw89_btc_dump_info(struct rtw89_dev *rtwdev, struct seq_file *m)
_show_summary_v5(rtwdev, m);
else if (ver->fcxbtcrpt == 105)
_show_summary_v105(rtwdev, m);
+ else if (ver->fcxbtcrpt == 8)
+ _show_summary_v8(rtwdev, m);
}
void rtw89_coex_recognize_ver(struct rtw89_dev *rtwdev)
diff --git a/sys/contrib/dev/rtw89/coex.h b/sys/contrib/dev/rtw89/coex.h
index f16421cb30ef..0e5f268616f7 100644
--- a/sys/contrib/dev/rtw89/coex.h
+++ b/sys/contrib/dev/rtw89/coex.h
@@ -7,6 +7,10 @@
#include "core.h"
+#define BTC_H2C_MAXLEN 2020
+#define BTC_TLV_SLOT_ID_LEN_V7 1
+#define BTC_SLOT_REQ_TH 2
+
enum btc_mode {
BTC_MODE_NORMAL,
BTC_MODE_WL,
@@ -23,6 +27,7 @@ enum btc_wl_rfk_type {
BTC_WRFKT_DACK = 4,
BTC_WRFKT_RXDCK = 5,
BTC_WRFKT_TSSI = 6,
+ BTC_WRFKT_CHLK = 7,
};
#define NM_EXEC false
@@ -142,6 +147,116 @@ enum btc_lps_state {
BTC_LPS_RF_ON = 2
};
+#define R_BTC_BB_BTG_RX 0x980
+#define R_BTC_BB_PRE_AGC_S1 0x476C
+#define R_BTC_BB_PRE_AGC_S0 0x4688
+
+#define B_BTC_BB_GNT_MUX GENMASK(20, 17)
+#define B_BTC_BB_PRE_AGC_MASK GENMASK(31, 24)
+#define B_BTC_BB_PRE_AGC_VAL BIT(31)
+
+#define BTC_REG_NOTFOUND 0xff
+
+#define R_BTC_ZB_COEX_TBL_0 0xE328
+#define R_BTC_ZB_COEX_TBL_1 0xE32c
+#define R_BTC_ZB_BREAK_TBL 0xE350
+
+enum btc_ant_div_pos {
+ BTC_ANT_DIV_MAIN = 0,
+ BTC_ANT_DIV_AUX = 1,
+};
+
+enum btc_get_reg_status {
+ BTC_CSTATUS_TXDIV_POS = 0,
+ BTC_CSTATUS_RXDIV_POS = 1,
+ BTC_CSTATUS_BB_GNT_MUX = 2,
+ BTC_CSTATUS_BB_GNT_MUX_MON = 3,
+ BTC_CSTATUS_BB_PRE_AGC = 4,
+ BTC_CSTATUS_BB_PRE_AGC_MON = 5,
+};
+
+enum btc_preagc_type {
+ BTC_PREAGC_DISABLE,
+ BTC_PREAGC_ENABLE,
+ BTC_PREAGC_BB_FWCTRL,
+ BTC_PREAGC_NOTFOUND,
+};
+
+enum btc_btgctrl_type {
+ BTC_BTGCTRL_DISABLE,
+ BTC_BTGCTRL_ENABLE,
+ BTC_BTGCTRL_BB_GNT_FWCTRL,
+ BTC_BTGCTRL_BB_GNT_NOTFOUND,
+};
+
+enum btc_wa_type {
+ BTC_WA_5G_HI_CH_RX = BIT(0),
+ BTC_WA_NULL_AP = BIT(1),
+ BTC_WA_HFP_ZB = BIT(2), /* HFP PTA req bit4 define issue */
+};
+
+enum btc_3cx_type {
+ BTC_3CX_NONE = 0,
+ BTC_3CX_BT2 = BIT(0),
+ BTC_3CX_ZB = BIT(1),
+ BTC_3CX_LTE = BIT(2),
+ BTC_3CX_MAX,
+};
+
+enum btc_chip_feature {
+ BTC_FEAT_PTA_ONOFF_CTRL = BIT(0), /* on/off ctrl by HW (not 0x73[2]) */
+ BTC_FEAT_NONBTG_GWL_THRU = BIT(1), /* non-BTG GNT_WL!=0 if GNT_BT = 1 */
+ BTC_FEAT_WLAN_ACT_MUX = BIT(2), /* separate wlan_act/gnt mux */
+ BTC_FEAT_NEW_BBAPI_FLOW = BIT(3), /* new btg_ctrl/pre_agc_ctrl */
+ BTC_FEAT_MLO_SUPPORT = BIT(4),
+ BTC_FEAT_H2C_MACRO = BIT(5),
+};
+
+enum btc_wl_mode {
+ BTC_WL_MODE_11B = 0,
+ BTC_WL_MODE_11A = 1,
+ BTC_WL_MODE_11G = 2,
+ BTC_WL_MODE_HT = 3,
+ BTC_WL_MODE_VHT = 4,
+ BTC_WL_MODE_HE = 5,
+ BTC_WL_MODE_NUM,
+};
+
+enum btc_wl_gpio_debug {
+ BTC_DBG_GNT_BT = 0,
+ BTC_DBG_GNT_WL = 1,
+ BTC_DBG_BCN_EARLY = 2,
+ BTC_DBG_WL_NULL0 = 3,
+ BTC_DBG_WL_NULL1 = 4,
+ BTC_DBG_WL_RXISR = 5,
+ BTC_DBG_TDMA_ENTRY = 6,
+ BTC_DBG_A2DP_EMPTY = 7,
+ BTC_DBG_BT_RETRY = 8,
+ BTC_DBG_BT_RELINK = 9,
+ BTC_DBG_SLOT_WL = 10,
+ BTC_DBG_SLOT_BT = 11,
+ BTC_DBG_WL_ERR = 12,
+ BTC_DBG_WL_OK = 13,
+ BTC_DBG_SLOT_B2W = 14,
+ BTC_DBG_SLOT_W1 = 15,
+ BTC_DBG_SLOT_W2 = 16,
+ BTC_DBG_SLOT_W2B = 17,
+ BTC_DBG_SLOT_B1 = 18,
+ BTC_DBG_SLOT_B2 = 19,
+ BTC_DBG_SLOT_B3 = 20,
+ BTC_DBG_SLOT_B4 = 21,
+ BTC_DBG_SLOT_LK = 22,
+ BTC_DBG_SLOT_E2G = 23,
+ BTC_DBG_SLOT_E5G = 24,
+ BTC_DBG_SLOT_EBT = 25,
+ BTC_DBG_SLOT_WLK = 26,
+ BTC_DBG_SLOT_B1FDD = 27,
+ BTC_DBG_BT_CHANGE = 28,
+ BTC_DBG_WL_CCA = 29,
+ BTC_DBG_BT_LEAUDIO = 30,
+ BTC_DBG_USER_DEF = 31,
+};
+
void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode);
@@ -193,4 +308,65 @@ static inline u8 rtw89_btc_path_phymap(struct rtw89_dev *rtwdev,
return rtw89_btc_phymap(rtwdev, phy_idx, BIT(path));
}
+/* return bt req len in TU */
+static inline u16 rtw89_coex_query_bt_req_len(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+
+ return btc->bt_req_len;
+}
+
+static inline u32 rtw89_get_antpath_type(u8 phy_map, u8 type)
+{
+ return ((phy_map << 8) + type);
+}
+
+static inline
+void _slot_set_le(struct rtw89_btc *btc, u8 sid, __le16 dura, __le32 tbl, __le16 type)
+{
+ if (btc->ver->fcxslots == 1) {
+ btc->dm.slot.v1[sid].dur = dura;
+ btc->dm.slot.v1[sid].cxtbl = tbl;
+ btc->dm.slot.v1[sid].cxtype = type;
+ } else if (btc->ver->fcxslots == 7) {
+ btc->dm.slot.v7[sid].dur = dura;
+ btc->dm.slot.v7[sid].cxtype = type;
+ btc->dm.slot.v7[sid].cxtbl = tbl;
+ }
+}
+
+static inline
+void _slot_set(struct rtw89_btc *btc, u8 sid, u16 dura, u32 tbl, u16 type)
+{
+ _slot_set_le(btc, sid, cpu_to_le16(dura), cpu_to_le32(tbl), cpu_to_le16(type));
+}
+
+static inline
+void _slot_set_dur(struct rtw89_btc *btc, u8 sid, u16 dura)
+{
+ if (btc->ver->fcxslots == 1)
+ btc->dm.slot.v1[sid].dur = cpu_to_le16(dura);
+ else if (btc->ver->fcxslots == 7)
+ btc->dm.slot.v7[sid].dur = cpu_to_le16(dura);
+}
+
+static inline
+void _slot_set_type(struct rtw89_btc *btc, u8 sid, u16 type)
+{
+ if (btc->ver->fcxslots == 1)
+ btc->dm.slot.v1[sid].cxtype = cpu_to_le16(type);
+ else if (btc->ver->fcxslots == 7)
+ btc->dm.slot.v7[sid].cxtype = cpu_to_le16(type);
+}
+
+static inline
+void _slot_set_tbl(struct rtw89_btc *btc, u8 sid, u32 tbl)
+{
+ if (btc->ver->fcxslots == 1)
+ btc->dm.slot.v1[sid].cxtbl = cpu_to_le32(tbl);
+ else if (btc->ver->fcxslots == 7)
+ btc->dm.slot.v7[sid].cxtbl = cpu_to_le32(tbl);
+}
+
#endif
diff --git a/sys/contrib/dev/rtw89/core.c b/sys/contrib/dev/rtw89/core.c
index fff00da406e2..d1f82bfad4a9 100644
--- a/sys/contrib/dev/rtw89/core.c
+++ b/sys/contrib/dev/rtw89/core.c
@@ -23,6 +23,7 @@
#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);
@@ -87,6 +88,9 @@ static struct ieee80211_channel rtw89_channels_5ghz[] = {
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),
@@ -177,13 +181,31 @@ static const struct ieee80211_iface_limit rtw89_iface_limits[] = {
},
};
+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,
.num_different_channels = 1,
- }
+ },
+ {
+ .limits = rtw89_iface_limits_mcc,
+ .n_limits = ARRAY_SIZE(rtw89_iface_limits_mcc),
+ .max_interfaces = 2,
+ .num_different_channels = 2,
+ },
};
bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate)
@@ -239,6 +261,9 @@ static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev,
{
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;
@@ -261,8 +286,8 @@ void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef)
NL80211_CHAN_NO_HT);
}
-static void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
- struct rtw89_chan *chan)
+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;
@@ -323,9 +348,11 @@ static void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
{
+ 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;
@@ -335,58 +362,83 @@ void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev)
return;
mode = rtw89_get_entity_mode(rtwdev);
- if (WARN(mode != RTW89_ENTITY_MODE_SCC, "Invalid ent mode: %d\n", mode))
+ 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;
+ }
+
+ roc_idx = atomic_read(&hal->roc_entity_idx);
+ if (roc_idx != RTW89_SUB_ENTITY_IDLE)
+ sub_entity_idx = roc_idx;
- sub_entity_idx = RTW89_SUB_ENTITY_0;
phy_idx = RTW89_PHY_0;
chan = rtw89_chan_get(rtwdev, sub_entity_idx);
chip->ops->set_txpwr(rtwdev, chan, phy_idx);
}
-void rtw89_set_channel(struct rtw89_dev *rtwdev)
+int rtw89_set_channel(struct rtw89_dev *rtwdev)
{
+ struct rtw89_hal *hal = &rtwdev->hal;
const struct rtw89_chip_info *chip = rtwdev->chip;
- const struct cfg80211_chan_def *chandef;
+ 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_chan chan;
struct rtw89_channel_help_params bak;
enum rtw89_entity_mode mode;
- bool band_changed;
bool entity_active;
entity_active = rtw89_get_entity_state(rtwdev);
mode = rtw89_entity_recalc(rtwdev);
- if (WARN(mode != RTW89_ENTITY_MODE_SCC, "Invalid ent mode: %d\n", mode))
- return;
+ 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;
- sub_entity_idx = RTW89_SUB_ENTITY_0;
mac_idx = RTW89_MAC_0;
phy_idx = RTW89_PHY_0;
- chandef = rtw89_chandef_get(rtwdev, sub_entity_idx);
- rtw89_get_channel_params(chandef, &chan);
- if (WARN(chan.channel == 0, "Invalid channel\n"))
- return;
- band_changed = rtw89_assign_entity_chan(rtwdev, sub_entity_idx, &chan);
+ chan = rtw89_chan_get(rtwdev, sub_entity_idx);
+ chan_rcd = rtw89_chan_rcd_get(rtwdev, sub_entity_idx);
- rtw89_chip_set_channel_prepare(rtwdev, &bak, &chan, mac_idx, phy_idx);
+ 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_channel(rtwdev, chan, mac_idx, phy_idx);
- chip->ops->set_txpwr(rtwdev, &chan, phy_idx);
+ chip->ops->set_txpwr(rtwdev, chan, phy_idx);
- rtw89_chip_set_channel_done(rtwdev, &bak, &chan, mac_idx, phy_idx);
+ rtw89_chip_set_channel_done(rtwdev, &bak, chan, mac_idx, phy_idx);
- if (!entity_active || band_changed) {
- rtw89_btc_ntfy_switch_band(rtwdev, phy_idx, chan.band_type);
+ 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_set_entity_state(rtwdev, true);
+ return 0;
}
void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
@@ -452,31 +504,21 @@ static void
rtw89_core_tx_update_sec_key(struct rtw89_dev *rtwdev,
struct rtw89_core_tx_request *tx_req)
{
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
const struct rtw89_chip_info *chip = rtwdev->chip;
- struct ieee80211_vif *vif = tx_req->vif;
- struct ieee80211_sta *sta = tx_req->sta;
+ const struct rtw89_sec_cam_entry *sec_cam;
struct ieee80211_tx_info *info;
struct ieee80211_key_conf *key;
- struct rtw89_vif *rtwvif;
- struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
- struct rtw89_addr_cam_entry *addr_cam;
- struct rtw89_sec_cam_entry *sec_cam;
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
struct sk_buff *skb = tx_req->skb;
u8 sec_type = RTW89_SEC_KEY_TYPE_NONE;
+ u8 sec_cam_idx;
u64 pn64;
- if (!vif) {
- rtw89_warn(rtwdev, "cannot set sec key without vif\n");
- return;
- }
-
- rtwvif = (struct rtw89_vif *)vif->drv_priv;
- addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta);
-
info = IEEE80211_SKB_CB(skb);
key = info->control.hw_key;
- sec_cam = addr_cam->sec_entries[key->hw_key_idx];
+ sec_cam_idx = key->hw_key_idx;
+ sec_cam = cam_info->sec_entries[sec_cam_idx];
if (!sec_cam) {
rtw89_warn(rtwdev, "sec cam entry is empty\n");
return;
@@ -528,12 +570,12 @@ rtw89_core_tx_update_sec_key(struct rtw89_dev *rtwdev,
}
static u16 rtw89_core_get_mgmt_rate(struct rtw89_dev *rtwdev,
- struct rtw89_core_tx_request *tx_req)
+ struct rtw89_core_tx_request *tx_req,
+ const struct rtw89_chan *chan)
{
struct sk_buff *skb = tx_req->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = tx_info->control.vif;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u16 lowest_rate;
if (tx_info->flags & IEEE80211_TX_CTL_NO_CCK_RATE ||
@@ -572,7 +614,8 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif = tx_req->vif;
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
u8 qsel, ch_dma;
qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : RTW89_TX_QSEL_B0_MGMT;
@@ -589,7 +632,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev,
desc_info->en_wd_info = true;
desc_info->use_rate = true;
desc_info->dis_data_fb = true;
- desc_info->data_rate = rtw89_core_get_mgmt_rate(rtwdev, tx_req);
+ desc_info->data_rate = rtw89_core_get_mgmt_rate(rtwdev, tx_req, chan);
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
"tx mgmt frame with rate 0x%x on channel %d (band %d, bw %d)\n",
@@ -608,7 +651,8 @@ rtw89_core_tx_update_h2c_info(struct rtw89_dev *rtwdev,
desc_info->ch_dma = RTW89_DMA_H2C;
}
-static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc)
+static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc,
+ const struct rtw89_chan *chan)
{
static const u8 rtw89_bandwidth_to_om[] = {
[RTW89_CHANNEL_WIDTH_20] = HTC_OM_CHANNEL_WIDTH_20,
@@ -619,7 +663,6 @@ static void rtw89_core_get_no_ul_ofdma_htc(struct rtw89_dev *rtwdev, __le32 *htc
};
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_hal *hal = &rtwdev->hal;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u8 om_bandwidth;
if (!chip->dis_2g_40m_ul_ofdma ||
@@ -787,6 +830,8 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev,
desc_info->mac_id = rtw89_core_tx_get_mac_id(rtwdev, tx_req);
desc_info->port = desc_info->hiq ? rtwvif->port : 0;
desc_info->er_cap = rtwsta ? rtwsta->er_cap : false;
+ desc_info->stbc = rtwsta ? rtwsta->ra.stbc_cap : false;
+ desc_info->ldpc = rtwsta ? rtwsta->ra.ldpc_cap : false;
/* enable wd_info for AMPDU */
desc_info->en_wd_info = true;
@@ -1101,6 +1146,8 @@ static __le32 rtw89_build_txwd_info0(struct rtw89_tx_desc_info *desc_info)
{
u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_USE_RATE, desc_info->use_rate) |
FIELD_PREP(RTW89_TXWD_INFO0_DATA_RATE, desc_info->data_rate) |
+ FIELD_PREP(RTW89_TXWD_INFO0_DATA_STBC, desc_info->stbc) |
+ FIELD_PREP(RTW89_TXWD_INFO0_DATA_LDPC, desc_info->ldpc) |
FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port);
@@ -1109,7 +1156,9 @@ static __le32 rtw89_build_txwd_info0(struct rtw89_tx_desc_info *desc_info)
static __le32 rtw89_build_txwd_info0_v1(struct rtw89_tx_desc_info *desc_info)
{
- u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
+ u32 dword = FIELD_PREP(RTW89_TXWD_INFO0_DATA_STBC, desc_info->stbc) |
+ FIELD_PREP(RTW89_TXWD_INFO0_DATA_LDPC, desc_info->ldpc) |
+ FIELD_PREP(RTW89_TXWD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
FIELD_PREP(RTW89_TXWD_INFO0_MULTIPORT_ID, desc_info->port) |
FIELD_PREP(RTW89_TXWD_INFO0_DATA_ER, desc_info->er_cap) |
FIELD_PREP(RTW89_TXWD_INFO0_DATA_BW_ER, 0);
@@ -1148,7 +1197,8 @@ static __le32 rtw89_build_txwd_info2_v1(struct rtw89_tx_desc_info *desc_info)
static __le32 rtw89_build_txwd_info4(struct rtw89_tx_desc_info *desc_info)
{
- u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, 1) |
+ bool rts_en = !desc_info->is_bmc;
+ u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, rts_en) |
FIELD_PREP(RTW89_TXWD_INFO4_HW_RTS_EN, 1);
return cpu_to_le32(dword);
@@ -1205,6 +1255,139 @@ void rtw89_core_fill_txdesc_v1(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(rtw89_core_fill_txdesc_v1);
+static __le32 rtw89_build_txwd_body0_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY0_WP_OFFSET_V1, desc_info->wp_offset) |
+ FIELD_PREP(BE_TXD_BODY0_WDINFO_EN, desc_info->en_wd_info) |
+ FIELD_PREP(BE_TXD_BODY0_CH_DMA, desc_info->ch_dma) |
+ FIELD_PREP(BE_TXD_BODY0_HDR_LLC_LEN, desc_info->hdr_llc_len) |
+ FIELD_PREP(BE_TXD_BODY0_WD_PAGE, desc_info->wd_page);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_body1_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY1_ADDR_INFO_NUM, desc_info->addr_info_nr) |
+ FIELD_PREP(BE_TXD_BODY1_SEC_KEYID, desc_info->sec_keyid) |
+ FIELD_PREP(BE_TXD_BODY1_SEC_TYPE, desc_info->sec_type);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_body2_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY2_TID_IND, desc_info->tid_indicate) |
+ FIELD_PREP(BE_TXD_BODY2_QSEL, desc_info->qsel) |
+ FIELD_PREP(BE_TXD_BODY2_TXPKTSIZE, desc_info->pkt_size) |
+ FIELD_PREP(BE_TXD_BODY2_AGG_EN, desc_info->agg_en) |
+ FIELD_PREP(BE_TXD_BODY2_BK, desc_info->bk) |
+ FIELD_PREP(BE_TXD_BODY2_MACID, desc_info->mac_id);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_body3_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY3_WIFI_SEQ, desc_info->seq);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_body4_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY4_SEC_IV_L0, desc_info->sec_seq[0]) |
+ FIELD_PREP(BE_TXD_BODY4_SEC_IV_L1, desc_info->sec_seq[1]);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_body5_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY5_SEC_IV_H2, desc_info->sec_seq[2]) |
+ FIELD_PREP(BE_TXD_BODY5_SEC_IV_H3, desc_info->sec_seq[3]) |
+ FIELD_PREP(BE_TXD_BODY5_SEC_IV_H4, desc_info->sec_seq[4]) |
+ FIELD_PREP(BE_TXD_BODY5_SEC_IV_H5, desc_info->sec_seq[5]);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_body7_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_BODY7_USERATE_SEL, desc_info->use_rate) |
+ FIELD_PREP(BE_TXD_BODY7_DATA_ER, desc_info->er_cap) |
+ FIELD_PREP(BE_TXD_BODY7_DATA_BW_ER, 0) |
+ FIELD_PREP(BE_TXD_BODY7_DATARATE, desc_info->data_rate);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_info0_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_INFO0_DATA_STBC, desc_info->stbc) |
+ FIELD_PREP(BE_TXD_INFO0_DATA_LDPC, desc_info->ldpc) |
+ FIELD_PREP(BE_TXD_INFO0_DISDATAFB, desc_info->dis_data_fb) |
+ FIELD_PREP(BE_TXD_INFO0_MULTIPORT_ID, desc_info->port);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_info1_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_INFO1_MAX_AGG_NUM, desc_info->ampdu_num) |
+ FIELD_PREP(BE_TXD_INFO1_A_CTRL_BSR, desc_info->a_ctrl_bsr) |
+ FIELD_PREP(BE_TXD_INFO1_DATA_RTY_LOWEST_RATE,
+ desc_info->data_retry_lowest_rate);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_TXD_INFO2_AMPDU_DENSITY, desc_info->ampdu_density) |
+ FIELD_PREP(BE_TXD_INFO2_FORCE_KEY_EN, desc_info->sec_en) |
+ FIELD_PREP(BE_TXD_INFO2_SEC_CAM_IDX, desc_info->sec_cam_idx);
+
+ return cpu_to_le32(dword);
+}
+
+static __le32 rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ bool rts_en = !desc_info->is_bmc;
+ u32 dword = FIELD_PREP(BE_TXD_INFO4_RTS_EN, rts_en) |
+ FIELD_PREP(BE_TXD_INFO4_HW_RTS_EN, 1);
+
+ return cpu_to_le32(dword);
+}
+
+void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_tx_desc_info *desc_info,
+ void *txdesc)
+{
+ struct rtw89_txwd_body_v2 *txwd_body = txdesc;
+ struct rtw89_txwd_info_v2 *txwd_info;
+
+ txwd_body->dword0 = rtw89_build_txwd_body0_v2(desc_info);
+ txwd_body->dword1 = rtw89_build_txwd_body1_v2(desc_info);
+ txwd_body->dword2 = rtw89_build_txwd_body2_v2(desc_info);
+ txwd_body->dword3 = rtw89_build_txwd_body3_v2(desc_info);
+ if (desc_info->sec_en) {
+ txwd_body->dword4 = rtw89_build_txwd_body4_v2(desc_info);
+ txwd_body->dword5 = rtw89_build_txwd_body5_v2(desc_info);
+ }
+ txwd_body->dword7 = rtw89_build_txwd_body7_v2(desc_info);
+
+ if (!desc_info->en_wd_info)
+ return;
+
+ txwd_info = (struct rtw89_txwd_info_v2 *)(txwd_body + 1);
+ txwd_info->dword0 = rtw89_build_txwd_info0_v2(desc_info);
+ txwd_info->dword1 = rtw89_build_txwd_info1_v2(desc_info);
+ txwd_info->dword2 = rtw89_build_txwd_info2_v2(desc_info);
+ txwd_info->dword4 = rtw89_build_txwd_info4_v2(desc_info);
+}
+EXPORT_SYMBOL(rtw89_core_fill_txdesc_v2);
+
static __le32 rtw89_build_txwd_fwcmd0_v1(struct rtw89_tx_desc_info *desc_info)
{
u32 dword = FIELD_PREP(AX_RXD_RPKT_LEN_MASK, desc_info->pkt_size) |
@@ -1225,33 +1408,89 @@ void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(rtw89_core_fill_txdesc_fwcmd_v1);
+static __le32 rtw89_build_txwd_fwcmd0_v2(struct rtw89_tx_desc_info *desc_info)
+{
+ u32 dword = FIELD_PREP(BE_RXD_RPKT_LEN_MASK, desc_info->pkt_size) |
+ FIELD_PREP(BE_RXD_RPKT_TYPE_MASK, desc_info->fw_dl ?
+ RTW89_CORE_RX_TYPE_FWDL :
+ RTW89_CORE_RX_TYPE_H2C);
+
+ return cpu_to_le32(dword);
+}
+
+void rtw89_core_fill_txdesc_fwcmd_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_tx_desc_info *desc_info,
+ void *txdesc)
+{
+ struct rtw89_rxdesc_short_v2 *txwd_v2 = (struct rtw89_rxdesc_short_v2 *)txdesc;
+
+ txwd_v2->dword0 = rtw89_build_txwd_fwcmd0_v2(desc_info);
+}
+EXPORT_SYMBOL(rtw89_core_fill_txdesc_fwcmd_v2);
+
static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev,
struct sk_buff *skb,
struct rtw89_rx_phy_ppdu *phy_ppdu)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data;
+ const struct rtw89_rxinfo_user *user;
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+ int rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE;
bool rx_cnt_valid = false;
+ bool invalid = false;
u8 plcp_size = 0;
- u8 usr_num = 0;
u8 *phy_sts;
+ u8 usr_num;
+ int i;
+
+ if (chip_gen == RTW89_CHIP_BE) {
+ invalid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_INVALID_V1);
+ rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE_V1;
+ }
+
+ if (invalid)
+ return -EINVAL;
rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD);
- plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3;
- usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM);
- if (usr_num > RTW89_PPDU_MAX_USR) {
- rtw89_warn(rtwdev, "Invalid user number in mac info\n");
+ if (chip_gen == RTW89_CHIP_BE) {
+ plcp_size = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_PLCP_LEN_V1) << 3;
+ usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM_V1);
+ } else {
+ plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3;
+ usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM);
+ }
+ if (usr_num > chip->ppdu_max_usr) {
+ rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n",
+ usr_num);
return -EINVAL;
}
+ /* For WiFi 7 chips, RXWD.mac_id of PPDU status is not set by hardware,
+ * so update mac_id by rxinfo_user[].mac_id.
+ */
+ for (i = 0; i < usr_num && chip_gen == RTW89_CHIP_BE; i++) {
+ user = &rxinfo->user[i];
+ if (!le32_get_bits(user->w0, RTW89_RXINFO_USER_MAC_ID_VALID))
+ continue;
+
+ phy_ppdu->mac_id =
+ le32_get_bits(user->w0, RTW89_RXINFO_USER_MACID);
+ break;
+ }
+
phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE;
phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE;
/* 8-byte alignment */
if (usr_num & BIT(0))
phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE;
if (rx_cnt_valid)
- phy_sts += RTW89_PPDU_MAC_RX_CNT_SIZE;
+ phy_sts += rx_cnt_size;
phy_sts += plcp_size;
+ if (phy_sts > skb->data + skb->len)
+ return -EINVAL;
+
phy_ppdu->buf = phy_sts;
phy_ppdu->len = skb->data + skb->len - phy_sts;
@@ -1299,14 +1538,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev,
const struct rtw89_phy_sts_iehdr *iehdr)
{
- static const u8 physts_ie_len_tab[32] = {
- 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
- VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
- VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
+ static const u8 physts_ie_len_tabs[RTW89_CHIP_GEN_NUM][32] = {
+ [RTW89_CHIP_AX] = {
+ 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
+ VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
+ VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
+ },
+ [RTW89_CHIP_BE] = {
+ 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
+ VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
+ VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
+ },
};
+ const u8 *physts_ie_len_tab;
u16 ie_len;
u8 ie;
+ physts_ie_len_tab = physts_ie_len_tabs[rtwdev->chip->chip_gen];
+
ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE);
if (physts_ie_len_tab[ie] != VAR_LEN)
ie_len = physts_ie_len_tab[ie];
@@ -1325,6 +1574,12 @@ static void rtw89_core_parse_phy_status_ie01(struct rtw89_dev *rtwdev,
u32 t;
phy_ppdu->chan_idx = le32_get_bits(ie->w0, RTW89_PHY_STS_IE01_W0_CH_IDX);
+
+ if (rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR) {
+ phy_ppdu->ldpc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_LDPC);
+ phy_ppdu->stbc = le32_get_bits(ie->w2, RTW89_PHY_STS_IE01_W2_STBC);
+ }
+
if (phy_ppdu->rate < RTW89_HW_RATE_OFDM6)
return;
@@ -1385,9 +1640,17 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev,
{
const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf;
u32 len_from_header;
+ bool physts_valid;
+
+ physts_valid = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_VALID);
+ if (!physts_valid)
+ return -EINVAL;
len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3;
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ len_from_header += PHY_STS_HDR_LEN;
+
if (len_from_header != phy_ppdu->len) {
rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n");
return -EINVAL;
@@ -1456,32 +1719,49 @@ static void rtw89_core_rx_process_phy_sts(struct rtw89_dev *rtwdev,
phy_ppdu);
}
-static u8 rtw89_rxdesc_to_nl_he_gi(struct rtw89_dev *rtwdev,
- const struct rtw89_rx_desc_info *desc_info,
- bool rx_status)
+static u8 rtw89_rxdesc_to_nl_he_eht_gi(struct rtw89_dev *rtwdev,
+ u8 desc_info_gi,
+ bool rx_status, bool eht)
{
- switch (desc_info->gi_ltf) {
+ switch (desc_info_gi) {
case RTW89_GILTF_SGI_4XHE08:
case RTW89_GILTF_2XHE08:
case RTW89_GILTF_1XHE08:
- return NL80211_RATE_INFO_HE_GI_0_8;
+ return eht ? NL80211_RATE_INFO_EHT_GI_0_8 :
+ NL80211_RATE_INFO_HE_GI_0_8;
case RTW89_GILTF_2XHE16:
case RTW89_GILTF_1XHE16:
- return NL80211_RATE_INFO_HE_GI_1_6;
+ return eht ? NL80211_RATE_INFO_EHT_GI_1_6 :
+ NL80211_RATE_INFO_HE_GI_1_6;
case RTW89_GILTF_LGI_4XHE32:
- return NL80211_RATE_INFO_HE_GI_3_2;
+ return eht ? NL80211_RATE_INFO_EHT_GI_3_2 :
+ NL80211_RATE_INFO_HE_GI_3_2;
default:
- rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info->gi_ltf);
- return rx_status ? NL80211_RATE_INFO_HE_GI_3_2 : U8_MAX;
+ rtw89_warn(rtwdev, "invalid gi_ltf=%d", desc_info_gi);
+ if (rx_status)
+ return eht ? NL80211_RATE_INFO_EHT_GI_3_2 :
+ NL80211_RATE_INFO_HE_GI_3_2;
+ return U8_MAX;
}
}
+static
+bool rtw89_check_rx_statu_gi_match(struct ieee80211_rx_status *status, u8 gi_ltf,
+ bool eht)
+{
+ if (eht)
+ return status->eht.gi == gi_ltf;
+
+ return status->he_gi == gi_ltf;
+}
+
static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev,
struct rtw89_rx_desc_info *desc_info,
struct ieee80211_rx_status *status)
{
u8 band = desc_info->bb_sel ? RTW89_PHY_1 : RTW89_PHY_0;
u8 data_rate_mode, bw, rate_idx = MASKBYTE0, gi_ltf;
+ bool eht = false;
u16 data_rate;
bool ret;
@@ -1492,19 +1772,20 @@ static bool rtw89_core_rx_ppdu_match(struct rtw89_dev *rtwdev,
/* rate_idx is still hardware value here */
} else if (data_rate_mode == DATA_RATE_MODE_HT) {
rate_idx = rtw89_get_data_ht_mcs(rtwdev, data_rate);
- } else if (data_rate_mode == DATA_RATE_MODE_VHT) {
- rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
- } else if (data_rate_mode == DATA_RATE_MODE_HE) {
+ } else if (data_rate_mode == DATA_RATE_MODE_VHT ||
+ data_rate_mode == DATA_RATE_MODE_HE ||
+ data_rate_mode == DATA_RATE_MODE_EHT) {
rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
} else {
rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
}
+ eht = data_rate_mode == DATA_RATE_MODE_EHT;
bw = rtw89_hw_to_rate_info_bw(desc_info->bw);
- gi_ltf = rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info, false);
+ gi_ltf = rtw89_rxdesc_to_nl_he_eht_gi(rtwdev, desc_info->gi_ltf, false, eht);
ret = rtwdev->ppdu_sts.curr_rx_ppdu_cnt[band] == desc_info->ppdu_cnt &&
status->rate_idx == rate_idx &&
- status->he_gi == gi_ltf &&
+ rtw89_check_rx_statu_gi_match(status, gi_ltf, eht) &&
status->bw == bw;
return ret;
@@ -1524,8 +1805,8 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
{
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct ieee80211_trigger *tf = (struct ieee80211_trigger *)skb->data;
- u8 *pos, *end, type;
- u16 aid;
+ u8 *pos, *end, type, tf_bw;
+ u16 aid, tf_rua;
if (!ether_addr_equal(vif->bss_conf.bssid, tf->ta) ||
rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION ||
@@ -1533,7 +1814,7 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
return;
type = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_TYPE_MASK);
- if (type != IEEE80211_TRIGGER_TYPE_BASIC)
+ if (type != IEEE80211_TRIGGER_TYPE_BASIC && type != IEEE80211_TRIGGER_TYPE_MU_BAR)
return;
end = (u8 *)tf + skb->len;
@@ -1541,17 +1822,24 @@ static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
while (end - pos >= RTW89_TF_BASIC_USER_INFO_SZ) {
aid = RTW89_GET_TF_USER_INFO_AID12(pos);
+ tf_rua = RTW89_GET_TF_USER_INFO_RUA(pos);
+ tf_bw = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_ULBW_MASK);
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
- "[TF] aid: %d, ul_mcs: %d, rua: %d\n",
+ "[TF] aid: %d, ul_mcs: %d, rua: %d, bw: %d\n",
aid, RTW89_GET_TF_USER_INFO_UL_MCS(pos),
- RTW89_GET_TF_USER_INFO_RUA(pos));
+ tf_rua, tf_bw);
if (aid == RTW89_TF_PAD)
break;
if (aid == vif->cfg.aid) {
+ enum nl80211_he_ru_alloc rua = rtw89_he_rua_to_ru_alloc(tf_rua >> 1);
+
rtwvif->stats.rx_tf_acc++;
rtwdev->stats.rx_tf_acc++;
+ if (tf_bw == IEEE80211_TRIGGER_ULBW_160_80P80MHZ &&
+ rua <= NL80211_RATE_INFO_HE_RU_ALLOC_106)
+ rtwvif->pwr_diff_en = true;
break;
}
@@ -1622,6 +1910,17 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev,
ieee80211_queue_work(rtwdev->hw, &rtwdev->cancel_6ghz_probe_work);
}
+static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif *rtwvif,
+ struct ieee80211_hdr *hdr, size_t len)
+{
+ struct ieee80211_mgmt *mgmt = (typeof(mgmt))hdr;
+
+ if (len < offsetof(typeof(*mgmt), u.beacon.variable))
+ return;
+
+ WRITE_ONCE(rtwvif->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp));
+}
+
static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
@@ -1652,8 +1951,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
return;
if (ieee80211_is_beacon(hdr->frame_control)) {
- if (vif->type == NL80211_IFTYPE_STATION)
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ !test_bit(RTW89_FLAG_WOWLAN, rtwdev->flags)) {
+ rtw89_vif_sync_bcn_tsf(rtwvif, hdr, skb->len);
rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu);
+ }
pkt_stat->beacon_nr++;
}
@@ -1689,8 +1991,7 @@ static void rtw89_correct_cck_chan(struct rtw89_dev *rtwdev,
const struct rtw89_chan_rcd *rcd =
rtw89_chan_rcd_get(rtwdev, RTW89_SUB_ENTITY_0);
u16 chan = rcd->prev_primary_channel;
- u8 band = rcd->prev_band_type == RTW89_BAND_2G ?
- NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
+ u8 band = rtw89_hw_to_nl80211_band(rcd->prev_band_type);
if (status->band != NL80211_BAND_2GHZ &&
status->encoding == RX_ENC_LEGACY &&
@@ -1718,12 +2019,105 @@ static void rtw89_core_hw_to_sband_rate(struct ieee80211_rx_status *rx_status)
rx_status->rate_idx -= 4;
}
+static
+void rtw89_core_update_rx_status_by_ppdu(struct rtw89_dev *rtwdev,
+ struct ieee80211_rx_status *rx_status,
+ struct rtw89_rx_phy_ppdu *phy_ppdu)
+{
+ if (!(rtwdev->hw->conf.flags & IEEE80211_CONF_MONITOR))
+ return;
+
+ if (!phy_ppdu)
+ return;
+
+ if (phy_ppdu->ldpc)
+ rx_status->enc_flags |= RX_ENC_FLAG_LDPC;
+ if (phy_ppdu->stbc)
+ rx_status->enc_flags |= u8_encode_bits(1, RX_ENC_FLAG_STBC_MASK);
+}
+
+static const u8 rx_status_bw_to_radiotap_eht_usig[] = {
+ [RATE_INFO_BW_20] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_20MHZ,
+ [RATE_INFO_BW_5] = U8_MAX,
+ [RATE_INFO_BW_10] = U8_MAX,
+ [RATE_INFO_BW_40] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_40MHZ,
+ [RATE_INFO_BW_80] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_80MHZ,
+ [RATE_INFO_BW_160] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_160MHZ,
+ [RATE_INFO_BW_HE_RU] = U8_MAX,
+ [RATE_INFO_BW_320] = IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_320MHZ_1,
+ [RATE_INFO_BW_EHT_RU] = U8_MAX,
+};
+
+static void rtw89_core_update_radiotap_eht(struct rtw89_dev *rtwdev,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_radiotap_eht_usig *usig;
+ struct ieee80211_radiotap_eht *eht;
+ struct ieee80211_radiotap_tlv *tlv;
+ int eht_len = struct_size(eht, user_info, 1);
+ int usig_len = sizeof(*usig);
+ int len;
+ u8 bw;
+
+ len = sizeof(*tlv) + ALIGN(eht_len, 4) +
+ sizeof(*tlv) + ALIGN(usig_len, 4);
+
+ rx_status->flag |= RX_FLAG_RADIOTAP_TLV_AT_END;
+ skb_reset_mac_header(skb);
+
+ /* EHT */
+ tlv = skb_push(skb, len);
+ memset(tlv, 0, len);
+ tlv->type = cpu_to_le16(IEEE80211_RADIOTAP_EHT);
+ tlv->len = cpu_to_le16(eht_len);
+
+ eht = (struct ieee80211_radiotap_eht *)tlv->data;
+ eht->known = cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI);
+ eht->data[0] =
+ le32_encode_bits(rx_status->eht.gi, IEEE80211_RADIOTAP_EHT_DATA0_GI);
+
+ eht->user_info[0] =
+ cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_MCS_KNOWN |
+ IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_KNOWN_O |
+ IEEE80211_RADIOTAP_EHT_USER_INFO_CODING_KNOWN);
+ eht->user_info[0] |=
+ le32_encode_bits(rx_status->rate_idx, IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) |
+ le32_encode_bits(rx_status->nss, IEEE80211_RADIOTAP_EHT_USER_INFO_NSS_O);
+ if (rx_status->enc_flags & RX_ENC_FLAG_LDPC)
+ eht->user_info[0] |=
+ cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_CODING);
+
+ /* U-SIG */
+#if defined(__linux__)
+ tlv = (void *)tlv + sizeof(*tlv) + ALIGN(eht_len, 4);
+#elif defined(__FreeBSD__)
+ tlv = (void *)((u8 *)tlv + sizeof(*tlv) + ALIGN(eht_len, 4));
+#endif
+ tlv->type = cpu_to_le16(IEEE80211_RADIOTAP_EHT_USIG);
+ tlv->len = cpu_to_le16(usig_len);
+
+ if (rx_status->bw >= ARRAY_SIZE(rx_status_bw_to_radiotap_eht_usig))
+ return;
+
+ bw = rx_status_bw_to_radiotap_eht_usig[rx_status->bw];
+ if (bw == U8_MAX)
+ return;
+
+ usig = (struct ieee80211_radiotap_eht_usig *)tlv->data;
+ usig->common =
+ le32_encode_bits(1, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN) |
+ le32_encode_bits(bw, IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW);
+}
+
static void rtw89_core_update_radiotap(struct rtw89_dev *rtwdev,
struct sk_buff *skb,
struct ieee80211_rx_status *rx_status)
{
static const struct ieee80211_radiotap_he known_he = {
.data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN |
+ IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN |
IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN),
.data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN),
};
@@ -1736,6 +2130,8 @@ static void rtw89_core_update_radiotap(struct rtw89_dev *rtwdev,
rx_status->flag |= RX_FLAG_RADIOTAP_HE;
he = skb_push(skb, sizeof(*he));
*he = known_he;
+ } else if (rx_status->encoding == RX_ENC_EHT) {
+ rtw89_core_update_radiotap_eht(rtwdev, skb, rx_status);
}
}
@@ -1748,11 +2144,12 @@ static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
struct napi_struct *napi = &rtwdev->napi;
/* In low power mode, napi isn't scheduled. Receive it to netif. */
- if (unlikely(!test_bit(NAPI_STATE_SCHED, &napi->state)))
+ if (unlikely(!napi_is_scheduled(napi)))
napi = NULL;
rtw89_core_hw_to_sband_rate(rx_status);
rtw89_core_rx_stats(rtwdev, phy_ppdu, desc_info, skb_ppdu);
+ rtw89_core_update_rx_status_by_ppdu(rtwdev, rx_status, phy_ppdu);
rtw89_core_update_radiotap(rtwdev, skb_ppdu, rx_status);
/* In low power mode, it does RX in thread context. */
local_bh_disable();
@@ -1795,13 +2192,19 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev,
.mac_id = desc_info->mac_id};
int ret;
- if (desc_info->mac_info_valid)
- rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu);
+ if (desc_info->mac_info_valid) {
+ ret = rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu);
+ if (ret)
+ goto out;
+ }
+
ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu);
if (ret)
- rtw89_debug(rtwdev, RTW89_DBG_TXRX, "process ppdu failed\n");
+ goto out;
rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu);
+
+out:
rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb);
dev_kfree_skb_any(skb);
}
@@ -1879,6 +2282,71 @@ void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(rtw89_core_query_rxdesc);
+void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ u8 *data, u32 data_offset)
+{
+ struct rtw89_rxdesc_short_v2 *rxd_s;
+ struct rtw89_rxdesc_long_v2 *rxd_l;
+ u16 shift_len, drv_info_len, phy_rtp_len, hdr_cnv_len;
+
+ rxd_s = (struct rtw89_rxdesc_short_v2 *)(data + data_offset);
+
+ desc_info->pkt_size = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_LEN_MASK);
+ desc_info->drv_info_size = le32_get_bits(rxd_s->dword0, BE_RXD_DRV_INFO_SZ_MASK);
+ desc_info->phy_rpt_size = le32_get_bits(rxd_s->dword0, BE_RXD_PHY_RPT_SZ_MASK);
+ desc_info->hdr_cnv_size = le32_get_bits(rxd_s->dword0, BE_RXD_HDR_CNV_SZ_MASK);
+ desc_info->shift = le32_get_bits(rxd_s->dword0, BE_RXD_SHIFT_MASK);
+ desc_info->long_rxdesc = le32_get_bits(rxd_s->dword0, BE_RXD_LONG_RXD);
+ desc_info->pkt_type = le32_get_bits(rxd_s->dword0, BE_RXD_RPKT_TYPE_MASK);
+ if (desc_info->pkt_type == RTW89_CORE_RX_TYPE_PPDU_STAT)
+ desc_info->mac_info_valid = true;
+
+ desc_info->frame_type = le32_get_bits(rxd_s->dword2, BE_RXD_TYPE_MASK);
+ desc_info->mac_id = le32_get_bits(rxd_s->dword2, BE_RXD_MAC_ID_MASK);
+ desc_info->addr_cam_valid = le32_get_bits(rxd_s->dword2, BE_RXD_ADDR_CAM_VLD);
+
+ desc_info->icv_err = le32_get_bits(rxd_s->dword3, BE_RXD_ICV_ERR);
+ desc_info->crc32_err = le32_get_bits(rxd_s->dword3, BE_RXD_CRC32_ERR);
+ desc_info->hw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_HW_DEC);
+ desc_info->sw_dec = le32_get_bits(rxd_s->dword3, BE_RXD_SW_DEC);
+ desc_info->addr1_match = le32_get_bits(rxd_s->dword3, BE_RXD_A1_MATCH);
+
+ desc_info->bw = le32_get_bits(rxd_s->dword4, BE_RXD_BW_MASK);
+ desc_info->data_rate = le32_get_bits(rxd_s->dword4, BE_RXD_RX_DATARATE_MASK);
+ desc_info->gi_ltf = le32_get_bits(rxd_s->dword4, BE_RXD_RX_GI_LTF_MASK);
+ desc_info->ppdu_cnt = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_CNT_MASK);
+ desc_info->ppdu_type = le32_get_bits(rxd_s->dword4, BE_RXD_PPDU_TYPE_MASK);
+
+ desc_info->free_run_cnt = le32_to_cpu(rxd_s->dword5);
+
+ shift_len = desc_info->shift << 1; /* 2-byte unit */
+ drv_info_len = desc_info->drv_info_size << 3; /* 8-byte unit */
+ phy_rtp_len = desc_info->phy_rpt_size << 3; /* 8-byte unit */
+ hdr_cnv_len = desc_info->hdr_cnv_size << 4; /* 16-byte unit */
+ desc_info->offset = data_offset + shift_len + drv_info_len +
+ phy_rtp_len + hdr_cnv_len;
+
+ if (desc_info->long_rxdesc)
+ desc_info->rxd_len = sizeof(struct rtw89_rxdesc_long_v2);
+ else
+ desc_info->rxd_len = sizeof(struct rtw89_rxdesc_short_v2);
+ desc_info->ready = true;
+
+ if (!desc_info->long_rxdesc)
+ return;
+
+ rxd_l = (struct rtw89_rxdesc_long_v2 *)(data + data_offset);
+
+ desc_info->sr_en = le32_get_bits(rxd_l->dword6, BE_RXD_SR_EN);
+ desc_info->user_id = le32_get_bits(rxd_l->dword6, BE_RXD_USER_ID_MASK);
+ desc_info->addr_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_ADDR_CAM_MASK);
+ desc_info->sec_cam_id = le32_get_bits(rxd_l->dword6, BE_RXD_SEC_CAM_IDX_MASK);
+
+ desc_info->rx_pl_id = le32_get_bits(rxd_l->dword7, BE_RXD_RX_PL_ID_MASK);
+}
+EXPORT_SYMBOL(rtw89_core_query_rxdesc_v2);
+
struct rtw89_core_iter_rx_status {
struct rtw89_dev *rtwdev;
struct ieee80211_rx_status *rx_status;
@@ -1930,9 +2398,10 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
{
const struct cfg80211_chan_def *chandef =
rtw89_chandef_get(rtwdev, RTW89_SUB_ENTITY_0);
- const struct rtw89_chan *cur = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u16 data_rate;
u8 data_rate_mode;
+ bool eht = false;
+ u8 gi;
/* currently using single PHY */
rx_status->freq = chandef->chan->center_freq;
@@ -1940,6 +2409,7 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
if (rtwdev->scanning &&
RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
+ const struct rtw89_chan *cur = rtw89_scan_chan_get(rtwdev);
u8 chan = cur->primary_channel;
u8 band = cur->band_type;
enum nl80211_band nl_band;
@@ -1979,12 +2449,21 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
rx_status->encoding = RX_ENC_HE;
rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
+ } else if (data_rate_mode == DATA_RATE_MODE_EHT) {
+ rx_status->encoding = RX_ENC_EHT;
+ rx_status->rate_idx = rtw89_get_data_mcs(rtwdev, data_rate);
+ rx_status->nss = rtw89_get_data_nss(rtwdev, data_rate) + 1;
+ eht = true;
} else {
rtw89_warn(rtwdev, "invalid RX rate mode %d\n", data_rate_mode);
}
/* he_gi is used to match ppdu, so we always fill it. */
- rx_status->he_gi = rtw89_rxdesc_to_nl_he_gi(rtwdev, desc_info, true);
+ gi = rtw89_rxdesc_to_nl_he_eht_gi(rtwdev, desc_info->gi_ltf, true, eht);
+ if (eht)
+ rx_status->eht.gi = gi;
+ else
+ rx_status->he_gi = gi;
rx_status->flag |= RX_FLAG_MACTIME_START;
rx_status->mactime = desc_info->free_run_cnt;
@@ -2076,11 +2555,15 @@ void rtw89_core_napi_stop(struct rtw89_dev *rtwdev)
}
EXPORT_SYMBOL(rtw89_core_napi_stop);
-void rtw89_core_napi_init(struct rtw89_dev *rtwdev)
+int rtw89_core_napi_init(struct rtw89_dev *rtwdev)
{
- init_dummy_netdev(&rtwdev->netdev);
- netif_napi_add(&rtwdev->netdev, &rtwdev->napi,
+ rtwdev->netdev = alloc_netdev_dummy(0);
+ if (!rtwdev->netdev)
+ return -ENOMEM;
+
+ netif_napi_add(rtwdev->netdev, &rtwdev->napi,
rtwdev->hci.ops->napi_poll);
+ return 0;
}
EXPORT_SYMBOL(rtw89_core_napi_init);
@@ -2088,6 +2571,7 @@ void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev)
{
rtw89_core_napi_stop(rtwdev);
netif_napi_del(&rtwdev->napi);
+ free_netdev(rtwdev->netdev);
}
EXPORT_SYMBOL(rtw89_core_napi_deinit);
@@ -2481,6 +2965,7 @@ out:
void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_roc *roc = &rtwvif->roc;
struct cfg80211_chan_def roc_chan;
@@ -2489,11 +2974,9 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
lockdep_assert_held(&rtwdev->mutex);
- ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work,
- msecs_to_jiffies(rtwvif->roc.duration));
-
rtw89_leave_ips_by_hwflags(rtwdev);
rtw89_leave_lps(rtwdev);
+ rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC);
ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, true);
if (ret)
@@ -2508,14 +2991,18 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_config_roc_chandef(rtwdev, rtwvif->sub_entity_idx, &roc_chan);
rtw89_set_channel(rtwdev);
rtw89_write32_clr(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH);
ieee80211_ready_on_channel(hw);
+ cancel_delayed_work(&rtwvif->roc.roc_work);
+ ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work,
+ msecs_to_jiffies(rtwvif->roc.duration));
}
void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_roc *roc = &rtwvif->roc;
struct rtw89_vif *tmp;
@@ -2529,13 +3016,13 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_leave_lps(rtwdev);
rtw89_write32_mask(rtwdev,
- rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0),
+ rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_RX_FLTR_CFG_MASK,
rtwdev->hal.rx_fltr);
roc->state = RTW89_ROC_IDLE;
rtw89_config_roc_chandef(rtwdev, rtwvif->sub_entity_idx, NULL);
- rtw89_set_channel(rtwdev);
+ rtw89_chanctx_proceed(rtwdev);
ret = rtw89_core_send_nullfunc(rtwdev, rtwvif, true, false);
if (ret)
rtw89_debug(rtwdev, RTW89_DBG_TXRX,
@@ -2550,7 +3037,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
if (hw->conf.flags & IEEE80211_CONF_IDLE)
ieee80211_queue_delayed_work(hw, &roc->roc_work,
- RTW89_ROC_IDLE_TIMEOUT);
+ msecs_to_jiffies(RTW89_ROC_IDLE_TIMEOUT));
}
void rtw89_roc_work(struct work_struct *work)
@@ -2664,6 +3151,27 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev)
rtw89_vif_enter_lps(rtwdev, rtwvif);
}
+static void rtw89_core_rfk_track(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_entity_mode mode;
+
+ mode = rtw89_get_entity_mode(rtwdev);
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ return;
+
+ rtw89_chip_rfk_track(rtwdev);
+}
+
+void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
+{
+ enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev);
+
+ if (mode == RTW89_ENTITY_MODE_MCC)
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_P2P_PS_CHANGE);
+ else
+ rtw89_process_p2p_ps(rtwdev, vif);
+}
+
void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev,
struct rtw89_traffic_stats *stats)
{
@@ -2706,12 +3214,15 @@ static void rtw89_track_work(struct work_struct *work)
rtw89_phy_stat_track(rtwdev);
rtw89_phy_env_monitor_track(rtwdev);
rtw89_phy_dig(rtwdev);
- rtw89_chip_rfk_track(rtwdev);
+ rtw89_core_rfk_track(rtwdev);
rtw89_phy_ra_update(rtwdev);
rtw89_phy_cfo_track(rtwdev);
rtw89_phy_tx_path_div_track(rtwdev);
rtw89_phy_antdiv_track(rtwdev);
rtw89_phy_ul_tb_ctrl_track(rtwdev);
+ rtw89_phy_edcca_track(rtwdev);
+ rtw89_tas_track(rtwdev);
+ rtw89_chanctx_track(rtwdev);
if (rtwdev->lps_enabled && !rtwdev->btc.lps)
rtw89_enter_lps_track(rtwdev);
@@ -2899,20 +3410,23 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
/* for station mode, assign the mac_id from itself */
rtwsta->mac_id = rtwvif->mac_id;
- /* must do rtw89_reg_6ghz_power_recalc() before rfk channel */
- rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, true);
+
+ /* must do rtw89_reg_6ghz_recalc() before rfk channel */
+ ret = rtw89_reg_6ghz_recalc(rtwdev, rtwvif, true);
+ if (ret)
+ return ret;
+
rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
BTC_ROLE_MSTS_STA_CONN_START);
rtw89_chip_rfk_channel(rtwdev);
} else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
- rtwsta->mac_id = rtw89_core_acquire_bit_map(rtwdev->mac_id_map,
- RTW89_MAX_MAC_ID_NUM);
+ rtwsta->mac_id = rtw89_acquire_mac_id(rtwdev);
if (rtwsta->mac_id == RTW89_MAX_MAC_ID_NUM)
return -ENOSPC;
ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta->mac_id, false);
if (ret) {
- rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id);
+ rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
rtw89_warn(rtwdev, "failed to send h2c macid pause\n");
return ret;
}
@@ -2920,10 +3434,20 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
RTW89_ROLE_CREATE);
if (ret) {
- rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id);
+ rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
rtw89_warn(rtwdev, "failed to send h2c role info\n");
return ret;
}
+
+ ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta);
+ if (ret)
+ return ret;
+
+ ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta);
+ if (ret)
+ return ret;
+
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
}
return 0;
@@ -2971,7 +3495,7 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev,
rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true);
}
- ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
+ ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
return ret;
@@ -3000,6 +3524,8 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
struct rtw89_bssid_cam_entry *bssid_cam = rtw89_get_bssid_cam_of(rtwvif, rtwsta);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
int ret;
if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
@@ -3018,7 +3544,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
}
}
- ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
+ ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta);
if (ret) {
rtw89_warn(rtwdev, "failed to send h2c cmac table\n");
return ret;
@@ -3053,7 +3579,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
BTC_ROLE_MSTS_STA_CONN_END);
- rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template);
+ rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta->htc_template, chan);
rtw89_phy_ul_tb_assoc(rtwdev, rtwvif);
ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif, rtwsta->mac_id);
@@ -3061,6 +3587,8 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev,
rtw89_warn(rtwdev, "failed to send h2c general packet\n");
return ret;
}
+
+ rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
}
return ret;
@@ -3075,11 +3603,11 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
int ret;
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) {
- rtw89_reg_6ghz_power_recalc(rtwdev, rtwvif, false);
+ rtw89_reg_6ghz_recalc(rtwdev, rtwvif, false);
rtw89_btc_ntfy_role_info(rtwdev, rtwvif, rtwsta,
BTC_ROLE_MSTS_STA_DIS_CONN);
} else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) {
- rtw89_core_release_bit_map(rtwdev->mac_id_map, rtwsta->mac_id);
+ rtw89_release_mac_id(rtwdev, rtwsta->mac_id);
ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, rtwsta,
RTW89_ROLE_REMOVE);
@@ -3087,6 +3615,8 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
rtw89_warn(rtwdev, "failed to send h2c role info\n");
return ret;
}
+
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE);
}
return 0;
@@ -3185,7 +3715,8 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev,
cpu_to_le16(867), cpu_to_le16(1733), cpu_to_le16(2600), cpu_to_le16(3467),
};
const struct rtw89_chip_info *chip = rtwdev->chip;
- const __le16 *highest = chip->support_bw160 ? highest_bw160 : highest_bw80;
+ const __le16 *highest = chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160) ?
+ highest_bw160 : highest_bw80;
struct rtw89_hal *hal = &rtwdev->hal;
u16 tx_mcs_map = 0, rx_mcs_map = 0;
u8 sts_cap = 3;
@@ -3214,34 +3745,34 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev,
vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
vht_cap->cap |= sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
- if (chip->support_bw160)
+ if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
IEEE80211_VHT_CAP_SHORT_GI_160;
vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rx_mcs_map);
vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(tx_mcs_map);
vht_cap->vht_mcs.rx_highest = highest[hal->rx_nss - 1];
vht_cap->vht_mcs.tx_highest = highest[hal->tx_nss - 1];
-}
-#define RTW89_SBAND_IFTYPES_NR 2
+ if (ieee80211_hw_check(rtwdev->hw, SUPPORTS_VHT_EXT_NSS_BW))
+ vht_cap->vht_mcs.tx_highest |=
+ cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE);
+}
static void rtw89_init_he_cap(struct rtw89_dev *rtwdev,
enum nl80211_band band,
- struct ieee80211_supported_band *sband)
+ enum nl80211_iftype iftype,
+ struct ieee80211_sband_iftype_data *iftype_data)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_hal *hal = &rtwdev->hal;
- struct ieee80211_sband_iftype_data *iftype_data;
bool no_ng16 = (chip->chip_id == RTL8852A && hal->cv == CHIP_CBV) ||
(chip->chip_id == RTL8852B && hal->cv == CHIP_CAV);
+ struct ieee80211_sta_he_cap *he_cap;
+ int nss = hal->rx_nss;
+ u8 *mac_cap_info;
+ u8 *phy_cap_info;
u16 mcs_map = 0;
int i;
- int nss = hal->rx_nss;
- int idx = 0;
-
- iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL);
- if (!iftype_data)
- return;
for (i = 0; i < 8; i++) {
if (i < nss)
@@ -3250,12 +3781,196 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev,
mcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2);
}
- for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
- struct ieee80211_sta_he_cap *he_cap;
- u8 *mac_cap_info;
- u8 *phy_cap_info;
+ he_cap = &iftype_data->he_cap;
+ mac_cap_info = he_cap->he_cap_elem.mac_cap_info;
+ phy_cap_info = he_cap->he_cap_elem.phy_cap_info;
+
+ he_cap->has_he = true;
+ mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE;
+ if (iftype == NL80211_IFTYPE_STATION)
+ mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
+ mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK |
+ IEEE80211_HE_MAC_CAP2_BSR;
+ mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2;
+ if (iftype == NL80211_IFTYPE_AP)
+ mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
+ mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS |
+ IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
+ if (iftype == NL80211_IFTYPE_STATION)
+ mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX;
+ if (band == NL80211_BAND_2GHZ) {
+ phy_cap_info[0] =
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
+ } else {
+ phy_cap_info[0] =
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
+ if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
+ phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
+ }
+ phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
+ IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
+ phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
+ IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
+ IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
+ IEEE80211_HE_PHY_CAP2_DOPPLER_TX;
+ phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM;
+ if (iftype == NL80211_IFTYPE_STATION)
+ phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM |
+ IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2;
+ if (iftype == NL80211_IFTYPE_AP)
+ phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
+ phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
+ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
+ if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
+ phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
+ phy_cap_info[5] = no_ng16 ? 0 :
+ IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
+ IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
+ phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
+ IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
+ IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
+ IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE;
+ phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
+ IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
+ IEEE80211_HE_PHY_CAP7_MAX_NC_1;
+ phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
+ IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
+ IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996;
+ if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
+ phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
+ IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
+ phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
+ IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
+ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
+ IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
+ u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
+ IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
+ if (iftype == NL80211_IFTYPE_STATION)
+ phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
+ he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map);
+ he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map);
+ if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) {
+ he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map);
+ he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map);
+ }
+
+ if (band == NL80211_BAND_6GHZ) {
+ __le16 capa;
- switch (i) {
+ capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE,
+ IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
+ le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
+ IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
+ le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
+ IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
+ iftype_data->he_6ghz_capa.capa = capa;
+ }
+}
+
+static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev,
+ enum nl80211_band band,
+ enum nl80211_iftype iftype,
+ struct ieee80211_sband_iftype_data *iftype_data)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct ieee80211_eht_cap_elem_fixed *eht_cap_elem;
+ struct ieee80211_eht_mcs_nss_supp *eht_nss;
+ struct ieee80211_sta_eht_cap *eht_cap;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool support_320mhz = false;
+ int sts = 8;
+ u8 val;
+
+ if (chip->chip_gen == RTW89_CHIP_AX)
+ return;
+
+ if (band == NL80211_BAND_6GHZ &&
+ chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_320))
+ support_320mhz = true;
+
+ eht_cap = &iftype_data->eht_cap;
+ eht_cap_elem = &eht_cap->eht_cap_elem;
+ eht_nss = &eht_cap->eht_mcs_nss_supp;
+
+ eht_cap->has_eht = true;
+
+ eht_cap_elem->mac_cap_info[0] =
+ u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991,
+ IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK);
+ eht_cap_elem->mac_cap_info[1] = 0;
+
+ eht_cap_elem->phy_cap_info[0] =
+ IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI |
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
+ if (support_320mhz)
+ eht_cap_elem->phy_cap_info[0] |=
+ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
+
+ eht_cap_elem->phy_cap_info[0] |=
+ u8_encode_bits(u8_get_bits(sts - 1, BIT(0)),
+ IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK);
+ eht_cap_elem->phy_cap_info[1] =
+ u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)),
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) |
+ u8_encode_bits(sts - 1,
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK);
+ if (support_320mhz)
+ eht_cap_elem->phy_cap_info[1] |=
+ u8_encode_bits(sts - 1,
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
+
+ eht_cap_elem->phy_cap_info[2] = 0;
+
+ eht_cap_elem->phy_cap_info[3] =
+ IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
+ IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
+ IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
+ IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK;
+
+ eht_cap_elem->phy_cap_info[4] =
+ IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP |
+ u8_encode_bits(1, IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK);
+
+ eht_cap_elem->phy_cap_info[5] =
+ u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US,
+ IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK);
+
+ eht_cap_elem->phy_cap_info[6] = 0;
+ eht_cap_elem->phy_cap_info[7] = 0;
+ eht_cap_elem->phy_cap_info[8] = 0;
+
+ val = u8_encode_bits(hal->rx_nss, IEEE80211_EHT_MCS_NSS_RX) |
+ u8_encode_bits(hal->tx_nss, IEEE80211_EHT_MCS_NSS_TX);
+ eht_nss->bw._80.rx_tx_mcs9_max_nss = val;
+ eht_nss->bw._80.rx_tx_mcs11_max_nss = val;
+ eht_nss->bw._80.rx_tx_mcs13_max_nss = val;
+ eht_nss->bw._160.rx_tx_mcs9_max_nss = val;
+ eht_nss->bw._160.rx_tx_mcs11_max_nss = val;
+ eht_nss->bw._160.rx_tx_mcs13_max_nss = val;
+ if (support_320mhz) {
+ eht_nss->bw._320.rx_tx_mcs9_max_nss = val;
+ eht_nss->bw._320.rx_tx_mcs11_max_nss = val;
+ eht_nss->bw._320.rx_tx_mcs13_max_nss = val;
+ }
+}
+
+#define RTW89_SBAND_IFTYPES_NR 2
+
+static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev,
+ enum nl80211_band band,
+ struct ieee80211_supported_band *sband)
+{
+ struct ieee80211_sband_iftype_data *iftype_data;
+ enum nl80211_iftype iftype;
+ int idx = 0;
+
+ iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL);
+ if (!iftype_data)
+ return;
+
+ for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+ switch (iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP:
break;
@@ -3268,98 +3983,15 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev,
break;
}
- iftype_data[idx].types_mask = BIT(i);
- he_cap = &iftype_data[idx].he_cap;
- mac_cap_info = he_cap->he_cap_elem.mac_cap_info;
- phy_cap_info = he_cap->he_cap_elem.phy_cap_info;
-
- he_cap->has_he = true;
- mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE;
- if (i == NL80211_IFTYPE_STATION)
- mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
- mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK |
- IEEE80211_HE_MAC_CAP2_BSR;
- mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2;
- if (i == NL80211_IFTYPE_AP)
- mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL;
- mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS |
- IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
- if (i == NL80211_IFTYPE_STATION)
- mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX;
- if (band == NL80211_BAND_2GHZ) {
- phy_cap_info[0] =
- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
- } else {
- phy_cap_info[0] =
- IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
- if (chip->support_bw160)
- phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
- }
- phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
- IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD |
- IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
- phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US |
- IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
- IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ |
- IEEE80211_HE_PHY_CAP2_DOPPLER_TX;
- phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM;
- if (i == NL80211_IFTYPE_STATION)
- phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM |
- IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2;
- if (i == NL80211_IFTYPE_AP)
- phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU;
- phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
- IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4;
- if (chip->support_bw160)
- phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
- phy_cap_info[5] = no_ng16 ? 0 :
- IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK |
- IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK;
- phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU |
- IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU |
- IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
- IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE;
- phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
- IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP7_MAX_NC_1;
- phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI |
- IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996;
- if (chip->support_bw160)
- phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
- IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU;
- phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
- IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
- IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
- IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB |
- u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
- IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
- if (i == NL80211_IFTYPE_STATION)
- phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
- he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map);
- he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map);
- if (chip->support_bw160) {
- he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map);
- he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map);
- }
-
- if (band == NL80211_BAND_6GHZ) {
- __le16 capa;
+ iftype_data[idx].types_mask = BIT(iftype);
- capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE,
- IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
- le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
- IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
- le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
- IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
- iftype_data[idx].he_6ghz_capa.capa = capa;
- }
+ rtw89_init_he_cap(rtwdev, band, iftype, &iftype_data[idx]);
+ rtw89_init_eht_cap(rtwdev, band, iftype, &iftype_data[idx]);
idx++;
}
- sband->iftype_data = iftype_data;
- sband->n_iftype_data = idx;
+ _ieee80211_set_sband_iftype_data(sband, iftype_data, idx);
}
static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
@@ -3375,7 +4007,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
if (!sband_2ghz)
goto err;
rtw89_init_ht_cap(rtwdev, &sband_2ghz->ht_cap);
- rtw89_init_he_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz);
+ rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz);
hw->wiphy->bands[NL80211_BAND_2GHZ] = sband_2ghz;
}
@@ -3385,7 +4017,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
goto err;
rtw89_init_ht_cap(rtwdev, &sband_5ghz->ht_cap);
rtw89_init_vht_cap(rtwdev, &sband_5ghz->vht_cap);
- rtw89_init_he_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz);
+ rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz);
hw->wiphy->bands[NL80211_BAND_5GHZ] = sband_5ghz;
}
@@ -3393,7 +4025,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev)
sband_6ghz = kmemdup(&rtw89_sband_6ghz, size, GFP_KERNEL);
if (!sband_6ghz)
goto err;
- rtw89_init_he_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz);
+ rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz);
hw->wiphy->bands[NL80211_BAND_6GHZ] = sband_6ghz;
}
@@ -3404,11 +4036,11 @@ err:
hw->wiphy->bands[NL80211_BAND_5GHZ] = NULL;
hw->wiphy->bands[NL80211_BAND_6GHZ] = NULL;
if (sband_2ghz)
- kfree(sband_2ghz->iftype_data);
+ kfree((__force void *)sband_2ghz->iftype_data);
if (sband_5ghz)
- kfree(sband_5ghz->iftype_data);
+ kfree((__force void *)sband_5ghz->iftype_data);
if (sband_6ghz)
- kfree(sband_6ghz->iftype_data);
+ kfree((__force void *)sband_6ghz->iftype_data);
kfree(sband_2ghz);
kfree(sband_5ghz);
kfree(sband_6ghz);
@@ -3420,11 +4052,11 @@ static void rtw89_core_clr_supported_band(struct rtw89_dev *rtwdev)
struct ieee80211_hw *hw = rtwdev->hw;
if (hw->wiphy->bands[NL80211_BAND_2GHZ])
- kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
+ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_2GHZ]->iftype_data);
if (hw->wiphy->bands[NL80211_BAND_5GHZ])
- kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
+ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_5GHZ]->iftype_data);
if (hw->wiphy->bands[NL80211_BAND_6GHZ])
- kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
+ kfree((__force void *)hw->wiphy->bands[NL80211_BAND_6GHZ]->iftype_data);
kfree(hw->wiphy->bands[NL80211_BAND_2GHZ]);
kfree(hw->wiphy->bands[NL80211_BAND_5GHZ]);
kfree(hw->wiphy->bands[NL80211_BAND_6GHZ]);
@@ -3454,22 +4086,22 @@ void rtw89_core_update_beacon_work(struct work_struct *work)
rtwdev = rtwvif->rtwdev;
mutex_lock(&rtwdev->mutex);
- rtw89_fw_h2c_update_beacon(rtwdev, rtwvif);
+ rtw89_chip_h2c_update_beacon(rtwdev, rtwvif);
mutex_unlock(&rtwdev->mutex);
}
int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond)
{
struct completion *cmpl = &wait->completion;
- unsigned long timeout;
+ unsigned long time_left;
unsigned int cur;
cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond);
if (cur != RTW89_WAIT_COND_IDLE)
return -EBUSY;
- timeout = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT);
- if (timeout == 0) {
+ time_left = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT);
+ if (time_left == 0) {
atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE);
return -ETIMEDOUT;
}
@@ -3493,11 +4125,50 @@ void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond,
complete(&wait->completion);
}
+void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event)
+{
+ u16 bt_req_len;
+
+ switch (event) {
+ case RTW89_BTC_HMSG_SET_BT_REQ_SLOT:
+ bt_req_len = rtw89_coex_query_bt_req_len(rtwdev, RTW89_PHY_0);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "coex updates BT req len to %d TU\n", bt_req_len);
+ rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_BT_SLOT_CHANGE);
+ break;
+ default:
+ if (event < NUM_OF_RTW89_BTC_HMSG)
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "unhandled BTC HMSG event: %d\n", event);
+ else
+ rtw89_warn(rtwdev,
+ "unrecognized BTC HMSG event: %d\n", event);
+ break;
+ }
+}
+
+void rtw89_check_quirks(struct rtw89_dev *rtwdev, const struct dmi_system_id *quirks)
+{
+ const struct dmi_system_id *match;
+ enum rtw89_quirks quirk;
+
+ if (!quirks)
+ return;
+
+ for (match = dmi_first_match(quirks); match; match = dmi_first_match(match + 1)) {
+ quirk = (uintptr_t)match->driver_data;
+ if (quirk >= NUM_OF_RTW89_QUIRKS)
+ continue;
+
+ set_bit(quirk, rtwdev->quirks);
+ }
+}
+EXPORT_SYMBOL(rtw89_check_quirks);
+
int rtw89_core_start(struct rtw89_dev *rtwdev)
{
int ret;
- rtwdev->mac.qta_mode = RTW89_QTA_SCC;
ret = rtw89_mac_init(rtwdev);
if (ret) {
rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret);
@@ -3509,14 +4180,12 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
/* efuse process */
/* pre-config BB/RF, BB reset/RFC reset */
- ret = rtw89_chip_disable_bb_rf(rtwdev);
- if (ret)
- return ret;
- ret = rtw89_chip_enable_bb_rf(rtwdev);
+ ret = rtw89_chip_reset_bb_rf(rtwdev);
if (ret)
return ret;
rtw89_phy_init_bb_reg(rtwdev);
+ rtw89_chip_bb_postinit(rtwdev);
rtw89_phy_init_rf_reg(rtwdev, false);
rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL);
@@ -3526,6 +4195,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
rtw89_mac_cfg_ppdu_status(rtwdev, RTW89_MAC_0, true);
rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0);
+ rtw89_tas_reset(rtwdev);
+
ret = rtw89_hci_start(rtwdev);
if (ret) {
rtw89_err(rtwdev, "failed to start hci\n");
@@ -3537,6 +4208,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
set_bit(RTW89_FLAG_RUNNING, rtwdev->flags);
+ rtw89_chip_rfk_init_late(rtwdev);
rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON);
rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable);
rtw89_fw_h2c_init_ba_cam(rtwdev);
@@ -3566,6 +4238,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
cancel_work_sync(&btc->icmp_notify_work);
cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work);
cancel_delayed_work_sync(&rtwdev->track_work);
+ cancel_delayed_work_sync(&rtwdev->chanctx_work);
cancel_delayed_work_sync(&rtwdev->coex_act1_work);
cancel_delayed_work_sync(&rtwdev->coex_bt_devinfo_work);
cancel_delayed_work_sync(&rtwdev->coex_rfk_chk_work);
@@ -3584,6 +4257,25 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev)
rtw89_hci_reset(rtwdev);
}
+u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 mac_id_num = chip->support_macid_num;
+ u8 mac_id;
+
+ mac_id = find_first_zero_bit(rtwdev->mac_id_map, mac_id_num);
+ if (mac_id == mac_id_num)
+ return RTW89_MAX_MAC_ID_NUM;
+
+ set_bit(mac_id, rtwdev->mac_id_map);
+ return mac_id;
+}
+
+void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id)
+{
+ clear_bit(mac_id, rtwdev->mac_id_map);
+}
+
int rtw89_core_init(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -3602,6 +4294,7 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work);
INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work);
INIT_DELAYED_WORK(&rtwdev->track_work, rtw89_track_work);
+ INIT_DELAYED_WORK(&rtwdev->chanctx_work, rtw89_chanctx_work);
INIT_DELAYED_WORK(&rtwdev->coex_act1_work, rtw89_coex_act1_work);
INIT_DELAYED_WORK(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work);
INIT_DELAYED_WORK(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work);
@@ -3630,6 +4323,15 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
rtw89_traffic_stats_init(rtwdev, &rtwdev->stats);
rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR;
+ rtwdev->dbcc_en = false;
+ rtwdev->mlo_dbcc_mode = MLO_DBCC_NOT_SUPPORT;
+ rtwdev->mac.qta_mode = RTW89_QTA_SCC;
+
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
+ rtwdev->dbcc_en = true;
+ rtwdev->mac.qta_mode = RTW89_QTA_DBCC;
+ rtwdev->mlo_dbcc_mode = MLO_2_PLUS_0_1RF;
+ }
INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work);
INIT_WORK(&btc->arp_notify_work, rtw89_btc_ntfy_arp_packet_work);
@@ -3637,11 +4339,13 @@ int rtw89_core_init(struct rtw89_dev *rtwdev)
INIT_WORK(&btc->icmp_notify_work, rtw89_btc_ntfy_icmp_packet_work);
init_completion(&rtwdev->fw.req.completion);
+ init_completion(&rtwdev->rfk_wait.completion);
schedule_work(&rtwdev->load_firmware_work);
rtw89_ser_init(rtwdev);
rtw89_entity_init(rtwdev);
+ rtw89_tas_init(rtwdev);
return 0;
}
@@ -3662,7 +4366,8 @@ EXPORT_SYMBOL(rtw89_core_deinit);
void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
const u8 *mac_addr, bool hw_scan)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
rtwdev->scanning = true;
rtw89_leave_lps(rtwdev);
@@ -3716,7 +4421,7 @@ static void rtw89_read_chip_ver(struct rtw89_dev *rtwdev)
rtwdev->hal.cv = cv;
- if (chip->chip_id == RTL8852B || chip->chip_id == RTL8851B) {
+ if (rtw89_is_rtl885xb(rtwdev)) {
ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_CV, &val);
if (ret)
return;
@@ -3739,36 +4444,43 @@ static void rtw89_core_setup_rfe_parms(struct rtw89_dev *rtwdev)
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_rfe_parms_conf *conf = chip->rfe_parms_conf;
struct rtw89_efuse *efuse = &rtwdev->efuse;
+ const struct rtw89_rfe_parms *sel;
u8 rfe_type = efuse->rfe_type;
- if (!conf)
+ if (!conf) {
+ sel = chip->dflt_parms;
goto out;
+ }
while (conf->rfe_parms) {
if (rfe_type == conf->rfe_type) {
- rtwdev->rfe_parms = conf->rfe_parms;
- return;
+ sel = conf->rfe_parms;
+ goto out;
}
conf++;
}
+ sel = chip->dflt_parms;
+
out:
- rtwdev->rfe_parms = chip->dflt_parms;
+ rtwdev->rfe_parms = rtw89_load_rfe_data_from_fw(rtwdev, sel);
+ rtw89_load_txpwr_table(rtwdev, rtwdev->rfe_parms->byr_tbl);
}
static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
- ret = rtw89_mac_partial_init(rtwdev);
+ ret = rtw89_mac_partial_init(rtwdev, false);
if (ret)
return ret;
- ret = rtw89_parse_efuse_map(rtwdev);
+ ret = mac->parse_efuse_map(rtwdev);
if (ret)
return ret;
- ret = rtw89_parse_phycap_map(rtwdev);
+ ret = mac->parse_phycap_map(rtwdev);
if (ret)
return ret;
@@ -3777,7 +4489,8 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
return ret;
rtw89_core_setup_phycap(rtwdev);
- rtw89_core_setup_rfe_parms(rtwdev);
+
+ rtw89_hci_mac_pre_deinit(rtwdev);
rtw89_mac_pwr_off(rtwdev);
@@ -3809,20 +4522,21 @@ int rtw89_chip_info_setup(struct rtw89_dev *rtwdev)
return ret;
}
+ ret = rtw89_chip_efuse_info_setup(rtwdev);
+ if (ret)
+ return ret;
+
ret = rtw89_fw_recognize_elements(rtwdev);
if (ret) {
rtw89_err(rtwdev, "failed to recognize firmware elements\n");
return ret;
}
- ret = rtw89_chip_efuse_info_setup(rtwdev);
- if (ret)
- return ret;
-
ret = rtw89_chip_board_info_setup(rtwdev);
if (ret)
return ret;
+ rtw89_core_setup_rfe_parms(rtwdev);
rtwdev->ps_mode = rtw89_update_ps_mode(rtwdev);
return 0;
@@ -3831,6 +4545,7 @@ EXPORT_SYMBOL(rtw89_chip_info_setup);
static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
struct ieee80211_hw *hw = rtwdev->hw;
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw89_hal *hal = &rtwdev->hal;
@@ -3850,6 +4565,10 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
hw->max_tx_aggregation_subframes = RTW89_MAX_TX_AGG_NUM;
hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;
+ hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |
+ IEEE80211_RADIOTAP_MCS_HAVE_STBC;
+ hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC;
+
ieee80211_hw_set(hw, SIGNAL_DBM);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
ieee80211_hw_set(hw, MFP_CAPABLE);
@@ -3864,6 +4583,10 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+
+ if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160))
+ ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
+
if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw))
ieee80211_hw_set(hw, CONNECTION_MONITOR);
@@ -3882,7 +4605,15 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_TDLS_EXTERNAL_SETUP |
- WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_SPLIT_SCAN_6GHZ;
+ WIPHY_FLAG_AP_UAPSD |
+ WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK;
+
+ if (!chip->support_rnr)
+ hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ;
+
+ if (chip->chip_gen == RTW89_CHIP_BE)
+ hw->wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT;
+
hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
hw->wiphy->max_scan_ssids = RTW89_SCANOFLD_MAX_SSID;
@@ -3899,6 +4630,8 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
hw->wiphy->max_remain_on_channel_duration = 1000;
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SCAN_RANDOM_SN);
+ wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
ret = rtw89_core_set_supported_band(rtwdev);
if (ret) {
@@ -3990,9 +4723,10 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
!RTW89_CHK_FW_FEATURE(BEACON_FILTER, &early_fw);
if (no_chanctx) {
- ops->add_chanctx = NULL;
- ops->remove_chanctx = NULL;
- ops->change_chanctx = NULL;
+ ops->add_chanctx = ieee80211_emulate_add_chanctx;
+ ops->remove_chanctx = ieee80211_emulate_remove_chanctx;
+ ops->change_chanctx = ieee80211_emulate_change_chanctx;
+ ops->switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx;
ops->assign_vif_chanctx = NULL;
ops->unassign_vif_chanctx = NULL;
ops->remain_on_channel = NULL;
@@ -4005,7 +4739,11 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
goto err;
hw->wiphy->iface_combinations = rtw89_iface_combs;
- hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw89_iface_combs);
+
+ if (no_chanctx || chip->support_chanctx_num == 1)
+ hw->wiphy->n_iface_combinations = 1;
+ else
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw89_iface_combs);
rtwdev = hw->priv;
rtwdev->hw = hw;
@@ -4030,6 +4768,7 @@ EXPORT_SYMBOL(rtw89_alloc_ieee80211_hw);
void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev)
{
kfree(rtwdev->ops);
+ kfree(rtwdev->rfe_data);
release_firmware(rtwdev->fw.req.firmware);
ieee80211_free_hw(rtwdev->hw);
}
diff --git a/sys/contrib/dev/rtw89/core.h b/sys/contrib/dev/rtw89/core.h
index 6843d84deb3a..287f384218f7 100644
--- a/sys/contrib/dev/rtw89/core.h
+++ b/sys/contrib/dev/rtw89/core.h
@@ -7,6 +7,7 @@
#include <linux/average.h>
#include <linux/bitfield.h>
+#include <linux/dmi.h>
#include <linux/firmware.h>
#include <linux/iopoll.h>
#include <linux/workqueue.h>
@@ -20,6 +21,12 @@
struct rtw89_dev;
struct rtw89_pci_info;
+struct rtw89_mac_gen_def;
+struct rtw89_phy_gen_def;
+struct rtw89_efuse_block_cfg;
+struct rtw89_h2c_rf_tssi;
+struct rtw89_fw_txpwr_track_cfg;
+struct rtw89_phy_rfk_log_fmt;
extern const struct ieee80211_ops rtw89_ops;
@@ -33,6 +40,7 @@ extern const struct ieee80211_ops rtw89_ops;
#define MASKDWORD 0xffffffff
#define RFREG_MASK 0xfffff
#define INV_RF_DATA 0xffffffff
+#define BYPASS_CR_DATA 0xbabecafe
#define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2)
#define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4)
@@ -41,7 +49,16 @@ extern const struct ieee80211_ops rtw89_ops;
#define RSSI_FACTOR 1
#define RTW89_RSSI_RAW_TO_DBM(rssi) ((s8)((rssi) >> RSSI_FACTOR) - MAX_RSSI)
#define RTW89_TX_DIV_RSSI_RAW_TH (2 << RSSI_FACTOR)
-#define RTW89_RADIOTAP_ROOM ALIGN(sizeof(struct ieee80211_radiotap_he), 64)
+#define DELTA_SWINGIDX_SIZE 30
+
+#define RTW89_RADIOTAP_ROOM_HE sizeof(struct ieee80211_radiotap_he)
+#define RTW89_RADIOTAP_ROOM_EHT \
+ (sizeof(struct ieee80211_radiotap_tlv) + \
+ ALIGN(struct_size((struct ieee80211_radiotap_eht *)0, user_info, 1), 4) + \
+ sizeof(struct ieee80211_radiotap_tlv) + \
+ ALIGN(sizeof(struct ieee80211_radiotap_eht_usig), 4))
+#define RTW89_RADIOTAP_ROOM \
+ ALIGN(max(RTW89_RADIOTAP_ROOM_HE, RTW89_RADIOTAP_ROOM_EHT), 64)
#define RTW89_HTC_MASK_VARIANT GENMASK(1, 0)
#define RTW89_HTC_VARIANT_HE 3
@@ -100,6 +117,14 @@ enum rtw89_gain_offset {
RTW89_GAIN_OFFSET_5G_LOW,
RTW89_GAIN_OFFSET_5G_MID,
RTW89_GAIN_OFFSET_5G_HIGH,
+ RTW89_GAIN_OFFSET_6G_L0,
+ RTW89_GAIN_OFFSET_6G_L1,
+ RTW89_GAIN_OFFSET_6G_M0,
+ RTW89_GAIN_OFFSET_6G_M1,
+ RTW89_GAIN_OFFSET_6G_H0,
+ RTW89_GAIN_OFFSET_6G_H1,
+ RTW89_GAIN_OFFSET_6G_UH0,
+ RTW89_GAIN_OFFSET_6G_UH1,
RTW89_GAIN_OFFSET_NR,
};
@@ -113,6 +138,7 @@ enum rtw89_hci_type {
enum rtw89_core_chip_id {
RTL8852A,
RTL8852B,
+ RTL8852BT,
RTL8852C,
RTL8851B,
RTL8922A,
@@ -644,12 +670,29 @@ enum rtw89_rate_section {
RTW89_RS_TX_SHAPE_NUM = RTW89_RS_OFDM + 1,
};
+enum rtw89_rate_offset_indexes {
+ RTW89_RATE_OFFSET_HE,
+ RTW89_RATE_OFFSET_VHT,
+ RTW89_RATE_OFFSET_HT,
+ RTW89_RATE_OFFSET_OFDM,
+ RTW89_RATE_OFFSET_CCK,
+ RTW89_RATE_OFFSET_DLRU_EHT,
+ RTW89_RATE_OFFSET_DLRU_HE,
+ RTW89_RATE_OFFSET_EHT,
+ __RTW89_RATE_OFFSET_NUM,
+
+ RTW89_RATE_OFFSET_NUM_AX = RTW89_RATE_OFFSET_CCK + 1,
+ RTW89_RATE_OFFSET_NUM_BE = RTW89_RATE_OFFSET_EHT + 1,
+};
+
enum rtw89_rate_num {
RTW89_RATE_CCK_NUM = 4,
RTW89_RATE_OFDM_NUM = 8,
- RTW89_RATE_MCS_NUM = 12,
RTW89_RATE_HEDCM_NUM = 4, /* for HEDCM MCS0/1/3/4 */
- RTW89_RATE_OFFSET_NUM = 5, /* for HE(HEDCM)/VHT/HT/OFDM/CCK offset */
+
+ RTW89_RATE_MCS_NUM_AX = 12,
+ RTW89_RATE_MCS_NUM_BE = 16,
+ __RTW89_RATE_MCS_NUM = 16,
};
enum rtw89_nss {
@@ -674,6 +717,12 @@ enum rtw89_beamforming_type {
RTW89_BF_NUM,
};
+enum rtw89_ofdma_type {
+ RTW89_NON_OFDMA = 0,
+ RTW89_OFDMA = 1,
+ RTW89_OFDMA_NUM,
+};
+
enum rtw89_regulation_type {
RTW89_WW = 0,
RTW89_ETSI = 1,
@@ -690,6 +739,7 @@ enum rtw89_regulation_type {
RTW89_CN = 12,
RTW89_QATAR = 13,
RTW89_UK = 14,
+ RTW89_THAILAND = 15,
RTW89_REGD_NUM,
};
@@ -702,6 +752,14 @@ enum rtw89_reg_6ghz_power {
RTW89_REG_6GHZ_POWER_DFLT = RTW89_REG_6GHZ_POWER_VLP,
};
+#define RTW89_MIN_VALID_POWER_CONSTRAINT (-10) /* unit: dBm */
+
+/* calculate based on ieee80211 Transmit Power Envelope */
+struct rtw89_reg_6ghz_tpe {
+ bool valid;
+ s8 constraint; /* unit: dBm */
+};
+
enum rtw89_fw_pkt_ofld_type {
RTW89_PKT_OFLD_TYPE_PROBE_RSP = 0,
RTW89_PKT_OFLD_TYPE_PS_POLL = 1,
@@ -719,44 +777,16 @@ enum rtw89_fw_pkt_ofld_type {
struct rtw89_txpwr_byrate {
s8 cck[RTW89_RATE_CCK_NUM];
s8 ofdm[RTW89_RATE_OFDM_NUM];
- s8 mcs[RTW89_NSS_NUM][RTW89_RATE_MCS_NUM];
- s8 hedcm[RTW89_NSS_HEDCM_NUM][RTW89_RATE_HEDCM_NUM];
- s8 offset[RTW89_RATE_OFFSET_NUM];
-};
-
-enum rtw89_bandwidth_section_num {
- RTW89_BW20_SEC_NUM = 8,
- RTW89_BW40_SEC_NUM = 4,
- RTW89_BW80_SEC_NUM = 2,
-};
-
-#define RTW89_TXPWR_LMT_PAGE_SIZE 40
-
-struct rtw89_txpwr_limit {
- s8 cck_20m[RTW89_BF_NUM];
- s8 cck_40m[RTW89_BF_NUM];
- s8 ofdm[RTW89_BF_NUM];
- s8 mcs_20m[RTW89_BW20_SEC_NUM][RTW89_BF_NUM];
- s8 mcs_40m[RTW89_BW40_SEC_NUM][RTW89_BF_NUM];
- s8 mcs_80m[RTW89_BW80_SEC_NUM][RTW89_BF_NUM];
- s8 mcs_160m[RTW89_BF_NUM];
- s8 mcs_40m_0p5[RTW89_BF_NUM];
- s8 mcs_40m_2p5[RTW89_BF_NUM];
-};
-
-#define RTW89_RU_SEC_NUM 8
-
-#define RTW89_TXPWR_LMT_RU_PAGE_SIZE 24
-
-struct rtw89_txpwr_limit_ru {
- s8 ru26[RTW89_RU_SEC_NUM];
- s8 ru52[RTW89_RU_SEC_NUM];
- s8 ru106[RTW89_RU_SEC_NUM];
+ s8 mcs[RTW89_OFDMA_NUM][RTW89_NSS_NUM][__RTW89_RATE_MCS_NUM];
+ s8 hedcm[RTW89_OFDMA_NUM][RTW89_NSS_HEDCM_NUM][RTW89_RATE_HEDCM_NUM];
+ s8 offset[__RTW89_RATE_OFFSET_NUM];
+ s8 trap;
};
struct rtw89_rate_desc {
enum rtw89_nss nss;
enum rtw89_rate_section rs;
+ enum rtw89_ofdma_type ofdma;
u8 idx;
};
@@ -778,6 +808,8 @@ struct rtw89_rx_phy_ppdu {
u8 evm_max;
u8 evm_min;
} ofdm;
+ bool ldpc;
+ bool stbc;
bool to_self;
bool valid;
};
@@ -785,6 +817,7 @@ struct rtw89_rx_phy_ppdu {
enum rtw89_mac_idx {
RTW89_MAC_0 = 0,
RTW89_MAC_1 = 1,
+ RTW89_MAC_NUM,
};
enum rtw89_phy_idx {
@@ -795,6 +828,7 @@ enum rtw89_phy_idx {
enum rtw89_sub_entity_idx {
RTW89_SUB_ENTITY_0 = 0,
+ RTW89_SUB_ENTITY_1 = 1,
NUM_OF_RTW89_SUB_ENTITY,
RTW89_SUB_ENTITY_IDLE = NUM_OF_RTW89_SUB_ENTITY,
@@ -844,9 +878,14 @@ enum rtw89_bandwidth {
RTW89_CHANNEL_WIDTH_40 = 1,
RTW89_CHANNEL_WIDTH_80 = 2,
RTW89_CHANNEL_WIDTH_160 = 3,
- RTW89_CHANNEL_WIDTH_80_80 = 4,
- RTW89_CHANNEL_WIDTH_5 = 5,
- RTW89_CHANNEL_WIDTH_10 = 6,
+ RTW89_CHANNEL_WIDTH_320 = 4,
+
+ /* keep index order above */
+ RTW89_CHANNEL_WIDTH_ORDINARY_NUM = 5,
+
+ RTW89_CHANNEL_WIDTH_80_80 = 5,
+ RTW89_CHANNEL_WIDTH_5 = 6,
+ RTW89_CHANNEL_WIDTH_10 = 7,
};
enum rtw89_ps_mode {
@@ -858,13 +897,23 @@ enum rtw89_ps_mode {
#define RTW89_2G_BW_NUM (RTW89_CHANNEL_WIDTH_40 + 1)
#define RTW89_5G_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1)
-#define RTW89_6G_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1)
-#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1)
+#define RTW89_6G_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1)
+#define RTW89_BYR_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1)
+#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1)
+
+enum rtw89_pe_duration {
+ RTW89_PE_DURATION_0 = 0,
+ RTW89_PE_DURATION_8 = 1,
+ RTW89_PE_DURATION_16 = 2,
+ RTW89_PE_DURATION_16_20 = 3,
+};
enum rtw89_ru_bandwidth {
RTW89_RU26 = 0,
RTW89_RU52 = 1,
RTW89_RU106 = 2,
+ RTW89_RU52_26 = 3,
+ RTW89_RU106_26 = 4,
RTW89_RU_NUM,
};
@@ -901,11 +950,13 @@ struct rtw89_chan {
u32 freq;
enum rtw89_subband subband_type;
enum rtw89_sc_offset pri_ch_idx;
+ u8 pri_sb_idx;
};
struct rtw89_chan_rcd {
u8 prev_primary_channel;
enum rtw89_band prev_band_type;
+ bool band_changed;
};
struct rtw89_channel_help_params {
@@ -928,6 +979,15 @@ struct rtw89_port_reg {
u32 bcn_cnt_tmr;
u32 tsftr_l;
u32 tsftr_h;
+ u32 md_tsft;
+ u32 bss_color;
+ u32 mbssid;
+ u32 mbssid_drop;
+ u32 tsf_sync;
+ u32 ptcl_dbg;
+ u32 ptcl_dbg_info;
+ u32 bcn_drop_all;
+ u32 hiq_win[RTW89_PORT_NUM];
};
struct rtw89_txwd_body {
@@ -950,6 +1010,17 @@ struct rtw89_txwd_body_v1 {
__le32 dword7;
} __packed;
+struct rtw89_txwd_body_v2 {
+ __le32 dword0;
+ __le32 dword1;
+ __le32 dword2;
+ __le32 dword3;
+ __le32 dword4;
+ __le32 dword5;
+ __le32 dword6;
+ __le32 dword7;
+} __packed;
+
struct rtw89_txwd_info {
__le32 dword0;
__le32 dword1;
@@ -959,10 +1030,23 @@ struct rtw89_txwd_info {
__le32 dword5;
} __packed;
+struct rtw89_txwd_info_v2 {
+ __le32 dword0;
+ __le32 dword1;
+ __le32 dword2;
+ __le32 dword3;
+ __le32 dword4;
+ __le32 dword5;
+ __le32 dword6;
+ __le32 dword7;
+} __packed;
+
struct rtw89_rx_desc_info {
u16 pkt_size;
u8 pkt_type;
u8 drv_info_size;
+ u8 phy_rpt_size;
+ u8 hdr_cnv_size;
u8 shift;
u8 wl_hd_iv_len;
bool long_rxdesc;
@@ -1001,6 +1085,15 @@ struct rtw89_rxdesc_short {
__le32 dword3;
} __packed;
+struct rtw89_rxdesc_short_v2 {
+ __le32 dword0;
+ __le32 dword1;
+ __le32 dword2;
+ __le32 dword3;
+ __le32 dword4;
+ __le32 dword5;
+} __packed;
+
struct rtw89_rxdesc_long {
__le32 dword0;
__le32 dword1;
@@ -1012,6 +1105,19 @@ struct rtw89_rxdesc_long {
__le32 dword7;
} __packed;
+struct rtw89_rxdesc_long_v2 {
+ __le32 dword0;
+ __le32 dword1;
+ __le32 dword2;
+ __le32 dword3;
+ __le32 dword4;
+ __le32 dword5;
+ __le32 dword6;
+ __le32 dword7;
+ __le32 dword8;
+ __le32 dword9;
+} __packed;
+
struct rtw89_tx_desc_info {
u16 pkt_size;
u8 wp_offset;
@@ -1047,6 +1153,8 @@ struct rtw89_tx_desc_info {
bool hiq;
u8 port;
bool er_cap;
+ bool stbc;
+ bool ldpc;
};
struct rtw89_core_tx_request {
@@ -1071,9 +1179,15 @@ struct rtw89_mac_ax_gnt {
u8 gnt_wl;
} __packed;
+struct rtw89_mac_ax_wl_act {
+ u8 wlan_act_en;
+ u8 wlan_act;
+};
+
#define RTW89_MAC_AX_COEX_GNT_NR 2
struct rtw89_mac_ax_coex_gnt {
struct rtw89_mac_ax_gnt band[RTW89_MAC_AX_COEX_GNT_NR];
+ struct rtw89_mac_ax_wl_act bt[RTW89_MAC_AX_COEX_GNT_NR];
};
enum rtw89_btc_ncnt {
@@ -1092,9 +1206,13 @@ enum rtw89_btc_ncnt {
BTC_NCNT_CUSTOMERIZE,
BTC_NCNT_WL_RFK,
BTC_NCNT_WL_STA,
+ BTC_NCNT_WL_STA_LAST,
BTC_NCNT_FWINFO,
BTC_NCNT_TIMER,
- BTC_NCNT_NUM
+ BTC_NCNT_SWITCH_CHBW,
+ BTC_NCNT_RESUME_DL_FW,
+ BTC_NCNT_COUNTRYCODE,
+ BTC_NCNT_NUM,
};
enum rtw89_btc_btinfo {
@@ -1123,6 +1241,7 @@ enum rtw89_btc_dcnt {
BTC_DCNT_TDMA_NONSYNC,
BTC_DCNT_SLOT_NONSYNC,
BTC_DCNT_BTCNT_HANG,
+ BTC_DCNT_BTTX_HANG,
BTC_DCNT_WL_SLOT_DRIFT,
BTC_DCNT_WL_STA_LAST,
BTC_DCNT_BT_SLOT_DRIFT,
@@ -1130,7 +1249,10 @@ enum rtw89_btc_dcnt {
BTC_DCNT_FDDT_TRIG,
BTC_DCNT_E2G,
BTC_DCNT_E2G_HANG,
- BTC_DCNT_NUM
+ BTC_DCNT_WL_FW_VER_MATCH,
+ BTC_DCNT_NULL_TX_FAIL,
+ BTC_DCNT_WL_STA_NTFY,
+ BTC_DCNT_NUM,
};
enum rtw89_btc_wl_state_cnt {
@@ -1144,6 +1266,13 @@ enum rtw89_btc_wl_state_cnt {
BTC_WCNT_RFK_REJECT,
BTC_WCNT_RFK_TIMEOUT,
BTC_WCNT_CH_UPDATE,
+ BTC_WCNT_DBCC_ALL_2G,
+ BTC_WCNT_DBCC_CHG,
+ BTC_WCNT_RX_OK_LAST,
+ BTC_WCNT_RX_OK_LAST2S,
+ BTC_WCNT_RX_ERR_LAST,
+ BTC_WCNT_RX_ERR_LAST2S,
+ BTC_WCNT_RX_LAST,
BTC_WCNT_NUM
};
@@ -1167,8 +1296,10 @@ enum rtw89_btc_bt_state_cnt {
BTC_BCNT_LOPRI_TX,
BTC_BCNT_LOPRI_RX,
BTC_BCNT_POLUT,
+ BTC_BCNT_POLUT_NOW,
+ BTC_BCNT_POLUT_DIFF,
BTC_BCNT_RATECHG,
- BTC_BCNT_NUM
+ BTC_BCNT_NUM,
};
enum rtw89_btc_bt_profile {
@@ -1191,6 +1322,18 @@ struct rtw89_btc_ant_info {
u8 stream_cnt: 4;
};
+struct rtw89_btc_ant_info_v7 {
+ u8 type; /* shared, dedicated(non-shared) */
+ u8 num; /* antenna count */
+ u8 isolation;
+ u8 single_pos;/* wifi 1ss-1ant at 0:S0 or 1:S1 */
+
+ u8 diversity; /* only for wifi use 1-antenna */
+ u8 btg_pos; /* btg-circuit at 0:S0/1:S1/others:all */
+ u8 stream_cnt; /* spatial_stream count */
+ u8 rsvd;
+} __packed;
+
enum rtw89_tfc_dir {
RTW89_TFC_UL,
RTW89_TFC_DL,
@@ -1201,6 +1344,8 @@ struct rtw89_btc_wl_smap {
u32 scan: 1;
u32 connecting: 1;
u32 roaming: 1;
+ u32 dbccing: 1;
+ u32 transacting: 1;
u32 _4way: 1;
u32 rf_off: 1;
u32 lps: 2;
@@ -1209,6 +1354,8 @@ struct rtw89_btc_wl_smap {
u32 traffic_dir : 2;
u32 rf_off_pre: 1;
u32 lps_pre: 2;
+ u32 lps_exiting: 1;
+ u32 emlsr: 1;
};
enum rtw89_tfc_lv {
@@ -1251,6 +1398,14 @@ struct rtw89_traffic_stats {
u16 rx_rate;
};
+struct rtw89_btc_chdef {
+ u8 center_ch;
+ u8 band;
+ u8 chan;
+ enum rtw89_sc_offset offset;
+ enum rtw89_bandwidth bw;
+};
+
struct rtw89_btc_statistic {
u8 rssi; /* 0%~110% (dBm = rssi -110) */
struct rtw89_traffic_stats traffic;
@@ -1259,6 +1414,7 @@ struct rtw89_btc_statistic {
#define BTC_WL_RSSI_THMAX 4
struct rtw89_btc_wl_link_info {
+ struct rtw89_btc_chdef chdef;
struct rtw89_btc_statistic stat;
enum rtw89_tfc_dir dir;
u8 rssi_state[BTC_WL_RSSI_THMAX];
@@ -1272,6 +1428,7 @@ struct rtw89_btc_wl_link_info {
u8 phy;
u8 dtim_period;
u8 mode;
+ u8 tx_1ss_limit;
u8 mac_id;
u8 tx_retry;
@@ -1281,6 +1438,7 @@ struct rtw89_btc_wl_link_info {
u32 tx_time;
u32 client_cnt;
u32 rx_rate_drop_cnt;
+ u32 noa_duration;
u32 active: 1;
u32 noa: 1;
@@ -1314,6 +1472,11 @@ struct rtw89_btc_bt_a2dp_desc {
u8 type: 3;
u8 active: 1;
u8 sink: 1;
+ u32 handle_update: 1;
+ u32 devinfo_query: 1;
+ u32 no_empty_streak_2s: 8;
+ u32 no_empty_streak_max: 8;
+ u32 rsvd: 6;
u8 bitpool;
u16 vendor_id;
@@ -1491,6 +1654,42 @@ struct rtw89_btc_wl_role_info_v2 { /* struct size must be n*4 bytes */
u32 rsvd: 27;
};
+struct rtw89_btc_wl_rlink { /* H2C info, struct size must be n*4 bytes */
+ u8 connected;
+ u8 pid;
+ u8 phy;
+ u8 noa;
+
+ u8 rf_band; /* enum band_type RF band: 2.4G/5G/6G */
+ u8 active; /* 0:rlink is under doze */
+ u8 bw; /* enum channel_width */
+ u8 role; /*enum role_type */
+
+ u8 ch;
+ u8 noa_dur; /* ms */
+ u8 client_cnt; /* for Role = P2P-Go/AP */
+ u8 mode; /* wifi protocol */
+} __packed;
+
+#define RTW89_BE_BTC_WL_MAX_ROLE_NUMBER 6
+struct rtw89_btc_wl_role_info_v8 { /* H2C info, struct size must be n*4 bytes */
+ u8 connect_cnt;
+ u8 link_mode;
+ u8 link_mode_chg;
+ u8 p2p_2g;
+
+ u8 pta_req_band;
+ u8 dbcc_en; /* 1+1 and 2.4G-included */
+ u8 dbcc_chg;
+ u8 dbcc_2g_phy; /* which phy operate in 2G, HW_PHY_0 or HW_PHY_1 */
+
+ struct rtw89_btc_wl_rlink rlink[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER][RTW89_MAC_NUM];
+
+ u32 role_map;
+ u32 mrole_type; /* btc_wl_mrole_type */
+ u32 mrole_noa_duration; /* ms */
+} __packed;
+
struct rtw89_btc_wl_ver_info {
u32 fw_coex; /* match with which coex_ver */
u32 fw;
@@ -1513,6 +1712,9 @@ struct rtw89_btc_wl_rfk_info {
u32 band: 2;
u32 type: 8;
u32 rsvd: 14;
+
+ u32 start_time;
+ u32 proc_time;
};
struct rtw89_btc_bt_smap {
@@ -1585,6 +1787,16 @@ struct rtw89_btc_dm_emap {
u32 wl_e2g_hang: 1;
u32 wl_ver_mismatch: 1;
u32 bt_ver_mismatch: 1;
+ u32 rfe_type0: 1;
+ u32 h2c_buffer_over: 1;
+ u32 bt_tx_hang: 1; /* for SNR too low bug, BT has no Tx req*/
+ u32 wl_no_sta_ntfy: 1;
+
+ u32 h2c_bmap_mismatch: 1;
+ u32 c2h_bmap_mismatch: 1;
+ u32 h2c_struct_invalid: 1;
+ u32 c2h_struct_invalid: 1;
+ u32 h2c_c2h_buffer_mismatch: 1;
};
union rtw89_btc_dm_error_map {
@@ -1616,12 +1828,14 @@ struct rtw89_btc_wl_nhm {
struct rtw89_btc_wl_info {
struct rtw89_btc_wl_link_info link_info[RTW89_PORT_NUM];
+ struct rtw89_btc_wl_link_info rlink_info[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER][RTW89_MAC_NUM];
struct rtw89_btc_wl_rfk_info rfk_info;
struct rtw89_btc_wl_ver_info ver_info;
struct rtw89_btc_wl_afh_info afh_info;
struct rtw89_btc_wl_role_info role_info;
struct rtw89_btc_wl_role_info_v1 role_info_v1;
struct rtw89_btc_wl_role_info_v2 role_info_v2;
+ struct rtw89_btc_wl_role_info_v8 role_info_v8;
struct rtw89_btc_wl_scan_info scan_info;
struct rtw89_btc_wl_dbcc_info dbcc_info;
struct rtw89_btc_rf_para rf_para;
@@ -1631,8 +1845,15 @@ struct rtw89_btc_wl_info {
u8 port_id[RTW89_WIFI_ROLE_MLME_MAX];
u8 rssi_level;
u8 cn_report;
+ u8 coex_mode;
+ u8 pta_req_mac;
+ u8 bt_polut_type[RTW89_PHY_MAX]; /* BT polluted WL-Tx type for phy0/1 */
+ bool is_5g_hi_channel;
+ bool pta_reg_mac_chg;
+ bool bg_mode;
bool scbd_change;
+ bool fw_ver_mismatch;
u32 scbd;
};
@@ -1649,6 +1870,25 @@ struct rtw89_btc_module {
u8 kt_ver_adie;
};
+struct rtw89_btc_module_v7 {
+ u8 rfe_type;
+ u8 kt_ver;
+ u8 bt_solo;
+ u8 bt_pos; /* wl-end view: get from efuse, must compare bt.btg_type*/
+
+ u8 switch_type; /* WL/BT switch type: 0: internal, 1: external */
+ u8 wa_type; /* WA type: 0:none, 1: 51B 5G_Hi-Ch_Rx */
+ u8 kt_ver_adie;
+ u8 rsvd;
+
+ struct rtw89_btc_ant_info_v7 ant;
+} __packed;
+
+union rtw89_btc_module_info {
+ struct rtw89_btc_module md;
+ struct rtw89_btc_module_v7 md_v7;
+};
+
#define RTW89_BTC_DM_MAXSTEP 30
#define RTW89_BTC_DM_CNT_MAX (RTW89_BTC_DM_MAXSTEP * 8)
@@ -1671,6 +1911,25 @@ struct rtw89_btc_init_info {
u16 rsvd;
};
+struct rtw89_btc_init_info_v7 {
+ u8 wl_guard_ch;
+ u8 wl_only;
+ u8 wl_init_ok;
+ u8 rsvd3;
+
+ u8 cx_other;
+ u8 bt_only;
+ u8 pta_mode;
+ u8 pta_direction;
+
+ struct rtw89_btc_module_v7 module;
+} __packed;
+
+union rtw89_btc_init_info_u {
+ struct rtw89_btc_init_info init;
+ struct rtw89_btc_init_info_v7 init_v7;
+};
+
struct rtw89_btc_wl_tx_limit_para {
u16 enable;
u32 tx_time; /* unit: us */
@@ -1722,9 +1981,18 @@ struct rtw89_btc_fbtc_btscan_v2 {
struct rtw89_btc_bt_scan_info_v2 para[CXSCAN_MAX];
} __packed;
+struct rtw89_btc_fbtc_btscan_v7 {
+ u8 fver; /* btc_ver::fcxbtscan */
+ u8 type;
+ u8 rsvd0;
+ u8 rsvd1;
+ struct rtw89_btc_bt_scan_info_v2 para[CXSCAN_MAX];
+} __packed;
+
union rtw89_btc_fbtc_btscan {
struct rtw89_btc_fbtc_btscan_v1 v1;
struct rtw89_btc_fbtc_btscan_v2 v2;
+ struct rtw89_btc_fbtc_btscan_v7 v7;
};
struct rtw89_btc_bt_info {
@@ -1738,6 +2006,7 @@ struct rtw89_btc_bt_info {
union rtw89_btc_bt_rfk_info_map rfk_info;
u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
+ u8 rssi_level;
u32 scbd;
u32 feature;
@@ -1754,7 +2023,8 @@ struct rtw89_btc_bt_info {
u32 hi_lna_rx: 1;
u32 scan_rx_low_pri: 1;
u32 scan_info_update: 1;
- u32 rsvd: 20;
+ u32 lna_constrain: 3;
+ u32 rsvd: 17;
};
struct rtw89_btc_cx {
@@ -1864,6 +2134,20 @@ struct rtw89_btc_fbtc_rpt_ctrl_info_v5 {
__le16 cnt_aoac_rf_off; /* rf-off counter for aoac switch notify */
} __packed;
+struct rtw89_btc_fbtc_rpt_ctrl_info_v8 {
+ __le16 cnt; /* fw report counter */
+ __le16 cnt_c2h; /* fw send c2h counter */
+ __le16 cnt_h2c; /* fw recv h2c counter */
+ __le16 len_c2h; /* The total length of the last C2H */
+
+ __le16 cnt_aoac_rf_on; /* rf-on counter for aoac switch notify */
+ __le16 cnt_aoac_rf_off; /* rf-off counter for aoac switch notify */
+
+ __le32 cx_ver; /* match which driver's coex version */
+ __le32 fw_ver;
+ __le32 en; /* report map */
+} __packed;
+
struct rtw89_btc_fbtc_rpt_ctrl_wl_fw_info {
__le32 cx_ver; /* match which driver's coex version */
__le32 cx_offload;
@@ -1920,11 +2204,25 @@ struct rtw89_btc_fbtc_rpt_ctrl_v105 {
struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info;
} __packed;
+struct rtw89_btc_fbtc_rpt_ctrl_v8 {
+ u8 fver;
+ u8 rsvd0;
+ u8 rpt_len_max_l; /* BTC_RPT_MAX bit0~7 */
+ u8 rpt_len_max_h; /* BTC_RPT_MAX bit8~15 */
+
+ u8 gnt_val[RTW89_PHY_MAX][4];
+ __le16 bt_cnt[BTC_BCNT_STA_MAX_V105];
+
+ struct rtw89_btc_fbtc_rpt_ctrl_info_v8 rpt_info;
+ struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info;
+} __packed;
+
union rtw89_btc_fbtc_rpt_ctrl_ver_info {
struct rtw89_btc_fbtc_rpt_ctrl_v1 v1;
struct rtw89_btc_fbtc_rpt_ctrl_v4 v4;
struct rtw89_btc_fbtc_rpt_ctrl_v5 v5;
struct rtw89_btc_fbtc_rpt_ctrl_v105 v105;
+ struct rtw89_btc_fbtc_rpt_ctrl_v8 v8;
};
enum rtw89_fbtc_ext_ctrl_type {
@@ -2031,15 +2329,32 @@ enum rtw89_btc_afh_map_type { /*AFH MAP TYPE */
};
#define BTC_DBG_MAX1 32
-struct rtw89_btc_fbtc_gpio_dbg {
+struct rtw89_btc_fbtc_gpio_dbg_v1 {
u8 fver; /* btc_ver::fcxgpiodbg */
u8 rsvd;
- u16 rsvd2;
- u32 en_map; /* which debug signal (see btc_wl_gpio_debug) is enable */
- u32 pre_state; /* the debug signal is 1 or 0 */
+ __le16 rsvd2;
+ __le32 en_map; /* which debug signal (see btc_wl_gpio_debug) is enable */
+ __le32 pre_state; /* the debug signal is 1 or 0 */
u8 gpio_map[BTC_DBG_MAX1]; /*the debug signals to GPIO-Position */
} __packed;
+struct rtw89_btc_fbtc_gpio_dbg_v7 {
+ u8 fver;
+ u8 rsvd0;
+ u8 rsvd1;
+ u8 rsvd2;
+
+ u8 gpio_map[BTC_DBG_MAX1];
+
+ __le32 en_map;
+ __le32 pre_state;
+} __packed;
+
+union rtw89_btc_fbtc_gpio_dbg {
+ struct rtw89_btc_fbtc_gpio_dbg_v1 v1;
+ struct rtw89_btc_fbtc_gpio_dbg_v7 v7;
+};
+
struct rtw89_btc_fbtc_mreg_val_v1 {
u8 fver; /* btc_ver::fcxmreg */
u8 reg_num;
@@ -2054,9 +2369,18 @@ struct rtw89_btc_fbtc_mreg_val_v2 {
__le32 mreg_val[CXMREG_MAX_V2];
} __packed;
+struct rtw89_btc_fbtc_mreg_val_v7 {
+ u8 fver;
+ u8 reg_num;
+ u8 rsvd0;
+ u8 rsvd1;
+ __le32 mreg_val[CXMREG_MAX_V2];
+} __packed;
+
union rtw89_btc_fbtc_mreg_val {
struct rtw89_btc_fbtc_mreg_val_v1 v1;
struct rtw89_btc_fbtc_mreg_val_v2 v2;
+ struct rtw89_btc_fbtc_mreg_val_v7 v7;
};
#define RTW89_DEF_FBTC_MREG(__type, __bytes, __offset) \
@@ -2083,6 +2407,40 @@ struct rtw89_btc_fbtc_slots {
struct rtw89_btc_fbtc_slot slot[CXST_MAX];
} __packed;
+struct rtw89_btc_fbtc_slot_v7 {
+ __le16 dur; /* slot duration */
+ __le16 cxtype;
+ __le32 cxtbl;
+} __packed;
+
+struct rtw89_btc_fbtc_slot_u16 {
+ __le16 dur; /* slot duration */
+ __le16 cxtype;
+ __le16 cxtbl_l16; /* coex table [15:0] */
+ __le16 cxtbl_h16; /* coex table [31:16] */
+} __packed;
+
+struct rtw89_btc_fbtc_1slot_v7 {
+ u8 fver;
+ u8 sid; /* slot id */
+ __le16 rsvd;
+ struct rtw89_btc_fbtc_slot_v7 slot;
+} __packed;
+
+struct rtw89_btc_fbtc_slots_v7 {
+ u8 fver;
+ u8 slot_cnt;
+ u8 rsvd0;
+ u8 rsvd1;
+ struct rtw89_btc_fbtc_slot_u16 slot[CXST_MAX];
+ __le32 update_map;
+} __packed;
+
+union rtw89_btc_fbtc_slots_info {
+ struct rtw89_btc_fbtc_slots v1;
+ struct rtw89_btc_fbtc_slots_v7 v7;
+} __packed;
+
struct rtw89_btc_fbtc_step {
u8 type;
u8 val;
@@ -2189,6 +2547,12 @@ struct rtw89_btc_fbtc_cycle_leak_info {
__le16 tmax; /* max leak-slot time */
} __packed;
+struct rtw89_btc_fbtc_cycle_leak_info_v7 {
+ __le16 tavg;
+ __le16 tamx;
+ __le32 cnt_rximr;
+} __packed;
+
#define RTW89_BTC_FDDT_PHASE_CYCLE GENMASK(9, 0)
#define RTW89_BTC_FDDT_TRAIN_STEP GENMASK(15, 10)
@@ -2232,12 +2596,6 @@ struct rtw89_btc_fbtc_fddt_cell_status {
u8 state_phase; /* [0:3] train state, [4:7] train phase */
} __packed;
-struct rtw89_btc_fbtc_fddt_cell_status_v5 {
- s8 wl_tx_pwr;
- s8 bt_tx_pwr;
- s8 bt_rx_gain;
-} __packed;
-
struct rtw89_btc_fbtc_cysta_v3 { /* statistics for cycles */
u8 fver;
u8 rsvd;
@@ -2301,9 +2659,33 @@ struct rtw89_btc_fbtc_cysta_v5 { /* statistics for cycles */
struct rtw89_btc_fbtc_cycle_a2dp_empty_info a2dp_ept;
struct rtw89_btc_fbtc_a2dp_trx_stat_v4 a2dp_trx[BTC_CYCLE_SLOT_MAX];
struct rtw89_btc_fbtc_cycle_fddt_info_v5 fddt_trx[BTC_CYCLE_SLOT_MAX];
- struct rtw89_btc_fbtc_fddt_cell_status_v5 fddt_cells[FDD_TRAIN_WL_DIRECTION]
- [FDD_TRAIN_WL_RSSI_LEVEL]
- [FDD_TRAIN_BT_RSSI_LEVEL];
+ struct rtw89_btc_fbtc_fddt_cell_status fddt_cells[FDD_TRAIN_WL_DIRECTION]
+ [FDD_TRAIN_WL_RSSI_LEVEL]
+ [FDD_TRAIN_BT_RSSI_LEVEL];
+ __le32 except_map;
+} __packed;
+
+struct rtw89_btc_fbtc_cysta_v7 { /* statistics for cycles */
+ u8 fver;
+ u8 rsvd;
+ u8 collision_cnt; /* counter for event/timer occur at the same time */
+ u8 except_cnt;
+
+ u8 wl_rx_err_ratio[BTC_CYCLE_SLOT_MAX];
+
+ struct rtw89_btc_fbtc_a2dp_trx_stat_v4 a2dp_trx[BTC_CYCLE_SLOT_MAX];
+
+ __le16 skip_cnt;
+ __le16 cycles; /* total cycle number */
+
+ __le16 slot_step_time[BTC_CYCLE_SLOT_MAX]; /* record the wl/bt slot time */
+ __le16 slot_cnt[CXST_MAX]; /* slot count */
+ __le16 bcn_cnt[CXBCN_MAX];
+
+ struct rtw89_btc_fbtc_cycle_time_info_v5 cycle_time;
+ struct rtw89_btc_fbtc_cycle_a2dp_empty_info a2dp_ept;
+ struct rtw89_btc_fbtc_cycle_leak_info_v7 leak_slot;
+
__le32 except_map;
} __packed;
@@ -2312,6 +2694,7 @@ union rtw89_btc_fbtc_cysta_info {
struct rtw89_btc_fbtc_cysta_v3 v3;
struct rtw89_btc_fbtc_cysta_v4 v4;
struct rtw89_btc_fbtc_cysta_v5 v5;
+ struct rtw89_btc_fbtc_cysta_v7 v7;
};
struct rtw89_btc_fbtc_cynullsta_v1 { /* cycle null statistics */
@@ -2332,12 +2715,24 @@ struct rtw89_btc_fbtc_cynullsta_v2 { /* cycle null statistics */
__le32 result[2][5]; /* 0:fail, 1:ok, 2:on_time, 3:retry, 4:tx */
} __packed;
+struct rtw89_btc_fbtc_cynullsta_v7 { /* cycle null statistics */
+ u8 fver;
+ u8 rsvd0;
+ u8 rsvd1;
+ u8 rsvd2;
+
+ __le32 tmax[2];
+ __le32 tavg[2];
+ __le32 result[2][5];
+} __packed;
+
union rtw89_btc_fbtc_cynullsta_info {
struct rtw89_btc_fbtc_cynullsta_v1 v1; /* info from fw */
struct rtw89_btc_fbtc_cynullsta_v2 v2;
+ struct rtw89_btc_fbtc_cynullsta_v7 v7;
};
-struct rtw89_btc_fbtc_btver {
+struct rtw89_btc_fbtc_btver_v1 {
u8 fver; /* btc_ver::fcxbtver */
u8 rsvd;
__le16 rsvd2;
@@ -2346,6 +2741,22 @@ struct rtw89_btc_fbtc_btver {
__le32 feature;
} __packed;
+struct rtw89_btc_fbtc_btver_v7 {
+ u8 fver;
+ u8 rsvd0;
+ u8 rsvd1;
+ u8 rsvd2;
+
+ __le32 coex_ver; /*bit[15:8]->shared, bit[7:0]->non-shared */
+ __le32 fw_ver;
+ __le32 feature;
+} __packed;
+
+union rtw89_btc_fbtc_btver {
+ struct rtw89_btc_fbtc_btver_v1 v1;
+ struct rtw89_btc_fbtc_btver_v7 v7;
+} __packed;
+
struct rtw89_btc_fbtc_btafh {
u8 fver; /* btc_ver::fcxbtafh */
u8 rsvd;
@@ -2367,6 +2778,18 @@ struct rtw89_btc_fbtc_btafh_v2 {
u8 afh_le_b[4];
} __packed;
+struct rtw89_btc_fbtc_btafh_v7 {
+ u8 fver;
+ u8 map_type;
+ u8 rsvd0;
+ u8 rsvd1;
+ u8 afh_l[4]; /*bit0:2402, bit1:2403.... bit31:2433 */
+ u8 afh_m[4]; /*bit0:2434, bit1:2435.... bit31:2465 */
+ u8 afh_h[4]; /*bit0:2466, bit1:2467.....bit14:2480 */
+ u8 afh_le_a[4];
+ u8 afh_le_b[4];
+} __packed;
+
struct rtw89_btc_fbtc_btdevinfo {
u8 fver; /* btc_ver::fcxbtdevinfo */
u8 rsvd;
@@ -2407,13 +2830,18 @@ struct rtw89_btc_trx_info {
u32 rx_err_ratio;
};
+union rtw89_btc_fbtc_slot_u {
+ struct rtw89_btc_fbtc_slot v1[CXST_MAX];
+ struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX];
+};
+
struct rtw89_btc_dm {
- struct rtw89_btc_fbtc_slot slot[CXST_MAX];
- struct rtw89_btc_fbtc_slot slot_now[CXST_MAX];
+ union rtw89_btc_fbtc_slot_u slot;
+ union rtw89_btc_fbtc_slot_u slot_now;
struct rtw89_btc_fbtc_tdma tdma;
struct rtw89_btc_fbtc_tdma tdma_now;
struct rtw89_mac_ax_coex_gnt gnt;
- struct rtw89_btc_init_info init_info; /* pass to wl_fw if offload */
+ union rtw89_btc_init_info_u init_info; /* pass to wl_fw if offload */
struct rtw89_btc_rf_trx_para rf_trx_para;
struct rtw89_btc_wl_tx_limit_para wl_tx_limit;
struct rtw89_btc_dm_step dm_step;
@@ -2425,6 +2853,8 @@ struct rtw89_btc_dm {
u32 update_slot_map;
u32 set_ant_path;
+ u32 e2g_slot_limit;
+ u32 e2g_slot_nulltx_time;
u32 wl_only: 1;
u32 wl_fw_cx_offload: 1;
@@ -2436,18 +2866,25 @@ struct rtw89_btc_dm {
u32 noisy_level: 3;
u32 coex_info_map: 8;
u32 bt_only: 1;
- u32 wl_btg_rx: 1;
+ u32 wl_btg_rx: 2;
u32 trx_para_level: 8;
u32 wl_stb_chg: 1;
u32 pta_owner: 1;
+
u32 tdma_instant_excute: 1;
+ u32 wl_btg_rx_rb: 2;
u16 slot_dur[CXST_MAX];
+ u16 bt_slot_flood;
u8 run_reason;
u8 run_action;
+ u8 wl_pre_agc: 2;
u8 wl_lna2: 1;
+ u8 wl_pre_agc_rb: 2;
+ u8 bt_select: 2; /* 0:s0, 1:s1, 2:s0 & s1, refer to enum btc_bt_index */
+ u8 slot_req_more: 1;
};
struct rtw89_btc_ctrl {
@@ -2458,6 +2895,18 @@ struct rtw89_btc_ctrl {
u32 rsvd: 12;
};
+struct rtw89_btc_ctrl_v7 {
+ u8 manual;
+ u8 igno_bt;
+ u8 always_freerun;
+ u8 rsvd;
+} __packed;
+
+union rtw89_btc_ctrl_list {
+ struct rtw89_btc_ctrl ctrl;
+ struct rtw89_btc_ctrl_v7 ctrl_v7;
+};
+
struct rtw89_btc_dbg {
/* cmd "rb" */
bool rb_done;
@@ -2483,6 +2932,7 @@ enum btf_fw_event_report {
BTC_RPT_TYPE_CYSTA,
BTC_RPT_TYPE_STEP,
BTC_RPT_TYPE_NULLSTA,
+ BTC_RPT_TYPE_FDDT, /* added by ver->fwevntrptl == 1 */
BTC_RPT_TYPE_MREG,
BTC_RPT_TYPE_GPIO_DBG,
BTC_RPT_TYPE_BT_VER,
@@ -2490,7 +2940,10 @@ enum btf_fw_event_report {
BTC_RPT_TYPE_BT_AFH,
BTC_RPT_TYPE_BT_DEVICE,
BTC_RPT_TYPE_TEST,
- BTC_RPT_TYPE_MAX = 31
+ BTC_RPT_TYPE_MAX = 31,
+
+ __BTC_RPT_TYPE_V0_SAME = BTC_RPT_TYPE_NULLSTA,
+ __BTC_RPT_TYPE_V0_MAX = 12,
};
enum rtw_btc_btf_reg_type {
@@ -2531,7 +2984,7 @@ struct rtw89_btc_rpt_fbtc_tdma {
struct rtw89_btc_rpt_fbtc_slots {
struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
- struct rtw89_btc_fbtc_slots finfo; /* info from fw */
+ union rtw89_btc_fbtc_slots_info finfo; /* info from fw */
};
struct rtw89_btc_rpt_fbtc_cysta {
@@ -2556,12 +3009,12 @@ struct rtw89_btc_rpt_fbtc_mreg {
struct rtw89_btc_rpt_fbtc_gpio_dbg {
struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
- struct rtw89_btc_fbtc_gpio_dbg finfo; /* info from fw */
+ union rtw89_btc_fbtc_gpio_dbg finfo; /* info from fw */
};
struct rtw89_btc_rpt_fbtc_btver {
struct rtw89_btc_rpt_cmn_info cinfo; /* common info, by driver */
- struct rtw89_btc_fbtc_btver finfo; /* info from fw */
+ union rtw89_btc_fbtc_btver finfo; /* info from fw */
};
struct rtw89_btc_rpt_fbtc_btscan {
@@ -2630,7 +3083,10 @@ struct rtw89_btc_ver {
u8 fwlrole;
u8 frptmap;
u8 fcxctrl;
+ u8 fcxinit;
+ u8 fwevntrptl;
+ u8 drvinfo_type;
u16 info_buf;
u8 max_role_num;
};
@@ -2642,8 +3098,8 @@ struct rtw89_btc {
struct rtw89_btc_cx cx;
struct rtw89_btc_dm dm;
- struct rtw89_btc_ctrl ctrl;
- struct rtw89_btc_module mdinfo;
+ union rtw89_btc_ctrl_list ctrl;
+ union rtw89_btc_module_info mdinfo;
struct rtw89_btc_btf_fwinfo fwinfo;
struct rtw89_btc_dbg dbg;
@@ -2655,11 +3111,26 @@ struct rtw89_btc {
u32 bt_req_len;
u8 policy[RTW89_BTC_POLICY_MAXLEN];
+ u8 ant_type;
+ u8 btg_pos;
u16 policy_len;
u16 policy_type;
+ u32 hubmsg_cnt;
bool bt_req_en;
bool update_policy_force;
bool lps;
+ bool manual_ctrl;
+};
+
+enum rtw89_btc_hmsg {
+ RTW89_BTC_HMSG_TMR_EN = 0x0,
+ RTW89_BTC_HMSG_BT_REG_READBACK = 0x1,
+ RTW89_BTC_HMSG_SET_BT_REQ_SLOT = 0x2,
+ RTW89_BTC_HMSG_FW_EV = 0x3,
+ RTW89_BTC_HMSG_BT_LINK_CHG = 0x4,
+ RTW89_BTC_HMSG_SET_BT_REQ_STBC = 0x5,
+
+ NUM_OF_RTW89_BTC_HMSG,
};
enum rtw89_ra_mode {
@@ -2668,6 +3139,7 @@ enum rtw89_ra_mode {
RTW89_RA_MODE_HT = BIT(2),
RTW89_RA_MODE_VHT = BIT(3),
RTW89_RA_MODE_HE = BIT(4),
+ RTW89_RA_MODE_EHT = BIT(5),
};
enum rtw89_ra_report_mode {
@@ -2675,6 +3147,7 @@ enum rtw89_ra_report_mode {
RTW89_RA_RPT_MODE_HT,
RTW89_RA_RPT_MODE_VHT,
RTW89_RA_RPT_MODE_HE,
+ RTW89_RA_RPT_MODE_EHT,
};
enum rtw89_dig_noisy_level {
@@ -2702,6 +3175,20 @@ enum rtw89_rx_frame_type {
RTW89_RX_TYPE_RSVD = 3,
};
+enum rtw89_efuse_block {
+ RTW89_EFUSE_BLOCK_SYS = 0,
+ RTW89_EFUSE_BLOCK_RF = 1,
+ RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO = 2,
+ RTW89_EFUSE_BLOCK_HCI_DIG_USB = 3,
+ RTW89_EFUSE_BLOCK_HCI_PHY_PCIE = 4,
+ RTW89_EFUSE_BLOCK_HCI_PHY_USB3 = 5,
+ RTW89_EFUSE_BLOCK_HCI_PHY_USB2 = 6,
+ RTW89_EFUSE_BLOCK_ADIE = 7,
+
+ RTW89_EFUSE_BLOCK_NUM,
+ RTW89_EFUSE_BLOCK_IGNORE,
+};
+
struct rtw89_ra_info {
u8 is_dis_ra:1;
/* Bit0 : CCK
@@ -2740,10 +3227,10 @@ struct rtw89_ra_info {
u8 csi_bw:3;
};
-#define RTW89_PPDU_MAX_USR 4
#define RTW89_PPDU_MAC_INFO_USR_SIZE 4
#define RTW89_PPDU_MAC_INFO_SIZE 8
#define RTW89_PPDU_MAC_RX_CNT_SIZE 96
+#define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128
#define RTW89_MAX_RX_AGG_NUM 64
#define RTW89_MAX_TX_AGG_NUM 128
@@ -2772,7 +3259,7 @@ struct rtw89_ba_cam_entry {
#define RTW89_MAX_ADDR_CAM_NUM 128
#define RTW89_MAX_BSSID_CAM_NUM 20
#define RTW89_MAX_SEC_CAM_NUM 128
-#define RTW89_MAX_BA_CAM_NUM 8
+#define RTW89_MAX_BA_CAM_NUM 24
#define RTW89_SEC_CAM_IN_ADDR_CAM 7
struct rtw89_addr_cam_entry {
@@ -2789,7 +3276,6 @@ struct rtw89_addr_cam_entry {
DECLARE_BITMAP(sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM);
u8 sec_ent_keyid[RTW89_SEC_CAM_IN_ADDR_CAM];
u8 sec_ent[RTW89_SEC_CAM_IN_ADDR_CAM];
- struct rtw89_sec_cam_entry *sec_entries[RTW89_SEC_CAM_IN_ADDR_CAM];
};
struct rtw89_bssid_cam_entry {
@@ -2829,6 +3315,7 @@ struct rtw89_sta {
struct ewma_evm evm_min[RF_PATH_MAX];
struct ewma_evm evm_max[RF_PATH_MAX];
struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS];
+ DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS);
struct ieee80211_rx_status rx_status;
u16 rx_hw_rate;
__le32 htc_template;
@@ -2891,17 +3378,46 @@ struct rtw89_roc {
#define RTW89_P2P_MAX_NOA_NUM 2
+struct rtw89_p2p_ie_head {
+ u8 eid;
+ u8 ie_len;
+ u8 oui[3];
+ u8 oui_type;
+} __packed;
+
+struct rtw89_noa_attr_head {
+ u8 attr_type;
+ __le16 attr_len;
+ u8 index;
+ u8 oppps_ctwindow;
+} __packed;
+
+struct rtw89_p2p_noa_ie {
+ struct rtw89_p2p_ie_head p2p_head;
+ struct rtw89_noa_attr_head noa_head;
+ struct ieee80211_p2p_noa_desc noa_desc[RTW89_P2P_MAX_NOA_NUM];
+} __packed;
+
+struct rtw89_p2p_noa_setter {
+ struct rtw89_p2p_noa_ie ie;
+ u8 noa_count;
+ u8 noa_index;
+};
+
struct rtw89_vif {
struct list_head list;
struct rtw89_dev *rtwdev;
struct rtw89_roc roc;
+ bool chanctx_assigned; /* only valid when running with chanctx_ops */
enum rtw89_sub_entity_idx sub_entity_idx;
enum rtw89_reg_6ghz_power reg_6ghz_power;
+ struct rtw89_reg_6ghz_tpe reg_6ghz_tpe;
u8 mac_id;
u8 port;
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
+ __be32 ip_addr;
u8 phy_idx;
u8 mac_idx;
u8 net_type;
@@ -2911,6 +3427,7 @@ struct rtw89_vif {
u8 bcn_hit_cond;
u8 hit_rule;
u8 last_noa_nr;
+ u64 sync_bcn_tsf;
bool offchan;
bool trigger;
bool lsig_txop;
@@ -2922,6 +3439,8 @@ struct rtw89_vif {
bool is_hesta;
bool last_a_ctrl;
bool dyn_tb_bedge_en;
+ bool pre_pwr_diff_en;
+ bool pwr_diff_en;
u8 def_tri_idx;
u32 tdls_peer;
struct work_struct update_beacon_work;
@@ -2933,6 +3452,7 @@ struct rtw89_vif {
struct cfg80211_scan_request *scan_req;
struct ieee80211_scan_ies *scan_ies;
struct list_head general_pkt_list;
+ struct rtw89_p2p_noa_setter p2p_noa;
};
enum rtw89_lv1_rcvy_step {
@@ -2959,6 +3479,7 @@ struct rtw89_hci_ops {
void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data);
int (*mac_pre_init)(struct rtw89_dev *rtwdev);
+ int (*mac_pre_deinit)(struct rtw89_dev *rtwdev);
int (*mac_post_init)(struct rtw89_dev *rtwdev);
int (*deinit)(struct rtw89_dev *rtwdev);
@@ -2977,7 +3498,7 @@ struct rtw89_hci_ops {
void (*ctrl_txdma_ch)(struct rtw89_dev *rtwdev, bool enable);
void (*ctrl_txdma_fw_ch)(struct rtw89_dev *rtwdev, bool enable);
void (*ctrl_trxhci)(struct rtw89_dev *rtwdev, bool enable);
- int (*poll_txdma_ch)(struct rtw89_dev *rtwdev);
+ int (*poll_txdma_ch_idle)(struct rtw89_dev *rtwdev);
void (*clr_idx_all)(struct rtw89_dev *rtwdev);
void (*clear)(struct rtw89_dev *rtwdev, struct pci_dev *pdev);
void (*disable_intr)(struct rtw89_dev *rtwdev);
@@ -2996,6 +3517,8 @@ struct rtw89_hci_info {
struct rtw89_chip_ops {
int (*enable_bb_rf)(struct rtw89_dev *rtwdev);
int (*disable_bb_rf)(struct rtw89_dev *rtwdev);
+ void (*bb_preinit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
+ void (*bb_postinit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
void (*bb_reset)(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx);
void (*bb_sethw)(struct rtw89_dev *rtwdev);
@@ -3012,11 +3535,14 @@ struct rtw89_chip_ops {
const struct rtw89_chan *chan,
enum rtw89_mac_idx mac_idx,
enum rtw89_phy_idx phy_idx);
- int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map);
+ int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block);
int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map);
void (*fem_setup)(struct rtw89_dev *rtwdev);
void (*rfe_gpio)(struct rtw89_dev *rtwdev);
+ void (*rfk_hw_init)(struct rtw89_dev *rtwdev);
void (*rfk_init)(struct rtw89_dev *rtwdev);
+ void (*rfk_init_late)(struct rtw89_dev *rtwdev);
void (*rfk_channel)(struct rtw89_dev *rtwdev);
void (*rfk_band_changed)(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx);
@@ -3030,11 +3556,13 @@ struct rtw89_chip_ops {
enum rtw89_phy_idx phy_idx);
int (*init_txpwr_unit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path);
- void (*ctrl_btg)(struct rtw89_dev *rtwdev, bool btg);
+ void (*ctrl_btg_bt_rx)(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx);
void (*query_ppdu)(struct rtw89_dev *rtwdev,
struct rtw89_rx_phy_ppdu *phy_ppdu,
struct ieee80211_rx_status *status);
- void (*bb_ctrl_btc_preagc)(struct rtw89_dev *rtwdev, bool bt_en);
+ void (*ctrl_nbtg_bt_tx)(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx);
void (*cfg_txrx_path)(struct rtw89_dev *rtwdev);
void (*set_txpwr_ul_tb_offset)(struct rtw89_dev *rtwdev,
s8 pw_ofst, enum rtw89_mac_idx mac_idx);
@@ -3058,6 +3586,22 @@ struct rtw89_chip_ops {
int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta);
+ int (*h2c_default_cmac_tbl)(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta);
+ int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+ int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+ int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta);
+ int (*h2c_update_beacon)(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif);
+ int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ bool valid, struct ieee80211_ampdu_params *params);
void (*btc_set_rfe)(struct rtw89_dev *rtwdev);
void (*btc_init_cfg)(struct rtw89_dev *rtwdev);
@@ -3087,8 +3631,62 @@ enum rtw89_dma_ch {
RTW89_DMA_CH_NUM = 13
};
+#define MLO_MODE_FOR_BB0_BB1_RF(bb0, bb1, rf) ((rf) << 12 | (bb1) << 4 | (bb0))
+
+enum rtw89_mlo_dbcc_mode {
+ MLO_DBCC_NOT_SUPPORT = 1,
+ MLO_0_PLUS_2_1RF = MLO_MODE_FOR_BB0_BB1_RF(0, 2, 1),
+ MLO_0_PLUS_2_2RF = MLO_MODE_FOR_BB0_BB1_RF(0, 2, 2),
+ MLO_1_PLUS_1_1RF = MLO_MODE_FOR_BB0_BB1_RF(1, 1, 1),
+ MLO_1_PLUS_1_2RF = MLO_MODE_FOR_BB0_BB1_RF(1, 1, 2),
+ MLO_2_PLUS_0_1RF = MLO_MODE_FOR_BB0_BB1_RF(2, 0, 1),
+ MLO_2_PLUS_0_2RF = MLO_MODE_FOR_BB0_BB1_RF(2, 0, 2),
+ MLO_2_PLUS_2_2RF = MLO_MODE_FOR_BB0_BB1_RF(2, 2, 2),
+ DBCC_LEGACY = 0xffffffff,
+};
+
+enum rtw89_scan_be_operation {
+ RTW89_SCAN_OP_STOP,
+ RTW89_SCAN_OP_START,
+ RTW89_SCAN_OP_SETPARM,
+ RTW89_SCAN_OP_GETRPT,
+ RTW89_SCAN_OP_NUM
+};
+
+enum rtw89_scan_be_mode {
+ RTW89_SCAN_MODE_SA,
+ RTW89_SCAN_MODE_MACC,
+ RTW89_SCAN_MODE_NUM
+};
+
+enum rtw89_scan_be_opmode {
+ RTW89_SCAN_OPMODE_NONE,
+ RTW89_SCAN_OPMODE_TBTT,
+ RTW89_SCAN_OPMODE_INTV,
+ RTW89_SCAN_OPMODE_CNT,
+ RTW89_SCAN_OPMODE_NUM,
+};
+
+struct rtw89_scan_option {
+ bool enable;
+ bool target_ch_mode;
+ u8 num_macc_role;
+ u8 num_opch;
+ u8 repeat;
+ u16 norm_pd;
+ u16 slow_pd;
+ u16 norm_cy;
+ u8 opch_end;
+ u64 prohib_chan;
+ enum rtw89_phy_idx band;
+ enum rtw89_scan_be_operation operation;
+ enum rtw89_scan_be_mode scan_mode;
+ enum rtw89_mlo_dbcc_mode mlo_mode;
+};
+
enum rtw89_qta_mode {
RTW89_QTA_SCC,
+ RTW89_QTA_DBCC,
RTW89_QTA_DLFW,
RTW89_QTA_WOW,
@@ -3159,6 +3757,8 @@ struct rtw89_dle_size {
u16 pge_size;
u16 lnk_pge_num;
u16 unlnk_pge_num;
+ /* for WiFi 7 chips below */
+ u32 srt_ofst;
};
struct rtw89_wde_quota {
@@ -3181,6 +3781,26 @@ struct rtw89_ple_quota {
u16 wd_rel;
u16 cpu_io;
u16 tx_rpt;
+ /* for WiFi 7 chips below */
+ u16 h2d;
+};
+
+struct rtw89_rsvd_quota {
+ u16 mpdu_info_tbl;
+ u16 b0_csi;
+ u16 b1_csi;
+ u16 b0_lmr;
+ u16 b1_lmr;
+ u16 b0_ftm;
+ u16 b1_ftm;
+ u16 b0_smr;
+ u16 b1_smr;
+ u16 others;
+};
+
+struct rtw89_dle_rsvd_size {
+ u32 srt_ofst;
+ u32 size;
};
struct rtw89_dle_mem {
@@ -3191,6 +3811,10 @@ struct rtw89_dle_mem {
const struct rtw89_wde_quota *wde_max_qt;
const struct rtw89_ple_quota *ple_min_qt;
const struct rtw89_ple_quota *ple_max_qt;
+ /* for WiFi 7 chips below */
+ const struct rtw89_rsvd_quota *rsvd_qt;
+ const struct rtw89_dle_rsvd_size *rsvd0_size;
+ const struct rtw89_dle_rsvd_size *rsvd1_size;
};
struct rtw89_reg_def {
@@ -3217,6 +3841,12 @@ struct rtw89_reg5_def {
u32 data;
};
+struct rtw89_reg_imr {
+ u32 addr;
+ u32 clr;
+ u32 set;
+};
+
struct rtw89_phy_table {
const struct rtw89_reg2_def *regs;
u32 n_regs;
@@ -3258,10 +3888,17 @@ struct rtw89_txpwr_rule_6ghz {
[RTW89_6G_CH_NUM];
};
+struct rtw89_tx_shape {
+ const u8 (*lmt)[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM][RTW89_REGD_NUM];
+ const u8 (*lmt_ru)[RTW89_BAND_NUM][RTW89_REGD_NUM];
+};
+
struct rtw89_rfe_parms {
+ const struct rtw89_txpwr_table *byr_tbl;
struct rtw89_txpwr_rule_2ghz rule_2ghz;
struct rtw89_txpwr_rule_5ghz rule_5ghz;
struct rtw89_txpwr_rule_6ghz rule_6ghz;
+ struct rtw89_tx_shape tx_shape;
};
struct rtw89_rfe_parms_conf {
@@ -3269,6 +3906,106 @@ struct rtw89_rfe_parms_conf {
u8 rfe_type;
};
+#define RTW89_TXPWR_CONF_DFLT_RFE_TYPE 0x0
+
+struct rtw89_txpwr_conf {
+ u8 rfe_type;
+ u8 ent_sz;
+ u32 num_ents;
+ const void *data;
+};
+
+#define rtw89_txpwr_conf_valid(conf) (!!(conf)->data)
+
+#if defined(__linux__)
+#define rtw89_for_each_in_txpwr_conf(entry, cursor, conf) \
+ for (typecheck(const void *, cursor), (cursor) = (conf)->data, \
+ memcpy(&(entry), cursor, \
+ min_t(u8, sizeof(entry), (conf)->ent_sz)); \
+ (cursor) < (conf)->data + (conf)->num_ents * (conf)->ent_sz; \
+ (cursor) += (conf)->ent_sz, \
+ memcpy(&(entry), cursor, \
+ min_t(u8, sizeof(entry), (conf)->ent_sz)))
+#elif defined(__FreeBSD__)
+#define rtw89_for_each_in_txpwr_conf(entry, cursor, conf) \
+ for (typecheck(const u8 *, cursor), (cursor) = (conf)->data, \
+ memcpy(&(entry), cursor, \
+ min_t(u8, sizeof(entry), (conf)->ent_sz)); \
+ (cursor) < (const u8 *)(conf)->data + (conf)->num_ents * (conf)->ent_sz; \
+ (cursor) += (conf)->ent_sz, \
+ memcpy(&(entry), cursor, \
+ min_t(u8, sizeof(entry), (conf)->ent_sz)))
+#endif
+
+struct rtw89_txpwr_byrate_data {
+ struct rtw89_txpwr_conf conf;
+ struct rtw89_txpwr_table tbl;
+};
+
+struct rtw89_txpwr_lmt_2ghz_data {
+ struct rtw89_txpwr_conf conf;
+ s8 v[RTW89_2G_BW_NUM][RTW89_NTX_NUM]
+ [RTW89_RS_LMT_NUM][RTW89_BF_NUM]
+ [RTW89_REGD_NUM][RTW89_2G_CH_NUM];
+};
+
+struct rtw89_txpwr_lmt_5ghz_data {
+ struct rtw89_txpwr_conf conf;
+ s8 v[RTW89_5G_BW_NUM][RTW89_NTX_NUM]
+ [RTW89_RS_LMT_NUM][RTW89_BF_NUM]
+ [RTW89_REGD_NUM][RTW89_5G_CH_NUM];
+};
+
+struct rtw89_txpwr_lmt_6ghz_data {
+ struct rtw89_txpwr_conf conf;
+ s8 v[RTW89_6G_BW_NUM][RTW89_NTX_NUM]
+ [RTW89_RS_LMT_NUM][RTW89_BF_NUM]
+ [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER]
+ [RTW89_6G_CH_NUM];
+};
+
+struct rtw89_txpwr_lmt_ru_2ghz_data {
+ struct rtw89_txpwr_conf conf;
+ s8 v[RTW89_RU_NUM][RTW89_NTX_NUM]
+ [RTW89_REGD_NUM][RTW89_2G_CH_NUM];
+};
+
+struct rtw89_txpwr_lmt_ru_5ghz_data {
+ struct rtw89_txpwr_conf conf;
+ s8 v[RTW89_RU_NUM][RTW89_NTX_NUM]
+ [RTW89_REGD_NUM][RTW89_5G_CH_NUM];
+};
+
+struct rtw89_txpwr_lmt_ru_6ghz_data {
+ struct rtw89_txpwr_conf conf;
+ s8 v[RTW89_RU_NUM][RTW89_NTX_NUM]
+ [RTW89_REGD_NUM][NUM_OF_RTW89_REG_6GHZ_POWER]
+ [RTW89_6G_CH_NUM];
+};
+
+struct rtw89_tx_shape_lmt_data {
+ struct rtw89_txpwr_conf conf;
+ u8 v[RTW89_BAND_NUM][RTW89_RS_TX_SHAPE_NUM][RTW89_REGD_NUM];
+};
+
+struct rtw89_tx_shape_lmt_ru_data {
+ struct rtw89_txpwr_conf conf;
+ u8 v[RTW89_BAND_NUM][RTW89_REGD_NUM];
+};
+
+struct rtw89_rfe_data {
+ struct rtw89_txpwr_byrate_data byrate;
+ struct rtw89_txpwr_lmt_2ghz_data lmt_2ghz;
+ struct rtw89_txpwr_lmt_5ghz_data lmt_5ghz;
+ struct rtw89_txpwr_lmt_6ghz_data lmt_6ghz;
+ struct rtw89_txpwr_lmt_ru_2ghz_data lmt_ru_2ghz;
+ struct rtw89_txpwr_lmt_ru_5ghz_data lmt_ru_5ghz;
+ struct rtw89_txpwr_lmt_ru_6ghz_data lmt_ru_6ghz;
+ struct rtw89_tx_shape_lmt_data tx_shape_lmt;
+ struct rtw89_tx_shape_lmt_ru_data tx_shape_lmt_ru;
+ struct rtw89_rfe_parms rfe_parms;
+};
+
struct rtw89_page_regs {
u32 hci_fc_ctrl;
u32 ch_page_ctrl;
@@ -3330,6 +4067,11 @@ struct rtw89_imr_info {
u32 tmac_imr_set;
};
+struct rtw89_imr_table {
+ const struct rtw89_reg_imr *regs;
+ u32 n_regs;
+};
+
struct rtw89_xtal_info {
u32 xcap_reg;
u32 sc_xo_mask;
@@ -3345,6 +4087,10 @@ struct rtw89_dig_regs {
u32 seg0_pd_reg;
u32 pd_lower_bound_mask;
u32 pd_spatial_reuse_en;
+ u32 bmode_pd_reg;
+ u32 bmode_cca_rssi_limit_en;
+ u32 bmode_pd_lower_bound_reg;
+ u32 bmode_rssi_nocca_low_th_mask;
struct rtw89_reg_def p0_lna_init;
struct rtw89_reg_def p1_lna_init;
struct rtw89_reg_def p0_tia_init;
@@ -3357,6 +4103,22 @@ struct rtw89_dig_regs {
struct rtw89_reg_def p1_s20_pagcugc_en;
};
+struct rtw89_edcca_regs {
+ u32 edcca_level;
+ u32 edcca_mask;
+ u32 edcca_p_mask;
+ u32 ppdu_level;
+ u32 ppdu_mask;
+ u32 rpt_a;
+ u32 rpt_b;
+ u32 rpt_sel;
+ u32 rpt_sel_mask;
+ u32 rpt_sel_be;
+ u32 rpt_sel_be_mask;
+ u32 tx_collision_t2r_st;
+ u32 tx_collision_t2r_st_mask;
+};
+
struct rtw89_phy_ul_tb_info {
bool dyn_tb_tri_en;
u8 def_if_bandedge;
@@ -3381,13 +4143,33 @@ struct rtw89_antdiv_info {
bool get_stats;
};
+enum rtw89_chanctx_state {
+ RTW89_CHANCTX_STATE_MCC_START,
+ RTW89_CHANCTX_STATE_MCC_STOP,
+};
+
+enum rtw89_chanctx_callbacks {
+ RTW89_CHANCTX_CALLBACK_PLACEHOLDER,
+ RTW89_CHANCTX_CALLBACK_RFK,
+
+ NUM_OF_RTW89_CHANCTX_CALLBACKS,
+};
+
+struct rtw89_chanctx_listener {
+ void (*callbacks[NUM_OF_RTW89_CHANCTX_CALLBACKS])
+ (struct rtw89_dev *rtwdev, enum rtw89_chanctx_state state);
+};
+
struct rtw89_chip_info {
enum rtw89_core_chip_id chip_id;
enum rtw89_chip_gen chip_gen;
const struct rtw89_chip_ops *ops;
+ const struct rtw89_mac_gen_def *mac_def;
+ const struct rtw89_phy_gen_def *phy_def;
const char *fw_basename;
u8 fw_format_max;
bool try_ce_fw;
+ u8 bbmcu_nr;
u32 needed_fw_elms;
u32 fifo_size;
bool small_fifo_size;
@@ -3397,14 +4179,17 @@ struct rtw89_chip_info {
u32 rsvd_ple_ofst;
const struct rtw89_hfc_param_ini *hfc_param_ini;
const struct rtw89_dle_mem *dle_mem;
- u8 wde_qempty_acq_num;
- u8 wde_qempty_mgq_sel;
+ u8 wde_qempty_acq_grpnum;
+ u8 wde_qempty_mgq_grpsel;
u32 rf_base_addr[2];
+ u8 support_macid_num;
u8 support_chanctx_num;
u8 support_bands;
- bool support_bw160;
+ u16 support_bandwidths;
bool support_unii4;
- bool support_ul_tb_ctrl;
+ bool support_rnr;
+ bool ul_tb_waveform_ctrl;
+ bool ul_tb_pwr_diff;
bool hw_sec_hdr;
u8 rf_path_num;
u8 tx_nss;
@@ -3415,6 +4200,7 @@ struct rtw89_chip_info {
u8 bacam_num;
u8 bacam_dynamic_num;
enum rtw89_bacam_ver bacam_ver;
+ u8 ppdu_max_usr;
u8 sec_ctrl_efuse_size;
u32 physical_efuse_size;
@@ -3424,6 +4210,7 @@ struct rtw89_chip_info {
u32 dav_log_efuse_size;
u32 phycap_addr;
u32 phycap_size;
+ const struct rtw89_efuse_block_cfg *efuse_blocks;
const struct rtw89_pwr_cfg * const *pwr_on_seq;
const struct rtw89_pwr_cfg * const *pwr_off_seq;
@@ -3432,7 +4219,6 @@ struct rtw89_chip_info {
const struct rtw89_phy_table *rf_table[RF_PATH_MAX];
const struct rtw89_phy_table *nctl_table;
const struct rtw89_rfk_tbl *nctl_post_table;
- const struct rtw89_txpwr_table *byr_table;
const struct rtw89_phy_dig_gain_table *dig_table;
const struct rtw89_dig_regs *dig_regs;
const struct rtw89_phy_tssi_dbw_table *tssi_dbw_table;
@@ -3440,6 +4226,7 @@ struct rtw89_chip_info {
/* NULL if no rfe-specific, or a null-terminated array by rfe_parms */
const struct rtw89_rfe_parms_conf *rfe_parms_conf;
const struct rtw89_rfe_parms *dflt_parms;
+ const struct rtw89_chanctx_listener *chanctx_listener;
u8 txpwr_factor_rf;
u8 txpwr_factor_mac;
@@ -3468,6 +4255,7 @@ struct rtw89_chip_info {
u32 hci_func_en_addr;
u32 h2c_desc_size;
u32 txwd_body_size;
+ u32 txwd_info_size;
u32 h2c_ctrl_reg;
const u32 *h2c_regs;
struct rtw89_reg_def h2c_counter_reg;
@@ -3475,15 +4263,19 @@ struct rtw89_chip_info {
const u32 *c2h_regs;
struct rtw89_reg_def c2h_counter_reg;
const struct rtw89_page_regs *page_regs;
+ const u32 *wow_reason_reg;
bool cfo_src_fd;
bool cfo_hw_comp;
const struct rtw89_reg_def *dcfo_comp;
u8 dcfo_comp_sft;
const struct rtw89_imr_info *imr_info;
+ const struct rtw89_imr_table *imr_dmac_table;
+ const struct rtw89_imr_table *imr_cmac_table;
const struct rtw89_rrsr_cfgs *rrsr_cfgs;
+ struct rtw89_reg_def bss_clr_vld;
u32 bss_clr_map_reg;
u32 dma_ch_mask;
- u32 edcca_lvl_reg;
+ const struct rtw89_edcca_regs *edcca_regs;
const struct wiphy_wowlan_support *wowlan_stub;
const struct rtw89_xtal_info *xtal_info;
};
@@ -3494,6 +4286,7 @@ union rtw89_bus_info {
struct rtw89_driver_info {
const struct rtw89_chip_info *chip;
+ const struct dmi_system_id *quirks;
union rtw89_bus_info bus;
};
@@ -3507,8 +4300,10 @@ enum rtw89_hcifc_mode {
};
struct rtw89_dle_info {
+ const struct rtw89_rsvd_quota *rsvd_qt;
enum rtw89_qta_mode qta_mode;
u16 ple_pg_size;
+ u16 ple_free_pg;
u16 c0_rx_qta;
u16 c1_rx_qta;
};
@@ -3518,7 +4313,7 @@ enum rtw89_host_rpr_mode {
RTW89_RPR_MODE_STF
};
-#define RTW89_COMPLETION_BUF_SIZE 24
+#define RTW89_COMPLETION_BUF_SIZE 40
#define RTW89_WAIT_COND_IDLE UINT_MAX
struct rtw89_completion_data {
@@ -3551,6 +4346,14 @@ struct rtw89_mac_info {
struct rtw89_wait_info fw_ofld_wait;
};
+enum rtw89_fwdl_check_type {
+ RTW89_FWDL_CHECK_FREERTOS_DONE,
+ RTW89_FWDL_CHECK_WCPU_FWDL_DONE,
+ RTW89_FWDL_CHECK_DCPU_FWDL_DONE,
+ RTW89_FWDL_CHECK_BB0_FWDL_DONE,
+ RTW89_FWDL_CHECK_BB1_FWDL_DONE,
+};
+
enum rtw89_fw_type {
RTW89_FW_NORMAL = 1,
RTW89_FW_WOWLAN = 3,
@@ -3569,6 +4372,8 @@ enum rtw89_fw_feature {
RTW89_FW_FEATURE_NO_DEEP_PS,
RTW89_FW_FEATURE_NO_LPS_PG,
RTW89_FW_FEATURE_BEACON_FILTER,
+ RTW89_FW_FEATURE_MACID_PAUSE_SLEEP,
+ RTW89_FW_FEATURE_WOW_REASON_V1,
};
struct rtw89_fw_suit {
@@ -3625,6 +4430,21 @@ struct rtw89_fw_elm_info {
struct rtw89_phy_table *bb_gain;
struct rtw89_phy_table *rf_radio[RF_PATH_MAX];
struct rtw89_phy_table *rf_nctl;
+ struct rtw89_fw_txpwr_track_cfg *txpwr_trk;
+ struct rtw89_phy_rfk_log_fmt *rfk_log_fmt;
+};
+
+enum rtw89_fw_mss_dev_type {
+ RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF = 0xF,
+ RTW89_FW_MSS_DEV_TYPE_FWSEC_INV = 0xFF,
+};
+
+struct rtw89_fw_secure {
+ bool secure_boot;
+ u32 sb_sel_mgn;
+ u8 mss_dev_type;
+ u8 mss_cust_idx;
+ u8 mss_key_num;
};
struct rtw89_fw_info {
@@ -3641,6 +4461,7 @@ struct rtw89_fw_info {
struct rtw89_fw_log log;
u32 feature_map;
struct rtw89_fw_elm_info elm_info;
+ struct rtw89_fw_secure sec;
};
#define RTW89_CHK_FW_FEATURE(_feat, _fw) \
@@ -3655,6 +4476,7 @@ struct rtw89_cam_info {
DECLARE_BITMAP(sec_cam_map, RTW89_MAX_SEC_CAM_NUM);
DECLARE_BITMAP(ba_cam_map, RTW89_MAX_BA_CAM_NUM);
struct rtw89_ba_cam_entry ba_cam_entry[RTW89_MAX_BA_CAM_NUM];
+ const struct rtw89_sec_cam_entry *sec_entries[RTW89_MAX_SEC_CAM_NUM];
};
enum rtw89_sar_sources {
@@ -3696,21 +4518,69 @@ struct rtw89_sar_info {
};
};
+enum rtw89_tas_state {
+ RTW89_TAS_STATE_DPR_OFF,
+ RTW89_TAS_STATE_DPR_ON,
+ RTW89_TAS_STATE_DPR_FORBID,
+};
+
+#define RTW89_TAS_MAX_WINDOW 50
+struct rtw89_tas_info {
+ s16 txpwr_history[RTW89_TAS_MAX_WINDOW];
+ s32 total_txpwr;
+ u8 cur_idx;
+ s8 dpr_gap;
+ s8 delta;
+ enum rtw89_tas_state state;
+ bool enable;
+};
+
struct rtw89_chanctx_cfg {
enum rtw89_sub_entity_idx idx;
+ int ref_count;
+};
+
+enum rtw89_chanctx_changes {
+ RTW89_CHANCTX_REMOTE_STA_CHANGE,
+ RTW89_CHANCTX_BCN_OFFSET_CHANGE,
+ RTW89_CHANCTX_P2P_PS_CHANGE,
+ RTW89_CHANCTX_BT_SLOT_CHANGE,
+ RTW89_CHANCTX_TSF32_TOGGLE_CHANGE,
+
+ NUM_OF_RTW89_CHANCTX_CHANGES,
+ RTW89_CHANCTX_CHANGE_DFLT = NUM_OF_RTW89_CHANCTX_CHANGES,
};
enum rtw89_entity_mode {
RTW89_ENTITY_MODE_SCC,
+ RTW89_ENTITY_MODE_MCC_PREPARE,
+ RTW89_ENTITY_MODE_MCC,
+
+ NUM_OF_RTW89_ENTITY_MODE,
+ RTW89_ENTITY_MODE_INVALID = -EINVAL,
+ RTW89_ENTITY_MODE_UNHANDLED = -ESRCH,
};
struct rtw89_sub_entity {
struct cfg80211_chan_def chandef;
struct rtw89_chan chan;
struct rtw89_chan_rcd rcd;
+
+ /* only assigned when running with chanctx_ops */
struct rtw89_chanctx_cfg *cfg;
};
+struct rtw89_edcca_bak {
+ u8 a;
+ u8 p;
+ u8 ppdu;
+ u8 th_old;
+};
+
+enum rtw89_dm_type {
+ RTW89_DM_DYNAMIC_EDCCA,
+};
+
struct rtw89_hal {
u32 rx_fltr;
u8 cv;
@@ -3726,14 +4596,17 @@ struct rtw89_hal {
bool support_igi;
atomic_t roc_entity_idx;
+ DECLARE_BITMAP(changes, NUM_OF_RTW89_CHANCTX_CHANGES);
DECLARE_BITMAP(entity_map, NUM_OF_RTW89_SUB_ENTITY);
struct rtw89_sub_entity sub[NUM_OF_RTW89_SUB_ENTITY];
struct cfg80211_chan_def roc_chandef;
bool entity_active;
+ bool entity_pause;
enum rtw89_entity_mode entity_mode;
- u32 edcca_bak;
+ struct rtw89_edcca_bak edcca_bak;
+ u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */
};
#define RTW89_MAX_MAC_ID_NUM 128
@@ -3741,8 +4614,12 @@ struct rtw89_hal {
enum rtw89_flags {
RTW89_FLAG_POWERON,
+ RTW89_FLAG_DMAC_FUNC,
+ RTW89_FLAG_CMAC0_FUNC,
+ RTW89_FLAG_CMAC1_FUNC,
RTW89_FLAG_FW_RDY,
RTW89_FLAG_RUNNING,
+ RTW89_FLAG_PROBE_DONE,
RTW89_FLAG_BFEE_MON,
RTW89_FLAG_BFEE_EN,
RTW89_FLAG_BFEE_TIMER_KEEP,
@@ -3759,6 +4636,12 @@ enum rtw89_flags {
NUM_OF_RTW89_FLAGS,
};
+enum rtw89_quirks {
+ RTW89_QUIRK_PCI_BER,
+
+ NUM_OF_RTW89_QUIRKS,
+};
+
enum rtw89_pkt_drop_sel {
RTW89_PKT_DROP_SEL_MACID_BE_ONCE,
RTW89_PKT_DROP_SEL_MACID_BK_ONCE,
@@ -3799,6 +4682,21 @@ struct rtw89_phy_stat {
struct rtw89_pkt_stat last_pkt_stat;
};
+enum rtw89_rfk_report_state {
+ RTW89_RFK_STATE_START = 0x0,
+ RTW89_RFK_STATE_OK = 0x1,
+ RTW89_RFK_STATE_FAIL = 0x2,
+ RTW89_RFK_STATE_TIMEOUT = 0x3,
+ RTW89_RFK_STATE_H2C_CMD_ERR = 0x4,
+};
+
+struct rtw89_rfk_wait_info {
+ struct completion completion;
+ ktime_t start_time;
+ enum rtw89_rfk_report_state state;
+ u8 version;
+};
+
#define RTW89_DACK_PATH_NR 2
#define RTW89_DACK_IDX_NR 2
#define RTW89_DACK_MSBK_NR 16
@@ -3814,15 +4712,23 @@ struct rtw89_dack_info {
bool msbk_timeout[RTW89_DACK_PATH_NR];
};
-#define RTW89_IQK_CHS_NR 2
-#define RTW89_IQK_PATH_NR 4
+enum rtw89_rfk_chs_nrs {
+ __RTW89_RFK_CHS_NR_V0 = 2,
+ __RTW89_RFK_CHS_NR_V1 = 3,
+
+ RTW89_RFK_CHS_NR = __RTW89_RFK_CHS_NR_V1,
+};
struct rtw89_rfk_mcc_info {
- u8 ch[RTW89_IQK_CHS_NR];
- u8 band[RTW89_IQK_CHS_NR];
+ u8 ch[RTW89_RFK_CHS_NR];
+ u8 band[RTW89_RFK_CHS_NR];
+ u8 bw[RTW89_RFK_CHS_NR];
u8 table_idx;
};
+#define RTW89_IQK_CHS_NR 2
+#define RTW89_IQK_PATH_NR 4
+
struct rtw89_lck_info {
u8 thermal[RF_PATH_MAX];
};
@@ -3890,6 +4796,8 @@ struct rtw89_dpk_info {
u8 cur_idx[RTW89_DPK_RF_PATH];
u8 cur_k_set;
struct rtw89_dpk_bkup_para bp[RTW89_DPK_RF_PATH][RTW89_DPK_BKUP_NUM];
+ u8 max_dpk_txagc[RTW89_DPK_RF_PATH];
+ u32 dpk_order[RTW89_DPK_RF_PATH];
};
struct rtw89_fem_info {
@@ -4000,6 +4908,11 @@ struct rtw89_cfo_tracking_info {
u8 lock_cnt;
};
+enum rtw89_tssi_mode {
+ RTW89_TSSI_NORMAL = 0,
+ RTW89_TSSI_SCAN = 1,
+};
+
enum rtw89_tssi_alimk_band {
TSSI_ALIMK_2G = 0,
TSSI_ALIMK_5GL,
@@ -4044,6 +4957,7 @@ struct rtw89_power_trim_info {
bool pg_pa_bias_trim;
u8 thermal_trim[RF_PATH_MAX];
u8 pa_bias_trim[RF_PATH_MAX];
+ u8 pad_bias_trim[RF_PATH_MAX];
};
struct rtw89_regd {
@@ -4051,9 +4965,17 @@ struct rtw89_regd {
u8 txpwr_regd[RTW89_BAND_NUM];
};
+#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX
+#define RTW89_5GHZ_UNII4_CHANNEL_NUM 3
+#define RTW89_5GHZ_UNII4_START_INDEX 25
+
struct rtw89_regulatory_info {
const struct rtw89_regd *regd;
enum rtw89_reg_6ghz_power reg_6ghz_power;
+ struct rtw89_reg_6ghz_tpe reg_6ghz_tpe;
+ DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM);
+ DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
+ DECLARE_BITMAP(block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM);
};
enum rtw89_ifs_clm_application {
@@ -4205,6 +5127,7 @@ struct rtw89_hw_scan_info {
struct ieee80211_vif *scanning_vif;
struct list_head pkt_list[NUM_NL80211_BANDS];
struct rtw89_chan op_chan;
+ bool abort;
u32 last_chan_idx;
};
@@ -4221,6 +5144,48 @@ enum rtw89_phy_bb_gain_band {
RTW89_BB_GAIN_BAND_NR,
};
+enum rtw89_phy_gain_band_be {
+ RTW89_BB_GAIN_BAND_2G_BE = 0,
+ RTW89_BB_GAIN_BAND_5G_L_BE = 1,
+ RTW89_BB_GAIN_BAND_5G_M_BE = 2,
+ RTW89_BB_GAIN_BAND_5G_H_BE = 3,
+ RTW89_BB_GAIN_BAND_6G_L0_BE = 4,
+ RTW89_BB_GAIN_BAND_6G_L1_BE = 5,
+ RTW89_BB_GAIN_BAND_6G_M0_BE = 6,
+ RTW89_BB_GAIN_BAND_6G_M1_BE = 7,
+ RTW89_BB_GAIN_BAND_6G_H0_BE = 8,
+ RTW89_BB_GAIN_BAND_6G_H1_BE = 9,
+ RTW89_BB_GAIN_BAND_6G_UH0_BE = 10,
+ RTW89_BB_GAIN_BAND_6G_UH1_BE = 11,
+
+ RTW89_BB_GAIN_BAND_NR_BE,
+};
+
+enum rtw89_phy_bb_bw_be {
+ RTW89_BB_BW_20_40 = 0,
+ RTW89_BB_BW_80_160_320 = 1,
+
+ RTW89_BB_BW_NR_BE,
+};
+
+enum rtw89_bw20_sc {
+ RTW89_BW20_SC_20M = 1,
+ RTW89_BW20_SC_40M = 2,
+ RTW89_BW20_SC_80M = 4,
+ RTW89_BW20_SC_160M = 8,
+ RTW89_BW20_SC_320M = 16,
+};
+
+enum rtw89_cmac_table_bw {
+ RTW89_CMAC_BW_20M = 0,
+ RTW89_CMAC_BW_40M = 1,
+ RTW89_CMAC_BW_80M = 2,
+ RTW89_CMAC_BW_160M = 3,
+ RTW89_CMAC_BW_320M = 4,
+
+ RTW89_CMAC_BW_NR,
+};
+
enum rtw89_phy_bb_rxsc_num {
RTW89_BB_RXSC_NUM_40 = 9, /* SC: 0, 1~8 */
RTW89_BB_RXSC_NUM_80 = 13, /* SC: 0, 1~8, 9~12 */
@@ -4243,6 +5208,27 @@ struct rtw89_phy_bb_gain_info {
[RTW89_BB_RXSC_NUM_160];
};
+struct rtw89_phy_bb_gain_info_be {
+ s8 lna_gain[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE][RF_PATH_MAX]
+ [LNA_GAIN_NUM];
+ s8 tia_gain[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE][RF_PATH_MAX]
+ [TIA_GAIN_NUM];
+ s8 lna_gain_bypass[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE]
+ [RF_PATH_MAX][LNA_GAIN_NUM];
+ s8 lna_op1db[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE]
+ [RF_PATH_MAX][LNA_GAIN_NUM];
+ s8 tia_lna_op1db[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE]
+ [RF_PATH_MAX][LNA_GAIN_NUM + 1];
+ s8 rpl_ofst_20[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX]
+ [RTW89_BW20_SC_20M];
+ s8 rpl_ofst_40[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX]
+ [RTW89_BW20_SC_40M];
+ s8 rpl_ofst_80[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX]
+ [RTW89_BW20_SC_80M];
+ s8 rpl_ofst_160[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX]
+ [RTW89_BW20_SC_160M];
+};
+
struct rtw89_phy_efuse_gain {
bool offset_valid;
bool comp_valid;
@@ -4269,15 +5255,159 @@ struct rtw89_wow_cam_info {
bool valid;
};
+struct rtw89_wow_key_info {
+ u8 ptk_tx_iv[8];
+ u8 valid_check;
+ u8 symbol_check_en;
+ u8 gtk_keyidx;
+ u8 rsvd[5];
+ u8 ptk_rx_iv[8];
+ u8 gtk_rx_iv[4][8];
+} __packed;
+
+struct rtw89_wow_gtk_info {
+ u8 kck[32];
+ u8 kek[32];
+ u8 tk1[16];
+ u8 txmickey[8];
+ u8 rxmickey[8];
+ __le32 igtk_keyid;
+ __le64 ipn;
+ u8 igtk[2][32];
+ u8 psk[32];
+} __packed;
+
+struct rtw89_wow_aoac_report {
+ u8 rpt_ver;
+ u8 sec_type;
+ u8 key_idx;
+ u8 pattern_idx;
+ u8 rekey_ok;
+ u8 ptk_tx_iv[8];
+ u8 eapol_key_replay_count[8];
+ u8 gtk[32];
+ u8 ptk_rx_iv[8];
+ u8 gtk_rx_iv[4][8];
+ u64 igtk_key_id;
+ u64 igtk_ipn;
+ u8 igtk[32];
+ u8 csa_pri_ch;
+ u8 csa_bw;
+ u8 csa_ch_offset;
+ u8 csa_chsw_failed;
+ u8 csa_ch_band;
+};
+
struct rtw89_wow_param {
struct ieee80211_vif *wow_vif;
DECLARE_BITMAP(flags, RTW89_WOW_FLAG_NUM);
struct rtw89_wow_cam_info patterns[RTW89_MAX_PATTERN_NUM];
+ struct rtw89_wow_key_info key_info;
+ struct rtw89_wow_gtk_info gtk_info;
+ struct rtw89_wow_aoac_report aoac_rpt;
u8 pattern_cnt;
+ u8 ptk_alg;
+ u8 gtk_alg;
+ u8 ptk_keyidx;
+ u8 akm;
+};
+
+struct rtw89_mcc_limit {
+ bool enable;
+ u16 max_tob; /* TU; max time offset behind */
+ u16 max_toa; /* TU; max time offset ahead */
+ u16 max_dur; /* TU */
+};
+
+struct rtw89_mcc_policy {
+ u8 c2h_rpt;
+ u8 tx_null_early;
+ u8 dis_tx_null;
+ u8 in_curr_ch;
+ u8 dis_sw_retry;
+ u8 sw_retry_count;
+};
+
+struct rtw89_mcc_role {
+ struct rtw89_vif *rtwvif;
+ struct rtw89_mcc_policy policy;
+ struct rtw89_mcc_limit limit;
+
+ /* only valid when running with FW MRC mechanism */
+ u8 slot_idx;
+
+ /* byte-array in LE order for FW */
+ u8 macid_bitmap[BITS_TO_BYTES(RTW89_MAX_MAC_ID_NUM)];
+
+ u16 duration; /* TU */
+ u16 beacon_interval; /* TU */
+ bool is_2ghz;
+ bool is_go;
+ bool is_gc;
+};
+
+struct rtw89_mcc_bt_role {
+ u16 duration; /* TU */
+};
+
+struct rtw89_mcc_courtesy {
+ bool enable;
+ u8 slot_num;
+ u8 macid_src;
+ u8 macid_tgt;
+};
+
+enum rtw89_mcc_plan {
+ RTW89_MCC_PLAN_TAIL_BT,
+ RTW89_MCC_PLAN_MID_BT,
+ RTW89_MCC_PLAN_NO_BT,
+
+ NUM_OF_RTW89_MCC_PLAN,
+};
+
+struct rtw89_mcc_pattern {
+ s16 tob_ref; /* TU; time offset behind of reference role */
+ s16 toa_ref; /* TU; time offset ahead of reference role */
+ s16 tob_aux; /* TU; time offset behind of auxiliary role */
+ s16 toa_aux; /* TU; time offset ahead of auxiliary role */
+
+ enum rtw89_mcc_plan plan;
+ struct rtw89_mcc_courtesy courtesy;
+};
+
+struct rtw89_mcc_sync {
+ bool enable;
+ u16 offset; /* TU */
+ u8 macid_src;
+ u8 band_src;
+ u8 port_src;
+ u8 macid_tgt;
+ u8 band_tgt;
+ u8 port_tgt;
+};
+
+struct rtw89_mcc_config {
+ struct rtw89_mcc_pattern pattern;
+ struct rtw89_mcc_sync sync;
+ u64 start_tsf;
+ u16 mcc_interval; /* TU */
+ u16 beacon_offset; /* TU */
+};
+
+enum rtw89_mcc_mode {
+ RTW89_MCC_MODE_GO_STA,
+ RTW89_MCC_MODE_GC_STA,
};
struct rtw89_mcc_info {
struct rtw89_wait_info wait;
+
+ u8 group;
+ enum rtw89_mcc_mode mode;
+ struct rtw89_mcc_role role_ref; /* reference role */
+ struct rtw89_mcc_role role_aux; /* auxiliary role */
+ struct rtw89_mcc_bt_role bt_role;
+ struct rtw89_mcc_config config;
};
struct rtw89_dev {
@@ -4286,6 +5416,7 @@ struct rtw89_dev {
const struct ieee80211_ops *ops;
bool dbcc_en;
+ enum rtw89_mlo_dbcc_mode mlo_dbcc_mode;
struct rtw89_hw_scan_info scan_info;
const struct rtw89_chip_info *chip;
const struct rtw89_pci_info *pci_info;
@@ -4297,6 +5428,7 @@ struct rtw89_dev {
struct rtw89_hci_info hci;
struct rtw89_efuse efuse;
struct rtw89_traffic_stats stats;
+ struct rtw89_rfe_data *rfe_data;
/* ensures exclusive access from mac80211 callbacks */
struct mutex mutex;
@@ -4332,8 +5464,10 @@ struct rtw89_dev {
DECLARE_BITMAP(mac_id_map, RTW89_MAX_MAC_ID_NUM);
DECLARE_BITMAP(flags, NUM_OF_RTW89_FLAGS);
DECLARE_BITMAP(pkt_offload, RTW89_MAX_PKT_OFLD_NUM);
+ DECLARE_BITMAP(quirks, NUM_OF_RTW89_QUIRKS);
struct rtw89_phy_stat phystat;
+ struct rtw89_rfk_wait_info rfk_wait;
struct rtw89_dack_info dack;
struct rtw89_iqk_info iqk;
struct rtw89_dpk_info dpk;
@@ -4344,7 +5478,7 @@ struct rtw89_dev {
bool is_bt_iqk_timeout;
struct rtw89_fem_info fem;
- struct rtw89_txpwr_byrate byr[RTW89_BAND_NUM];
+ struct rtw89_txpwr_byrate byr[RTW89_BAND_NUM][RTW89_BYR_BW_NUM];
struct rtw89_tssi_info tssi;
struct rtw89_power_trim_info pwr_trim;
@@ -4352,12 +5486,16 @@ struct rtw89_dev {
struct rtw89_env_monitor_info env_monitor;
struct rtw89_dig_info dig;
struct rtw89_phy_ch_info ch_info;
- struct rtw89_phy_bb_gain_info bb_gain;
+ union {
+ struct rtw89_phy_bb_gain_info ax;
+ struct rtw89_phy_bb_gain_info_be be;
+ } bb_gain;
struct rtw89_phy_efuse_gain efuse_gain;
struct rtw89_phy_ul_tb_info ul_tb_info;
struct rtw89_antdiv_info antdiv;
struct delayed_work track_work;
+ struct delayed_work chanctx_work;
struct delayed_work coex_act1_work;
struct delayed_work coex_bt_devinfo_work;
struct delayed_work coex_rfk_chk_work;
@@ -4371,6 +5509,7 @@ struct rtw89_dev {
struct rtw89_regulatory_info regulatory;
struct rtw89_sar_info sar;
+ struct rtw89_tas_info tas;
struct rtw89_btc btc;
enum rtw89_ps_mode ps_mode;
@@ -4379,7 +5518,7 @@ struct rtw89_dev {
struct rtw89_wow_param wow;
/* napi structure */
- struct net_device netdev;
+ struct net_device *netdev;
struct napi_struct napi;
int napi_budget_countdown;
@@ -4438,6 +5577,11 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
return rtwdev->hci.ops->tx_kick_off(rtwdev, txch);
}
+static inline int rtw89_hci_mac_pre_deinit(struct rtw89_dev *rtwdev)
+{
+ return rtwdev->hci.ops->mac_pre_deinit(rtwdev);
+}
+
static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues,
bool drop)
{
@@ -4490,12 +5634,12 @@ static inline void rtw89_hci_ctrl_trxhci(struct rtw89_dev *rtwdev, bool enable)
rtwdev->hci.ops->ctrl_trxhci(rtwdev, enable);
}
-static inline int rtw89_hci_poll_txdma_ch(struct rtw89_dev *rtwdev)
+static inline int rtw89_hci_poll_txdma_ch_idle(struct rtw89_dev *rtwdev)
{
int ret = 0;
- if (rtwdev->hci.ops->poll_txdma_ch)
- ret = rtwdev->hci.ops->poll_txdma_ch(rtwdev);
+ if (rtwdev->hci.ops->poll_txdma_ch_idle)
+ ret = rtwdev->hci.ops->poll_txdma_ch_idle(rtwdev);
return ret;
}
@@ -4828,6 +5972,30 @@ enum rtw89_bandwidth nl_to_rtw89_bandwidth(enum nl80211_chan_width width)
}
static inline
+enum nl80211_he_ru_alloc rtw89_he_rua_to_ru_alloc(u16 rua)
+{
+ switch (rua) {
+ default:
+ WARN(1, "Invalid RU allocation: %d\n", rua);
+ fallthrough;
+ case 0 ... 36:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_26;
+ case 37 ... 52:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_52;
+ case 53 ... 60:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_106;
+ case 61 ... 64:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_242;
+ case 65 ... 66:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_484;
+ case 67:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_996;
+ case 68:
+ return NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
+ }
+}
+
+static inline
struct rtw89_addr_cam_entry *rtw89_get_addr_cam_of(struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta)
{
@@ -4906,6 +6074,18 @@ const struct rtw89_chan_rcd *rtw89_chan_rcd_get(struct rtw89_dev *rtwdev,
return &hal->sub[idx].rcd;
}
+static inline
+const struct rtw89_chan *rtw89_scan_chan_get(struct rtw89_dev *rtwdev)
+{
+ struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
+ struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
+
+ if (rtwvif)
+ return rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx);
+ else
+ return rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+}
+
static inline void rtw89_chip_fem_setup(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -4922,6 +6102,37 @@ static inline void rtw89_chip_rfe_gpio(struct rtw89_dev *rtwdev)
chip->ops->rfe_gpio(rtwdev);
}
+static inline void rtw89_chip_rfk_hw_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ if (chip->ops->rfk_hw_init)
+ chip->ops->rfk_hw_init(rtwdev);
+}
+
+static inline
+void rtw89_chip_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ if (chip->ops->bb_preinit)
+ chip->ops->bb_preinit(rtwdev, phy_idx);
+}
+
+static inline
+void rtw89_chip_bb_postinit(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ if (!chip->ops->bb_postinit)
+ return;
+
+ chip->ops->bb_postinit(rtwdev, RTW89_PHY_0);
+
+ if (rtwdev->dbcc_en)
+ chip->ops->bb_postinit(rtwdev, RTW89_PHY_1);
+}
+
static inline void rtw89_chip_bb_sethw(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -4938,6 +6149,14 @@ static inline void rtw89_chip_rfk_init(struct rtw89_dev *rtwdev)
chip->ops->rfk_init(rtwdev);
}
+static inline void rtw89_chip_rfk_init_late(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ if (chip->ops->rfk_init_late)
+ chip->ops->rfk_init_late(rtwdev);
+}
+
static inline void rtw89_chip_rfk_channel(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -5017,13 +6236,13 @@ static inline void rtw89_chip_query_ppdu(struct rtw89_dev *rtwdev,
chip->ops->query_ppdu(rtwdev, phy_ppdu, status);
}
-static inline void rtw89_chip_bb_ctrl_btc_preagc(struct rtw89_dev *rtwdev,
- bool bt_en)
+static inline void rtw89_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- if (chip->ops->bb_ctrl_btc_preagc)
- chip->ops->bb_ctrl_btc_preagc(rtwdev, bt_en);
+ if (chip->ops->ctrl_nbtg_bt_tx)
+ chip->ops->ctrl_nbtg_bt_tx(rtwdev, en, phy_idx);
}
static inline void rtw89_chip_cfg_txrx_path(struct rtw89_dev *rtwdev)
@@ -5061,12 +6280,13 @@ static inline u8 rtw89_regd_get(struct rtw89_dev *rtwdev, u8 band)
return regd->txpwr_regd[band];
}
-static inline void rtw89_ctrl_btg(struct rtw89_dev *rtwdev, bool btg)
+static inline void rtw89_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en,
+ enum rtw89_phy_idx phy_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
- if (chip->ops->ctrl_btg)
- chip->ops->ctrl_btg(rtwdev, btg);
+ if (chip->ops->ctrl_btg_bt_rx)
+ chip->ops->ctrl_btg_bt_rx(rtwdev, en, phy_idx);
}
static inline
@@ -5229,6 +6449,28 @@ out:
rcu_read_unlock();
}
+static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev)
+{
+ switch (rtwdev->mlo_dbcc_mode) {
+ case MLO_1_PLUS_1_1RF:
+ case MLO_1_PLUS_1_2RF:
+ case DBCC_LEGACY:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
+
+ if (chip_id == RTL8852B || chip_id == RTL8851B || chip_id == RTL8852BT)
+ return true;
+
+ return false;
+}
+
int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel);
int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
@@ -5242,18 +6484,27 @@ void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev,
void rtw89_core_fill_txdesc_v1(struct rtw89_dev *rtwdev,
struct rtw89_tx_desc_info *desc_info,
void *txdesc);
+void rtw89_core_fill_txdesc_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_tx_desc_info *desc_info,
+ void *txdesc);
void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev,
struct rtw89_tx_desc_info *desc_info,
void *txdesc);
+void rtw89_core_fill_txdesc_fwcmd_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_tx_desc_info *desc_info,
+ void *txdesc);
void rtw89_core_rx(struct rtw89_dev *rtwdev,
struct rtw89_rx_desc_info *desc_info,
struct sk_buff *skb);
void rtw89_core_query_rxdesc(struct rtw89_dev *rtwdev,
struct rtw89_rx_desc_info *desc_info,
u8 *data, u32 data_offset);
+void rtw89_core_query_rxdesc_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_rx_desc_info *desc_info,
+ u8 *data, u32 data_offset);
void rtw89_core_napi_start(struct rtw89_dev *rtwdev);
void rtw89_core_napi_stop(struct rtw89_dev *rtwdev);
-void rtw89_core_napi_init(struct rtw89_dev *rtwdev);
+int rtw89_core_napi_init(struct rtw89_dev *rtwdev);
void rtw89_core_napi_deinit(struct rtw89_dev *rtwdev);
int rtw89_core_sta_add(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
@@ -5273,6 +6524,7 @@ int rtw89_core_sta_remove(struct rtw89_dev *rtwdev,
void rtw89_core_set_tid_config(struct rtw89_dev *rtwdev,
struct ieee80211_sta *sta,
struct cfg80211_tid_config *tid_config);
+void rtw89_check_quirks(struct rtw89_dev *rtwdev, const struct dmi_system_id *quirks);
int rtw89_core_init(struct rtw89_dev *rtwdev);
void rtw89_core_deinit(struct rtw89_dev *rtwdev);
int rtw89_core_register(struct rtw89_dev *rtwdev);
@@ -5281,9 +6533,13 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device,
u32 bus_data_size,
const struct rtw89_chip_info *chip);
void rtw89_free_ieee80211_hw(struct rtw89_dev *rtwdev);
+u8 rtw89_acquire_mac_id(struct rtw89_dev *rtwdev);
+void rtw89_release_mac_id(struct rtw89_dev *rtwdev, u8 mac_id);
void rtw89_core_set_chip_txpwr(struct rtw89_dev *rtwdev);
void rtw89_get_default_chandef(struct cfg80211_chan_def *chandef);
-void rtw89_set_channel(struct rtw89_dev *rtwdev);
+void rtw89_get_channel_params(const struct cfg80211_chan_def *chandef,
+ struct rtw89_chan *chan);
+int rtw89_set_channel(struct rtw89_dev *rtwdev);
void rtw89_get_channel(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_chan *chan);
u8 rtw89_core_acquire_bit_map(unsigned long *addr, unsigned long size);
@@ -5315,8 +6571,10 @@ void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
const u8 *mac_addr, bool hw_scan);
void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif, bool hw_scan);
-void rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool active);
+int rtw89_reg_6ghz_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ bool active);
+void rtw89_core_update_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
+void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event);
#if defined(__linux__)
#define rtw89_static_assert(_x) static_assert(_x)
diff --git a/sys/contrib/dev/rtw89/debug.c b/sys/contrib/dev/rtw89/debug.c
index b2fa13bf77ac..750ef1578e18 100644
--- a/sys/contrib/dev/rtw89/debug.c
+++ b/sys/contrib/dev/rtw89/debug.c
@@ -376,7 +376,11 @@ static int rtw89_debug_priv_rf_reg_dump_get(struct seq_file *m, void *v)
}
struct txpwr_ent {
- const char *txt;
+ bool nested;
+ union {
+ const char *txt;
+ const struct txpwr_ent *ptr;
+ };
u8 len;
};
@@ -388,6 +392,12 @@ struct txpwr_map {
u32 addr_to_1ss;
};
+#define __GEN_TXPWR_ENT_NESTED(_e) \
+ { .nested = true, .ptr = __txpwr_ent_##_e, \
+ .len = ARRAY_SIZE(__txpwr_ent_##_e) }
+
+#define __GEN_TXPWR_ENT0(_t) { .len = 0, .txt = _t }
+
#define __GEN_TXPWR_ENT2(_t, _e0, _e1) \
{ .len = 2, .txt = _t "\t- " _e0 " " _e1 }
@@ -399,7 +409,7 @@ struct txpwr_map {
_e0 " " _e1 " " _e2 " " _e3 " " \
_e4 " " _e5 " " _e6 " " _e7 }
-static const struct txpwr_ent __txpwr_ent_byr[] = {
+static const struct txpwr_ent __txpwr_ent_byr_ax[] = {
__GEN_TXPWR_ENT4("CCK ", "1M ", "2M ", "5.5M ", "11M "),
__GEN_TXPWR_ENT4("LEGACY ", "6M ", "9M ", "12M ", "18M "),
__GEN_TXPWR_ENT4("LEGACY ", "24M ", "36M ", "48M ", "54M "),
@@ -416,21 +426,21 @@ static const struct txpwr_ent __txpwr_ent_byr[] = {
};
#if defined(__linux__)
-static_assert((ARRAY_SIZE(__txpwr_ent_byr) * 4) ==
+static_assert((ARRAY_SIZE(__txpwr_ent_byr_ax) * 4) ==
#elif defined(__FreeBSD__)
-rtw89_static_assert((ARRAY_SIZE(__txpwr_ent_byr) * 4) ==
+rtw89_static_assert((ARRAY_SIZE(__txpwr_ent_byr_ax) * 4) ==
#endif
(R_AX_PWR_BY_RATE_MAX - R_AX_PWR_BY_RATE + 4));
-static const struct txpwr_map __txpwr_map_byr = {
- .ent = __txpwr_ent_byr,
- .size = ARRAY_SIZE(__txpwr_ent_byr),
+static const struct txpwr_map __txpwr_map_byr_ax = {
+ .ent = __txpwr_ent_byr_ax,
+ .size = ARRAY_SIZE(__txpwr_ent_byr_ax),
.addr_from = R_AX_PWR_BY_RATE,
.addr_to = R_AX_PWR_BY_RATE_MAX,
.addr_to_1ss = R_AX_PWR_BY_RATE_1SS_MAX,
};
-static const struct txpwr_ent __txpwr_ent_lmt[] = {
+static const struct txpwr_ent __txpwr_ent_lmt_ax[] = {
/* 1TX */
__GEN_TXPWR_ENT2("CCK_1TX_20M ", "NON_BF", "BF"),
__GEN_TXPWR_ENT2("CCK_1TX_40M ", "NON_BF", "BF"),
@@ -476,21 +486,21 @@ static const struct txpwr_ent __txpwr_ent_lmt[] = {
};
#if defined(__linux__)
-static_assert((ARRAY_SIZE(__txpwr_ent_lmt) * 2) ==
+static_assert((ARRAY_SIZE(__txpwr_ent_lmt_ax) * 2) ==
#elif defined(__FreeBSD__)
-rtw89_static_assert((ARRAY_SIZE(__txpwr_ent_lmt) * 2) ==
+rtw89_static_assert((ARRAY_SIZE(__txpwr_ent_lmt_ax) * 2) ==
#endif
(R_AX_PWR_LMT_MAX - R_AX_PWR_LMT + 4));
-static const struct txpwr_map __txpwr_map_lmt = {
- .ent = __txpwr_ent_lmt,
- .size = ARRAY_SIZE(__txpwr_ent_lmt),
+static const struct txpwr_map __txpwr_map_lmt_ax = {
+ .ent = __txpwr_ent_lmt_ax,
+ .size = ARRAY_SIZE(__txpwr_ent_lmt_ax),
.addr_from = R_AX_PWR_LMT,
.addr_to = R_AX_PWR_LMT_MAX,
.addr_to_1ss = R_AX_PWR_LMT_1SS_MAX,
};
-static const struct txpwr_ent __txpwr_ent_lmt_ru[] = {
+static const struct txpwr_ent __txpwr_ent_lmt_ru_ax[] = {
/* 1TX */
__GEN_TXPWR_ENT8("1TX", "RU26__0", "RU26__1", "RU26__2", "RU26__3",
"RU26__4", "RU26__5", "RU26__6", "RU26__7"),
@@ -508,28 +518,210 @@ static const struct txpwr_ent __txpwr_ent_lmt_ru[] = {
};
#if defined(__linux__)
-static_assert((ARRAY_SIZE(__txpwr_ent_lmt_ru) * 8) ==
+static_assert((ARRAY_SIZE(__txpwr_ent_lmt_ru_ax) * 8) ==
#elif defined(__FreeBSD__)
-rtw89_static_assert((ARRAY_SIZE(__txpwr_ent_lmt_ru) * 8) ==
+rtw89_static_assert((ARRAY_SIZE(__txpwr_ent_lmt_ru_ax) * 8) ==
#endif
(R_AX_PWR_RU_LMT_MAX - R_AX_PWR_RU_LMT + 4));
-static const struct txpwr_map __txpwr_map_lmt_ru = {
- .ent = __txpwr_ent_lmt_ru,
- .size = ARRAY_SIZE(__txpwr_ent_lmt_ru),
+static const struct txpwr_map __txpwr_map_lmt_ru_ax = {
+ .ent = __txpwr_ent_lmt_ru_ax,
+ .size = ARRAY_SIZE(__txpwr_ent_lmt_ru_ax),
.addr_from = R_AX_PWR_RU_LMT,
.addr_to = R_AX_PWR_RU_LMT_MAX,
.addr_to_1ss = R_AX_PWR_RU_LMT_1SS_MAX,
};
-static u8 __print_txpwr_ent(struct seq_file *m, const struct txpwr_ent *ent,
- const s8 *buf, const u8 cur)
+static const struct txpwr_ent __txpwr_ent_byr_mcs_be[] = {
+ __GEN_TXPWR_ENT4("MCS_1SS ", "MCS0 ", "MCS1 ", "MCS2 ", "MCS3 "),
+ __GEN_TXPWR_ENT4("MCS_1SS ", "MCS4 ", "MCS5 ", "MCS6 ", "MCS7 "),
+ __GEN_TXPWR_ENT4("MCS_1SS ", "MCS8 ", "MCS9 ", "MCS10", "MCS11"),
+ __GEN_TXPWR_ENT2("MCS_1SS ", "MCS12 ", "MCS13 \t"),
+ __GEN_TXPWR_ENT4("HEDCM_1SS ", "MCS0 ", "MCS1 ", "MCS3 ", "MCS4 "),
+ __GEN_TXPWR_ENT4("DLRU_MCS_1SS ", "MCS0 ", "MCS1 ", "MCS2 ", "MCS3 "),
+ __GEN_TXPWR_ENT4("DLRU_MCS_1SS ", "MCS4 ", "MCS5 ", "MCS6 ", "MCS7 "),
+ __GEN_TXPWR_ENT4("DLRU_MCS_1SS ", "MCS8 ", "MCS9 ", "MCS10", "MCS11"),
+ __GEN_TXPWR_ENT2("DLRU_MCS_1SS ", "MCS12 ", "MCS13 \t"),
+ __GEN_TXPWR_ENT4("DLRU_HEDCM_1SS", "MCS0 ", "MCS1 ", "MCS3 ", "MCS4 "),
+ __GEN_TXPWR_ENT4("MCS_2SS ", "MCS0 ", "MCS1 ", "MCS2 ", "MCS3 "),
+ __GEN_TXPWR_ENT4("MCS_2SS ", "MCS4 ", "MCS5 ", "MCS6 ", "MCS7 "),
+ __GEN_TXPWR_ENT4("MCS_2SS ", "MCS8 ", "MCS9 ", "MCS10", "MCS11"),
+ __GEN_TXPWR_ENT2("MCS_2SS ", "MCS12 ", "MCS13 \t"),
+ __GEN_TXPWR_ENT4("HEDCM_2SS ", "MCS0 ", "MCS1 ", "MCS3 ", "MCS4 "),
+ __GEN_TXPWR_ENT4("DLRU_MCS_2SS ", "MCS0 ", "MCS1 ", "MCS2 ", "MCS3 "),
+ __GEN_TXPWR_ENT4("DLRU_MCS_2SS ", "MCS4 ", "MCS5 ", "MCS6 ", "MCS7 "),
+ __GEN_TXPWR_ENT4("DLRU_MCS_2SS ", "MCS8 ", "MCS9 ", "MCS10", "MCS11"),
+ __GEN_TXPWR_ENT2("DLRU_MCS_2SS ", "MCS12 ", "MCS13 \t"),
+ __GEN_TXPWR_ENT4("DLRU_HEDCM_2SS", "MCS0 ", "MCS1 ", "MCS3 ", "MCS4 "),
+};
+
+static const struct txpwr_ent __txpwr_ent_byr_be[] = {
+ __GEN_TXPWR_ENT0("BW20"),
+ __GEN_TXPWR_ENT4("CCK ", "1M ", "2M ", "5.5M ", "11M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "6M ", "9M ", "12M ", "18M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "24M ", "36M ", "48M ", "54M "),
+ __GEN_TXPWR_ENT2("EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT2("DLRU_EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT_NESTED(byr_mcs_be),
+
+ __GEN_TXPWR_ENT0("BW40"),
+ __GEN_TXPWR_ENT4("CCK ", "1M ", "2M ", "5.5M ", "11M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "6M ", "9M ", "12M ", "18M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "24M ", "36M ", "48M ", "54M "),
+ __GEN_TXPWR_ENT2("EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT2("DLRU_EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT_NESTED(byr_mcs_be),
+
+ /* there is no CCK section after BW80 */
+ __GEN_TXPWR_ENT0("BW80"),
+ __GEN_TXPWR_ENT4("LEGACY ", "6M ", "9M ", "12M ", "18M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "24M ", "36M ", "48M ", "54M "),
+ __GEN_TXPWR_ENT2("EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT2("DLRU_EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT_NESTED(byr_mcs_be),
+
+ __GEN_TXPWR_ENT0("BW160"),
+ __GEN_TXPWR_ENT4("LEGACY ", "6M ", "9M ", "12M ", "18M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "24M ", "36M ", "48M ", "54M "),
+ __GEN_TXPWR_ENT2("EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT2("DLRU_EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT_NESTED(byr_mcs_be),
+
+ __GEN_TXPWR_ENT0("BW320"),
+ __GEN_TXPWR_ENT4("LEGACY ", "6M ", "9M ", "12M ", "18M "),
+ __GEN_TXPWR_ENT4("LEGACY ", "24M ", "36M ", "48M ", "54M "),
+ __GEN_TXPWR_ENT2("EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT2("DLRU_EHT ", "MCS14 ", "MCS15 \t"),
+ __GEN_TXPWR_ENT_NESTED(byr_mcs_be),
+};
+
+static const struct txpwr_map __txpwr_map_byr_be = {
+ .ent = __txpwr_ent_byr_be,
+ .size = ARRAY_SIZE(__txpwr_ent_byr_be),
+ .addr_from = R_BE_PWR_BY_RATE,
+ .addr_to = R_BE_PWR_BY_RATE_MAX,
+ .addr_to_1ss = 0, /* not support */
+};
+
+static const struct txpwr_ent __txpwr_ent_lmt_mcs_be[] = {
+ __GEN_TXPWR_ENT2("MCS_20M_0 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_1 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_2 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_3 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_4 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_5 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_6 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_7 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_8 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_9 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_10 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_11 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_12 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_13 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_14 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_20M_15 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_0 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_1 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_2 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_3 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_4 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_5 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_6 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_7 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_80M_0 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_80M_1 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_80M_2 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_80M_3 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_160M_0 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_160M_1 ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_320M ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_0p5", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_2p5", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_4p5", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("MCS_40M_6p5", "NON_BF", "BF"),
+};
+
+static const struct txpwr_ent __txpwr_ent_lmt_be[] = {
+ __GEN_TXPWR_ENT0("1TX"),
+ __GEN_TXPWR_ENT2("CCK_20M ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("CCK_40M ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("OFDM ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT_NESTED(lmt_mcs_be),
+
+ __GEN_TXPWR_ENT0("2TX"),
+ __GEN_TXPWR_ENT2("CCK_20M ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("CCK_40M ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT2("OFDM ", "NON_BF", "BF"),
+ __GEN_TXPWR_ENT_NESTED(lmt_mcs_be),
+};
+
+static const struct txpwr_map __txpwr_map_lmt_be = {
+ .ent = __txpwr_ent_lmt_be,
+ .size = ARRAY_SIZE(__txpwr_ent_lmt_be),
+ .addr_from = R_BE_PWR_LMT,
+ .addr_to = R_BE_PWR_LMT_MAX,
+ .addr_to_1ss = 0, /* not support */
+};
+
+static const struct txpwr_ent __txpwr_ent_lmt_ru_indexes_be[] = {
+ __GEN_TXPWR_ENT8("RU26 ", "IDX_0 ", "IDX_1 ", "IDX_2 ", "IDX_3 ",
+ "IDX_4 ", "IDX_5 ", "IDX_6 ", "IDX_7 "),
+ __GEN_TXPWR_ENT8("RU26 ", "IDX_8 ", "IDX_9 ", "IDX_10", "IDX_11",
+ "IDX_12", "IDX_13", "IDX_14", "IDX_15"),
+ __GEN_TXPWR_ENT8("RU52 ", "IDX_0 ", "IDX_1 ", "IDX_2 ", "IDX_3 ",
+ "IDX_4 ", "IDX_5 ", "IDX_6 ", "IDX_7 "),
+ __GEN_TXPWR_ENT8("RU52 ", "IDX_8 ", "IDX_9 ", "IDX_10", "IDX_11",
+ "IDX_12", "IDX_13", "IDX_14", "IDX_15"),
+ __GEN_TXPWR_ENT8("RU106 ", "IDX_0 ", "IDX_1 ", "IDX_2 ", "IDX_3 ",
+ "IDX_4 ", "IDX_5 ", "IDX_6 ", "IDX_7 "),
+ __GEN_TXPWR_ENT8("RU106 ", "IDX_8 ", "IDX_9 ", "IDX_10", "IDX_11",
+ "IDX_12", "IDX_13", "IDX_14", "IDX_15"),
+ __GEN_TXPWR_ENT8("RU52_26 ", "IDX_0 ", "IDX_1 ", "IDX_2 ", "IDX_3 ",
+ "IDX_4 ", "IDX_5 ", "IDX_6 ", "IDX_7 "),
+ __GEN_TXPWR_ENT8("RU52_26 ", "IDX_8 ", "IDX_9 ", "IDX_10", "IDX_11",
+ "IDX_12", "IDX_13", "IDX_14", "IDX_15"),
+ __GEN_TXPWR_ENT8("RU106_26", "IDX_0 ", "IDX_1 ", "IDX_2 ", "IDX_3 ",
+ "IDX_4 ", "IDX_5 ", "IDX_6 ", "IDX_7 "),
+ __GEN_TXPWR_ENT8("RU106_26", "IDX_8 ", "IDX_9 ", "IDX_10", "IDX_11",
+ "IDX_12", "IDX_13", "IDX_14", "IDX_15"),
+};
+
+static const struct txpwr_ent __txpwr_ent_lmt_ru_be[] = {
+ __GEN_TXPWR_ENT0("1TX"),
+ __GEN_TXPWR_ENT_NESTED(lmt_ru_indexes_be),
+
+ __GEN_TXPWR_ENT0("2TX"),
+ __GEN_TXPWR_ENT_NESTED(lmt_ru_indexes_be),
+};
+
+static const struct txpwr_map __txpwr_map_lmt_ru_be = {
+ .ent = __txpwr_ent_lmt_ru_be,
+ .size = ARRAY_SIZE(__txpwr_ent_lmt_ru_be),
+ .addr_from = R_BE_PWR_RU_LMT,
+ .addr_to = R_BE_PWR_RU_LMT_MAX,
+ .addr_to_1ss = 0, /* not support */
+};
+
+static unsigned int
+__print_txpwr_ent(struct seq_file *m, const struct txpwr_ent *ent,
+ const s8 *buf, const unsigned int cur)
{
+ unsigned int cnt, i;
char *fmt;
+ if (ent->nested) {
+ for (cnt = 0, i = 0; i < ent->len; i++)
+ cnt += __print_txpwr_ent(m, ent->ptr + i, buf,
+ cur + cnt);
+ return cnt;
+ }
+
switch (ent->len) {
+ case 0:
+ seq_printf(m, "\t<< %s >>\n", ent->txt);
+ return 0;
case 2:
- fmt = "%s\t| %3d, %3d,\tdBm\n";
+ fmt = "%s\t| %3d, %3d,\t\tdBm\n";
seq_printf(m, fmt, ent->txt, buf[cur], buf[cur + 1]);
return 2;
case 4:
@@ -553,10 +745,10 @@ static int __print_txpwr_map(struct seq_file *m, struct rtw89_dev *rtwdev,
{
u8 fct = rtwdev->chip->txpwr_factor_mac;
u8 path_num = rtwdev->chip->rf_path_num;
+ unsigned int cur, i;
u32 max_valid_addr;
u32 val, addr;
s8 *buf, tmp;
- u8 cur, i;
int ret;
buf = vzalloc(map->addr_to - map->addr_from + 4);
@@ -568,6 +760,9 @@ static int __print_txpwr_map(struct seq_file *m, struct rtw89_dev *rtwdev,
else
max_valid_addr = map->addr_to;
+ if (max_valid_addr == 0)
+ return -EOPNOTSUPP;
+
for (addr = map->addr_from; addr <= max_valid_addr; addr += 4) {
ret = rtw89_mac_txpwr_read32(rtwdev, RTW89_PHY_0, addr, &val);
if (ret)
@@ -593,9 +788,9 @@ static int __print_txpwr_map(struct seq_file *m, struct rtw89_dev *rtwdev,
seq_puts(m, #_regd "\n"); \
break
-static void __print_regd(struct seq_file *m, struct rtw89_dev *rtwdev)
+static void __print_regd(struct seq_file *m, struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
u8 band = chan->band_type;
u8 regd = rtw89_regd_get(rtwdev, band);
@@ -621,33 +816,90 @@ static void __print_regd(struct seq_file *m, struct rtw89_dev *rtwdev)
#undef case_REGD
+struct dbgfs_txpwr_table {
+ const struct txpwr_map *byr;
+ const struct txpwr_map *lmt;
+ const struct txpwr_map *lmt_ru;
+};
+
+static const struct dbgfs_txpwr_table dbgfs_txpwr_table_ax = {
+ .byr = &__txpwr_map_byr_ax,
+ .lmt = &__txpwr_map_lmt_ax,
+ .lmt_ru = &__txpwr_map_lmt_ru_ax,
+};
+
+static const struct dbgfs_txpwr_table dbgfs_txpwr_table_be = {
+ .byr = &__txpwr_map_byr_be,
+ .lmt = &__txpwr_map_lmt_be,
+ .lmt_ru = &__txpwr_map_lmt_ru_be,
+};
+
+static const struct dbgfs_txpwr_table *dbgfs_txpwr_tables[RTW89_CHIP_GEN_NUM] = {
+ [RTW89_CHIP_AX] = &dbgfs_txpwr_table_ax,
+ [RTW89_CHIP_BE] = &dbgfs_txpwr_table_be,
+};
+
+static
+void rtw89_debug_priv_txpwr_table_get_regd(struct seq_file *m,
+ struct rtw89_dev *rtwdev,
+ const struct rtw89_chan *chan)
+{
+ const struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ const struct rtw89_reg_6ghz_tpe *tpe6 = &regulatory->reg_6ghz_tpe;
+
+ seq_printf(m, "[Chanctx] band %u, ch %u, bw %u\n",
+ chan->band_type, chan->channel, chan->band_width);
+
+ seq_puts(m, "[Regulatory] ");
+ __print_regd(m, rtwdev, chan);
+
+ if (chan->band_type == RTW89_BAND_6G) {
+ seq_printf(m, "[reg6_pwr_type] %u\n", regulatory->reg_6ghz_power);
+
+ if (tpe6->valid)
+ seq_printf(m, "[TPE] %d dBm\n", tpe6->constraint);
+ }
+}
+
static int rtw89_debug_priv_txpwr_table_get(struct seq_file *m, void *v)
{
struct rtw89_debugfs_priv *debugfs_priv = m->private;
struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+ const struct dbgfs_txpwr_table *tbl;
+ const struct rtw89_chan *chan;
int ret = 0;
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
+ chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- seq_puts(m, "[Regulatory] ");
- __print_regd(m, rtwdev);
+ rtw89_debug_priv_txpwr_table_get_regd(m, rtwdev, chan);
seq_puts(m, "[SAR]\n");
- rtw89_print_sar(m, rtwdev);
+ rtw89_print_sar(m, rtwdev, chan->freq);
+
+ seq_puts(m, "[TAS]\n");
+ rtw89_print_tas(m, rtwdev);
+
+ tbl = dbgfs_txpwr_tables[chip_gen];
+ if (!tbl) {
+ ret = -EOPNOTSUPP;
+ goto err;
+ }
seq_puts(m, "\n[TX power byrate]\n");
- ret = __print_txpwr_map(m, rtwdev, &__txpwr_map_byr);
+ ret = __print_txpwr_map(m, rtwdev, tbl->byr);
if (ret)
goto err;
seq_puts(m, "\n[TX power limit]\n");
- ret = __print_txpwr_map(m, rtwdev, &__txpwr_map_lmt);
+ ret = __print_txpwr_map(m, rtwdev, tbl->lmt);
if (ret)
goto err;
seq_puts(m, "\n[TX power limit_ru]\n");
- ret = __print_txpwr_map(m, rtwdev, &__txpwr_map_lmt_ru);
+ ret = __print_txpwr_map(m, rtwdev, tbl->lmt_ru);
if (ret)
goto err;
@@ -811,6 +1063,9 @@ static void rtw89_debug_dump_mac_mem(struct seq_file *m,
struct rtw89_dev *rtwdev,
u8 sel, u32 start_addr, u32 len)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 filter_model_addr = mac->filter_model_addr;
+ u32 indir_access_addr = mac->indir_access_addr;
u32 base_addr, start_page, residue;
u32 i, j, p, pages;
u32 dump_len, remain;
@@ -820,17 +1075,17 @@ static void rtw89_debug_dump_mac_mem(struct seq_file *m,
pages = len / MAC_MEM_DUMP_PAGE_SIZE + 1;
start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE;
residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE;
- base_addr = rtw89_mac_mem_base_addrs[sel];
+ base_addr = mac->mem_base_addrs[sel];
base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE;
for (p = 0; p < pages; p++) {
dump_len = min_t(u32, remain, MAC_MEM_DUMP_PAGE_SIZE);
- rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, base_addr);
- for (i = R_AX_INDIR_ACCESS_ENTRY + residue;
- i < R_AX_INDIR_ACCESS_ENTRY + dump_len;) {
+ rtw89_write32(rtwdev, filter_model_addr, base_addr);
+ for (i = indir_access_addr + residue;
+ i < indir_access_addr + dump_len;) {
seq_printf(m, "%08xh:", i);
for (j = 0;
- j < 4 && i < R_AX_INDIR_ACCESS_ENTRY + dump_len;
+ j < 4 && i < indir_access_addr + dump_len;
j++, i += 4) {
val = rtw89_read32(rtwdev, i);
seq_printf(m, " %08x", val);
@@ -2783,7 +3038,7 @@ static bool is_dbg_port_valid(struct rtw89_dev *rtwdev, u32 sel)
sel >= RTW89_DBG_PORT_SEL_PCIE_TXDMA &&
sel <= RTW89_DBG_PORT_SEL_PCIE_MISC2)
return false;
- if (rtwdev->chip->chip_id == RTL8852B &&
+ if (rtw89_is_rtl885xb(rtwdev) &&
sel >= RTW89_DBG_PORT_SEL_PTCL_C1 &&
sel <= RTW89_DBG_PORT_SEL_TXTF_INFOH_C1)
return false;
@@ -3117,13 +3372,14 @@ out:
static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_cpuio_ctrl ctrl_para = {0};
u16 pkt_id;
int ret;
rtw89_leave_ps_mode(rtwdev);
- ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id);
+ ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id);
if (ret)
return ret;
@@ -3135,7 +3391,7 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS;
ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT;
- if (rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true))
+ if (mac->set_cpuio(rtwdev, &ctrl_para, true))
return -EFAULT;
return 0;
@@ -3213,14 +3469,17 @@ static ssize_t rtw89_debug_priv_btc_manual_set(struct file *filp,
struct rtw89_debugfs_priv *debugfs_priv = filp->private_data;
struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
struct rtw89_btc *btc = &rtwdev->btc;
- bool btc_manual;
+ const struct rtw89_btc_ver *ver = btc->ver;
int ret;
- ret = kstrtobool_from_user(user_buf, count, &btc_manual);
+ ret = kstrtobool_from_user(user_buf, count, &btc->manual_ctrl);
if (ret)
return ret;
- btc->ctrl.manual = btc_manual;
+ if (ver->fcxctrl == 7)
+ btc->ctrl.ctrl_v7.manual = btc->manual_ctrl;
+ else
+ btc->ctrl.ctrl.manual = btc->manual_ctrl;
return count;
}
@@ -3254,6 +3513,11 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
[NL80211_RATE_INFO_HE_GI_1_6] = "1.6",
[NL80211_RATE_INFO_HE_GI_3_2] = "3.2",
};
+ static const char * const eht_gi_str[] = {
+ [NL80211_RATE_INFO_EHT_GI_0_8] = "0.8",
+ [NL80211_RATE_INFO_EHT_GI_1_6] = "1.6",
+ [NL80211_RATE_INFO_EHT_GI_3_2] = "3.2",
+ };
struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
struct rate_info *rate = &rtwsta->ra_report.txrate;
struct ieee80211_rx_status *status = &rtwsta->rx_status;
@@ -3279,6 +3543,10 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
seq_printf(m, "HE %dSS MCS-%d GI:%s", rate->nss, rate->mcs,
rate->he_gi <= NL80211_RATE_INFO_HE_GI_3_2 ?
he_gi_str[rate->he_gi] : "N/A");
+ else if (rate->flags & RATE_INFO_FLAGS_EHT_MCS)
+ seq_printf(m, "EHT %dSS MCS-%d GI:%s", rate->nss, rate->mcs,
+ rate->eht_gi < ARRAY_SIZE(eht_gi_str) ?
+ eht_gi_str[rate->eht_gi] : "N/A");
else
seq_printf(m, "Legacy %d", rate->legacy);
seq_printf(m, "%s", rtwsta->ra_report.might_fallback_legacy ? " FB_G" : "");
@@ -3305,7 +3573,12 @@ static void rtw89_sta_info_get_iter(void *data, struct ieee80211_sta *sta)
case RX_ENC_HE:
seq_printf(m, "HE %dSS MCS-%d GI:%s", status->nss, status->rate_idx,
status->he_gi <= NL80211_RATE_INFO_HE_GI_3_2 ?
- he_gi_str[rate->he_gi] : "N/A");
+ he_gi_str[status->he_gi] : "N/A");
+ break;
+ case RX_ENC_EHT:
+ seq_printf(m, "EHT %dSS MCS-%d GI:%s", status->nss, status->rate_idx,
+ status->eht.gi < ARRAY_SIZE(eht_gi_str) ?
+ eht_gi_str[status->eht.gi] : "N/A");
break;
}
seq_printf(m, " BW:%u", rtw89_rate_info_bw_to_mhz(status->bw));
@@ -3414,17 +3687,21 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v)
}
static void rtw89_dump_addr_cam(struct seq_file *m,
+ struct rtw89_dev *rtwdev,
struct rtw89_addr_cam_entry *addr_cam)
{
- struct rtw89_sec_cam_entry *sec_entry;
+ struct rtw89_cam_info *cam_info = &rtwdev->cam_info;
+ const struct rtw89_sec_cam_entry *sec_entry;
+ u8 sec_cam_idx;
int i;
seq_printf(m, "\taddr_cam_idx=%u\n", addr_cam->addr_cam_idx);
seq_printf(m, "\t-> bssid_cam_idx=%u\n", addr_cam->bssid_cam_idx);
seq_printf(m, "\tsec_cam_bitmap=%*ph\n", (int)sizeof(addr_cam->sec_cam_map),
addr_cam->sec_cam_map);
- for (i = 0; i < RTW89_SEC_CAM_IN_ADDR_CAM; i++) {
- sec_entry = addr_cam->sec_entries[i];
+ for_each_set_bit(i, addr_cam->sec_cam_map, RTW89_SEC_CAM_IN_ADDR_CAM) {
+ sec_cam_idx = addr_cam->sec_ent[i];
+ sec_entry = cam_info->sec_entries[sec_cam_idx];
if (!sec_entry)
continue;
seq_printf(m, "\tsec[%d]: sec_cam_idx %u", i, sec_entry->sec_cam_idx);
@@ -3463,12 +3740,13 @@ static
void rtw89_vif_ids_get_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
{
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_dev *rtwdev = rtwvif->rtwdev;
struct seq_file *m = (struct seq_file *)data;
struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
seq_printf(m, "VIF [%d] %pM\n", rtwvif->mac_id, rtwvif->mac_addr);
seq_printf(m, "\tbssid_cam_idx=%u\n", bssid_cam->bssid_cam_idx);
- rtw89_dump_addr_cam(m, &rtwvif->addr_cam);
+ rtw89_dump_addr_cam(m, rtwdev, &rtwvif->addr_cam);
rtw89_dump_pkt_offload(m, &rtwvif->general_pkt_list, "\tpkt_ofld[GENERAL]: ");
}
@@ -3495,11 +3773,12 @@ static void rtw89_dump_ba_cam(struct seq_file *m, struct rtw89_sta *rtwsta)
static void rtw89_sta_ids_get_iter(void *data, struct ieee80211_sta *sta)
{
struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_dev *rtwdev = rtwsta->rtwdev;
struct seq_file *m = (struct seq_file *)data;
seq_printf(m, "STA [%d] %pM %s\n", rtwsta->mac_id, sta->addr,
sta->tdls ? "(TDLS)" : "");
- rtw89_dump_addr_cam(m, &rtwsta->addr_cam);
+ rtw89_dump_addr_cam(m, rtwdev, &rtwsta->addr_cam);
rtw89_dump_ba_cam(m, rtwsta);
}
@@ -3543,6 +3822,58 @@ static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v)
return 0;
}
+#define DM_INFO(type) {RTW89_DM_ ## type, #type}
+
+static const struct rtw89_disabled_dm_info {
+ enum rtw89_dm_type type;
+ const char *name;
+} rtw89_disabled_dm_infos[] = {
+ DM_INFO(DYNAMIC_EDCCA),
+};
+
+static int
+rtw89_debug_priv_disable_dm_get(struct seq_file *m, void *v)
+{
+ struct rtw89_debugfs_priv *debugfs_priv = m->private;
+ struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
+ const struct rtw89_disabled_dm_info *info;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 disabled;
+ int i;
+
+ seq_printf(m, "Disabled DM: 0x%x\n", hal->disabled_dm_bitmap);
+
+ for (i = 0; i < ARRAY_SIZE(rtw89_disabled_dm_infos); i++) {
+ info = &rtw89_disabled_dm_infos[i];
+ disabled = BIT(info->type) & hal->disabled_dm_bitmap;
+
+ seq_printf(m, "[%d] %s: %c\n", info->type, info->name,
+ disabled ? 'X' : 'O');
+ }
+
+ return 0;
+}
+
+static ssize_t
+rtw89_debug_priv_disable_dm_set(struct file *filp, const char __user *user_buf,
+ size_t count, loff_t *loff)
+{
+ struct seq_file *m = (struct seq_file *)filp->private_data;
+ struct rtw89_debugfs_priv *debugfs_priv = m->private;
+ struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 conf;
+ int ret;
+
+ ret = kstrtou32_from_user(user_buf, count, 0, &conf);
+ if (ret)
+ return -EINVAL;
+
+ hal->disabled_dm_bitmap = conf;
+
+ return count;
+}
+
static struct rtw89_debugfs_priv rtw89_debug_priv_read_reg = {
.cb_read = rtw89_debug_priv_read_reg_get,
.cb_write = rtw89_debug_priv_read_reg_select,
@@ -3618,6 +3949,11 @@ static struct rtw89_debugfs_priv rtw89_debug_priv_stations = {
.cb_read = rtw89_debug_priv_stations_get,
};
+static struct rtw89_debugfs_priv rtw89_debug_priv_disable_dm = {
+ .cb_read = rtw89_debug_priv_disable_dm_get,
+ .cb_write = rtw89_debug_priv_disable_dm_set,
+};
+
#define rtw89_debugfs_add(name, mode, fopname, parent) \
do { \
rtw89_debug_priv_ ##name.rtwdev = rtwdev; \
@@ -3658,13 +3994,13 @@ void rtw89_debugfs_init(struct rtw89_dev *rtwdev)
rtw89_debugfs_add_w(fw_log_manual);
rtw89_debugfs_add_r(phy_info);
rtw89_debugfs_add_r(stations);
+ rtw89_debugfs_add_rw(disable_dm);
}
#endif
#ifdef CONFIG_RTW89_DEBUGMSG
-void __rtw89_debug(struct rtw89_dev *rtwdev,
- enum rtw89_debug_mask mask,
- const char *fmt, ...)
+void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask,
+ const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -3689,5 +4025,5 @@ void __rtw89_debug(struct rtw89_dev *rtwdev,
va_end(args);
}
-EXPORT_SYMBOL(__rtw89_debug);
+EXPORT_SYMBOL(rtw89_debug);
#endif
diff --git a/sys/contrib/dev/rtw89/debug.h b/sys/contrib/dev/rtw89/debug.h
index a4ded7024657..ded730b59be2 100644
--- a/sys/contrib/dev/rtw89/debug.h
+++ b/sys/contrib/dev/rtw89/debug.h
@@ -36,6 +36,8 @@ enum rtw89_debug_mask {
RTW89_DBG_WOW = BIT(18),
RTW89_DBG_UL_TB = BIT(19),
RTW89_DBG_CHAN = BIT(20),
+ RTW89_DBG_ACPI = BIT(21),
+ RTW89_DBG_EDCCA = BIT(22),
#if defined(__FreeBSD__)
RTW89_DBG_IO_RW = BIT(30),
@@ -67,12 +69,10 @@ static inline void rtw89_debugfs_init(struct rtw89_dev *rtwdev) {}
#ifdef CONFIG_RTW89_DEBUGMSG
extern unsigned int rtw89_debug_mask;
-#define rtw89_debug(rtwdev, a...) __rtw89_debug(rtwdev, ##a)
__printf(3, 4)
-void __rtw89_debug(struct rtw89_dev *rtwdev,
- enum rtw89_debug_mask mask,
- const char *fmt, ...);
+void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask,
+ const char *fmt, ...);
static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev,
enum rtw89_debug_mask mask,
const char *prefix_str,
@@ -83,6 +83,12 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev,
print_hex_dump_bytes(prefix_str, DUMP_PREFIX_OFFSET, buf, len);
}
+
+static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev,
+ enum rtw89_debug_mask mask)
+{
+ return !!(rtw89_debug_mask & mask);
+}
#else
static inline void rtw89_debug(struct rtw89_dev *rtwdev,
enum rtw89_debug_mask mask,
@@ -91,6 +97,11 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev,
enum rtw89_debug_mask mask,
const char *prefix_str,
const void *buf, size_t len) {}
+static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev,
+ enum rtw89_debug_mask mask)
+{
+ return false;
+}
#endif
#endif
diff --git a/sys/contrib/dev/rtw89/efuse.c b/sys/contrib/dev/rtw89/efuse.c
index 2aaf4d013e46..e1236079a84a 100644
--- a/sys/contrib/dev/rtw89/efuse.c
+++ b/sys/contrib/dev/rtw89/efuse.c
@@ -114,6 +114,11 @@ static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
return 0;
}
+int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle)
+{
+ return 0;
+}
+
static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
u32 dump_addr, u32 dump_size)
{
@@ -231,7 +236,7 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
return 0;
}
-int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
+int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev)
{
u32 phy_size = rtwdev->chip->physical_efuse_size;
u32 log_size = rtwdev->chip->logical_efuse_size;
@@ -286,7 +291,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
- ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map);
+ ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, RTW89_EFUSE_BLOCK_IGNORE);
if (ret) {
rtw89_warn(rtwdev, "failed to read efuse map\n");
goto out_free;
@@ -300,7 +305,7 @@ out_free:
return ret;
}
-int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
+int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev)
{
u32 phycap_addr = rtwdev->chip->phycap_addr;
u32 phycap_size = rtwdev->chip->phycap_size;
diff --git a/sys/contrib/dev/rtw89/efuse.h b/sys/contrib/dev/rtw89/efuse.h
index 79071aff28de..72416f56a071 100644
--- a/sys/contrib/dev/rtw89/efuse.h
+++ b/sys/contrib/dev/rtw89/efuse.h
@@ -7,8 +7,22 @@
#include "core.h"
-int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev);
-int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev);
+#define RTW89_EFUSE_BLOCK_ID_MASK GENMASK(31, 16)
+#define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0)
+#define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000
+
+struct rtw89_efuse_block_cfg {
+ u32 offset;
+ u32 size;
+};
+
+int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev);
+int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev);
+int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle);
+int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev);
+int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev);
+int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle);
int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv);
+int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev);
#endif
diff --git a/sys/contrib/dev/rtw89/efuse_be.c b/sys/contrib/dev/rtw89/efuse_be.c
new file mode 100644
index 000000000000..0be26d5fdf7c
--- /dev/null
+++ b/sys/contrib/dev/rtw89/efuse_be.c
@@ -0,0 +1,562 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#include "debug.h"
+#include "efuse.h"
+#include "mac.h"
+#include "reg.h"
+
+#define EFUSE_EXTERNALPN_ADDR_BE 0x1580
+#define EFUSE_B1_MSSDEVTYPE_MASK GENMASK(3, 0)
+#define EFUSE_B1_MSSCUSTIDX0_MASK GENMASK(7, 4)
+#define EFUSE_SERIALNUM_ADDR_BE 0x1581
+#define EFUSE_B2_MSSKEYNUM_MASK GENMASK(3, 0)
+#define EFUSE_B2_MSSCUSTIDX1_MASK BIT(6)
+#define EFUSE_SB_CRYP_SEL_ADDR 0x1582
+#define EFUSE_SB_CRYP_SEL_SIZE 2
+#define EFUSE_SB_CRYP_SEL_DEFAULT 0xFFFF
+#define SB_SEL_MGN_MAX_SIZE 2
+#define EFUSE_SEC_BE_START 0x1580
+#define EFUSE_SEC_BE_SIZE 4
+
+enum rtw89_efuse_mss_dev_type {
+ MSS_DEV_TYPE_FWSEC_DEF = 0xF,
+ MSS_DEV_TYPE_FWSEC_WINLIN_INBOX = 0xC,
+ MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB = 0xA,
+ MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB = 0x9,
+ MSS_DEV_TYPE_FWSEC_NONWIN_INBOX = 0x6,
+};
+
+static const u32 sb_sel_mgn[SB_SEL_MGN_MAX_SIZE] = {
+ 0x8000100, 0xC000180
+};
+
+static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool aphy_patch = true;
+
+ if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
+ aphy_patch = false;
+
+ rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+
+ if (aphy_patch) {
+ rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
+ mdelay(1);
+ rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
+ rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
+ }
+
+ rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
+}
+
+static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool aphy_patch = true;
+
+ if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
+ aphy_patch = false;
+
+ if (aphy_patch) {
+ rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
+ rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
+ mdelay(1);
+ rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
+ }
+
+ rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+ rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
+}
+
+static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size)
+{
+ u32 efuse_ctl;
+ u32 addr;
+ u32 data;
+ int ret;
+
+ if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) {
+ rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n",
+ dump_addr, dump_size);
+ return -EINVAL;
+ }
+
+ rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev);
+
+ for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) {
+ efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK);
+ rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY);
+
+ ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
+ efuse_ctl & B_BE_EF_RDY, 1, 1000000,
+ true, rtwdev, R_BE_EFUSE_CTRL);
+ if (ret)
+ return -EBUSY;
+
+ data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1);
+ *((__le32 *)map) = cpu_to_le32(data);
+ }
+
+ rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev);
+
+ return 0;
+}
+
+static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size)
+{
+ u32 addr;
+ u8 val8;
+ int err;
+ int ret;
+
+ for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40,
+ FULL_BIT_MASK);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff,
+ XTAL_SI_LOW_ADDR_MASK);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
+ XTAL_SI_HIGH_ADDR_MASK);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
+ XTAL_SI_MODE_SEL_MASK);
+ if (ret)
+ return ret;
+
+ ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
+ !err && (val8 & XTAL_SI_RDY),
+ 1, 10000, false,
+ rtwdev, XTAL_SI_CTRL, &val8);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to read dav efuse\n");
+ return ret;
+ }
+
+ ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
+ if (ret)
+ return ret;
+ *map++ = val8;
+ }
+
+ return 0;
+}
+
+int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle)
+{
+ u32 val;
+ int ret = 0;
+
+ if (idle) {
+ rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
+ } else {
+ rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
+
+ ret = read_poll_timeout(rtw89_read32_mask, val,
+ val == MAC_AX_SYS_ACT, 50, 5000,
+ false, rtwdev, R_BE_IC_PWR_STATE,
+ B_BE_WHOLE_SYS_PWR_STE_MASK);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to convert efuse state\n");
+ }
+
+ return ret;
+}
+
+static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size, bool dav)
+{
+ int ret;
+
+ if (!map || dump_size == 0)
+ return 0;
+
+ rtw89_cnv_efuse_state_be(rtwdev, false);
+
+ if (dav) {
+ ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map,
+ dump_addr, dump_size);
+ if (ret)
+ return ret;
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size);
+ } else {
+ ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map,
+ dump_addr, dump_size);
+ if (ret)
+ return ret;
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size);
+ }
+
+ rtw89_cnv_efuse_state_be(rtwdev, true);
+
+ return 0;
+}
+
+#define EFUSE_HDR_CONST_MASK GENMASK(23, 20)
+#define EFUSE_HDR_PAGE_MASK GENMASK(19, 17)
+#define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4)
+#define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4)
+#define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0)
+
+#define invalid_efuse_header_be(hdr1, hdr2, hdr3) \
+ ((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff)
+#define invalid_efuse_content_be(word_en, i) \
+ (((word_en) & BIT(i)) != 0x0)
+#define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \
+ (((hdr1) << 16) | ((hdr2) << 8) | (hdr3))
+#define block_idx_to_logical_idx_be(blk_idx, i) \
+ (((blk_idx) << 3) + ((i) << 1))
+
+#define invalid_efuse_header_dav_be(hdr1, hdr2) \
+ ((hdr1) == 0xff || (hdr2) == 0xff)
+#define get_efuse_blk_idx_dav_be(hdr1, hdr2) \
+ (((hdr1) << 8) | (hdr2))
+
+static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev,
+ const u8 *phy_map, u32 phy_size, u8 *log_map,
+ const struct rtw89_efuse_block_cfg *efuse_block)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ enum rtw89_efuse_block blk_page, page;
+ u32 size = efuse_block->size;
+ u32 phy_idx, log_idx;
+ u32 hdr, page_offset;
+ u8 hdr1, hdr2, hdr3;
+ u8 i, val0, val1;
+ u32 min, max;
+ u16 blk_idx;
+ u8 word_en;
+
+ page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK);
+ page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK);
+
+ min = ALIGN_DOWN(page_offset, 2);
+ max = ALIGN(page_offset + size, 2);
+
+ memset(log_map, 0xff, size);
+
+ phy_idx = chip->sec_ctrl_efuse_size;
+
+ do {
+ if (page == RTW89_EFUSE_BLOCK_ADIE) {
+ hdr1 = phy_map[phy_idx];
+ hdr2 = phy_map[phy_idx + 1];
+ if (invalid_efuse_header_dav_be(hdr1, hdr2))
+ break;
+
+ phy_idx += 2;
+
+ hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2);
+
+ blk_page = RTW89_EFUSE_BLOCK_ADIE;
+ blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK);
+ word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
+ } else {
+ hdr1 = phy_map[phy_idx];
+ hdr2 = phy_map[phy_idx + 1];
+ hdr3 = phy_map[phy_idx + 2];
+ if (invalid_efuse_header_be(hdr1, hdr2, hdr3))
+ break;
+
+ phy_idx += 3;
+
+ hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3);
+
+ blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK);
+ blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK);
+ word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
+ }
+
+ if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) {
+ rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3);
+ rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (invalid_efuse_content_be(word_en, i))
+ continue;
+
+ if (phy_idx >= phy_size - 1)
+ return -EINVAL;
+
+ log_idx = block_idx_to_logical_idx_be(blk_idx, i);
+
+ if (blk_page == page && log_idx >= min && log_idx < max) {
+ val0 = phy_map[phy_idx];
+ val1 = phy_map[phy_idx + 1];
+
+ if (log_idx == min && page_offset > min) {
+ log_map[log_idx - page_offset + 1] = val1;
+ } else if (log_idx + 2 == max &&
+ page_offset + size < max) {
+ log_map[log_idx - page_offset] = val0;
+ } else {
+ log_map[log_idx - page_offset] = val0;
+ log_map[log_idx - page_offset + 1] = val1;
+ }
+ }
+ phy_idx += 2;
+ }
+ } while (phy_idx < phy_size);
+
+ return 0;
+}
+
+static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev,
+ const u8 *phy_map, u32 phy_size,
+ enum rtw89_efuse_block block)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_efuse_block_cfg *efuse_block;
+ u8 *log_map;
+ int ret;
+
+ efuse_block = &chip->efuse_blocks[block];
+
+ log_map = kmalloc(efuse_block->size, GFP_KERNEL);
+ if (!log_map)
+ return -ENOMEM;
+
+ ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block);
+ goto out_free;
+ }
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size);
+
+ ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to read efuse map\n");
+ goto out_free;
+ }
+
+out_free:
+ kfree(log_map);
+
+ return ret;
+}
+
+int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev)
+{
+ u32 phy_size = rtwdev->chip->physical_efuse_size;
+ u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
+ enum rtw89_efuse_block block;
+ u8 *phy_map = NULL;
+ u8 *dav_phy_map = NULL;
+ int ret;
+
+ if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS)
+ rtwdev->efuse.valid = true;
+ else
+ rtw89_warn(rtwdev, "failed to check efuse autoload\n");
+
+ phy_map = kmalloc(phy_size, GFP_KERNEL);
+ if (dav_phy_size)
+ dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
+
+ if (!phy_map || (dav_phy_size && !dav_phy_map)) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
+ goto out_free;
+ }
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
+ goto out_free;
+ }
+
+ if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
+ block = RTW89_EFUSE_BLOCK_HCI_DIG_USB;
+ else
+ block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO;
+
+ ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
+ RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO);
+ goto out_free;
+ }
+
+ ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size,
+ RTW89_EFUSE_BLOCK_RF);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
+ RTW89_EFUSE_BLOCK_RF);
+ goto out_free;
+ }
+
+out_free:
+ kfree(dav_phy_map);
+ kfree(phy_map);
+
+ return ret;
+}
+
+int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev)
+{
+ u32 phycap_addr = rtwdev->chip->phycap_addr;
+ u32 phycap_size = rtwdev->chip->phycap_size;
+ u8 *phycap_map = NULL;
+ int ret = 0;
+
+ if (!phycap_size)
+ return 0;
+
+ phycap_map = kmalloc(phycap_size, GFP_KERNEL);
+ if (!phycap_map)
+ return -ENOMEM;
+
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map,
+ phycap_addr, phycap_size, false);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump phycap map\n");
+ goto out_free;
+ }
+
+ ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to read phycap map\n");
+ goto out_free;
+ }
+
+out_free:
+ kfree(phycap_map);
+
+ return ret;
+}
+
+static u16 get_sb_cryp_sel_idx(u16 sb_cryp_sel)
+{
+ u8 low_bit, high_bit, cnt_zero = 0;
+ u8 idx, sel_form_v, sel_idx_v;
+ u16 sb_cryp_sel_v = 0x0;
+
+ sel_form_v = u16_get_bits(sb_cryp_sel, MASKBYTE0);
+ sel_idx_v = u16_get_bits(sb_cryp_sel, MASKBYTE1);
+
+ for (idx = 0; idx < 4; idx++) {
+ low_bit = !!(sel_form_v & BIT(idx));
+ high_bit = !!(sel_form_v & BIT(7 - idx));
+ if (low_bit != high_bit)
+ return U16_MAX;
+ if (low_bit)
+ continue;
+
+ cnt_zero++;
+ if (cnt_zero == 1)
+ sb_cryp_sel_v = idx * 16;
+ else if (cnt_zero > 1)
+ return U16_MAX;
+ }
+
+ low_bit = u8_get_bits(sel_idx_v, 0x0F);
+ high_bit = u8_get_bits(sel_idx_v, 0xF0);
+
+ if ((low_bit ^ high_bit) != 0xF)
+ return U16_MAX;
+
+ return sb_cryp_sel_v + low_bit;
+}
+
+static u8 get_mss_dev_type_idx(struct rtw89_dev *rtwdev, u8 mss_dev_type)
+{
+ switch (mss_dev_type) {
+ case MSS_DEV_TYPE_FWSEC_WINLIN_INBOX:
+ mss_dev_type = 0x0;
+ break;
+ case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_NON_COB:
+ mss_dev_type = 0x1;
+ break;
+ case MSS_DEV_TYPE_FWSEC_NONLIN_INBOX_COB:
+ mss_dev_type = 0x2;
+ break;
+ case MSS_DEV_TYPE_FWSEC_NONWIN_INBOX:
+ mss_dev_type = 0x3;
+ break;
+ case MSS_DEV_TYPE_FWSEC_DEF:
+ mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF;
+ break;
+ default:
+ rtw89_warn(rtwdev, "unknown mss_dev_type %d", mss_dev_type);
+ mss_dev_type = RTW89_FW_MSS_DEV_TYPE_FWSEC_INV;
+ break;
+ }
+
+ return mss_dev_type;
+}
+
+int rtw89_efuse_read_fw_secure_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+ u32 sec_addr = EFUSE_SEC_BE_START;
+ u32 sec_size = EFUSE_SEC_BE_SIZE;
+ u16 sb_cryp_sel, sb_cryp_sel_idx;
+ u8 sec_map[EFUSE_SEC_BE_SIZE];
+ u8 mss_dev_type;
+ u8 b1, b2;
+ int ret;
+
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, sec_map,
+ sec_addr, sec_size, false);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump secsel map\n");
+ return ret;
+ }
+
+ sb_cryp_sel = sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr] |
+ sec_map[EFUSE_SB_CRYP_SEL_ADDR - sec_addr + 1] << 8;
+ if (sb_cryp_sel == EFUSE_SB_CRYP_SEL_DEFAULT)
+ goto out;
+
+ sb_cryp_sel_idx = get_sb_cryp_sel_idx(sb_cryp_sel);
+ if (sb_cryp_sel_idx >= SB_SEL_MGN_MAX_SIZE) {
+ rtw89_warn(rtwdev, "invalid SB cryp sel idx %d\n", sb_cryp_sel_idx);
+ goto out;
+ }
+
+ sec->sb_sel_mgn = sb_sel_mgn[sb_cryp_sel_idx];
+
+ b1 = sec_map[EFUSE_EXTERNALPN_ADDR_BE - sec_addr];
+ b2 = sec_map[EFUSE_SERIALNUM_ADDR_BE - sec_addr];
+
+ mss_dev_type = u8_get_bits(b1, EFUSE_B1_MSSDEVTYPE_MASK);
+ sec->mss_cust_idx = 0x1F - (u8_get_bits(b1, EFUSE_B1_MSSCUSTIDX0_MASK) |
+ u8_get_bits(b2, EFUSE_B2_MSSCUSTIDX1_MASK) << 4);
+ sec->mss_key_num = 0xF - u8_get_bits(b2, EFUSE_B2_MSSKEYNUM_MASK);
+
+ sec->mss_dev_type = get_mss_dev_type_idx(rtwdev, mss_dev_type);
+ if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_INV) {
+ rtw89_warn(rtwdev, "invalid mss_dev_type %d\n", mss_dev_type);
+ goto out;
+ }
+
+ sec->secure_boot = true;
+
+out:
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "MSS secure_boot=%d dev_type=%d cust_idx=%d key_num=%d\n",
+ sec->secure_boot, sec->mss_dev_type, sec->mss_cust_idx,
+ sec->mss_key_num);
+
+ return 0;
+}
+EXPORT_SYMBOL(rtw89_efuse_read_fw_secure_be);
diff --git a/sys/contrib/dev/rtw89/fw.c b/sys/contrib/dev/rtw89/fw.c
index c1dade182d88..1e20ecbc3cff 100644
--- a/sys/contrib/dev/rtw89/fw.c
+++ b/sys/contrib/dev/rtw89/fw.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
+#include <linux/if_arp.h>
#include "cam.h"
#include "chan.h"
#include "coex.h"
@@ -9,8 +10,47 @@
#include "fw.h"
#include "mac.h"
#include "phy.h"
+#include "ps.h"
#include "reg.h"
#include "util.h"
+#include "wow.h"
+
+struct rtw89_eapol_2_of_2 {
+ u8 gtkbody[14];
+ u8 key_des_ver;
+ u8 rsvd[92];
+} __packed;
+
+struct rtw89_sa_query {
+ u8 category;
+ u8 action;
+} __packed;
+
+struct rtw89_arp_rsp {
+ u8 llc_hdr[sizeof(rfc1042_header)];
+ __be16 llc_type;
+ struct arphdr arp_hdr;
+ u8 sender_hw[ETH_ALEN];
+ __be32 sender_ip;
+ u8 target_hw[ETH_ALEN];
+ __be32 target_ip;
+} __packed;
+
+static const u8 mss_signature[] = {0x4D, 0x53, 0x53, 0x4B, 0x50, 0x4F, 0x4F, 0x4C};
+
+union rtw89_fw_element_arg {
+ size_t offset;
+ enum rtw89_rf_path rf_path;
+ enum rtw89_fw_type fw_type;
+};
+
+struct rtw89_fw_element_handler {
+ int (*fn)(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const union rtw89_fw_element_arg arg);
+ const union rtw89_fw_element_arg arg;
+ const char *name;
+};
static void rtw89_fw_c2h_cmd_handle(struct rtw89_dev *rtwdev,
struct sk_buff *skb);
@@ -46,22 +86,15 @@ struct sk_buff *rtw89_fw_h2c_alloc_skb_no_hdr(struct rtw89_dev *rtwdev, u32 len)
return rtw89_fw_h2c_alloc_skb(rtwdev, len, false);
}
-static u8 _fw_get_rdy(struct rtw89_dev *rtwdev)
-{
- u8 val = rtw89_read8(rtwdev, R_AX_WCPU_FW_CTRL);
-
- return FIELD_GET(B_AX_WCPU_FWDL_STS_MASK, val);
-}
-
-#define FWDL_WAIT_CNT 400000
-int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
+int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
u8 val;
int ret;
- ret = read_poll_timeout_atomic(_fw_get_rdy, val,
+ ret = read_poll_timeout_atomic(mac->fwdl_get_status, val,
val == RTW89_FWDL_WCPU_FW_INIT_RDY,
- 1, FWDL_WAIT_CNT, false, rtwdev);
+ 1, FWDL_WAIT_CNT, false, rtwdev, type);
if (ret) {
switch (val) {
case RTW89_FWDL_CHECKSUM_FAIL:
@@ -77,6 +110,7 @@ int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev)
return -EINVAL;
default:
+ rtw89_err(rtwdev, "fw unexpected status %d\n", val);
return -EBUSY;
}
}
@@ -154,6 +188,174 @@ static int rtw89_fw_hdr_parser_v0(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
return 0;
}
+static int __get_mssc_key_idx(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_mss_pool_hdr *mss_hdr,
+ u32 rmp_tbl_size, u32 *key_idx)
+{
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+ u32 sel_byte_idx;
+ u32 mss_sel_idx;
+ u8 sel_bit_idx;
+ int i;
+
+ if (sec->mss_dev_type == RTW89_FW_MSS_DEV_TYPE_FWSEC_DEF) {
+ if (!mss_hdr->defen)
+ return -ENOENT;
+
+ mss_sel_idx = sec->mss_cust_idx * le16_to_cpu(mss_hdr->msskey_num_max) +
+ sec->mss_key_num;
+ } else {
+ if (mss_hdr->defen)
+ mss_sel_idx = FWDL_MSS_POOL_DEFKEYSETS_SIZE << 3;
+ else
+ mss_sel_idx = 0;
+ mss_sel_idx += sec->mss_dev_type * le16_to_cpu(mss_hdr->msskey_num_max) *
+ le16_to_cpu(mss_hdr->msscust_max) +
+ sec->mss_cust_idx * le16_to_cpu(mss_hdr->msskey_num_max) +
+ sec->mss_key_num;
+ }
+
+ sel_byte_idx = mss_sel_idx >> 3;
+ sel_bit_idx = mss_sel_idx & 0x7;
+
+ if (sel_byte_idx >= rmp_tbl_size)
+ return -EFAULT;
+
+ if (!(mss_hdr->rmp_tbl[sel_byte_idx] & BIT(sel_bit_idx)))
+ return -ENOENT;
+
+ *key_idx = hweight8(mss_hdr->rmp_tbl[sel_byte_idx] & (BIT(sel_bit_idx) - 1));
+
+ for (i = 0; i < sel_byte_idx; i++)
+ *key_idx += hweight8(mss_hdr->rmp_tbl[i]);
+
+ return 0;
+}
+
+static int __parse_formatted_mssc(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_bin_info *info,
+ struct rtw89_fw_hdr_section_info *section_info,
+ const struct rtw89_fw_hdr_section_v1 *section,
+#if defined(__linux__)
+ const void *content,
+#elif defined(__FreeBSD__)
+ const u8 *content,
+#endif
+ u32 *mssc_len)
+{
+#if defined(__linux__)
+ const struct rtw89_fw_mss_pool_hdr *mss_hdr = content + section_info->len;
+ const union rtw89_fw_section_mssc_content *section_content = content;
+#elif defined(__FreeBSD__)
+ const struct rtw89_fw_mss_pool_hdr *mss_hdr = (const void *)(content + section_info->len);
+ const union rtw89_fw_section_mssc_content *section_content = (const void *)content;
+#endif
+ struct rtw89_fw_secure *sec = &rtwdev->fw.sec;
+ u32 rmp_tbl_size;
+ u32 key_sign_len;
+ u32 real_key_idx;
+ u32 sb_sel_ver;
+ int ret;
+
+ if (memcmp(mss_signature, mss_hdr->signature, sizeof(mss_signature)) != 0) {
+ rtw89_err(rtwdev, "[ERR] wrong MSS signature\n");
+ return -ENOENT;
+ }
+
+ if (mss_hdr->rmpfmt == MSS_POOL_RMP_TBL_BITMASK) {
+ rmp_tbl_size = (le16_to_cpu(mss_hdr->msskey_num_max) *
+ le16_to_cpu(mss_hdr->msscust_max) *
+ mss_hdr->mssdev_max) >> 3;
+ if (mss_hdr->defen)
+ rmp_tbl_size += FWDL_MSS_POOL_DEFKEYSETS_SIZE;
+ } else {
+ rtw89_err(rtwdev, "[ERR] MSS Key Pool Remap Table Format Unsupport:%X\n",
+ mss_hdr->rmpfmt);
+ return -EINVAL;
+ }
+
+ if (rmp_tbl_size + sizeof(*mss_hdr) != le32_to_cpu(mss_hdr->key_raw_offset)) {
+ rtw89_err(rtwdev, "[ERR] MSS Key Pool Format Error:0x%X + 0x%X != 0x%X\n",
+ rmp_tbl_size, (int)sizeof(*mss_hdr),
+ le32_to_cpu(mss_hdr->key_raw_offset));
+ return -EINVAL;
+ }
+
+ key_sign_len = le16_to_cpu(section_content->key_sign_len.v) >> 2;
+ if (!key_sign_len)
+ key_sign_len = 512;
+
+ if (info->dsp_checksum)
+ key_sign_len += FWDL_SECURITY_CHKSUM_LEN;
+
+ *mssc_len = sizeof(*mss_hdr) + rmp_tbl_size +
+ le16_to_cpu(mss_hdr->keypair_num) * key_sign_len;
+
+ if (!sec->secure_boot)
+ goto out;
+
+ sb_sel_ver = le32_to_cpu(section_content->sb_sel_ver.v);
+ if (sb_sel_ver && sb_sel_ver != sec->sb_sel_mgn)
+ goto ignore;
+
+ ret = __get_mssc_key_idx(rtwdev, mss_hdr, rmp_tbl_size, &real_key_idx);
+ if (ret)
+ goto ignore;
+
+ section_info->key_addr = content + section_info->len +
+ le32_to_cpu(mss_hdr->key_raw_offset) +
+ key_sign_len * real_key_idx;
+ section_info->key_len = key_sign_len;
+ section_info->key_idx = real_key_idx;
+
+out:
+ if (info->secure_section_exist) {
+ section_info->ignore = true;
+ return 0;
+ }
+
+ info->secure_section_exist = true;
+
+ return 0;
+
+ignore:
+ section_info->ignore = true;
+
+ return 0;
+}
+
+static int __parse_security_section(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_bin_info *info,
+ struct rtw89_fw_hdr_section_info *section_info,
+ const struct rtw89_fw_hdr_section_v1 *section,
+#if defined(__linux__)
+ const void *content,
+#elif defined(__FreeBSD__)
+ const u8 *content,
+#endif
+ u32 *mssc_len)
+{
+ int ret;
+
+ section_info->mssc =
+ le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC);
+
+ if (section_info->mssc == FORMATTED_MSSC) {
+ ret = __parse_formatted_mssc(rtwdev, info, section_info,
+ section, content, mssc_len);
+ if (ret)
+ return -EINVAL;
+ } else {
+ *mssc_len = section_info->mssc * FWDL_SECURITY_SIGLEN;
+ if (info->dsp_checksum)
+ *mssc_len += section_info->mssc * FWDL_SECURITY_CHKSUM_LEN;
+
+ info->secure_section_exist = true;
+ }
+
+ return 0;
+}
+
static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 len,
struct rtw89_fw_bin_info *info)
{
@@ -164,10 +366,12 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
const u8 *fw_end = fw + len;
const u8 *bin;
u32 base_hdr_len;
- u32 mssc_len = 0;
+ u32 mssc_len;
+ int ret;
u32 i;
info->section_num = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_SEC_NUM);
+ info->dsp_checksum = le32_get_bits(fw_hdr->w6, FW_HDR_V1_W6_DSP_CHKSUM);
base_hdr_len = struct_size(fw_hdr, sections, info->section_num);
info->dynamic_hdr_en = le32_get_bits(fw_hdr->w7, FW_HDR_V1_W7_DYN_HDR);
@@ -190,16 +394,9 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
section_info = info->section_info;
for (i = 0; i < info->section_num; i++) {
section = &fw_hdr->sections[i];
+
section_info->type =
le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SECTIONTYPE);
- if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
- section_info->mssc =
- le32_get_bits(section->w2, FWSECTION_HDR_V1_W2_MSSC);
- mssc_len += section_info->mssc * FWDL_SECURITY_SIGLEN;
- } else {
- section_info->mssc = 0;
- }
-
section_info->len =
le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_SEC_SIZE);
if (le32_get_bits(section->w1, FWSECTION_HDR_V1_W1_CHECKSUM))
@@ -208,15 +405,40 @@ static int rtw89_fw_hdr_parser_v1(struct rtw89_dev *rtwdev, const u8 *fw, u32 le
section_info->dladdr =
le32_get_bits(section->w0, FWSECTION_HDR_V1_W0_DL_ADDR);
section_info->addr = bin;
- bin += section_info->len;
+
+ if (section_info->type == FWDL_SECURITY_SECTION_TYPE) {
+ ret = __parse_security_section(rtwdev, info, section_info,
+ section, bin, &mssc_len);
+ if (ret)
+ return ret;
+ } else {
+ section_info->mssc = 0;
+ mssc_len = 0;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ "section[%d] type=%d len=0x%-6x mssc=%d mssc_len=%d addr=%tx\n",
+ i, section_info->type, section_info->len,
+ section_info->mssc, mssc_len, bin - fw);
+ rtw89_debug(rtwdev, RTW89_DBG_FW,
+ " ignore=%d key_addr=%p (0x%tx) key_len=%d key_idx=%d\n",
+ section_info->ignore, section_info->key_addr,
+ section_info->key_addr ?
+ section_info->key_addr - section_info->addr : 0,
+ section_info->key_len, section_info->key_idx);
+
+ bin += section_info->len + mssc_len;
section_info++;
}
- if (fw_end != bin + mssc_len) {
+ if (fw_end != bin) {
rtw89_err(rtwdev, "[ERR]fw bin size\n");
return -EINVAL;
}
+ if (!info->secure_section_exist)
+ rtw89_warn(rtwdev, "no firmware secure section\n");
+
return 0;
}
@@ -251,7 +473,7 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
const u8 *mfw = firmware->data;
u32 mfw_len = firmware->size;
const struct rtw89_mfw_hdr *mfw_hdr = (const struct rtw89_mfw_hdr *)mfw;
- const struct rtw89_mfw_info *mfw_info;
+ const struct rtw89_mfw_info *mfw_info = NULL, *tmp;
int i;
if (mfw_hdr->sig != RTW89_MFW_SIG) {
@@ -265,15 +487,27 @@ int rtw89_mfw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
}
for (i = 0; i < mfw_hdr->fw_nr; i++) {
- mfw_info = &mfw_hdr->info[i];
- if (mfw_info->type == type) {
- if (mfw_info->cv == rtwdev->hal.cv && !mfw_info->mp)
- goto found;
- if (type == RTW89_FW_LOGFMT)
- goto found;
+ tmp = &mfw_hdr->info[i];
+ if (tmp->type != type)
+ continue;
+
+ if (type == RTW89_FW_LOGFMT) {
+ mfw_info = tmp;
+ goto found;
+ }
+
+ /* Version order of WiFi firmware in firmware file are not in order,
+ * pass all firmware to find the equal or less but closest version.
+ */
+ if (tmp->cv <= rtwdev->hal.cv && !tmp->mp) {
+ if (!mfw_info || mfw_info->cv < tmp->cv)
+ mfw_info = tmp;
}
}
+ if (mfw_info)
+ goto found;
+
if (!nowarn)
rtw89_err(rtwdev, "no suitable firmware found\n");
return -ENOENT;
@@ -389,21 +623,27 @@ int __rtw89_fw_recognize(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
static
int __rtw89_fw_recognize_from_elm(struct rtw89_dev *rtwdev,
const struct rtw89_fw_element_hdr *elm,
-#if defined(__linux__)
- const void *data)
-#elif defined(__FreeBSD__)
- const int data)
-#endif
+ const union rtw89_fw_element_arg arg)
{
#if defined(__linux__)
- enum rtw89_fw_type type = (enum rtw89_fw_type)data;
+ enum rtw89_fw_type type = arg.fw_type;
#elif defined(__FreeBSD__)
- const enum rtw89_fw_type type = (const enum rtw89_fw_type)data;
+ const enum rtw89_fw_type type = arg.fw_type;
#endif
+ struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_fw_suit *fw_suit;
+ /* Version of BB MCU is in decreasing order in firmware file, so take
+ * first equal or less version, which is equal or less but closest version.
+ */
+ if (hal->cv < elm->u.bbmcu.cv)
+ return 1; /* ignore this element */
+
fw_suit = rtw89_fw_suit_get(rtwdev, type);
- fw_suit->data = elm->u.common.contents;
+ if (fw_suit->data)
+ return 1; /* ignore this element (a firmware is taken already) */
+
+ fw_suit->data = elm->u.bbmcu.contents;
fw_suit->size = le32_to_cpu(elm->size);
return rtw89_fw_update_ver(rtwdev, type, fw_suit);
@@ -452,6 +692,12 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER),
+ __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1),
};
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -555,11 +801,7 @@ normal_done:
static
int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
const struct rtw89_fw_element_hdr *elm,
-#if defined(__linux__)
- const void *data)
-#elif defined(__FreeBSD__)
- const int data)
-#endif
+ const union rtw89_fw_element_arg arg)
{
struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
struct rtw89_phy_table *tbl;
@@ -583,7 +825,11 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
case RTW89_FW_ELEMENT_ID_RADIO_B:
case RTW89_FW_ELEMENT_ID_RADIO_C:
case RTW89_FW_ELEMENT_ID_RADIO_D:
- rf_path = (enum rtw89_rf_path)data;
+#if defined(__linux__)
+ rf_path = arg.rf_path;
+#elif defined(__FreeBSD__)
+ rf_path = __DECONST(enum rtw89_rf_path, arg.rf_path);
+#endif
idx = elm->u.reg2.idx;
elm_info->rf_radio[idx] = tbl;
@@ -618,52 +864,202 @@ out:
return -ENOMEM;
}
-struct rtw89_fw_element_handler {
- int (*fn)(struct rtw89_dev *rtwdev,
+static
+int rtw89_fw_recognize_txpwr_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const union rtw89_fw_element_arg arg)
+{
+ const struct __rtw89_fw_txpwr_element *txpwr_elm = &elm->u.txpwr;
+ const unsigned long offset = arg.offset;
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+ struct rtw89_txpwr_conf *conf;
+
+ if (!rtwdev->rfe_data) {
+ rtwdev->rfe_data = kzalloc(sizeof(*rtwdev->rfe_data), GFP_KERNEL);
+ if (!rtwdev->rfe_data)
+ return -ENOMEM;
+ }
+
#if defined(__linux__)
- const struct rtw89_fw_element_hdr *elm, const void *data);
- const void *data;
+ conf = (void *)rtwdev->rfe_data + offset;
#elif defined(__FreeBSD__)
- const struct rtw89_fw_element_hdr *elm, const int data);
- const int data;
+ conf = (void *)((u8 *)rtwdev->rfe_data + offset);
#endif
- const char *name;
-};
+
+ /* if multiple matched, take the last eventually */
+ if (txpwr_elm->rfe_type == efuse->rfe_type)
+ goto setup;
+
+ /* without one is matched, accept default */
+ if (txpwr_elm->rfe_type == RTW89_TXPWR_CONF_DFLT_RFE_TYPE &&
+ (!rtw89_txpwr_conf_valid(conf) ||
+ conf->rfe_type == RTW89_TXPWR_CONF_DFLT_RFE_TYPE))
+ goto setup;
+
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "skip txpwr element ID %u RFE %u\n",
+ elm->id, txpwr_elm->rfe_type);
+ return 0;
+
+setup:
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "take txpwr element ID %u RFE %u\n",
+ elm->id, txpwr_elm->rfe_type);
+
+ conf->rfe_type = txpwr_elm->rfe_type;
+ conf->ent_sz = txpwr_elm->ent_sz;
+ conf->num_ents = le32_to_cpu(txpwr_elm->num_ents);
+ conf->data = txpwr_elm->content;
+ return 0;
+}
+
+static
+int rtw89_build_txpwr_trk_tbl_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const union rtw89_fw_element_arg arg)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 needed_bitmap = 0;
+ u32 offset = 0;
+ int subband;
+ u32 bitmap;
+ int type;
+
+ if (chip->support_bands & BIT(NL80211_BAND_6GHZ))
+ needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_6GHZ;
+ if (chip->support_bands & BIT(NL80211_BAND_5GHZ))
+ needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_5GHZ;
+ if (chip->support_bands & BIT(NL80211_BAND_2GHZ))
+ needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_2GHZ;
+
+ bitmap = le32_to_cpu(elm->u.txpwr_trk.bitmap);
+
+ if ((bitmap & needed_bitmap) != needed_bitmap) {
+ rtw89_warn(rtwdev, "needed txpwr trk bitmap %08x but %0x8x\n",
+ needed_bitmap, bitmap);
+ return -ENOENT;
+ }
+
+ elm_info->txpwr_trk = kzalloc(sizeof(*elm_info->txpwr_trk), GFP_KERNEL);
+ if (!elm_info->txpwr_trk)
+ return -ENOMEM;
+
+ for (type = 0; bitmap; type++, bitmap >>= 1) {
+ if (!(bitmap & BIT(0)))
+ continue;
+
+ if (type >= __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_START &&
+ type <= __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_MAX)
+ subband = 4;
+ else if (type >= __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_START &&
+ type <= __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_MAX)
+ subband = 3;
+ else if (type >= __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_START &&
+ type <= __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_MAX)
+ subband = 1;
+ else
+ break;
+
+ elm_info->txpwr_trk->delta[type] = &elm->u.txpwr_trk.contents[offset];
+
+ offset += subband;
+ if (offset * DELTA_SWINGIDX_SIZE > le32_to_cpu(elm->size))
+ goto err;
+ }
+
+ return 0;
+
+err:
+ rtw89_warn(rtwdev, "unexpected txpwr trk offset %d over size %d\n",
+ offset, le32_to_cpu(elm->size));
+ kfree(elm_info->txpwr_trk);
+ elm_info->txpwr_trk = NULL;
+
+ return -EFAULT;
+}
+
+static
+int rtw89_build_rfk_log_fmt_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const union rtw89_fw_element_arg arg)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ u8 rfk_id;
+
+ if (elm_info->rfk_log_fmt)
+ goto allocated;
+
+ elm_info->rfk_log_fmt = kzalloc(sizeof(*elm_info->rfk_log_fmt), GFP_KERNEL);
+ if (!elm_info->rfk_log_fmt)
+ return 1; /* this is an optional element, so just ignore this */
+
+allocated:
+ rfk_id = elm->u.rfk_log_fmt.rfk_id;
+ if (rfk_id >= RTW89_PHY_C2H_RFK_LOG_FUNC_NUM)
+ return 1;
+
+ elm_info->rfk_log_fmt->elm[rfk_id] = elm;
+
+ return 0;
+}
static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
-#if defined(__linux__)
- [RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
- (const void *)RTW89_FW_BBMCU0, NULL},
- [RTW89_FW_ELEMENT_ID_BBMCU1] = {__rtw89_fw_recognize_from_elm,
- (const void *)RTW89_FW_BBMCU1, NULL},
- [RTW89_FW_ELEMENT_ID_BB_REG] = {rtw89_build_phy_tbl_from_elm, NULL, "BB"},
- [RTW89_FW_ELEMENT_ID_BB_GAIN] = {rtw89_build_phy_tbl_from_elm, NULL, NULL},
- [RTW89_FW_ELEMENT_ID_RADIO_A] = {rtw89_build_phy_tbl_from_elm,
- (const void *)RF_PATH_A, "radio A"},
- [RTW89_FW_ELEMENT_ID_RADIO_B] = {rtw89_build_phy_tbl_from_elm,
- (const void *)RF_PATH_B, NULL},
- [RTW89_FW_ELEMENT_ID_RADIO_C] = {rtw89_build_phy_tbl_from_elm,
- (const void *)RF_PATH_C, NULL},
- [RTW89_FW_ELEMENT_ID_RADIO_D] = {rtw89_build_phy_tbl_from_elm,
- (const void *)RF_PATH_D, NULL},
- [RTW89_FW_ELEMENT_ID_RF_NCTL] = {rtw89_build_phy_tbl_from_elm, NULL, "NCTL"},
-#elif defined(__FreeBSD__)
[RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
- RTW89_FW_BBMCU0, NULL},
+ { .fw_type = RTW89_FW_BBMCU0 }, NULL},
[RTW89_FW_ELEMENT_ID_BBMCU1] = {__rtw89_fw_recognize_from_elm,
- RTW89_FW_BBMCU1, NULL},
- [RTW89_FW_ELEMENT_ID_BB_REG] = {rtw89_build_phy_tbl_from_elm, -1, "BB"},
- [RTW89_FW_ELEMENT_ID_BB_GAIN] = {rtw89_build_phy_tbl_from_elm, -1, NULL},
+ { .fw_type = RTW89_FW_BBMCU1 }, NULL},
+ [RTW89_FW_ELEMENT_ID_BB_REG] = {rtw89_build_phy_tbl_from_elm, {}, "BB"},
+ [RTW89_FW_ELEMENT_ID_BB_GAIN] = {rtw89_build_phy_tbl_from_elm, {}, NULL},
[RTW89_FW_ELEMENT_ID_RADIO_A] = {rtw89_build_phy_tbl_from_elm,
- RF_PATH_A, "radio A"},
+ { .rf_path = RF_PATH_A }, "radio A"},
[RTW89_FW_ELEMENT_ID_RADIO_B] = {rtw89_build_phy_tbl_from_elm,
- RF_PATH_B, NULL},
+ { .rf_path = RF_PATH_B }, NULL},
[RTW89_FW_ELEMENT_ID_RADIO_C] = {rtw89_build_phy_tbl_from_elm,
- RF_PATH_C, NULL},
+ { .rf_path = RF_PATH_C }, NULL},
[RTW89_FW_ELEMENT_ID_RADIO_D] = {rtw89_build_phy_tbl_from_elm,
- RF_PATH_D, NULL},
- [RTW89_FW_ELEMENT_ID_RF_NCTL] = {rtw89_build_phy_tbl_from_elm, -1, "NCTL"},
-#endif
+ { .rf_path = RF_PATH_D }, NULL},
+ [RTW89_FW_ELEMENT_ID_RF_NCTL] = {rtw89_build_phy_tbl_from_elm, {}, "NCTL"},
+ [RTW89_FW_ELEMENT_ID_TXPWR_BYRATE] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, byrate.conf) }, "TXPWR",
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_LMT_2GHZ] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, lmt_2ghz.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_LMT_5GHZ] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, lmt_5ghz.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_LMT_6GHZ] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, lmt_6ghz.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_2GHZ] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, lmt_ru_2ghz.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_5GHZ] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, lmt_ru_5ghz.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_6GHZ] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, lmt_ru_6ghz.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, tx_shape_lmt.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT_RU] = {
+ rtw89_fw_recognize_txpwr_from_elm,
+ { .offset = offsetof(struct rtw89_rfe_data, tx_shape_lmt_ru.conf) }, NULL,
+ },
+ [RTW89_FW_ELEMENT_ID_TXPWR_TRK] = {
+ rtw89_build_txpwr_trk_tbl_from_elm, {}, "PWR_TRK",
+ },
+ [RTW89_FW_ELEMENT_ID_RFKLOG_FMT] = {
+ rtw89_build_rfk_log_fmt_from_elm, {}, NULL,
+ },
};
int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
@@ -703,7 +1099,9 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
if (!handler->fn)
goto next;
- ret = handler->fn(rtwdev, hdr, handler->data);
+ ret = handler->fn(rtwdev, hdr, handler->arg);
+ if (ret == 1) /* ignore this element */
+ goto next;
if (ret)
return ret;
@@ -769,9 +1167,56 @@ static void rtw89_h2c_pkt_set_hdr_fwdl(struct rtw89_dev *rtwdev,
len + H2C_HEADER_LEN));
}
-static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len)
+static u32 __rtw89_fw_download_tweak_hdr_v0(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_bin_info *info,
+ struct rtw89_fw_hdr *fw_hdr)
+{
+ le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN,
+ FW_HDR_W7_PART_SIZE);
+
+ return 0;
+}
+
+static u32 __rtw89_fw_download_tweak_hdr_v1(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_bin_info *info,
+ struct rtw89_fw_hdr_v1 *fw_hdr)
+{
+ struct rtw89_fw_hdr_section_info *section_info;
+ struct rtw89_fw_hdr_section_v1 *section;
+ u8 dst_sec_idx = 0;
+ u8 sec_idx;
+
+ le32p_replace_bits(&fw_hdr->w7, FWDL_SECTION_PER_PKT_LEN,
+ FW_HDR_V1_W7_PART_SIZE);
+
+ for (sec_idx = 0; sec_idx < info->section_num; sec_idx++) {
+ section_info = &info->section_info[sec_idx];
+ section = &fw_hdr->sections[sec_idx];
+
+ if (section_info->ignore)
+ continue;
+
+ if (dst_sec_idx != sec_idx)
+ fw_hdr->sections[dst_sec_idx] = *section;
+
+ dst_sec_idx++;
+ }
+
+ le32p_replace_bits(&fw_hdr->w6, dst_sec_idx, FW_HDR_V1_W6_SEC_NUM);
+
+ return (info->section_num - dst_sec_idx) * sizeof(*section);
+}
+
+static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit,
+ struct rtw89_fw_bin_info *info)
{
+ u32 len = info->hdr_len - info->dynamic_hdr_len;
+ struct rtw89_fw_hdr_v1 *fw_hdr_v1;
+ const u8 *fw = fw_suit->data;
+ struct rtw89_fw_hdr *fw_hdr;
struct sk_buff *skb;
+ u32 truncated;
u32 ret = 0;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
@@ -781,7 +1226,26 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 l
}
skb_put_data(skb, fw, len);
- SET_FW_HDR_PART_SIZE(skb->data, FWDL_SECTION_PER_PKT_LEN);
+
+ switch (fw_suit->hdr_ver) {
+ case 0:
+ fw_hdr = (struct rtw89_fw_hdr *)skb->data;
+ truncated = __rtw89_fw_download_tweak_hdr_v0(rtwdev, info, fw_hdr);
+ break;
+ case 1:
+ fw_hdr_v1 = (struct rtw89_fw_hdr_v1 *)skb->data;
+ truncated = __rtw89_fw_download_tweak_hdr_v1(rtwdev, info, fw_hdr_v1);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ if (truncated) {
+ len -= truncated;
+ skb_trim(skb, len);
+ }
+
rtw89_h2c_pkt_set_hdr_fwdl(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FWDL,
H2C_FUNC_MAC_FWHDR_DL, len);
@@ -800,20 +1264,20 @@ fail:
return ret;
}
-static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, const u8 *fw, u32 len)
+static int rtw89_fw_download_hdr(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit,
+ struct rtw89_fw_bin_info *info)
{
- u8 val;
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
- ret = __rtw89_fw_download_hdr(rtwdev, fw, len);
+ ret = __rtw89_fw_download_hdr(rtwdev, fw_suit, info);
if (ret) {
rtw89_err(rtwdev, "[ERR]FW header download\n");
return ret;
}
- ret = read_poll_timeout_atomic(rtw89_read8, val, val & B_AX_FWDL_PATH_RDY,
- 1, FWDL_WAIT_CNT, false,
- rtwdev, R_AX_WCPU_FW_CTRL);
+ ret = mac->fwdl_check_path_ready(rtwdev, false);
if (ret) {
rtw89_err(rtwdev, "[ERR]FWDL path ready\n");
return ret;
@@ -831,9 +1295,21 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev,
struct sk_buff *skb;
const u8 *section = info->addr;
u32 residue_len = info->len;
+ bool copy_key = false;
u32 pkt_len;
int ret;
+ if (info->ignore)
+ return 0;
+
+ if (info->key_addr && info->key_len) {
+ if (info->len > FWDL_SECTION_PER_PKT_LEN || info->len < info->key_len)
+ rtw89_warn(rtwdev, "ignore to copy key data because of len %d, %d, %d\n",
+ info->len, FWDL_SECTION_PER_PKT_LEN, info->key_len);
+ else
+ copy_key = true;
+ }
+
while (residue_len) {
if (residue_len >= FWDL_SECTION_PER_PKT_LEN)
pkt_len = FWDL_SECTION_PER_PKT_LEN;
@@ -847,6 +1323,10 @@ static int __rtw89_fw_download_main(struct rtw89_dev *rtwdev,
}
skb_put_data(skb, section, pkt_len);
+ if (copy_key)
+ memcpy(skb->data + pkt_len - info->key_len,
+ info->key_addr, info->key_len);
+
ret = rtw89_h2c_tx(rtwdev, skb, true);
if (ret) {
rtw89_err(rtwdev, "failed to send h2c\n");
@@ -865,10 +1345,27 @@ fail:
return ret;
}
-static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw,
+static enum rtw89_fwdl_check_type
+rtw89_fw_get_fwdl_chk_type_from_suit(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit)
+{
+ switch (fw_suit->type) {
+ case RTW89_FW_BBMCU0:
+ return RTW89_FWDL_CHECK_BB0_FWDL_DONE;
+ case RTW89_FW_BBMCU1:
+ return RTW89_FWDL_CHECK_BB1_FWDL_DONE;
+ default:
+ return RTW89_FWDL_CHECK_WCPU_FWDL_DONE;
+ }
+}
+
+static int rtw89_fw_download_main(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_suit *fw_suit,
struct rtw89_fw_bin_info *info)
{
struct rtw89_fw_hdr_section_info *section_info = info->section_info;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ enum rtw89_fwdl_check_type chk_type;
u8 section_num = info->section_num;
int ret;
@@ -879,11 +1376,14 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw,
section_info++;
}
- mdelay(5);
+ if (chip->chip_gen == RTW89_CHIP_AX)
+ return 0;
- ret = rtw89_fw_check_rdy(rtwdev);
+ chk_type = rtw89_fw_get_fwdl_chk_type_from_suit(rtwdev, fw_suit);
+ ret = rtw89_fw_check_rdy(rtwdev, chk_type);
if (ret) {
- rtw89_warn(rtwdev, "download firmware fail\n");
+ rtw89_warn(rtwdev, "failed to download firmware type %u\n",
+ fw_suit->type);
return ret;
}
@@ -892,16 +1392,24 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev, const u8 *fw,
static void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev)
{
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+ u32 addr = R_AX_DBG_PORT_SEL;
u32 val32;
u16 index;
+ if (chip_gen == RTW89_CHIP_BE) {
+ addr = R_BE_WLCPU_PORT_PC;
+ goto dump;
+ }
+
rtw89_write32(rtwdev, R_AX_DBG_CTRL,
FIELD_PREP(B_AX_DBG_SEL0, FW_PROG_CNTR_DBG_SEL) |
FIELD_PREP(B_AX_DBG_SEL1, FW_PROG_CNTR_DBG_SEL));
rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0_MASK, MAC_DBG_SEL);
+dump:
for (index = 0; index < 15; index++) {
- val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL);
+ val32 = rtw89_read32(rtwdev, addr);
rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32);
#if defined(__linux__)
fsleep(10);
@@ -915,55 +1423,76 @@ static void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev)
static void rtw89_fw_dl_fail_dump(struct rtw89_dev *rtwdev)
{
u32 val32;
- u16 val16;
val32 = rtw89_read32(rtwdev, R_AX_WCPU_FW_CTRL);
rtw89_err(rtwdev, "[ERR]fwdl 0x1E0 = 0x%x\n", val32);
- val16 = rtw89_read16(rtwdev, R_AX_BOOT_DBG + 2);
- rtw89_err(rtwdev, "[ERR]fwdl 0x83F2 = 0x%x\n", val16);
+ val32 = rtw89_read32(rtwdev, R_AX_BOOT_DBG);
+ rtw89_err(rtwdev, "[ERR]fwdl 0x83F0 = 0x%x\n", val32);
rtw89_fw_prog_cnt_dump(rtwdev);
}
-int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
+static int rtw89_fw_download_suit(struct rtw89_dev *rtwdev,
+ struct rtw89_fw_suit *fw_suit)
{
- struct rtw89_fw_info *fw_info = &rtwdev->fw;
- struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
- struct rtw89_fw_bin_info info;
- u8 val;
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ struct rtw89_fw_bin_info info = {};
int ret;
- rtw89_mac_disable_cpu(rtwdev);
- ret = rtw89_mac_enable_cpu(rtwdev, 0, true);
- if (ret)
- return ret;
-
ret = rtw89_fw_hdr_parser(rtwdev, fw_suit, &info);
if (ret) {
rtw89_err(rtwdev, "parse fw header fail\n");
- goto fwdl_err;
+ return ret;
}
- ret = read_poll_timeout_atomic(rtw89_read8, val, val & B_AX_H2C_PATH_RDY,
- 1, FWDL_WAIT_CNT, false,
- rtwdev, R_AX_WCPU_FW_CTRL);
+ if (rtwdev->chip->chip_id == RTL8922A &&
+ (fw_suit->type == RTW89_FW_NORMAL || fw_suit->type == RTW89_FW_WOWLAN))
+ rtw89_write32(rtwdev, R_BE_SECURE_BOOT_MALLOC_INFO, 0x20248000);
+
+ ret = mac->fwdl_check_path_ready(rtwdev, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]H2C path ready\n");
- goto fwdl_err;
+ return ret;
}
- ret = rtw89_fw_download_hdr(rtwdev, fw_suit->data, info.hdr_len -
- info.dynamic_hdr_len);
- if (ret) {
- ret = -EBUSY;
- goto fwdl_err;
- }
+ ret = rtw89_fw_download_hdr(rtwdev, fw_suit, &info);
+ if (ret)
+ return ret;
- ret = rtw89_fw_download_main(rtwdev, fw_suit->data, &info);
- if (ret) {
- ret = -EBUSY;
+ ret = rtw89_fw_download_main(rtwdev, fw_suit, &info);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static
+int __rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ bool include_bb)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ struct rtw89_fw_info *fw_info = &rtwdev->fw;
+ struct rtw89_fw_suit *fw_suit = rtw89_fw_suit_get(rtwdev, type);
+ u8 bbmcu_nr = rtwdev->chip->bbmcu_nr;
+ int ret;
+ int i;
+
+ mac->disable_cpu(rtwdev);
+ ret = mac->fwdl_enable_wcpu(rtwdev, 0, true, include_bb);
+ if (ret)
+ return ret;
+
+ ret = rtw89_fw_download_suit(rtwdev, fw_suit);
+ if (ret)
goto fwdl_err;
+
+ for (i = 0; i < bbmcu_nr && include_bb; i++) {
+ fw_suit = rtw89_fw_suit_get(rtwdev, RTW89_FW_BBMCU0 + i);
+
+ ret = rtw89_fw_download_suit(rtwdev, fw_suit);
+ if (ret)
+ goto fwdl_err;
}
fw_info->h2c_seq = 0;
@@ -973,6 +1502,14 @@ int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type)
rtwdev->mac.rpwm_seq_num = RPWM_SEQ_NUM_MAX;
rtwdev->mac.cpwm_seq_num = CPWM_SEQ_NUM_MAX;
+ mdelay(5);
+
+ ret = rtw89_fw_check_rdy(rtwdev, RTW89_FWDL_CHECK_FREERTOS_DONE);
+ if (ret) {
+ rtw89_warn(rtwdev, "download firmware fail\n");
+ goto fwdl_err;
+ }
+
return ret;
fwdl_err:
@@ -980,6 +1517,21 @@ fwdl_err:
return ret;
}
+int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type,
+ bool include_bb)
+{
+ int retry;
+ int ret;
+
+ for (retry = 0; retry < 5; retry++) {
+ ret = __rtw89_fw_download(rtwdev, type, include_bb);
+ if (!ret)
+ return 0;
+ }
+
+ return ret;
+}
+
int rtw89_wait_firmware_completion(struct rtw89_dev *rtwdev)
{
struct rtw89_fw_info *fw = &rtwdev->fw;
@@ -1046,6 +1598,9 @@ static void rtw89_unload_firmware_elements(struct rtw89_dev *rtwdev)
for (i = 0; i < ARRAY_SIZE(elm_info->rf_radio); i++)
rtw89_free_phy_tbl_from_elm(elm_info->rf_radio[i]);
rtw89_free_phy_tbl_from_elm(elm_info->rf_nctl);
+
+ kfree(elm_info->txpwr_trk);
+ kfree(elm_info->rfk_log_fmt);
}
void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
@@ -1213,7 +1768,7 @@ void rtw89_fw_log_dump(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
return;
plain_log:
- rtw89_info(rtwdev, "C2H log: %*s", len, buf);
+ rtw89_info(rtwdev, "C2H log: %.*s", len, buf);
}
@@ -1252,28 +1807,30 @@ fail:
return ret;
}
-#define H2C_DCTL_SEC_CAM_LEN 68
int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta)
{
+ struct rtw89_h2c_dctlinfo_ud_v1 *h2c;
+ u32 len = sizeof(*h2c);
struct sk_buff *skb;
int ret;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_DCTL_SEC_CAM_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for dctl sec cam\n");
return -ENOMEM;
}
- skb_put(skb, H2C_DCTL_SEC_CAM_LEN);
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_dctlinfo_ud_v1 *)skb->data;
- rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, skb->data);
+ rtw89_cam_fill_dctl_sec_cam_info_v1(rtwdev, rtwvif, rtwsta, h2c);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_MAC_FR_EXCHG,
H2C_FUNC_MAC_DCTLINFO_UD_V1, 0, 0,
- H2C_DCTL_SEC_CAM_LEN);
+ len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
@@ -1289,13 +1846,108 @@ fail:
}
EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1);
-#define H2C_BA_CAM_LEN 8
+int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
+{
+ struct rtw89_h2c_dctlinfo_ud_v2 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for dctl sec cam\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data;
+
+ rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif, rtwsta, h2c);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_DCTLINFO_UD_V2, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2);
+
+int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
+{
+ u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ struct rtw89_h2c_dctlinfo_ud_v2 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for dctl v2\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data;
+
+ h2c->c0 = le32_encode_bits(mac_id, DCTLINFO_V2_C0_MACID) |
+ le32_encode_bits(1, DCTLINFO_V2_C0_OP);
+
+ h2c->m0 = cpu_to_le32(DCTLINFO_V2_W0_ALL);
+ h2c->m1 = cpu_to_le32(DCTLINFO_V2_W1_ALL);
+ h2c->m2 = cpu_to_le32(DCTLINFO_V2_W2_ALL);
+ h2c->m3 = cpu_to_le32(DCTLINFO_V2_W3_ALL);
+ h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_ALL);
+ h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_ALL);
+ h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_ALL);
+ h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_ALL);
+ h2c->m8 = cpu_to_le32(DCTLINFO_V2_W8_ALL);
+ h2c->m9 = cpu_to_le32(DCTLINFO_V2_W9_ALL);
+ h2c->m10 = cpu_to_le32(DCTLINFO_V2_W10_ALL);
+ h2c->m11 = cpu_to_le32(DCTLINFO_V2_W11_ALL);
+ h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_DCTLINFO_UD_V2, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2);
+
int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
bool valid, struct ieee80211_ampdu_params *params)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct rtw89_h2c_ba_cam *h2c;
u8 macid = rtwsta->mac_id;
+ u32 len = sizeof(*h2c);
struct sk_buff *skb;
u8 entry_idx;
int ret;
@@ -1313,32 +1965,34 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
return 0;
}
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n");
return -ENOMEM;
}
- skb_put(skb, H2C_BA_CAM_LEN);
- SET_BA_CAM_MACID(skb->data, macid);
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_ba_cam *)skb->data;
+
+ h2c->w0 = le32_encode_bits(macid, RTW89_H2C_BA_CAM_W0_MACID);
if (chip->bacam_ver == RTW89_BACAM_V0_EXT)
- SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx);
+ h2c->w1 |= le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1);
else
- SET_BA_CAM_ENTRY_IDX(skb->data, entry_idx);
+ h2c->w0 |= le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W0_ENTRY_IDX);
if (!valid)
goto end;
- SET_BA_CAM_VALID(skb->data, valid);
- SET_BA_CAM_TID(skb->data, params->tid);
+ h2c->w0 |= le32_encode_bits(valid, RTW89_H2C_BA_CAM_W0_VALID) |
+ le32_encode_bits(params->tid, RTW89_H2C_BA_CAM_W0_TID);
if (params->buf_size > 64)
- SET_BA_CAM_BMAP_SIZE(skb->data, 4);
+ h2c->w0 |= le32_encode_bits(4, RTW89_H2C_BA_CAM_W0_BMAP_SIZE);
else
- SET_BA_CAM_BMAP_SIZE(skb->data, 0);
+ h2c->w0 |= le32_encode_bits(0, RTW89_H2C_BA_CAM_W0_BMAP_SIZE);
/* If init req is set, hw will set the ssn */
- SET_BA_CAM_INIT_REQ(skb->data, 1);
- SET_BA_CAM_SSN(skb->data, params->ssn);
+ h2c->w0 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W0_INIT_REQ) |
+ le32_encode_bits(params->ssn, RTW89_H2C_BA_CAM_W0_SSN);
if (chip->bacam_ver == RTW89_BACAM_V0_EXT) {
- SET_BA_CAM_STD_EN(skb->data, 1);
- SET_BA_CAM_BAND(skb->data, rtwvif->mac_idx);
+ h2c->w1 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W1_STD_EN) |
+ le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BA_CAM_W1_BAND);
}
end:
@@ -1346,7 +2000,7 @@ end:
H2C_CAT_MAC,
H2C_CL_BA_CAM,
H2C_FUNC_MAC_BA_CAM, 0, 1,
- H2C_BA_CAM_LEN);
+ len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
@@ -1360,31 +2014,35 @@ fail:
return ret;
}
+EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam);
static int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev,
u8 entry_idx, u8 uid)
{
+ struct rtw89_h2c_ba_cam *h2c;
+ u32 len = sizeof(*h2c);
struct sk_buff *skb;
int ret;
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for dynamic h2c ba cam\n");
return -ENOMEM;
}
- skb_put(skb, H2C_BA_CAM_LEN);
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_ba_cam *)skb->data;
- SET_BA_CAM_VALID(skb->data, 1);
- SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx);
- SET_BA_CAM_UID(skb->data, uid);
- SET_BA_CAM_BAND(skb->data, 0);
- SET_BA_CAM_STD_EN(skb->data, 0);
+ h2c->w0 = le32_encode_bits(1, RTW89_H2C_BA_CAM_W0_VALID);
+ h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1) |
+ le32_encode_bits(uid, RTW89_H2C_BA_CAM_W1_UID) |
+ le32_encode_bits(0, RTW89_H2C_BA_CAM_W1_BAND) |
+ le32_encode_bits(0, RTW89_H2C_BA_CAM_W1_STD_EN);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC,
H2C_CL_BA_CAM,
H2C_FUNC_MAC_BA_CAM, 0, 1,
- H2C_BA_CAM_LEN);
+ len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
@@ -1413,14 +2071,132 @@ void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev)
}
}
+int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta,
+ bool valid, struct ieee80211_ampdu_params *params)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_vif *rtwvif = rtwsta->rtwvif;
+ struct rtw89_h2c_ba_cam_v1 *h2c;
+ u8 macid = rtwsta->mac_id;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ u8 entry_idx;
+ u8 bmap_size;
+ int ret;
+
+ ret = valid ?
+ rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) :
+ rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx);
+ if (ret) {
+ /* it still works even if we don't have static BA CAM, because
+ * hardware can create dynamic BA CAM automatically.
+ */
+ rtw89_debug(rtwdev, RTW89_DBG_TXRX,
+ "failed to %s entry tid=%d for h2c ba cam\n",
+ valid ? "alloc" : "free", params->tid);
+ return 0;
+ }
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_ba_cam_v1 *)skb->data;
+
+ if (params->buf_size > 512)
+ bmap_size = 10;
+ else if (params->buf_size > 256)
+ bmap_size = 8;
+ else if (params->buf_size > 64)
+ bmap_size = 4;
+ else
+ bmap_size = 0;
+
+ h2c->w0 = le32_encode_bits(valid, RTW89_H2C_BA_CAM_V1_W0_VALID) |
+ le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W0_INIT_REQ) |
+ le32_encode_bits(macid, RTW89_H2C_BA_CAM_V1_W0_MACID_MASK) |
+ le32_encode_bits(params->tid, RTW89_H2C_BA_CAM_V1_W0_TID_MASK) |
+ le32_encode_bits(bmap_size, RTW89_H2C_BA_CAM_V1_W0_BMAP_SIZE_MASK) |
+ le32_encode_bits(params->ssn, RTW89_H2C_BA_CAM_V1_W0_SSN_MASK);
+
+ entry_idx += chip->bacam_dynamic_num; /* std entry right after dynamic ones */
+ h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK) |
+ le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN) |
+ le32_encode_bits(!!rtwvif->mac_idx, RTW89_H2C_BA_CAM_V1_W1_BAND_SEL);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_BA_CAM,
+ H2C_FUNC_MAC_BA_CAM_V1, 0, 1,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam_v1);
+
+int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users,
+ u8 offset, u8 mac_idx)
+{
+ struct rtw89_h2c_ba_cam_init *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam init\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_ba_cam_init *)skb->data;
+
+ h2c->w0 = le32_encode_bits(users, RTW89_H2C_BA_CAM_INIT_USERS_MASK) |
+ le32_encode_bits(offset, RTW89_H2C_BA_CAM_INIT_OFFSET_MASK) |
+ le32_encode_bits(mac_idx, RTW89_H2C_BA_CAM_INIT_BAND_SEL);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC,
+ H2C_CL_BA_CAM,
+ H2C_FUNC_MAC_BA_CAM_INIT, 0, 1,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define H2C_LOG_CFG_LEN 12
int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable)
{
struct sk_buff *skb;
- u32 comp = enable ? BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) |
- BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) : 0;
+ u32 comp = 0;
int ret;
+ if (enable)
+ comp = BIT(RTW89_FW_LOG_COMP_INIT) | BIT(RTW89_FW_LOG_COMP_TASK) |
+ BIT(RTW89_FW_LOG_COMP_PS) | BIT(RTW89_FW_LOG_COMP_ERROR) |
+ BIT(RTW89_FW_LOG_COMP_SCAN);
+
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LOG_CFG_LEN);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw log cfg\n");
@@ -1452,6 +2228,128 @@ fail:
return ret;
}
+static struct sk_buff *rtw89_eapol_get(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ static const u8 gtkbody[] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x88,
+ 0x8E, 0x01, 0x03, 0x00, 0x5F, 0x02, 0x03};
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
+ struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ struct rtw89_eapol_2_of_2 *eapol_pkt;
+ struct ieee80211_hdr_3addr *hdr;
+ struct sk_buff *skb;
+ u8 key_des_ver;
+
+ if (rtw_wow->ptk_alg == 3)
+ key_des_ver = 1;
+ else if (rtw_wow->akm == 1 || rtw_wow->akm == 2)
+ key_des_ver = 2;
+ else if (rtw_wow->akm > 2 && rtw_wow->akm < 7)
+ key_des_ver = 3;
+ else
+ key_des_ver = 0;
+
+ skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*eapol_pkt));
+ if (!skb)
+ return NULL;
+
+ hdr = skb_put_zero(skb, sizeof(*hdr));
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_FCTL_TODS |
+ IEEE80211_FCTL_PROTECTED);
+ ether_addr_copy(hdr->addr1, bss_conf->bssid);
+ ether_addr_copy(hdr->addr2, vif->addr);
+ ether_addr_copy(hdr->addr3, bss_conf->bssid);
+
+ skb_put_zero(skb, sec_hdr_len);
+
+ eapol_pkt = skb_put_zero(skb, sizeof(*eapol_pkt));
+ memcpy(eapol_pkt->gtkbody, gtkbody, sizeof(gtkbody));
+ eapol_pkt->key_des_ver = key_des_ver;
+
+ return skb;
+}
+
+static struct sk_buff *rtw89_sa_query_get(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
+ struct ieee80211_hdr_3addr *hdr;
+ struct rtw89_sa_query *sa_query;
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*sa_query));
+ if (!skb)
+ return NULL;
+
+ hdr = skb_put_zero(skb, sizeof(*hdr));
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION |
+ IEEE80211_FCTL_PROTECTED);
+ ether_addr_copy(hdr->addr1, bss_conf->bssid);
+ ether_addr_copy(hdr->addr2, vif->addr);
+ ether_addr_copy(hdr->addr3, bss_conf->bssid);
+
+ skb_put_zero(skb, sec_hdr_len);
+
+ sa_query = skb_put_zero(skb, sizeof(*sa_query));
+ sa_query->category = WLAN_CATEGORY_SA_QUERY;
+ sa_query->action = WLAN_ACTION_SA_QUERY_RESPONSE;
+
+ return skb;
+}
+
+static struct sk_buff *rtw89_arp_response_get(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ u8 sec_hdr_len = rtw89_wow_get_sec_hdr_len(rtwdev);
+ struct rtw89_wow_param *rtw_wow = &rtwdev->wow;
+ struct ieee80211_hdr_3addr *hdr;
+ struct rtw89_arp_rsp *arp_skb;
+ struct arphdr *arp_hdr;
+ struct sk_buff *skb;
+ __le16 fc;
+
+ skb = dev_alloc_skb(sizeof(*hdr) + sec_hdr_len + sizeof(*arp_skb));
+ if (!skb)
+ return NULL;
+
+ hdr = skb_put_zero(skb, sizeof(*hdr));
+
+ if (rtw_wow->ptk_alg)
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS |
+ IEEE80211_FCTL_PROTECTED);
+ else
+ fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS);
+
+ hdr->frame_control = fc;
+ ether_addr_copy(hdr->addr1, rtwvif->bssid);
+ ether_addr_copy(hdr->addr2, rtwvif->mac_addr);
+ ether_addr_copy(hdr->addr3, rtwvif->bssid);
+
+ skb_put_zero(skb, sec_hdr_len);
+
+ arp_skb = skb_put_zero(skb, sizeof(*arp_skb));
+ memcpy(arp_skb->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
+ arp_skb->llc_type = htons(ETH_P_ARP);
+
+ arp_hdr = &arp_skb->arp_hdr;
+ arp_hdr->ar_hrd = htons(ARPHRD_ETHER);
+ arp_hdr->ar_pro = htons(ETH_P_IP);
+ arp_hdr->ar_hln = ETH_ALEN;
+ arp_hdr->ar_pln = 4;
+ arp_hdr->ar_op = htons(ARPOP_REPLY);
+
+ ether_addr_copy(arp_skb->sender_hw, rtwvif->mac_addr);
+ arp_skb->sender_ip = rtwvif->ip_addr;
+
+ return skb;
+}
+
static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif,
enum rtw89_fw_pkt_ofld_type type,
@@ -1479,6 +2377,15 @@ static int rtw89_fw_h2c_add_general_pkt(struct rtw89_dev *rtwdev,
case RTW89_PKT_OFLD_TYPE_QOS_NULL:
skb = ieee80211_nullfunc_get(rtwdev->hw, vif, -1, true);
break;
+ case RTW89_PKT_OFLD_TYPE_EAPOL_KEY:
+ skb = rtw89_eapol_get(rtwdev, rtwvif);
+ break;
+ case RTW89_PKT_OFLD_TYPE_SA_QUERY:
+ skb = rtw89_sa_query_get(rtwdev, rtwvif);
+ break;
+ case RTW89_PKT_OFLD_TYPE_ARP_RSP:
+ skb = rtw89_arp_response_get(rtwdev, rtwvif);
+ break;
default:
goto err;
}
@@ -1619,6 +2526,57 @@ fail:
return ret;
}
+int rtw89_fw_h2c_lps_ch_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_h2c_lps_ch_info *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ u32 done;
+ int ret;
+
+ if (chip->chip_gen != RTW89_CHIP_BE)
+ return 0;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c lps_ch_info\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_lps_ch_info *)skb->data;
+
+ h2c->info[0].central_ch = chan->channel;
+ h2c->info[0].pri_ch = chan->primary_channel;
+ h2c->info[0].band = chan->band_type;
+ h2c->info[0].bw = chan->band_width;
+ h2c->mlo_dbcc_mode_lps = cpu_to_le32(MLO_2_PLUS_0_1RF);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_DM,
+ H2C_FUNC_FW_LPS_CH_INFO, 0, 0, len);
+
+ rtw89_phy_write32_mask(rtwdev, R_CHK_LPS_STAT, B_CHK_LPS_STAT, 0);
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ ret = read_poll_timeout(rtw89_phy_read32_mask, done, done, 50, 5000,
+ true, rtwdev, R_CHK_LPS_STAT, B_CHK_LPS_STAT);
+ if (ret)
+ rtw89_warn(rtwdev, "h2c_lps_ch_info done polling timeout\n");
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define H2C_P2P_ACT_LEN 20
int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_p2p_noa_desc *desc,
@@ -1696,11 +2654,12 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev,
#define H2C_CMC_TBL_LEN 68
int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 macid = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
struct sk_buff *skb;
- u8 macid = rtwvif->mac_id;
int ret;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN);
@@ -1741,6 +2700,91 @@ fail:
return ret;
}
+EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl);
+
+int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
+{
+ u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data;
+
+ h2c->c0 = le32_encode_bits(mac_id, CCTLINFO_G7_C0_MACID) |
+ le32_encode_bits(1, CCTLINFO_G7_C0_OP);
+
+ h2c->w0 = le32_encode_bits(4, CCTLINFO_G7_W0_DATARATE);
+ h2c->m0 = cpu_to_le32(CCTLINFO_G7_W0_ALL);
+
+ h2c->w1 = le32_encode_bits(4, CCTLINFO_G7_W1_DATA_RTY_LOWEST_RATE) |
+ le32_encode_bits(0xa, CCTLINFO_G7_W1_RTSRATE) |
+ le32_encode_bits(4, CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE);
+ h2c->m1 = cpu_to_le32(CCTLINFO_G7_W1_ALL);
+
+ h2c->m2 = cpu_to_le32(CCTLINFO_G7_W2_ALL);
+
+ h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_ALL);
+
+ h2c->w4 = le32_encode_bits(0xFFFF, CCTLINFO_G7_W4_ACT_SUBCH_CBW);
+ h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_ALL);
+
+ h2c->w5 = le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0) |
+ le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1) |
+ le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2) |
+ le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3) |
+ le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4);
+ h2c->m5 = cpu_to_le32(CCTLINFO_G7_W5_ALL);
+
+ h2c->w6 = le32_encode_bits(0xb, CCTLINFO_G7_W6_RESP_REF_RATE);
+ h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ALL);
+
+ h2c->w7 = le32_encode_bits(1, CCTLINFO_G7_W7_NC) |
+ le32_encode_bits(1, CCTLINFO_G7_W7_NR) |
+ le32_encode_bits(1, CCTLINFO_G7_W7_CB) |
+ le32_encode_bits(0x1, CCTLINFO_G7_W7_CSI_PARA_EN) |
+ le32_encode_bits(0xb, CCTLINFO_G7_W7_CSI_FIX_RATE);
+ h2c->m7 = cpu_to_le32(CCTLINFO_G7_W7_ALL);
+
+ h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_ALL);
+
+ h2c->w14 = le32_encode_bits(0, CCTLINFO_G7_W14_VO_CURR_RATE) |
+ le32_encode_bits(0, CCTLINFO_G7_W14_VI_CURR_RATE) |
+ le32_encode_bits(0, CCTLINFO_G7_W14_BE_CURR_RATE_L);
+ h2c->m14 = cpu_to_le32(CCTLINFO_G7_W14_ALL);
+
+ h2c->w15 = le32_encode_bits(0, CCTLINFO_G7_W15_BE_CURR_RATE_H) |
+ le32_encode_bits(0, CCTLINFO_G7_W15_BK_CURR_RATE) |
+ le32_encode_bits(0, CCTLINFO_G7_W15_MGNT_CURR_RATE);
+ h2c->m15 = cpu_to_le32(CCTLINFO_G7_W15_ALL);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7);
static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
struct ieee80211_sta *sta, u8 *pads)
@@ -1754,9 +2798,6 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
u16 ppe;
int i;
- if (!sta->deflink.he_cap.has_he)
- return;
-
ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT,
sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]);
if (!ppe_th) {
@@ -1791,11 +2832,11 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev,
ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
if (ppe16 != 7 && ppe8 == 7)
- pads[i] = 2;
+ pads[i] = RTW89_PE_DURATION_16;
else if (ppe8 != 7)
- pads[i] = 1;
+ pads[i] = RTW89_PE_DURATION_8;
else
- pads[i] = 0;
+ pads[i] = RTW89_PE_DURATION_0;
}
}
@@ -1806,7 +2847,8 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct sk_buff *skb;
u8 pads[RTW89_PPE_BW_NUM];
u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
@@ -1814,7 +2856,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev,
int ret;
memset(pads, 0, sizeof(pads));
- if (sta)
+ if (sta && sta->deflink.he_cap.has_he)
__get_sta_he_pkt_padding(rtwdev, sta, pads);
if (vif->p2p)
@@ -1876,6 +2918,246 @@ fail:
return ret;
}
+EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl);
+
+static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev,
+ struct ieee80211_sta *sta, u8 *pads)
+{
+ u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1;
+ u16 ppe_thres_hdr;
+ u8 ppe16, ppe8;
+ u8 n, idx, sh;
+ u8 ru_bitmap;
+ bool ppe_th;
+ u16 ppe;
+ int i;
+
+ ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5],
+ IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT);
+ if (!ppe_th) {
+ u8 pad;
+
+ pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5],
+ IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK);
+
+ for (i = 0; i < RTW89_PPE_BW_NUM; i++)
+ pads[i] = pad;
+
+ return;
+ }
+
+ ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres);
+ ru_bitmap = u16_get_bits(ppe_thres_hdr,
+ IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK);
+ n = hweight8(ru_bitmap);
+ n = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE +
+ (n * IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2) * nss;
+
+ for (i = 0; i < RTW89_PPE_BW_NUM; i++) {
+ if (!(ru_bitmap & BIT(i))) {
+ pads[i] = 1;
+ continue;
+ }
+
+ idx = n >> 3;
+ sh = n & 7;
+ n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2;
+
+ ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx);
+ ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
+ sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE;
+ ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK;
+
+ if (ppe16 != 7 && ppe8 == 7)
+ pads[i] = RTW89_PE_DURATION_16_20;
+ else if (ppe8 != 7)
+ pads[i] = RTW89_PE_DURATION_8;
+ else
+ pads[i] = RTW89_PE_DURATION_0;
+ }
+}
+
+int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta);
+ u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
+ struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
+ u8 pads[RTW89_PPE_BW_NUM];
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ u16 lowest_rate;
+ int ret;
+
+ memset(pads, 0, sizeof(pads));
+ if (sta) {
+ if (sta->deflink.eht_cap.has_eht)
+ __get_sta_eht_pkt_padding(rtwdev, sta, pads);
+ else if (sta->deflink.he_cap.has_he)
+ __get_sta_he_pkt_padding(rtwdev, sta, pads);
+ }
+
+ if (vif->p2p)
+ lowest_rate = RTW89_HW_RATE_OFDM6;
+ else if (chan->band_type == RTW89_BAND_2G)
+ lowest_rate = RTW89_HW_RATE_CCK1;
+ else
+ lowest_rate = RTW89_HW_RATE_OFDM6;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data;
+
+ h2c->c0 = le32_encode_bits(mac_id, CCTLINFO_G7_C0_MACID) |
+ le32_encode_bits(1, CCTLINFO_G7_C0_OP);
+
+ h2c->w0 = le32_encode_bits(1, CCTLINFO_G7_W0_DISRTSFB) |
+ le32_encode_bits(1, CCTLINFO_G7_W0_DISDATAFB);
+ h2c->m0 = cpu_to_le32(CCTLINFO_G7_W0_DISRTSFB |
+ CCTLINFO_G7_W0_DISDATAFB);
+
+ h2c->w1 = le32_encode_bits(lowest_rate, CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE);
+ h2c->m1 = cpu_to_le32(CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE);
+
+ h2c->w2 = le32_encode_bits(0, CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL);
+ h2c->m2 = cpu_to_le32(CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL);
+
+ h2c->w3 = le32_encode_bits(0, CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL);
+ h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL);
+
+ h2c->w4 = le32_encode_bits(rtwvif->port, CCTLINFO_G7_W4_MULTI_PORT_ID);
+ h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_MULTI_PORT_ID);
+
+ if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) {
+ h2c->w4 |= le32_encode_bits(0, CCTLINFO_G7_W4_DATA_DCM);
+ h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_DATA_DCM);
+ }
+
+ if (vif->bss_conf.eht_support) {
+ u16 punct = vif->bss_conf.chanreq.oper.punctured;
+
+ h2c->w4 |= le32_encode_bits(~punct,
+ CCTLINFO_G7_W4_ACT_SUBCH_CBW);
+ h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW);
+ }
+
+ h2c->w5 = le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_20],
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0) |
+ le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_40],
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1) |
+ le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_80],
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2) |
+ le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_160],
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3) |
+ le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_320],
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4);
+ h2c->m5 = cpu_to_le32(CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0 |
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1 |
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2 |
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3 |
+ CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4);
+
+ h2c->w6 = le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0,
+ CCTLINFO_G7_W6_ULDL);
+ h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL);
+
+ if (sta) {
+ h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he,
+ CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT);
+ h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT);
+ }
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7);
+
+int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv;
+ struct rtw89_h2c_cctlinfo_ud_g7 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ u16 agg_num = 0;
+ u8 ba_bmap = 0;
+ int ret;
+ u8 tid;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for ampdu cmac g7\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data;
+
+ for_each_set_bit(tid, rtwsta->ampdu_map, IEEE80211_NUM_TIDS) {
+ if (agg_num == 0)
+ agg_num = rtwsta->ampdu_params[tid].agg_num;
+ else
+ agg_num = min(agg_num, rtwsta->ampdu_params[tid].agg_num);
+ }
+
+ if (agg_num <= 0x20)
+ ba_bmap = 3;
+ else if (agg_num > 0x20 && agg_num <= 0x40)
+ ba_bmap = 0;
+ else if (agg_num > 0x40 && agg_num <= 0x80)
+ ba_bmap = 1;
+ else if (agg_num > 0x80 && agg_num <= 0x100)
+ ba_bmap = 2;
+ else if (agg_num > 0x100 && agg_num <= 0x200)
+ ba_bmap = 4;
+ else if (agg_num > 0x200 && agg_num <= 0x400)
+ ba_bmap = 5;
+
+ h2c->c0 = le32_encode_bits(rtwsta->mac_id, CCTLINFO_G7_C0_MACID) |
+ le32_encode_bits(1, CCTLINFO_G7_C0_OP);
+
+ h2c->w3 = le32_encode_bits(ba_bmap, CCTLINFO_G7_W3_BA_BMAP);
+ h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_BA_BMAP);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7);
int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev,
struct rtw89_sta *rtwsta)
@@ -1958,17 +3240,22 @@ fail:
return ret;
}
-#define H2C_BCN_BASE_LEN 12
int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif)
{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ rtwvif->sub_entity_idx);
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
- struct sk_buff *skb;
+ struct rtw89_h2c_bcn_upd *h2c;
struct sk_buff *skb_beacon;
- u16 tim_offset;
+ struct ieee80211_hdr *hdr;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
int bcn_total_len;
u16 beacon_rate;
+ u16 tim_offset;
+ void *noa_data;
+ u8 noa_len;
int ret;
if (vif->p2p)
@@ -1985,23 +3272,34 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
return -ENOMEM;
}
- bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len;
+ noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data);
+ if (noa_len &&
+ (noa_len <= skb_tailroom(skb_beacon) ||
+ pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) {
+ skb_put_data(skb_beacon, noa_data, noa_len);
+ }
+
+ hdr = (struct ieee80211_hdr *)skb_beacon;
+ tim_offset -= ieee80211_hdrlen(hdr->frame_control);
+
+ bcn_total_len = len + skb_beacon->len;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
dev_kfree_skb_any(skb_beacon);
return -ENOMEM;
}
- skb_put(skb, H2C_BCN_BASE_LEN);
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_bcn_upd *)skb->data;
- SET_BCN_UPD_PORT(skb->data, rtwvif->port);
- SET_BCN_UPD_MBSSID(skb->data, 0);
- SET_BCN_UPD_BAND(skb->data, rtwvif->mac_idx);
- SET_BCN_UPD_GRP_IE_OFST(skb->data, tim_offset);
- SET_BCN_UPD_MACID(skb->data, rtwvif->mac_id);
- SET_BCN_UPD_SSN_SEL(skb->data, RTW89_MGMT_HW_SSN_SEL);
- SET_BCN_UPD_SSN_MODE(skb->data, RTW89_MGMT_HW_SEQ_MODE);
- SET_BCN_UPD_RATE(skb->data, beacon_rate);
+ h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_W0_PORT) |
+ le32_encode_bits(0, RTW89_H2C_BCN_UPD_W0_MBSSID) |
+ le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) |
+ le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST);
+ h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) |
+ le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_W1_SSN_SEL) |
+ le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_W1_SSN_MODE) |
+ le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_W1_RATE);
skb_put_data(skb, skb_beacon->data, skb_beacon->len);
dev_kfree_skb_any(skb_beacon);
@@ -2020,6 +3318,90 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev,
return 0;
}
+EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon);
+
+int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ struct rtw89_h2c_bcn_upd_be *h2c;
+ struct sk_buff *skb_beacon;
+ struct ieee80211_hdr *hdr;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int bcn_total_len;
+ u16 beacon_rate;
+ u16 tim_offset;
+ void *noa_data;
+ u8 noa_len;
+ int ret;
+
+ if (vif->p2p)
+ beacon_rate = RTW89_HW_RATE_OFDM6;
+ else if (chan->band_type == RTW89_BAND_2G)
+ beacon_rate = RTW89_HW_RATE_CCK1;
+ else
+ beacon_rate = RTW89_HW_RATE_OFDM6;
+
+ skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset,
+ NULL, 0);
+ if (!skb_beacon) {
+ rtw89_err(rtwdev, "failed to get beacon skb\n");
+ return -ENOMEM;
+ }
+
+ noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data);
+ if (noa_len &&
+ (noa_len <= skb_tailroom(skb_beacon) ||
+ pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) {
+ skb_put_data(skb_beacon, noa_data, noa_len);
+ }
+
+ hdr = (struct ieee80211_hdr *)skb_beacon;
+ tim_offset -= ieee80211_hdrlen(hdr->frame_control);
+
+ bcn_total_len = len + skb_beacon->len;
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for fw dl\n");
+ dev_kfree_skb_any(skb_beacon);
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_bcn_upd_be *)skb->data;
+
+ h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) |
+ le32_encode_bits(0, RTW89_H2C_BCN_UPD_BE_W0_MBSSID) |
+ le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) |
+ le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST);
+ h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) |
+ le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL) |
+ le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE) |
+ le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_BE_W1_RATE);
+
+ skb_put_data(skb, skb_beacon->data, skb_beacon->len);
+ dev_kfree_skb_any(skb_beacon);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG,
+ H2C_FUNC_MAC_BCN_UPD_BE, 0, 1,
+ bcn_total_len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be);
#define H2C_ROLE_MAINTAIN_LEN 4
int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
@@ -2070,45 +3452,128 @@ fail:
return ret;
}
-#define H2C_JOIN_INFO_LEN 4
+static enum rtw89_fw_sta_type
+rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
+ struct rtw89_sta *rtwsta)
+{
+ struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta);
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+
+ if (!sta)
+ goto by_vif;
+
+ if (sta->deflink.eht_cap.has_eht)
+ return RTW89_FW_BE_STA;
+ else if (sta->deflink.he_cap.has_he)
+ return RTW89_FW_AX_STA;
+ else
+ return RTW89_FW_N_AC_STA;
+
+by_vif:
+ if (vif->bss_conf.eht_support)
+ return RTW89_FW_BE_STA;
+ else if (vif->bss_conf.he_support)
+ return RTW89_FW_AX_STA;
+ else
+ return RTW89_FW_N_AC_STA;
+}
+
int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta, bool dis_conn)
{
struct sk_buff *skb;
u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id;
u8 self_role = rtwvif->self_role;
+ enum rtw89_fw_sta_type sta_type;
u8 net_type = rtwvif->net_type;
+ struct rtw89_h2c_join_v1 *h2c_v1;
+ struct rtw89_h2c_join *h2c;
+ u32 len = sizeof(*h2c);
+ bool format_v1 = false;
int ret;
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) {
+ len = sizeof(*h2c_v1);
+ format_v1 = true;
+ }
+
if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) {
self_role = RTW89_SELF_ROLE_AP_CLIENT;
net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type;
}
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
return -ENOMEM;
}
- skb_put(skb, H2C_JOIN_INFO_LEN);
- SET_JOININFO_MACID(skb->data, mac_id);
- SET_JOININFO_OP(skb->data, dis_conn);
- SET_JOININFO_BAND(skb->data, rtwvif->mac_idx);
- SET_JOININFO_WMM(skb->data, rtwvif->wmm);
- SET_JOININFO_TGR(skb->data, rtwvif->trigger);
- SET_JOININFO_ISHESTA(skb->data, 0);
- SET_JOININFO_DLBW(skb->data, 0);
- SET_JOININFO_TF_MAC_PAD(skb->data, 0);
- SET_JOININFO_DL_T_PE(skb->data, 0);
- SET_JOININFO_PORT_ID(skb->data, rtwvif->port);
- SET_JOININFO_NET_TYPE(skb->data, net_type);
- SET_JOININFO_WIFI_ROLE(skb->data, rtwvif->wifi_role);
- SET_JOININFO_SELF_ROLE(skb->data, self_role);
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_join *)skb->data;
+
+ h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_JOININFO_W0_MACID) |
+ le32_encode_bits(dis_conn, RTW89_H2C_JOININFO_W0_OP) |
+ le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_JOININFO_W0_BAND) |
+ le32_encode_bits(rtwvif->wmm, RTW89_H2C_JOININFO_W0_WMM) |
+ le32_encode_bits(rtwvif->trigger, RTW89_H2C_JOININFO_W0_TGR) |
+ le32_encode_bits(0, RTW89_H2C_JOININFO_W0_ISHESTA) |
+ le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DLBW) |
+ le32_encode_bits(0, RTW89_H2C_JOININFO_W0_TF_MAC_PAD) |
+ le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DL_T_PE) |
+ le32_encode_bits(rtwvif->port, RTW89_H2C_JOININFO_W0_PORT_ID) |
+ le32_encode_bits(net_type, RTW89_H2C_JOININFO_W0_NET_TYPE) |
+ le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) |
+ le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE);
+
+ if (!format_v1)
+ goto done;
+ h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data;
+
+ sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif, rtwsta);
+
+ h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE);
+ h2c_v1->w2 = 0;
+
+done:
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT,
H2C_FUNC_MAC_JOININFO, 0, 1,
- H2C_JOIN_INFO_LEN);
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en)
+{
+ struct rtw89_h2c_notify_dbcc *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c notify dbcc\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_notify_dbcc *)skb->data;
+
+ h2c->w0 = le32_encode_bits(en, RTW89_H2C_NOTIFY_DBCC_EN);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT,
+ H2C_FUNC_NOTIFY_DBCC, 0, 1,
+ len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
if (ret) {
@@ -2126,28 +3591,49 @@ fail:
int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp,
bool pause)
{
- struct rtw89_fw_macid_pause_grp h2c = {{0}};
- u8 len = sizeof(struct rtw89_fw_macid_pause_grp);
+ struct rtw89_fw_macid_pause_sleep_grp *h2c_new;
+ struct rtw89_fw_macid_pause_grp *h2c;
+ __le32 set = cpu_to_le32(BIT(sh));
+ u8 h2c_macid_pause_id;
struct sk_buff *skb;
+ u32 len;
int ret;
-#if defined(__linux__)
- skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN);
-#elif defined(__FreeBSD__)
+ if (RTW89_CHK_FW_FEATURE(MACID_PAUSE_SLEEP, &rtwdev->fw)) {
+ h2c_macid_pause_id = H2C_FUNC_MAC_MACID_PAUSE_SLEEP;
+ len = sizeof(*h2c_new);
+ } else {
+ h2c_macid_pause_id = H2C_FUNC_MAC_MACID_PAUSE;
+ len = sizeof(*h2c);
+ }
+
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
-#endif
if (!skb) {
- rtw89_err(rtwdev, "failed to alloc skb for h2c join\n");
+ rtw89_err(rtwdev, "failed to alloc skb for h2c macid pause\n");
return -ENOMEM;
}
- h2c.mask_grp[grp] = cpu_to_le32(BIT(sh));
- if (pause)
- h2c.pause_grp[grp] = cpu_to_le32(BIT(sh));
- skb_put_data(skb, &h2c, len);
+ skb_put(skb, len);
+
+ if (h2c_macid_pause_id == H2C_FUNC_MAC_MACID_PAUSE_SLEEP) {
+ h2c_new = (struct rtw89_fw_macid_pause_sleep_grp *)skb->data;
+
+ h2c_new->n[0].pause_mask_grp[grp] = set;
+ h2c_new->n[0].sleep_mask_grp[grp] = set;
+ if (pause) {
+ h2c_new->n[0].pause_grp[grp] = set;
+ h2c_new->n[0].sleep_grp[grp] = set;
+ }
+ } else {
+ h2c = (struct rtw89_fw_macid_pause_grp *)skb->data;
+
+ h2c->mask_grp[grp] = set;
+ if (pause)
+ h2c->pause_grp[grp] = set;
+ }
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
- H2C_FUNC_MAC_MACID_PAUSE, 1, 0,
+ h2c_macid_pause_id, 1, 0,
len);
ret = rtw89_h2c_tx(rtwdev, skb, false);
@@ -2278,6 +3764,8 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
{
struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif);
struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL;
+ s32 thold = RTW89_DEFAULT_CQM_THOLD;
+ u32 hyst = RTW89_DEFAULT_CQM_HYST;
struct rtw89_h2c_bcnfltr *h2c;
u32 len = sizeof(*h2c);
struct sk_buff *skb;
@@ -2298,14 +3786,19 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev,
skb_put(skb, len);
h2c = (struct rtw89_h2c_bcnfltr *)skb->data;
+ if (bss_conf->cqm_rssi_hyst)
+ hyst = bss_conf->cqm_rssi_hyst;
+ if (bss_conf->cqm_rssi_thold)
+ thold = bss_conf->cqm_rssi_thold;
+
h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) |
le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) |
le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) |
le32_encode_bits(RTW89_BCN_FLTR_OFFLOAD_MODE_DEFAULT,
RTW89_H2C_BCNFLTR_W0_MODE) |
le32_encode_bits(RTW89_BCN_LOSS_CNT, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT) |
- le32_encode_bits(bss_conf->cqm_rssi_hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) |
- le32_encode_bits(bss_conf->cqm_rssi_thold + MAX_RSSI,
+ le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) |
+ le32_encode_bits(thold + MAX_RSSI,
RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) |
le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID);
@@ -2501,11 +3994,11 @@ fail:
return ret;
}
-int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_dm *dm = &btc->dm;
- struct rtw89_btc_init_info *init_info = &dm->init_info;
+ struct rtw89_btc_init_info *init_info = &dm->init_info.init;
struct rtw89_btc_module *module = &init_info->module;
struct rtw89_btc_ant_info *ant = &module->ant;
struct rtw89_h2c_cxinit *h2c;
@@ -2521,7 +4014,7 @@ int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev)
skb_put(skb, len);
h2c = (struct rtw89_h2c_cxinit *)skb->data;
- h2c->hdr.type = CXDRVINFO_INIT;
+ h2c->hdr.type = type;
h2c->hdr.len = len - H2C_LEN_CXDRVHDR;
h2c->ant_type = ant->type;
@@ -2568,12 +4061,53 @@ fail:
return ret;
}
+int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_init_info_v7 *init_info = &dm->init_info.init_v7;
+ struct rtw89_h2c_cxinit_v7 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init_v7\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cxinit_v7 *)skb->data;
+
+ h2c->hdr.type = type;
+ h2c->hdr.ver = btc->ver->fcxinit;
+ h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+ h2c->init = *init_info;
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, BTFC_SET,
+ SET_DRV_INFO, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define PORT_DATA_OFFSET 4
#define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12
#define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \
(4 + 12 * (max_role_num) + H2C_LEN_CXDRVHDR)
-int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
@@ -2598,7 +4132,7 @@ int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev)
skb_put(skb, len);
cmd = skb->data;
- RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE);
+ RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type);
RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR);
RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt);
@@ -2654,7 +4188,7 @@ fail:
#define H2C_LEN_CXDRVINFO_ROLE_SIZE_V1(max_role_num) \
(4 + 16 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR)
-int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
@@ -2678,7 +4212,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev)
skb_put(skb, len);
cmd = skb->data;
- RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE);
+ RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type);
RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR);
RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt);
@@ -2744,7 +4278,7 @@ fail:
#define H2C_LEN_CXDRVINFO_ROLE_SIZE_V2(max_role_num) \
(4 + 8 * (max_role_num) + H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN + H2C_LEN_CXDRVHDR)
-int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
@@ -2768,7 +4302,7 @@ int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev)
skb_put(skb, len);
cmd = skb->data;
- RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_ROLE);
+ RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type);
RTW89_SET_FWCMD_CXHDR_LEN(cmd, len - H2C_LEN_CXDRVHDR);
RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(cmd, role_info->connect_cnt);
@@ -2827,12 +4361,54 @@ fail:
return ret;
}
+int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_wl_role_info_v8 *role = &btc->cx.wl.role_info_v8;
+ struct rtw89_h2c_cxrole_v8 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cxrole_v8 *)skb->data;
+
+ h2c->hdr.type = type;
+ h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+ memcpy(&h2c->_u8, role, sizeof(h2c->_u8));
+ h2c->_u32.role_map = cpu_to_le32(role->role_map);
+ h2c->_u32.mrole_type = cpu_to_le32(role->mrole_type);
+ h2c->_u32.mrole_noa_duration = cpu_to_le32(role->mrole_noa_duration);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, BTFC_SET,
+ SET_DRV_INFO, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR)
-int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
const struct rtw89_btc_ver *ver = btc->ver;
- struct rtw89_btc_ctrl *ctrl = &btc->ctrl;
+ struct rtw89_btc_ctrl *ctrl = &btc->ctrl.ctrl;
struct sk_buff *skb;
u8 *cmd;
int ret;
@@ -2845,7 +4421,7 @@ int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev)
skb_put(skb, H2C_LEN_CXDRVINFO_CTRL);
cmd = skb->data;
- RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_CTRL);
+ RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type);
RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_CTRL - H2C_LEN_CXDRVHDR);
RTW89_SET_FWCMD_CXCTRL_MANUAL(cmd, ctrl->manual);
@@ -2872,8 +4448,47 @@ fail:
return ret;
}
+int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev, u8 type)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_ctrl_v7 *ctrl = &btc->ctrl.ctrl_v7;
+ struct rtw89_h2c_cxctrl_v7 *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_cxctrl_v7 *)skb->data;
+
+ h2c->hdr.type = type;
+ h2c->hdr.ver = btc->ver->fcxctrl;
+ h2c->hdr.len = sizeof(*h2c) - H2C_LEN_CXDRVHDR_V7;
+ h2c->ctrl = *ctrl;
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, BTFC_SET,
+ SET_DRV_INFO, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
#define H2C_LEN_CXDRVINFO_TRX (28 + H2C_LEN_CXDRVHDR)
-int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_trx_info *trx = &btc->dm.trx_info;
@@ -2889,7 +4504,7 @@ int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev)
skb_put(skb, H2C_LEN_CXDRVINFO_TRX);
cmd = skb->data;
- RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_TRX);
+ RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type);
RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_TRX - H2C_LEN_CXDRVHDR);
RTW89_SET_FWCMD_CXTRX_TXLV(cmd, trx->tx_lvl);
@@ -2929,7 +4544,7 @@ fail:
}
#define H2C_LEN_CXDRVINFO_RFK (4 + H2C_LEN_CXDRVHDR)
-int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev)
+int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev, u8 type)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
@@ -2946,7 +4561,7 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev)
skb_put(skb, H2C_LEN_CXDRVINFO_RFK);
cmd = skb->data;
- RTW89_SET_FWCMD_CXHDR_TYPE(cmd, CXDRVINFO_RFK);
+ RTW89_SET_FWCMD_CXHDR_TYPE(cmd, type);
RTW89_SET_FWCMD_CXHDR_LEN(cmd, H2C_LEN_CXDRVINFO_RFK - H2C_LEN_CXDRVHDR);
RTW89_SET_FWCMD_CXRFK_STATE(cmd, rfk_info->state);
@@ -3062,62 +4677,163 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id,
return 0;
}
-#define H2C_LEN_SCAN_LIST_OFFLOAD 4
-int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len,
+int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num,
struct list_head *chan_list)
{
struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
+ struct rtw89_h2c_chinfo_elem *elem;
struct rtw89_mac_chinfo *ch_info;
+ struct rtw89_h2c_chinfo *h2c;
struct sk_buff *skb;
- int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE;
unsigned int cond;
- u8 *cmd;
+ int skb_len;
int ret;
+ static_assert(sizeof(*elem) == RTW89_MAC_CHINFO_SIZE);
+
+ skb_len = struct_size(h2c, elem, ch_num);
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len);
if (!skb) {
rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n");
return -ENOMEM;
}
- skb_put(skb, H2C_LEN_SCAN_LIST_OFFLOAD);
- cmd = skb->data;
+ skb_put(skb, sizeof(*h2c));
+ h2c = (struct rtw89_h2c_chinfo *)skb->data;
- RTW89_SET_FWCMD_SCANOFLD_CH_NUM(cmd, len);
- /* in unit of 4 bytes */
- RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(cmd, RTW89_MAC_CHINFO_SIZE / 4);
+ h2c->ch_num = ch_num;
+ h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */
list_for_each_entry(ch_info, chan_list, list) {
- cmd = skb_put(skb, RTW89_MAC_CHINFO_SIZE);
-
- RTW89_SET_FWCMD_CHINFO_PERIOD(cmd, ch_info->period);
- RTW89_SET_FWCMD_CHINFO_DWELL(cmd, ch_info->dwell_time);
- RTW89_SET_FWCMD_CHINFO_CENTER_CH(cmd, ch_info->central_ch);
- RTW89_SET_FWCMD_CHINFO_PRI_CH(cmd, ch_info->pri_ch);
- RTW89_SET_FWCMD_CHINFO_BW(cmd, ch_info->bw);
- RTW89_SET_FWCMD_CHINFO_ACTION(cmd, ch_info->notify_action);
- RTW89_SET_FWCMD_CHINFO_NUM_PKT(cmd, ch_info->num_pkt);
- RTW89_SET_FWCMD_CHINFO_TX(cmd, ch_info->tx_pkt);
- RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(cmd, ch_info->pause_data);
- RTW89_SET_FWCMD_CHINFO_BAND(cmd, ch_info->ch_band);
- RTW89_SET_FWCMD_CHINFO_PKT_ID(cmd, ch_info->probe_id);
- RTW89_SET_FWCMD_CHINFO_DFS(cmd, ch_info->dfs_ch);
- RTW89_SET_FWCMD_CHINFO_TX_NULL(cmd, ch_info->tx_null);
- RTW89_SET_FWCMD_CHINFO_RANDOM(cmd, ch_info->rand_seq_num);
- RTW89_SET_FWCMD_CHINFO_PKT0(cmd, ch_info->pkt_id[0]);
- RTW89_SET_FWCMD_CHINFO_PKT1(cmd, ch_info->pkt_id[1]);
- RTW89_SET_FWCMD_CHINFO_PKT2(cmd, ch_info->pkt_id[2]);
- RTW89_SET_FWCMD_CHINFO_PKT3(cmd, ch_info->pkt_id[3]);
- RTW89_SET_FWCMD_CHINFO_PKT4(cmd, ch_info->pkt_id[4]);
- RTW89_SET_FWCMD_CHINFO_PKT5(cmd, ch_info->pkt_id[5]);
- RTW89_SET_FWCMD_CHINFO_PKT6(cmd, ch_info->pkt_id[6]);
- RTW89_SET_FWCMD_CHINFO_PKT7(cmd, ch_info->pkt_id[7]);
+ elem = (struct rtw89_h2c_chinfo_elem *)skb_put(skb, sizeof(*elem));
+
+ elem->w0 = le32_encode_bits(ch_info->period, RTW89_H2C_CHINFO_W0_PERIOD) |
+ le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_W0_DWELL) |
+ le32_encode_bits(ch_info->central_ch, RTW89_H2C_CHINFO_W0_CENTER_CH) |
+ le32_encode_bits(ch_info->pri_ch, RTW89_H2C_CHINFO_W0_PRI_CH);
+
+ elem->w1 = le32_encode_bits(ch_info->bw, RTW89_H2C_CHINFO_W1_BW) |
+ le32_encode_bits(ch_info->notify_action, RTW89_H2C_CHINFO_W1_ACTION) |
+ le32_encode_bits(ch_info->num_pkt, RTW89_H2C_CHINFO_W1_NUM_PKT) |
+ le32_encode_bits(ch_info->tx_pkt, RTW89_H2C_CHINFO_W1_TX) |
+ le32_encode_bits(ch_info->pause_data, RTW89_H2C_CHINFO_W1_PAUSE_DATA) |
+ le32_encode_bits(ch_info->ch_band, RTW89_H2C_CHINFO_W1_BAND) |
+ le32_encode_bits(ch_info->probe_id, RTW89_H2C_CHINFO_W1_PKT_ID) |
+ le32_encode_bits(ch_info->dfs_ch, RTW89_H2C_CHINFO_W1_DFS) |
+ le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_W1_TX_NULL) |
+ le32_encode_bits(ch_info->rand_seq_num, RTW89_H2C_CHINFO_W1_RANDOM);
+
+ elem->w2 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_W2_PKT0) |
+ le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_W2_PKT1) |
+ le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_W2_PKT2) |
+ le32_encode_bits(ch_info->pkt_id[3], RTW89_H2C_CHINFO_W2_PKT3);
+
+ elem->w3 = le32_encode_bits(ch_info->pkt_id[4], RTW89_H2C_CHINFO_W3_PKT4) |
+ le32_encode_bits(ch_info->pkt_id[5], RTW89_H2C_CHINFO_W3_PKT5) |
+ le32_encode_bits(ch_info->pkt_id[6], RTW89_H2C_CHINFO_W3_PKT6) |
+ le32_encode_bits(ch_info->pkt_id[7], RTW89_H2C_CHINFO_W3_PKT7);
}
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len);
- cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH);
+ cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH;
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to add scan ofld ch\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num,
+ struct list_head *chan_list)
+{
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
+ struct rtw89_h2c_chinfo_elem_be *elem;
+ struct rtw89_mac_chinfo_be *ch_info;
+ struct rtw89_h2c_chinfo *h2c;
+ struct sk_buff *skb;
+ unsigned int cond;
+ int skb_len;
+ int ret;
+
+ static_assert(sizeof(*elem) == RTW89_MAC_CHINFO_SIZE);
+
+ skb_len = struct_size(h2c, elem, ch_num);
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, sizeof(*h2c));
+ h2c = (struct rtw89_h2c_chinfo *)skb->data;
+
+ h2c->ch_num = ch_num;
+ h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */
+ h2c->arg = u8_encode_bits(RTW89_PHY_0, RTW89_H2C_CHINFO_ARG_MAC_IDX_MASK);
+
+ list_for_each_entry(ch_info, chan_list, list) {
+ elem = (struct rtw89_h2c_chinfo_elem_be *)skb_put(skb, sizeof(*elem));
+
+ elem->w0 = le32_encode_bits(ch_info->period, RTW89_H2C_CHINFO_BE_W0_PERIOD) |
+ le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_BE_W0_DWELL) |
+ le32_encode_bits(ch_info->central_ch,
+ RTW89_H2C_CHINFO_BE_W0_CENTER_CH) |
+ le32_encode_bits(ch_info->pri_ch, RTW89_H2C_CHINFO_BE_W0_PRI_CH);
+
+ elem->w1 = le32_encode_bits(ch_info->bw, RTW89_H2C_CHINFO_BE_W1_BW) |
+ le32_encode_bits(ch_info->ch_band, RTW89_H2C_CHINFO_BE_W1_CH_BAND) |
+ le32_encode_bits(ch_info->dfs_ch, RTW89_H2C_CHINFO_BE_W1_DFS) |
+ le32_encode_bits(ch_info->pause_data,
+ RTW89_H2C_CHINFO_BE_W1_PAUSE_DATA) |
+ le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_BE_W1_TX_NULL) |
+ le32_encode_bits(ch_info->rand_seq_num,
+ RTW89_H2C_CHINFO_BE_W1_RANDOM) |
+ le32_encode_bits(ch_info->notify_action,
+ RTW89_H2C_CHINFO_BE_W1_NOTIFY) |
+ le32_encode_bits(ch_info->probe_id != 0xff ? 1 : 0,
+ RTW89_H2C_CHINFO_BE_W1_PROBE) |
+ le32_encode_bits(ch_info->leave_crit,
+ RTW89_H2C_CHINFO_BE_W1_EARLY_LEAVE_CRIT) |
+ le32_encode_bits(ch_info->chkpt_timer,
+ RTW89_H2C_CHINFO_BE_W1_CHKPT_TIMER);
+
+ elem->w2 = le32_encode_bits(ch_info->leave_time,
+ RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TIME) |
+ le32_encode_bits(ch_info->leave_th,
+ RTW89_H2C_CHINFO_BE_W2_EARLY_LEAVE_TH) |
+ le32_encode_bits(ch_info->tx_pkt_ctrl,
+ RTW89_H2C_CHINFO_BE_W2_TX_PKT_CTRL);
+
+ elem->w3 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_BE_W3_PKT0) |
+ le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_BE_W3_PKT1) |
+ le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_BE_W3_PKT2) |
+ le32_encode_bits(ch_info->pkt_id[3], RTW89_H2C_CHINFO_BE_W3_PKT3);
+
+ elem->w4 = le32_encode_bits(ch_info->pkt_id[4], RTW89_H2C_CHINFO_BE_W4_PKT4) |
+ le32_encode_bits(ch_info->pkt_id[5], RTW89_H2C_CHINFO_BE_W4_PKT5) |
+ le32_encode_bits(ch_info->pkt_id[6], RTW89_H2C_CHINFO_BE_W4_PKT6) |
+ le32_encode_bits(ch_info->pkt_id[7], RTW89_H2C_CHINFO_BE_W4_PKT7);
+
+ elem->w5 = le32_encode_bits(ch_info->sw_def, RTW89_H2C_CHINFO_BE_W5_SW_DEF) |
+ le32_encode_bits(ch_info->fw_probe0_ssids,
+ RTW89_H2C_CHINFO_BE_W5_FW_PROBE0_SSIDS);
+
+ elem->w6 = le32_encode_bits(ch_info->fw_probe0_shortssids,
+ RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_SHORTSSIDS) |
+ le32_encode_bits(ch_info->fw_probe0_bssids,
+ RTW89_H2C_CHINFO_BE_W6_FW_PROBE0_BSSIDS);
+ }
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
+ H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len);
+
+ cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH;
ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
@@ -3176,7 +4892,10 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
H2C_FUNC_SCANOFLD, 1, 1,
len);
- cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD);
+ if (option->enable)
+ cond = RTW89_SCANOFLD_WAIT_COND_START;
+ else
+ cond = RTW89_SCANOFLD_WAIT_COND_STOP;
ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
if (ret) {
@@ -3187,6 +4906,202 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
return 0;
}
+static void rtw89_scan_get_6g_disabled_chan(struct rtw89_dev *rtwdev,
+ struct rtw89_scan_option *option)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ u8 i, idx;
+
+ sband = rtwdev->hw->wiphy->bands[NL80211_BAND_6GHZ];
+ if (!sband) {
+ option->prohib_chan = U64_MAX;
+ return;
+ }
+
+ for (i = 0; i < sband->n_channels; i++) {
+ chan = &sband->channels[i];
+ if (chan->flags & IEEE80211_CHAN_DISABLED) {
+ idx = (chan->hw_value - 1) / 4;
+ option->prohib_chan |= BIT(idx);
+ }
+ }
+}
+
+int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev,
+ struct rtw89_scan_option *option,
+ struct rtw89_vif *rtwvif)
+{
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait;
+ struct cfg80211_scan_request *req = rtwvif->scan_req;
+ struct rtw89_h2c_scanofld_be_macc_role *macc_role;
+ struct rtw89_chan *op = &scan_info->op_chan;
+ struct rtw89_h2c_scanofld_be_opch *opch;
+ struct rtw89_pktofld_info *pkt_info;
+ struct rtw89_h2c_scanofld_be *h2c;
+ struct sk_buff *skb;
+ u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role;
+ u8 opch_size = sizeof(*opch) * option->num_opch;
+ u8 probe_id[NUM_NL80211_BANDS];
+ unsigned int cond;
+#if defined(__linux__)
+ void *ptr;
+#elif defined(__FreeBSD__)
+ u8 *ptr;
+#endif
+ int ret;
+ u32 len;
+ u8 i;
+
+ rtw89_scan_get_6g_disabled_chan(rtwdev, option);
+
+ len = sizeof(*h2c) + macc_role_size + opch_size;
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c scan offload\n");
+ return -ENOMEM;
+ }
+
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_scanofld_be *)skb->data;
+ ptr = skb->data;
+
+ memset(probe_id, RTW89_SCANOFLD_PKT_NONE, sizeof(probe_id));
+
+ list_for_each_entry(pkt_info, &scan_info->pkt_list[NL80211_BAND_6GHZ], list) {
+ if (pkt_info->wildcard_6ghz) {
+ /* Provide wildcard as template */
+ probe_id[NL80211_BAND_6GHZ] = pkt_info->id;
+ break;
+ }
+ }
+
+ h2c->w0 = le32_encode_bits(option->operation, RTW89_H2C_SCANOFLD_BE_W0_OP) |
+ le32_encode_bits(option->scan_mode,
+ RTW89_H2C_SCANOFLD_BE_W0_SCAN_MODE) |
+ le32_encode_bits(option->repeat, RTW89_H2C_SCANOFLD_BE_W0_REPEAT) |
+ le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_NOTIFY_END) |
+ le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_LEARN_CH) |
+ le32_encode_bits(rtwvif->mac_id, RTW89_H2C_SCANOFLD_BE_W0_MACID) |
+ le32_encode_bits(rtwvif->port, RTW89_H2C_SCANOFLD_BE_W0_PORT) |
+ le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_W0_BAND);
+
+ h2c->w1 = le32_encode_bits(option->num_macc_role, RTW89_H2C_SCANOFLD_BE_W1_NUM_MACC_ROLE) |
+ le32_encode_bits(option->num_opch, RTW89_H2C_SCANOFLD_BE_W1_NUM_OP) |
+ le32_encode_bits(option->norm_pd, RTW89_H2C_SCANOFLD_BE_W1_NORM_PD);
+
+ h2c->w2 = le32_encode_bits(option->slow_pd, RTW89_H2C_SCANOFLD_BE_W2_SLOW_PD) |
+ le32_encode_bits(option->norm_cy, RTW89_H2C_SCANOFLD_BE_W2_NORM_CY) |
+ le32_encode_bits(option->opch_end, RTW89_H2C_SCANOFLD_BE_W2_OPCH_END);
+
+ h2c->w3 = le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_SSID) |
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_SHORT_SSID) |
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W3_NUM_BSSID) |
+ le32_encode_bits(probe_id[NL80211_BAND_2GHZ], RTW89_H2C_SCANOFLD_BE_W3_PROBEID);
+
+ h2c->w4 = le32_encode_bits(probe_id[NL80211_BAND_5GHZ],
+ RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G) |
+ le32_encode_bits(probe_id[NL80211_BAND_6GHZ],
+ RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G) |
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START);
+
+ h2c->w5 = le32_encode_bits(option->mlo_mode, RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE);
+
+ h2c->w6 = le32_encode_bits(option->prohib_chan,
+ RTW89_H2C_SCANOFLD_BE_W6_CHAN_PROHIB_LOW);
+ h2c->w7 = le32_encode_bits(option->prohib_chan >> 32,
+ RTW89_H2C_SCANOFLD_BE_W7_CHAN_PROHIB_HIGH);
+ if (req->no_cck) {
+ h2c->w0 |= le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_W0_PROBE_WITH_RATE);
+ h2c->w8 = le32_encode_bits(RTW89_HW_RATE_OFDM6,
+ RTW89_H2C_SCANOFLD_BE_W8_PROBE_RATE_2GHZ) |
+ le32_encode_bits(RTW89_HW_RATE_OFDM6,
+ RTW89_H2C_SCANOFLD_BE_W8_PROBE_RATE_5GHZ) |
+ le32_encode_bits(RTW89_HW_RATE_OFDM6,
+ RTW89_H2C_SCANOFLD_BE_W8_PROBE_RATE_6GHZ);
+ }
+ ptr += sizeof(*h2c);
+
+ for (i = 0; i < option->num_macc_role; i++) {
+ macc_role = (struct rtw89_h2c_scanofld_be_macc_role *)&h2c->role[i];
+ macc_role->w0 =
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_BAND) |
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_PORT) |
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_MACID) |
+ le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_MACC_ROLE_W0_OPCH_END);
+ ptr += sizeof(*macc_role);
+ }
+
+ for (i = 0; i < option->num_opch; i++) {
+#if defined(__linux__)
+ opch = ptr;
+#elif defined(__FreeBSD__)
+ opch = (void *)ptr;
+#endif
+ opch->w0 = le32_encode_bits(rtwvif->mac_id,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) |
+ le32_encode_bits(option->band,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) |
+ le32_encode_bits(rtwvif->port,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) |
+ le32_encode_bits(RTW89_SCAN_OPMODE_INTV,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) |
+ le32_encode_bits(true,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) |
+ le32_encode_bits(RTW89_OFF_CHAN_TIME / 10,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL);
+
+ opch->w1 = le32_encode_bits(RTW89_CHANNEL_TIME,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W1_DURATION) |
+ le32_encode_bits(op->band_type,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND) |
+ le32_encode_bits(op->band_width,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW) |
+ le32_encode_bits(0x3,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY) |
+ le32_encode_bits(op->primary_channel,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH) |
+ le32_encode_bits(op->channel,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH);
+
+ opch->w2 = le32_encode_bits(0,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL) |
+ le32_encode_bits(0,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) |
+ le32_encode_bits(2,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS);
+
+ opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0) |
+ le32_encode_bits(RTW89_SCANOFLD_PKT_NONE,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1) |
+ le32_encode_bits(RTW89_SCANOFLD_PKT_NONE,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2) |
+ le32_encode_bits(RTW89_SCANOFLD_PKT_NONE,
+ RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT3);
+ ptr += sizeof(*opch);
+ }
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD,
+ H2C_FUNC_SCANOFLD_BE, 1, 1,
+ len);
+
+ if (option->enable)
+ cond = RTW89_SCANOFLD_BE_WAIT_COND_START;
+ else
+ cond = RTW89_SCANOFLD_BE_WAIT_COND_STOP;
+
+ ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_FW, "failed to scan be ofld\n");
+ return ret;
+ }
+
+ return 0;
+}
+
int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
struct rtw89_fw_h2c_rf_reg_info *info,
u16 len, u8 page)
@@ -3222,11 +5137,11 @@ fail:
int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
{
- const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0);
struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
struct rtw89_fw_h2c_rf_get_mccch *mccch;
struct sk_buff *skb;
int ret;
+ u8 idx;
skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, sizeof(*mccch));
if (!skb) {
@@ -3236,12 +5151,13 @@ int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
skb_put(skb, sizeof(*mccch));
mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data;
+ idx = rfk_mcc->table_idx;
mccch->ch_0 = cpu_to_le32(rfk_mcc->ch[0]);
mccch->ch_1 = cpu_to_le32(rfk_mcc->ch[1]);
mccch->band_0 = cpu_to_le32(rfk_mcc->band[0]);
mccch->band_1 = cpu_to_le32(rfk_mcc->band[1]);
- mccch->current_channel = cpu_to_le32(chan->channel);
- mccch->current_band_type = cpu_to_le32(chan->band_type);
+ mccch->current_channel = cpu_to_le32(rfk_mcc->ch[idx]);
+ mccch->current_band_type = cpu_to_le32(rfk_mcc->band[idx]);
rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY,
@@ -3262,6 +5178,328 @@ fail:
}
EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc);
+int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc;
+ struct rtw89_fw_h2c_rfk_pre_info *h2c;
+ u8 tbl_sel = rfk_mcc->table_idx;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ u8 tbl, path;
+ u32 val32;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c rfk_pre_ntfy\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_fw_h2c_rfk_pre_info *)skb->data;
+
+ h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode);
+
+ BUILD_BUG_ON(NUM_OF_RTW89_FW_RFK_TBL > RTW89_RFK_CHS_NR);
+
+ for (tbl = 0; tbl < NUM_OF_RTW89_FW_RFK_TBL; tbl++) {
+ for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) {
+ h2c->dbcc.ch[path][tbl] = cpu_to_le32(rfk_mcc->ch[tbl]);
+ h2c->dbcc.band[path][tbl] = cpu_to_le32(rfk_mcc->band[tbl]);
+ }
+ }
+
+ for (path = 0; path < NUM_OF_RTW89_FW_RFK_PATH; path++) {
+ h2c->tbl.cur_ch[path] = cpu_to_le32(rfk_mcc->ch[tbl_sel]);
+ h2c->tbl.cur_band[path] = cpu_to_le32(rfk_mcc->band[tbl_sel]);
+ }
+
+ h2c->phy_idx = cpu_to_le32(phy_idx);
+ h2c->cur_band = cpu_to_le32(rfk_mcc->band[tbl_sel]);
+ h2c->cur_bw = cpu_to_le32(rfk_mcc->bw[tbl_sel]);
+ h2c->cur_center_ch = cpu_to_le32(rfk_mcc->ch[tbl_sel]);
+
+ val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL, B_COEF_SEL_IQC_V1);
+ h2c->ktbl_sel0 = cpu_to_le32(val32);
+ val32 = rtw89_phy_read32_mask(rtwdev, R_COEF_SEL_C1, B_COEF_SEL_IQC_V1);
+ h2c->ktbl_sel1 = cpu_to_le32(val32);
+ val32 = rtw89_read_rf(rtwdev, RF_PATH_A, RR_CFGCH, RFREG_MASK);
+ h2c->rfmod0 = cpu_to_le32(val32);
+ val32 = rtw89_read_rf(rtwdev, RF_PATH_B, RR_CFGCH, RFREG_MASK);
+ h2c->rfmod1 = cpu_to_le32(val32);
+
+ if (rtw89_is_mlo_1_1(rtwdev))
+ h2c->mlo_1_1 = cpu_to_le32(1);
+
+ h2c->rfe_type = cpu_to_le32(rtwdev->efuse.rfe_type);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_PRE_NOTIFY, 0, 0,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
+ enum rtw89_tssi_mode tssi_mode)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ RTW89_SUB_ENTITY_0);
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_h2c_rf_tssi *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF TSSI\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_tssi *)skb->data;
+
+ h2c->len = cpu_to_le16(len);
+ h2c->phy = phy_idx;
+ h2c->ch = chan->channel;
+ h2c->bw = chan->band_width;
+ h2c->band = chan->band_type;
+ h2c->hwtx_en = true;
+ h2c->cv = hal->cv;
+ h2c->tssi_mode = tssi_mode;
+
+ rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(rtwdev, phy_idx, chan, h2c);
+ rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(rtwdev, phy_idx, chan, h2c);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_TSSI_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_h2c_rf_iqk *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF IQK\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_iqk *)skb->data;
+
+ h2c->phy_idx = cpu_to_le32(phy_idx);
+ h2c->dbcc = cpu_to_le32(rtwdev->dbcc_en);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_IQK_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_rf_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ RTW89_SUB_ENTITY_0);
+ struct rtw89_h2c_rf_dpk *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF DPK\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_dpk *)skb->data;
+
+ h2c->len = len;
+ h2c->phy = phy_idx;
+ h2c->dpk_enable = true;
+ h2c->kpath = RF_AB;
+ h2c->cur_band = chan->band_type;
+ h2c->cur_bw = chan->band_width;
+ h2c->cur_ch = chan->channel;
+ h2c->dpk_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_DPK_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_rf_txgapk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ RTW89_SUB_ENTITY_0);
+ struct rtw89_hal *hal = &rtwdev->hal;
+ struct rtw89_h2c_rf_txgapk *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF TXGAPK\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_txgapk *)skb->data;
+
+ h2c->len = len;
+ h2c->ktype = 2;
+ h2c->phy = phy_idx;
+ h2c->kpath = RF_AB;
+ h2c->band = chan->band_type;
+ h2c->bw = chan->band_width;
+ h2c->ch = chan->channel;
+ h2c->cv = hal->cv;
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_TXGAPK_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ struct rtw89_h2c_rf_dack *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF DACK\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_dack *)skb->data;
+
+ h2c->len = cpu_to_le32(len);
+ h2c->phy = cpu_to_le32(phy_idx);
+ h2c->type = cpu_to_le32(0);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_DACK_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+ const struct rtw89_chan *chan = rtw89_chan_get(rtwdev,
+ RTW89_SUB_ENTITY_0);
+ struct rtw89_h2c_rf_rxdck *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c RF RXDCK\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_rf_rxdck *)skb->data;
+
+ h2c->len = len;
+ h2c->phy = phy_idx;
+ h2c->is_afe = false;
+ h2c->kpath = RF_AB;
+ h2c->cur_band = chan->band_type;
+ h2c->cur_bw = chan->band_width;
+ h2c->cur_ch = chan->channel;
+ h2c->rxdck_dbg_en = rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
+ H2C_FUNC_RFK_RXDCK_OFFLOAD, 0, 0, len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
bool rack, bool dack)
@@ -3365,7 +5603,9 @@ static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev,
default:
return false;
case RTW89_C2H_CAT_MAC:
- return rtw89_mac_c2h_chk_atomic(rtwdev, class, func);
+ return rtw89_mac_c2h_chk_atomic(rtwdev, c2h, class, func);
+ case RTW89_C2H_CAT_OUTSRC:
+ return rtw89_phy_c2h_chk_atomic(rtwdev, class, func);
}
}
@@ -3587,6 +5827,7 @@ static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev,
info->ssid_len = req->ssids[ssid_idx].ssid_len;
return false;
} else {
+ info->wildcard_6ghz = true;
return true;
}
}
@@ -3621,12 +5862,8 @@ static int rtw89_append_probe_req_ie(struct rtw89_dev *rtwdev,
goto out;
}
- if (rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band,
- ssid_idx)) {
- kfree_skb(new);
- kfree(info);
- goto out;
- }
+ rtw89_is_6ghz_wildcard_probe_req(rtwdev, rtwvif, info, band,
+ ssid_idx);
ret = rtw89_fw_h2c_add_pkt_offload(rtwdev, &info->id, new);
if (ret) {
@@ -3782,6 +6019,12 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
if (info->channel_6ghz &&
ch_info->pri_ch != info->channel_6ghz)
continue;
+ else if (info->channel_6ghz && probe_count != 0)
+ ch_info->period += RTW89_CHANNEL_TIME_6G;
+
+ if (info->wildcard_6ghz)
+ continue;
+
ch_info->pkt_id[probe_count++] = info->id;
if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
break;
@@ -3811,8 +6054,70 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
}
}
-static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif, bool connected)
+static void rtw89_hw_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type,
+ int ssid_num,
+ struct rtw89_mac_chinfo_be *ch_info)
+{
+ struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
+ struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif;
+ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+ struct cfg80211_scan_request *req = rtwvif->scan_req;
+ struct rtw89_pktofld_info *info;
+ u8 band, probe_count = 0, i;
+
+ ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK;
+ ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS;
+ ch_info->bw = RTW89_SCAN_WIDTH;
+ ch_info->tx_null = false;
+ ch_info->pause_data = false;
+ ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
+
+ if (ssid_num) {
+ band = rtw89_hw_to_nl80211_band(ch_info->ch_band);
+
+ list_for_each_entry(info, &scan_info->pkt_list[band], list) {
+ if (info->channel_6ghz &&
+ ch_info->pri_ch != info->channel_6ghz)
+ continue;
+
+ if (info->wildcard_6ghz)
+ continue;
+
+ ch_info->pkt_id[probe_count++] = info->id;
+ if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
+ break;
+ }
+ }
+
+ if (ch_info->ch_band == RTW89_BAND_6G) {
+ if ((ssid_num == 1 && req->ssids[0].ssid_len == 0) ||
+ !ch_info->is_psc) {
+ ch_info->probe_id = RTW89_SCANOFLD_PKT_NONE;
+ if (!req->duration_mandatory)
+ ch_info->period -= RTW89_DWELL_TIME_6G;
+ }
+ }
+
+ for (i = probe_count; i < RTW89_SCANOFLD_MAX_SSID; i++)
+ ch_info->pkt_id[i] = RTW89_SCANOFLD_PKT_NONE;
+
+ switch (chan_type) {
+ case RTW89_CHAN_DFS:
+ if (ch_info->ch_band != RTW89_BAND_6G)
+ ch_info->period =
+ max_t(u8, ch_info->period, RTW89_DFS_CHAN_TIME);
+ ch_info->dwell_time = RTW89_DWELL_TIME;
+ break;
+ case RTW89_CHAN_ACTIVE:
+ break;
+ default:
+ rtw89_warn(rtwdev, "Channel type out of bound\n");
+ break;
+ }
+}
+
+int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif, bool connected)
{
struct cfg80211_scan_request *req = rtwvif->scan_req;
struct rtw89_mac_chinfo *ch_info, *tmp;
@@ -3835,7 +6140,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
goto out;
}
- if (req->duration_mandatory)
+ if (req->duration)
ch_info->period = req->duration;
else if (channel->band == NL80211_BAND_6GHZ)
ch_info->period = RTW89_CHANNEL_TIME_6G +
@@ -3888,9 +6193,69 @@ out:
return ret;
}
+int rtw89_hw_scan_add_chan_list_be(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif, bool connected)
+{
+ struct cfg80211_scan_request *req = rtwvif->scan_req;
+ struct rtw89_mac_chinfo_be *ch_info, *tmp;
+ struct ieee80211_channel *channel;
+ struct list_head chan_list;
+ enum rtw89_chan_type type;
+ int list_len, ret;
+ bool random_seq;
+ u32 idx;
+
+ random_seq = !!(req->flags & NL80211_SCAN_FLAG_RANDOM_SN);
+ INIT_LIST_HEAD(&chan_list);
+
+ for (idx = rtwdev->scan_info.last_chan_idx, list_len = 0;
+ idx < req->n_channels && list_len < RTW89_SCAN_LIST_LIMIT;
+ idx++, list_len++) {
+ channel = req->channels[idx];
+ ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
+ if (!ch_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (req->duration)
+ ch_info->period = req->duration;
+ else if (channel->band == NL80211_BAND_6GHZ)
+ ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G;
+ else
+ ch_info->period = RTW89_CHANNEL_TIME;
+
+ ch_info->ch_band = rtw89_nl80211_to_hw_band(channel->band);
+ ch_info->central_ch = channel->hw_value;
+ ch_info->pri_ch = channel->hw_value;
+ ch_info->rand_seq_num = random_seq;
+ ch_info->is_psc = cfg80211_channel_is_psc(channel);
+
+ if (channel->flags & (IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR))
+ type = RTW89_CHAN_DFS;
+ else
+ type = RTW89_CHAN_ACTIVE;
+ rtw89_hw_scan_add_chan_be(rtwdev, type, req->n_ssids, ch_info);
+
+ list_add_tail(&ch_info->list, &chan_list);
+ }
+
+ rtwdev->scan_info.last_chan_idx = idx;
+ ret = rtw89_fw_h2c_scan_list_offload_be(rtwdev, list_len, &chan_list);