* [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C
@ 2026-09-23 7:13 Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping Ping-Ke Shih
` (6 more replies)
0 siblings, 7 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
Patches to support newer firmware formats, especially for RTL8852C, and
use IO pack to offload IO to firmware to speed initialization.
Ching-Te Ku (6):
wifi: rtw89: coex: log FCX report version mismatch without dropping
wifi: rtw89: coex: add fbtc_rpt_ctrl v205 report struct and handling
wifi: rtw89: coex: Add firmware 0.27.130.1 support for RTL8852C
wifi: rtw89: coex: fix BT scoreboard update for non-C2H paths
wifi: rtw89: coex: offload 8852C IO writes via firmware CMD pack
region
wifi: rtw89: coex: batch PTA init with masked IO offload
Zong-Zhe Yang (1):
wifi: rtw89: add instance of IO ops for (un)pack and [um]delay
drivers/net/wireless/realtek/rtw89/coex.c | 236 +++++++++++++++++-
drivers/net/wireless/realtek/rtw89/core.h | 170 ++++++++++---
drivers/net/wireless/realtek/rtw89/fw.c | 122 ++++++++-
drivers/net/wireless/realtek/rtw89/fw.h | 8 +-
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 12 +
5 files changed, 491 insertions(+), 57 deletions(-)
base-commit: 2f77c66694108785a1f6ae6c5de06453e7f7a91f
--
2.25.1
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
2026-09-30 2:14 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 2/7] wifi: rtw89: coex: add fbtc_rpt_ctrl v205 report struct and handling Ping-Ke Shih
` (5 subsequent siblings)
6 siblings, 1 reply; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Ching-Te Ku <ku920601@realtek.com>
_chk_btc_report() validated the reported firmware struct version only
for the control report, so a version mismatch on any other report type
was copied in silently and left no trace, making a ver_defs or firmware
version error hard to diagnose.
Read the reported fver, which is the leading field of every report
struct, and when it differs from the driver-selected version set the
per-type bit in fver_mismch and emit a debug line. The length-valid
report is still processed, because the driver must stay compatible with
every released firmware and a mismatch usually points at a ver_defs
entry that needs fixing rather than a report that should be discarded.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 305d8edb0d4d..d3f9ef02e982 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1866,6 +1866,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr;
u8 i, j, val = 0, val1, val2;
u32 *bt_cnt, start_idx;
+ const u8 *rpt_fver;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): index:%d\n",
@@ -2181,6 +2182,21 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
memcpy(pfinfo, rpt_content, pcinfo->req_len);
pcinfo->valid = 1;
+ /*
+ * fver is the leading field of every report struct. A mismatch
+ * vs the driver-selected version means ver_defs needs a fix, so
+ * flag it for debug but keep processing the length-valid report.
+ */
+ rpt_fver = pfinfo;
+ pcinfo->rsp_fver = rpt_fver[0];
+ if (pcinfo->rsp_fver != pcinfo->req_fver) {
+ pfwinfo->fver_mismch |= BIT(rpt_type);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): %d rsp_fver:%d!=req_fver:%d\n",
+ __func__, rpt_type, pcinfo->rsp_fver,
+ pcinfo->req_fver);
+ }
+
switch (rpt_type) {
case BTC_RPT_TYPE_CTRL:
if (ver->fcxbtcrpt == 1) {
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH rtw-next 2/7] wifi: rtw89: coex: add fbtc_rpt_ctrl v205 report struct and handling
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 3/7] wifi: rtw89: coex: Add firmware 0.27.130.1 support for RTL8852C Ping-Ke Shih
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Ching-Te Ku <ku920601@realtek.com>
Define struct rtw89_btc_fbtc_rpt_ctrl_v205 and add it to the
rtw89_btc_fbtc_rpt_ctrl_ver_info union. Wire up the v205 dispatch
path in _chk_btc_report() including req_len, fver extraction, and
rsp_fver assignment (H2C fver=5). Decode the v205 report block for
rpt_en_map, fw_coex/fw version, cx_offload, build timestamps, gnt_val,
and BT counters. Add fw_ver_match checking for fcxbtcrpt=205, and add
BTTX_HANG detection in the v205 error-check block.
Also add _show_summary_v205() and wire it into the coex info dump so
the fcxbtcrpt=205 statistics block is printed instead of skipped.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 179 +++++++++++++++++++++-
drivers/net/wireless/realtek/rtw89/core.h | 14 ++
2 files changed, 191 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index d3f9ef02e982..0f3347fdbb01 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1910,6 +1910,14 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v105.fver;
pcinfo->req_fver = 5;
break;
+ } else if (ver->fcxbtcrpt == 205) {
+ pfinfo = &pfwinfo->rpt_ctrl.finfo.v205;
+ pcinfo->req_len =
+ sizeof(pfwinfo->rpt_ctrl.finfo.v205);
+ fwsubver->fcxbtcrpt =
+ pfwinfo->rpt_ctrl.finfo.v205.fver;
+ 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);
@@ -2304,6 +2312,52 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
_chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
pfwinfo->event[BTF_EVNT_RPT]);
+ dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
+ } else if (ver->fcxbtcrpt == 205) {
+ prpt->v205 = pfwinfo->rpt_ctrl.finfo.v205;
+ pfwinfo->rpt_en_map =
+ le32_to_cpu(prpt->v205.rpt_info.en);
+ wl->ver_info.fw_coex =
+ le32_to_cpu(prpt->v205.wl_fw_info.cx_ver);
+ wl->ver_info.fw =
+ le32_to_cpu(prpt->v205.wl_fw_info.fw_ver);
+ dm->wl_fw_cx_offload =
+ !!le32_to_cpu(prpt->v205.wl_fw_info.cx_offload);
+
+ memcpy(wl->ver_info.build_time,
+ prpt->v205.build_time,
+ sizeof(wl->ver_info.build_time));
+ memcpy(wl->ver_info.build_date,
+ prpt->v205.build_date,
+ sizeof(wl->ver_info.build_date));
+
+ for (i = RTW89_PHY_0; i < RTW89_PHY_NUM; i++)
+ memcpy(&dm->gnt_val[i],
+ &prpt->v205.gnt_val[i],
+ sizeof(prpt->v205.gnt_val[i]));
+
+ bt->bcnt[BTC_BCNT_HIPRI_TX] =
+ le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_HI_TX]);
+ bt->bcnt[BTC_BCNT_HIPRI_RX] =
+ le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_HI_RX]);
+ bt->bcnt[BTC_BCNT_LOPRI_TX] =
+ le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_LO_TX]);
+ bt->bcnt[BTC_BCNT_LOPRI_RX] =
+ le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_LO_RX]);
+ bt->bcnt[BTC_BCNT_POLLUTED] =
+ le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_POLLUTED]);
+
+ _chk_btc_err(rtwdev, BTC_DCNT_BTCNT_HANG, 0);
+ _chk_btc_err(rtwdev, BTC_DCNT_RPT_HANG,
+ pfwinfo->event[BTF_EVNT_RPT]);
+ _chk_btc_err(rtwdev, BTC_DCNT_WL_FW_VER_MATCH, 0);
+ _chk_btc_err(rtwdev, BTC_DCNT_BTTX_HANG, 0);
+
+ if (le32_to_cpu(prpt->v205.bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
+ bt->rfk_info.map.timeout = 1;
+ else
+ bt->rfk_info.map.timeout = 0;
+
dm->error.map.bt_rfk_timeout = bt->rfk_info.map.timeout;
} else if (ver->fcxbtcrpt == 7) {
prpt->v7 = pfwinfo->rpt_ctrl.finfo.v7;
@@ -3332,9 +3386,13 @@ static void rtw89_btc_fw_en_rpt(struct rtw89_dev *rtwdev,
if (btc->ver->fcxbtcrpt == 7 ||
btc->ver->fcxbtcrpt == 8 ||
btc->ver->fcxbtcrpt == 9 ||
- btc->ver->fcxbtcrpt == 11) {
+ btc->ver->fcxbtcrpt == 11 ||
+ btc->ver->fcxbtcrpt == 205) {
r.v8.type = SET_REPORT_EN;
- r.v8.fver = btc->ver->fcxbtcrpt;
+ if (btc->ver->fcxbtcrpt == 205)
+ r.v8.fver = 5;
+ else
+ r.v8.fver = btc->ver->fcxbtcrpt;
r.v8.len = sizeof(r.v8.map);
r.v8.map = cpu_to_le32(rpt_map);
ret = _send_fw_cmd(rtwdev, BTFC_SET, SET_REPORT_EN, &r.v8,
@@ -13644,6 +13702,121 @@ static int _show_summary_v11(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
return p - buf;
}
+static int _show_summary_v205(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_btf_fwinfo *pfwinfo = &btc->fwinfo;
+ struct rtw89_btc_fbtc_rpt_ctrl_v205 *prptctrl;
+ struct rtw89_btc_rpt_cmn_info *pcinfo;
+ struct rtw89_btc_cx *cx = &btc->cx;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct rtw89_btc_wl_info *wl = &cx->wl;
+ struct rtw89_btc_bt_info *bt = &cx->bt0;
+ u32 cnt_sum = 0, *cnt = btc->dm.cnt_notify;
+ char *p = buf, *end = buf + bufsz;
+ u8 i;
+
+ if (!(dm->coex_info_map & BTC_COEX_INFO_SUMMARY))
+ return 0;
+
+ p += scnprintf(p, end - p, "========== [Statistics] ==========\n");
+
+ pcinfo = &pfwinfo->rpt_ctrl.cinfo;
+ if (pcinfo->valid && !wl->status.map.lps && !wl->status.map.rf_off) {
+ prptctrl = &pfwinfo->rpt_ctrl.finfo.v205;
+
+ p += scnprintf(p, end - p,
+ " %-15s : h2c_cnt=%d(fail:%d, fw_recv:%d), c2h_cnt=%d(fw_send:%d), ",
+ "[summary]", pfwinfo->cnt_h2c,
+ pfwinfo->cnt_h2c_fail,
+ le32_to_cpu(prptctrl->rpt_info.cnt_h2c),
+ pfwinfo->cnt_c2h,
+ le32_to_cpu(prptctrl->rpt_info.cnt_c2h));
+
+ p += scnprintf(p, end - p,
+ "rpt_cnt=%d(fw_send:%d), rpt_map=0x%x, dm_error_map:0x%x",
+ pfwinfo->event[BTF_EVNT_RPT],
+ le32_to_cpu(prptctrl->rpt_info.cnt),
+ le32_to_cpu(prptctrl->rpt_info.en),
+ dm->error.val);
+
+ if (dm->error.map.wl_fw_hang)
+ p += scnprintf(p, end - p, " (WL FW Hang!!)");
+ p += scnprintf(p, end - p, "\n");
+ p += scnprintf(p, end - p,
+ " %-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));
+
+ p += scnprintf(p, end - p,
+ "A2DP_empty:%d(stop:%d, tx:%d, ack:%d, nack:%d)\n",
+ 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));
+
+ p += scnprintf(p, end - p,
+ " %-15s : wl_rfk[req:%d/go:%d/reject:%d/timeout:%d]",
+ "[RFK]", wl->wcnt[BTC_WCNT_RFK_REQ],
+ wl->wcnt[BTC_WCNT_RFK_GO],
+ wl->wcnt[BTC_WCNT_RFK_REJECT],
+ wl->wcnt[BTC_WCNT_RFK_TIMEOUT]);
+
+ p += scnprintf(p, end - p,
+ ", bt_rfk[req:%d/go:%d/reject:%d/timeout:%d/fail:%d]\n",
+ le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REQ]),
+ le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_GO]),
+ le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_REJECT]),
+ le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]),
+ le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_FAIL]));
+
+ if (le32_to_cpu(prptctrl->bt_cnt[BTC_BCNT_RFK_TIMEOUT]) > 0)
+ bt->rfk_info.map.timeout = 1;
+ else
+ bt->rfk_info.map.timeout = 0;
+
+ dm->error.map.wl_rfk_timeout = bt->rfk_info.map.timeout;
+ } else {
+ p += scnprintf(p, end - p,
+ " %-15s : h2c_cnt=%d(fail:%d), c2h_cnt=%d, rpt_cnt=%d, rpt_map=0x%x",
+ "[summary]", pfwinfo->cnt_h2c,
+ pfwinfo->cnt_h2c_fail, pfwinfo->cnt_c2h,
+ pfwinfo->event[BTF_EVNT_RPT],
+ btc->fwinfo.rpt_en_map);
+ p += scnprintf(p, end - p, " (WL FW report invalid!!)\n");
+ }
+
+ for (i = 0; i < BTC_NCNT_NUM; i++)
+ cnt_sum += dm->cnt_notify[i];
+
+ p += scnprintf(p, end - p,
+ " %-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]);
+
+ p += scnprintf(p, end - p,
+ "power_off=%d, radio_state=%d, role_info=%d, wl_rfk=%d, wl_sta=%d\n",
+ 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]);
+
+ p += scnprintf(p, end - p,
+ " %-15s : scan_start=%d, scan_finish=%d, switch_band=%d, special_pkt=%d, ",
+ "[notify_cnt]", cnt[BTC_NCNT_SCAN_START],
+ cnt[BTC_NCNT_SCAN_FINISH], cnt[BTC_NCNT_SWITCH_BAND],
+ cnt[BTC_NCNT_SPECIAL_PACKET]);
+
+ p += scnprintf(p, end - p,
+ "timer=%d, control=%d, customerize=%d\n",
+ cnt[BTC_NCNT_TIMER], cnt[BTC_NCNT_CONTROL],
+ cnt[BTC_NCNT_CUSTOMERIZE]);
+
+ return p - buf;
+}
+
ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
{
struct rtw89_btc *btc = &rtwdev->btc;
@@ -13704,6 +13877,8 @@ ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz)
p += _show_summary_v5(rtwdev, p, end - p);
else if (ver->fcxbtcrpt == 105)
p += _show_summary_v105(rtwdev, p, end - p);
+ else if (ver->fcxbtcrpt == 205)
+ p += _show_summary_v205(rtwdev, p, end - p);
else if (ver->fcxbtcrpt == 7)
p += _show_summary_v7(rtwdev, p, end - p);
else if (ver->fcxbtcrpt == 8)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 3a6099386b09..fc51419a1782 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3006,6 +3006,19 @@ struct rtw89_btc_fbtc_rpt_ctrl_v11 {
__le32 scbd_b2w[2];
} __packed;
+struct rtw89_btc_fbtc_rpt_ctrl_v205 {
+ u8 fver;
+ u8 rsvd;
+ u8 build_time[RTW89_BTC_TIME_DATE_FMT];
+ u8 build_date[RTW89_BTC_TIME_DATE_FMT];
+ __le16 rsvd1;
+ struct rtw89_btc_fbtc_rpt_ctrl_info rpt_info;
+ struct rtw89_btc_fbtc_rpt_ctrl_wl_fw_info wl_fw_info;
+ struct rtw89_btc_fbtc_rpt_ctrl_bt_mailbox bt_mbx_info;
+ __le32 bt_cnt[BTC_BCNT_STA_MAX];
+ u8 gnt_val[RTW89_PHY_NUM][4];
+} __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;
@@ -3015,6 +3028,7 @@ union rtw89_btc_fbtc_rpt_ctrl_ver_info {
struct rtw89_btc_fbtc_rpt_ctrl_v8 v8;
struct rtw89_btc_fbtc_rpt_ctrl_v9 v9;
struct rtw89_btc_fbtc_rpt_ctrl_v11 v11;
+ struct rtw89_btc_fbtc_rpt_ctrl_v205 v205;
};
enum rtw89_fbtc_ext_ctrl_type {
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH rtw-next 3/7] wifi: rtw89: coex: Add firmware 0.27.130.1 support for RTL8852C
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 2/7] wifi: rtw89: coex: add fbtc_rpt_ctrl v205 report struct and handling Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 4/7] wifi: rtw89: coex: fix BT scoreboard update for non-C2H paths Ping-Ke Shih
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Ching-Te Ku <ku920601@realtek.com>
Add a new entry in rtw89_btc_ver_defs for RTL8852C firmware version
0.27.130.1, which introduces fcxbtcrpt=205. The new entry activates
the v205 coexistence report path added in the preceding commit.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 0f3347fdbb01..b80e7979a1ae 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -146,7 +146,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxbtcrpt = 11, .fcxtdma = 8, .fcxslots = 7, .fcxcysta = 8,
.fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 8,
.fcxbtver = 8, .fcxbtscan = 8, .fcxbtafh = 8, .fcxbtdevinfo = 8,
- .fwlrole = 10, .frptmap = 5, .fcxctrl = 9, .fcxinit = 10,
+ .fwlrole = 10, .frptmap = 5, .fcxctrl = 9, .fcxinit = 10,
.fwevntrptl = 1, .fwc2hfunc = 4, .drvinfo_ver = 3, .info_buf = 1800,
.max_role_num = 6, .fcxosi = 6, .fcxmlo = 2, .bt_desired = 8,
.fcxtrx = 9, .fcxtxpwr = 1,
@@ -224,7 +224,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxtrx = 107, .fcxtxpwr = 0,
},
{RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0),
- .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5,
+ .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 = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
@@ -232,6 +232,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7,
.fcxtrx = 0, .fcxtxpwr = 0,
},
+ {RTL8852C, RTW89_FW_VER_CODE(0, 27, 130, 1),
+ .fcxbtcrpt = 205, .fcxtdma = 4, .fcxslots = 2, .fcxcysta = 105,
+ .fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1,
+ .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1,
+ .fwlrole = 101, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0,
+ .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_ver = 0, .info_buf = 1280,
+ .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7,
+ .fcxtrx = 107, .fcxtxpwr = 0,
+ },
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 97, 0),
.fcxbtcrpt = 4, .fcxtdma = 4, .fcxslots = 2, .fcxcysta = 105,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1,
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH rtw-next 4/7] wifi: rtw89: coex: fix BT scoreboard update for non-C2H paths
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
` (2 preceding siblings ...)
2026-09-23 7:13 ` [PATCH rtw-next 3/7] wifi: rtw89: coex: Add firmware 0.27.130.1 support for RTL8852C Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 5/7] wifi: rtw89: add instance of IO ops for (un)pack and [um]delay Ping-Ke Shih
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Ching-Te Ku <ku920601@realtek.com>
The scoreboard update function was changed to always read from
scbd_c2h, which is populated only by BTF_EVNT_BT_SCBD C2H events from
the BT firmware. This caused two problems.
First, calling _update_bt_scbd at the NTFY_INIT notification with
scbd_c2h still zero would set bt->enable.now to 0, overwriting the
bt-on assumption that _ntfy_init_coex establishes for all chips. Remove
the NTFY_INIT call to preserve that default.
Second, chips whose BT firmware does not send BTF_EVNT_BT_SCBD events
have scbd_c2h stuck at zero indefinitely, making scoreboard updates
non-functional. Restore a hardware register read path by adding
_read_scbd() and an is_c2h flag to _update_bt_scbd. The
NTFY_RADIO_STATE path passes is_c2h=false to read the hardware
scoreboard register directly, ensuring correct BT state even without
C2H support. Pass BTC_ALL_BT so both BT devices are refreshed on
dual-BT chips.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/coex.c | 28 +++++++++++++++++------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index b80e7979a1ae..6b72e2c80d14 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -1010,7 +1010,7 @@ static void _run_coex(struct rtw89_dev *rtwdev,
enum btc_reason_and_action reason);
static void _write_scbd(struct rtw89_dev *rtwdev, u8 bid, u32 val, bool state);
static u8 _sned_h2c_w2bscbd(struct rtw89_dev *rtwdev, bool force_exec, u8 bid);
-static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid);
+static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid, bool is_c2h);
static const char *id_to_h2c(u32 id);
static void _reset_h2c_macro(struct rtw89_btc *btc)
@@ -3902,7 +3902,7 @@ void btc_fw_event(struct rtw89_dev *rtwdev, u8 evt_id, void *data, u32 len)
"[BTC], %s() bt%d:c2h->0x%08x, rb->0x%08x\n",
__func__, i, bt->scbd_c2h, bt->scbd_rb);
bt->scbd_c2h = bt->scbd_rb;
- _update_bt_scbd(rtwdev, i);
+ _update_bt_scbd(rtwdev, i, true);
btc->dm.scbd_b2w_update = false;
}
}
@@ -8116,7 +8116,21 @@ static void _update_bt_ctrl_lps(struct rtw89_dev *rtwdev)
}
}
-static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid)
+static u32 _read_scbd(struct rtw89_dev *rtwdev, u8 id)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 val;
+
+ if (!chip->scbd)
+ return 0;
+
+ val = rtw89_read32(rtwdev, chip->btc_sb.n[id].get);
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], read scbd bt%d: 0x%08x\n", id, val);
+ return val;
+}
+
+static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid, bool is_c2h)
{
struct rtw89_btc_bt_link_info *bt_2g, *bt_56g;
struct rtw89_btc *btc = &rtwdev->btc;
@@ -8149,7 +8163,7 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, u8 bid)
if (!(rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) && id == BTC_BT_2ND)
break;
- val = bt->scbd_c2h;
+ val = is_c2h ? bt->scbd_c2h : _read_scbd(rtwdev, id);
if (val == 0xffffffff) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -8785,8 +8799,8 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
_update_run_ctrl_info(rtwdev);
- if (reason == BTC_RSN_NTFY_INIT || reason == BTC_RSN_NTFY_RADIO_STATE)
- _update_bt_scbd(rtwdev, false);
+ if (reason == BTC_RSN_NTFY_RADIO_STATE)
+ _update_bt_scbd(rtwdev, BTC_ALL_BT, false);
dm->freerun = false;
dm->cnt_dm[BTC_DCNT_RUN]++;
@@ -10131,7 +10145,7 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], handle C2H BT%d SCBD with data 0x%08x\n",
bid, bt->scbd_c2h);
- _update_bt_scbd(rtwdev, bid);
+ _update_bt_scbd(rtwdev, bid, true);
_run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD);
break;
case BTF_EVNT_BT_PSD:
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH rtw-next 5/7] wifi: rtw89: add instance of IO ops for (un)pack and [um]delay
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
` (3 preceding siblings ...)
2026-09-23 7:13 ` [PATCH rtw-next 4/7] wifi: rtw89: coex: fix BT scoreboard update for non-C2H paths Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 6/7] wifi: rtw89: coex: offload 8852C IO writes via firmware CMD pack region Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 7/7] wifi: rtw89: coex: batch PTA init with masked IO offload Ping-Ke Shih
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Zong-Zhe Yang <kevin_yang@realtek.com>
To make IO wrappers of pack/unpack/udely/mdely can intuitively call
the loaded IO ops as others do, add corresponding instances for them.
And, expect all rtw89_io_ops initializers should assign all members.
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.h | 38 ++++++++++++++---------
drivers/net/wireless/realtek/rtw89/fw.c | 10 +++---
2 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index fc51419a1782..128667fb95b0 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -8097,36 +8097,44 @@ struct rtw89_tx_skb_data *RTW89_TX_SKB_CB(struct sk_buff *skb)
return (struct rtw89_tx_skb_data *)info->driver_data;
}
-static inline int rtw89_io_pack(struct rtw89_dev *rtwdev)
+static inline int rtw89_raw_io_pack(struct rtw89_dev *rtwdev)
{
- if (rtwdev->io->pack)
- return rtwdev->io->pack(rtwdev);
+ return 0;
+}
+static inline int rtw89_raw_io_unpack(struct rtw89_dev *rtwdev)
+{
return 0;
}
-static inline int rtw89_io_unpack(struct rtw89_dev *rtwdev)
+static inline void rtw89_raw_io_udelay(struct rtw89_dev *rtwdev, u32 us)
{
- if (rtwdev->io->unpack)
- return rtwdev->io->unpack(rtwdev);
+ udelay(us);
+}
- return 0;
+static inline void rtw89_raw_io_mdelay(struct rtw89_dev *rtwdev, u32 ms)
+{
+ mdelay(ms);
+}
+
+static inline int rtw89_io_pack(struct rtw89_dev *rtwdev)
+{
+ return rtwdev->io->pack(rtwdev);
+}
+
+static inline int rtw89_io_unpack(struct rtw89_dev *rtwdev)
+{
+ return rtwdev->io->unpack(rtwdev);
}
static inline void rtw89_io_udelay(struct rtw89_dev *rtwdev, u32 us)
{
- if (rtwdev->io->do_udelay)
- rtwdev->io->do_udelay(rtwdev, us);
- else
- udelay(us);
+ rtwdev->io->do_udelay(rtwdev, us);
}
static inline void rtw89_io_mdelay(struct rtw89_dev *rtwdev, u32 ms)
{
- if (rtwdev->io->do_mdelay)
- rtwdev->io->do_mdelay(rtwdev, ms);
- else
- mdelay(ms);
+ rtwdev->io->do_mdelay(rtwdev, ms);
}
static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 535cc2ad8611..7cf51e78ce98 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -12916,8 +12916,10 @@ static int rtw89_fw_cmd_ofld_enqueue(struct rtw89_dev *rtwdev,
}
static const struct rtw89_io_ops rtw89_raw_io = {
- .pack = NULL,
- .unpack = NULL,
+ .pack = rtw89_raw_io_pack,
+ .unpack = rtw89_raw_io_unpack,
+ .do_udelay = rtw89_raw_io_udelay,
+ .do_mdelay = rtw89_raw_io_mdelay,
.write8 = rtw89_raw_write8,
.write16 = rtw89_raw_write16,
.write32 = rtw89_raw_write32,
@@ -13096,7 +13098,7 @@ static void rtw89_fw_cmd_ofld_udelay(struct rtw89_dev *rtwdev, u32 us)
ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
if (ret)
- udelay(us);
+ rtw89_raw_io.do_udelay(rtwdev, us);
}
static void rtw89_fw_cmd_ofld_mdelay(struct rtw89_dev *rtwdev, u32 ms)
@@ -13110,7 +13112,7 @@ static void rtw89_fw_cmd_ofld_mdelay(struct rtw89_dev *rtwdev, u32 ms)
ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
if (ret)
- mdelay(ms);
+ rtw89_raw_io.do_mdelay(rtwdev, ms);
}
static const struct rtw89_io_ops rtw89_fw_cmd_ofld_io = {
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH rtw-next 6/7] wifi: rtw89: coex: offload 8852C IO writes via firmware CMD pack region
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
` (4 preceding siblings ...)
2026-09-23 7:13 ` [PATCH rtw-next 5/7] wifi: rtw89: add instance of IO ops for (un)pack and [um]delay Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 7/7] wifi: rtw89: coex: batch PTA init with masked IO offload Ping-Ke Shih
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Ching-Te Ku <ku920601@realtek.com>
On USB, 8852C is the only chip with .support_fw_cmd_ofld set, which
routes register writes through the FW command offload path via the
transparent io_ops indirection. The coex layer never entered an
rtw89_io_pack() region, so its register writes were always issued
individually instead of being batched to the firmware.
Wrap the RF LUT and GNT write sequences in rtw8852c_btc_init_cfg(),
rtw8852c_btc_wl_s1_standby() and rtw8852c_set_wl_lna2() with
rtw89_io_pack()/rtw89_io_unpack() so that on USB these writes are
enqueued and flushed as a single FW command batch. On PCIe the pack
region is a no-op and raw MMIO proceeds unchanged.
Only write_rf partial-mask, write-only sequences are offloaded, for
which the firmware performs the read-modify-write. Driver-side
same-register read-modify-write helpers and BB phy_write32 flows are
kept outside the pack region to avoid the offload full-dword
overwrite hazard.
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index c68959b63a01..7649706b67e6 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2706,6 +2706,8 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true);
chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true);
+ rtw89_io_pack(rtwdev);
+
/* set rf gnt debug off */
rtw89_write_rf(rtwdev, RF_PATH_A, RR_WLSEL, RFREG_MASK, 0x0);
rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0);
@@ -2733,6 +2735,8 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
rtw89_write32_set(rtwdev,
R_AX_BT_CNT_CFG, B_AX_BT_CNT_EN |
B_AX_BT_CNT_RST_V1);
+
+ rtw89_io_unpack(rtwdev);
}
static
@@ -2888,6 +2892,8 @@ void rtw8852c_btc_update_bt_cnt(struct rtw89_dev *rtwdev)
static
void rtw8852c_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state)
{
+ rtw89_io_pack(rtwdev);
+
rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x80000);
rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1);
rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD1, RFREG_MASK, 0x620);
@@ -2901,6 +2907,8 @@ void rtw8852c_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state)
RFREG_MASK, 0x208);
rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0);
+
+ rtw89_io_unpack(rtwdev);
}
static void rtw8852c_set_wl_lna2(struct rtw89_dev *rtwdev, u8 level)
@@ -2910,6 +2918,8 @@ static void rtw8852c_set_wl_lna2(struct rtw89_dev *rtwdev, u8 level)
* To improve BT ACI in co-rx
*/
+ rtw89_io_pack(rtwdev);
+
switch (level) {
case 0: /* default */
rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x1000);
@@ -2936,6 +2946,8 @@ static void rtw8852c_set_wl_lna2(struct rtw89_dev *rtwdev, u8 level)
rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0);
break;
}
+
+ rtw89_io_unpack(rtwdev);
}
static void rtw8852c_btc_set_wl_rx_gain(struct rtw89_dev *rtwdev, u32 level)
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH rtw-next 7/7] wifi: rtw89: coex: batch PTA init with masked IO offload
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
` (5 preceding siblings ...)
2026-09-23 7:13 ` [PATCH rtw-next 6/7] wifi: rtw89: coex: offload 8852C IO writes via firmware CMD pack region Ping-Ke Shih
@ 2026-09-23 7:13 ` Ping-Ke Shih
6 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-23 7:13 UTC (permalink / raw)
To: linux-wireless; +Cc: ku920601, kevin_yang
From: Ching-Te Ku <ku920601@realtek.com>
On USB, the register writes in coex init cannot be fully batched
into a single H2C because the write32 IO offload only carries
MASKDWORD, i.e. a full-dword overwrite. Read-modify-write helpers
derive the new value from a driver-side read that cannot observe
other writes still queued in the same pack region, so packing a
same-register sequence would drop bits. mac_coex_init_v1() and
btc_set_wl_pri() were thus left outside the pack region and issued
as separate H2C commands, costing hundreds of ms.
Add write8_mask/write16_mask/write32_mask to the IO ops. For the raw
IO path, these ops are implemented as direct read-modify-write on the
hardware. For the firmware offload path, they forward the field mask
to the FW so it can perform the read-modify-write server-side,
removing the dependency on a driver-side read of a register whose
new value may still be queued.
Extract the raw read-modify-write bodies of write8_set, write16_set,
write32_set, write8_clr, write16_clr, write32_clr, write8_mask,
write16_mask, and write32_mask into rtw89_raw_write*() helpers,
grouping raw_* variants before the io-dispatching thin wrappers.
Replace the original functions with thin wrappers that dispatch
through rtwdev->io, removing the inline capability checks. With that
in place, extend the 8852c PTA init pack region to cover
mac_coex_init_v1() and btc_set_wl_pri().
Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/core.h | 118 ++++++++++++++----
drivers/net/wireless/realtek/rtw89/fw.c | 112 +++++++++++++++++
drivers/net/wireless/realtek/rtw89/fw.h | 8 +-
drivers/net/wireless/realtek/rtw89/rtw8852c.c | 4 +-
4 files changed, 213 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 128667fb95b0..762d0db8b721 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -7591,6 +7591,18 @@ struct rtw89_io_ops {
void (*phy_write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data);
void (*write_rf)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path,
u32 addr, u32 mask, u32 data);
+ void (*write8_set)(struct rtw89_dev *rtwdev, u32 addr, u8 bit);
+ void (*write16_set)(struct rtw89_dev *rtwdev, u32 addr, u16 bit);
+ void (*write32_set)(struct rtw89_dev *rtwdev, u32 addr, u32 bit);
+ void (*write8_clr)(struct rtw89_dev *rtwdev, u32 addr, u8 bit);
+ void (*write16_clr)(struct rtw89_dev *rtwdev, u32 addr, u16 bit);
+ void (*write32_clr)(struct rtw89_dev *rtwdev, u32 addr, u32 bit);
+ void (*write8_mask)(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
+ u8 data);
+ void (*write16_mask)(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
+ u16 data);
+ void (*write32_mask)(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
+ u32 data);
};
struct rtw89_dev {
@@ -8183,57 +8195,93 @@ static inline void rtw89_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data)
}
static inline void
-rtw89_write8_set(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
+rtw89_raw_write8_set(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
{
u8 val;
val = rtw89_read8(rtwdev, addr);
- rtw89_write8(rtwdev, addr, val | bit);
+ rtw89_raw_write8(rtwdev, addr, val | bit);
}
static inline void
-rtw89_write16_set(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
+rtw89_raw_write16_set(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
{
u16 val;
val = rtw89_read16(rtwdev, addr);
- rtw89_write16(rtwdev, addr, val | bit);
+ rtw89_raw_write16(rtwdev, addr, val | bit);
}
static inline void
-rtw89_write32_set(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
+rtw89_raw_write32_set(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
{
u32 val;
val = rtw89_read32(rtwdev, addr);
- rtw89_write32(rtwdev, addr, val | bit);
+ rtw89_raw_write32(rtwdev, addr, val | bit);
}
static inline void
-rtw89_write8_clr(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
+rtw89_write8_set(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
+{
+ rtwdev->io->write8_set(rtwdev, addr, bit);
+}
+
+static inline void
+rtw89_write16_set(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
+{
+ rtwdev->io->write16_set(rtwdev, addr, bit);
+}
+
+static inline void
+rtw89_write32_set(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
+{
+ rtwdev->io->write32_set(rtwdev, addr, bit);
+}
+
+static inline void
+rtw89_raw_write8_clr(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
{
u8 val;
val = rtw89_read8(rtwdev, addr);
- rtw89_write8(rtwdev, addr, val & ~bit);
+ rtw89_raw_write8(rtwdev, addr, val & ~bit);
}
static inline void
-rtw89_write16_clr(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
+rtw89_raw_write16_clr(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
{
u16 val;
val = rtw89_read16(rtwdev, addr);
- rtw89_write16(rtwdev, addr, val & ~bit);
+ rtw89_raw_write16(rtwdev, addr, val & ~bit);
}
static inline void
-rtw89_write32_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
+rtw89_raw_write32_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
{
u32 val;
val = rtw89_read32(rtwdev, addr);
- rtw89_write32(rtwdev, addr, val & ~bit);
+ rtw89_raw_write32(rtwdev, addr, val & ~bit);
+}
+
+static inline void
+rtw89_write8_clr(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
+{
+ rtwdev->io->write8_clr(rtwdev, addr, bit);
+}
+
+static inline void
+rtw89_write16_clr(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
+{
+ rtwdev->io->write16_clr(rtwdev, addr, bit);
+}
+
+static inline void
+rtw89_write32_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
+{
+ rtwdev->io->write32_clr(rtwdev, addr, bit);
}
static inline u32
@@ -8275,46 +8323,66 @@ rtw89_read8_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask)
return ret;
}
+static inline void
+rtw89_raw_write8_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u8 data)
+{
+ u8 orig, set;
+
+ orig = rtw89_read8(rtwdev, addr);
+ set = (orig & ~mask) | (data & mask);
+ rtw89_raw_write8(rtwdev, addr, set);
+}
+
+static inline void
+rtw89_raw_write16_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u16 data)
+{
+ u16 orig, set;
+
+ orig = rtw89_read16(rtwdev, addr);
+ set = (orig & ~mask) | (data & mask);
+ rtw89_raw_write16(rtwdev, addr, set);
+}
+
+static inline void
+rtw89_raw_write32_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data)
+{
+ u32 orig, set;
+
+ orig = rtw89_read32(rtwdev, addr);
+ set = (orig & ~mask) | (data & mask);
+ rtw89_raw_write32(rtwdev, addr, set);
+}
+
static inline void
rtw89_write32_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data)
{
u32 shift = __ffs(mask);
- u32 orig;
- u32 set;
WARN(addr & 0x3, "should be 4-byte aligned, addr = 0x%08x\n", addr);
- orig = rtw89_read32(rtwdev, addr);
- set = (orig & ~mask) | ((data << shift) & mask);
- rtw89_write32(rtwdev, addr, set);
+ rtwdev->io->write32_mask(rtwdev, addr, mask, (data << shift) & mask);
}
static inline void
rtw89_write16_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u16 data)
{
u32 shift;
- u16 orig, set;
mask &= 0xffff;
shift = __ffs(mask);
- orig = rtw89_read16(rtwdev, addr);
- set = (orig & ~mask) | ((data << shift) & mask);
- rtw89_write16(rtwdev, addr, set);
+ rtwdev->io->write16_mask(rtwdev, addr, mask, (data << shift) & mask);
}
static inline void
rtw89_write8_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u8 data)
{
u32 shift;
- u8 orig, set;
mask &= 0xff;
shift = __ffs(mask);
- orig = rtw89_read8(rtwdev, addr);
- set = (orig & ~mask) | ((data << shift) & mask);
- rtw89_write8(rtwdev, addr, set);
+ rtwdev->io->write8_mask(rtwdev, addr, mask, (data << shift) & mask);
}
static inline u32
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 7cf51e78ce98..b1cfde6278c3 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -12923,6 +12923,15 @@ static const struct rtw89_io_ops rtw89_raw_io = {
.write8 = rtw89_raw_write8,
.write16 = rtw89_raw_write16,
.write32 = rtw89_raw_write32,
+ .write8_set = rtw89_raw_write8_set,
+ .write16_set = rtw89_raw_write16_set,
+ .write32_set = rtw89_raw_write32_set,
+ .write8_clr = rtw89_raw_write8_clr,
+ .write16_clr = rtw89_raw_write16_clr,
+ .write32_clr = rtw89_raw_write32_clr,
+ .write8_mask = rtw89_raw_write8_mask,
+ .write16_mask = rtw89_raw_write16_mask,
+ .write32_mask = rtw89_raw_write32_mask,
.phy_write8 = rtw89_raw_phy_write8,
.phy_write16 = rtw89_raw_phy_write16,
.phy_write32 = rtw89_raw_phy_write32,
@@ -13031,6 +13040,100 @@ void rtw89_fw_cmd_ofld_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data)
rtw89_raw_io.write32(rtwdev, addr, data);
}
+static void
+rtw89_fw_cmd_ofld_write8_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
+ u8 data)
+{
+ u32 dword_mask = RTW89_W8_MASK_OF_ALIGNED_ADDR(addr);
+ u32 shift = RTW89_W8_SHIFT_OF_ALIGNED_ADDR(addr);
+ struct rtw89_fw_cmd_ofld_arg cmd = {
+ .src = RTW89_FW_CMD_OFLD_SRC_MAC,
+ .type = RTW89_FW_CMD_OFLD_WRITE,
+ .offset = ALIGN_DOWN(addr, 4),
+ .mask = (mask << shift) & dword_mask,
+ .value = (data << shift) & dword_mask,
+ };
+ int ret;
+
+ ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
+ if (ret)
+ rtw89_raw_io.write8_mask(rtwdev, addr, mask, data);
+}
+
+static void
+rtw89_fw_cmd_ofld_write16_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
+ u16 data)
+{
+ u32 dword_mask = RTW89_W16_MASK_OF_ALIGNED_ADDR(addr);
+ u32 shift = RTW89_W16_SHIFT_OF_ALIGNED_ADDR(addr);
+ struct rtw89_fw_cmd_ofld_arg cmd = {
+ .src = RTW89_FW_CMD_OFLD_SRC_MAC,
+ .type = RTW89_FW_CMD_OFLD_WRITE,
+ .offset = ALIGN_DOWN(addr, 4),
+ .mask = (mask << shift) & dword_mask,
+ .value = (data << shift) & dword_mask,
+ };
+ int ret;
+
+ ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
+ if (ret)
+ rtw89_raw_io.write16_mask(rtwdev, addr, mask, data);
+}
+
+static void
+rtw89_fw_cmd_ofld_write32_mask(struct rtw89_dev *rtwdev, u32 addr, u32 mask,
+ u32 data)
+{
+ struct rtw89_fw_cmd_ofld_arg cmd = {
+ .src = RTW89_FW_CMD_OFLD_SRC_MAC,
+ .type = RTW89_FW_CMD_OFLD_WRITE,
+ .offset = addr,
+ .mask = mask,
+ .value = data,
+ };
+ int ret;
+
+ ret = rtw89_fw_cmd_ofld_enqueue(rtwdev, &cmd);
+ if (ret)
+ rtw89_raw_io.write32_mask(rtwdev, addr, mask, data);
+}
+
+static void
+rtw89_fw_cmd_ofld_write8_set(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
+{
+ rtw89_fw_cmd_ofld_write8_mask(rtwdev, addr, bit, bit);
+}
+
+static void
+rtw89_fw_cmd_ofld_write16_set(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
+{
+ rtw89_fw_cmd_ofld_write16_mask(rtwdev, addr, bit, bit);
+}
+
+static void
+rtw89_fw_cmd_ofld_write32_set(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
+{
+ rtw89_fw_cmd_ofld_write32_mask(rtwdev, addr, bit, bit);
+}
+
+static void
+rtw89_fw_cmd_ofld_write8_clr(struct rtw89_dev *rtwdev, u32 addr, u8 bit)
+{
+ rtw89_fw_cmd_ofld_write8_mask(rtwdev, addr, bit, 0);
+}
+
+static void
+rtw89_fw_cmd_ofld_write16_clr(struct rtw89_dev *rtwdev, u32 addr, u16 bit)
+{
+ rtw89_fw_cmd_ofld_write16_mask(rtwdev, addr, bit, 0);
+}
+
+static void
+rtw89_fw_cmd_ofld_write32_clr(struct rtw89_dev *rtwdev, u32 addr, u32 bit)
+{
+ rtw89_fw_cmd_ofld_write32_mask(rtwdev, addr, bit, 0);
+}
+
static void rtw89_fw_cmd_ofld_write_rf_ddv(struct rtw89_dev *rtwdev,
struct rtw89_fw_cmd_ofld_arg *cmd,
enum rtw89_rf_path rf_path, u32 addr, u32 mask,
@@ -13127,6 +13230,15 @@ static const struct rtw89_io_ops rtw89_fw_cmd_ofld_io = {
.phy_write16 = rtw89_fw_cmd_ofld_phy_write16,
.phy_write32 = rtw89_fw_cmd_ofld_phy_write32,
.write_rf = rtw89_fw_cmd_ofld_write_rf,
+ .write8_set = rtw89_fw_cmd_ofld_write8_set,
+ .write16_set = rtw89_fw_cmd_ofld_write16_set,
+ .write32_set = rtw89_fw_cmd_ofld_write32_set,
+ .write8_clr = rtw89_fw_cmd_ofld_write8_clr,
+ .write16_clr = rtw89_fw_cmd_ofld_write16_clr,
+ .write32_clr = rtw89_fw_cmd_ofld_write32_clr,
+ .write8_mask = rtw89_fw_cmd_ofld_write8_mask,
+ .write16_mask = rtw89_fw_cmd_ofld_write16_mask,
+ .write32_mask = rtw89_fw_cmd_ofld_write32_mask,
};
const struct rtw89_io_ops *
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 473278f6bbea..f8839d6cd3bb 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -3281,8 +3281,12 @@ struct rtw89_h2c_cmd_ofld {
#define RTW89_H2C_CMD_OFLD_W1_BASE_OFFSET GENMASK(31, 16)
#define RTW89_H2C_CMD_OFLD_W2_VALUE GENMASK(31, 0)
#define RTW89_H2C_CMD_OFLD_W3_MASK GENMASK(31, 0)
-#define RTW89_W8_MASK_OF_ALIGNED_ADDR(offset) (0xff << (((offset) & 0x3) << 3))
-#define RTW89_W16_MASK_OF_ALIGNED_ADDR(offset) (0xffff << (((offset) & 0x2) * 8))
+#define RTW89_W8_SHIFT_OF_ALIGNED_ADDR(offset) (((offset) & 0x3) << 3)
+#define RTW89_W16_SHIFT_OF_ALIGNED_ADDR(offset) (((offset) & 0x2) << 3)
+#define RTW89_W8_MASK_OF_ALIGNED_ADDR(offset) \
+ (0xff << RTW89_W8_SHIFT_OF_ALIGNED_ADDR(offset))
+#define RTW89_W16_MASK_OF_ALIGNED_ADDR(offset) \
+ (0xffff << RTW89_W16_SHIFT_OF_ALIGNED_ADDR(offset))
#define RTW89_FW_CMD_OFLD_NR 125
struct rtw89_fw_cmd_ofld_info {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 7649706b67e6..624f23b3f2a1 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2699,6 +2699,8 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
.direction = RTW89_MAC_AX_COEX_INNER,
};
+ rtw89_io_pack(rtwdev);
+
/* PTA init */
rtw89_mac_coex_init_v1(rtwdev, &coex_params);
@@ -2706,8 +2708,6 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_TX_RESP, true);
chip->ops->btc_set_wl_pri(rtwdev, BTC_PRI_MASK_BEACON, true);
- rtw89_io_pack(rtwdev);
-
/* set rf gnt debug off */
rtw89_write_rf(rtwdev, RF_PATH_A, RR_WLSEL, RFREG_MASK, 0x0);
rtw89_write_rf(rtwdev, RF_PATH_B, RR_WLSEL, RFREG_MASK, 0x0);
--
2.25.1
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping
2026-09-23 7:13 ` [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping Ping-Ke Shih
@ 2026-09-30 2:14 ` Ping-Ke Shih
0 siblings, 0 replies; 9+ messages in thread
From: Ping-Ke Shih @ 2026-09-30 2:14 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: ku920601, kevin_yang
Ping-Ke Shih <pkshih@realtek.com> wrote:
> From: Ching-Te Ku <ku920601@realtek.com>
>
> _chk_btc_report() validated the reported firmware struct version only
> for the control report, so a version mismatch on any other report type
> was copied in silently and left no trace, making a ver_defs or firmware
> version error hard to diagnose.
>
> Read the reported fver, which is the leading field of every report
> struct, and when it differs from the driver-selected version set the
> per-type bit in fver_mismch and emit a debug line. The length-valid
> report is still processed, because the driver must stay compatible with
> every released firmware and a mismatch usually points at a ver_defs
> entry that needs fixing rather than a report that should be discarded.
>
> Signed-off-by: Ching-Te Ku <ku920601@realtek.com>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
7 patch(es) applied to rtw-next branch of rtw.git, thanks.
0266773d404b wifi: rtw89: coex: log FCX report version mismatch without dropping
0104c69ba225 wifi: rtw89: coex: add fbtc_rpt_ctrl v205 report struct and handling
6047d2f7efd0 wifi: rtw89: coex: Add firmware 0.27.130.1 support for RTL8852C
d6c34b67ad5c wifi: rtw89: coex: fix BT scoreboard update for non-C2H paths
5f57e5453946 wifi: rtw89: add instance of IO ops for (un)pack and [um]delay
6d0c77424034 wifi: rtw89: coex: offload 8852C IO writes via firmware CMD pack region
6c095c657b31 wifi: rtw89: coex: batch PTA init with masked IO offload
---
https://github.com/pkshih/rtw.git
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-09-30 2:14 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23 7:13 [PATCH rtw-next 0/7] wifi: rtw89: coex: update to support newer firmware especially RTL8852C Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 1/7] wifi: rtw89: coex: log FCX report version mismatch without dropping Ping-Ke Shih
2026-09-30 2:14 ` Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 2/7] wifi: rtw89: coex: add fbtc_rpt_ctrl v205 report struct and handling Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 3/7] wifi: rtw89: coex: Add firmware 0.27.130.1 support for RTL8852C Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 4/7] wifi: rtw89: coex: fix BT scoreboard update for non-C2H paths Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 5/7] wifi: rtw89: add instance of IO ops for (un)pack and [um]delay Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 6/7] wifi: rtw89: coex: offload 8852C IO writes via firmware CMD pack region Ping-Ke Shih
2026-09-23 7:13 ` [PATCH rtw-next 7/7] wifi: rtw89: coex: batch PTA init with masked IO offload Ping-Ke Shih
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox