Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH] wifi: ath10k: sdio: add missing lock protection in ath10k_sdio_fw_crashed_dump()
From: Ziyi Guo @ 2026-01-23  4:58 UTC (permalink / raw)
  To: Jeff Johnson; +Cc: linux-wireless, ath10k, linux-kernel, Ziyi Guo

ath10k_sdio_fw_crashed_dump() calls ath10k_coredump_new() which requires
ar->dump_mutex to be held, as indicated by lockdep_assert_held() in that
function. However, the SDIO implementation does not acquire this lock,
unlike the PCI and SNOC implementations which properly hold the mutex.

Additionally, ar->stats.fw_crash_counter is documented as protected by
ar->data_lock in core.h, but the SDIO implementation modifies it without
holding this spinlock.

Add the missing mutex_lock()/mutex_unlock() around the coredump
operations, and add spin_lock_bh()/spin_unlock_bh() around the
fw_crash_counter increment, following the pattern used in
ath10k_pci_fw_dump_work() and ath10k_snoc_fw_crashed_dump().

Fixes: 3c45f21af84e ("ath10k: sdio: add firmware coredump support")
Signed-off-by: Ziyi Guo <n7l8m4@u.northwestern.edu>
---
 drivers/net/wireless/ath/ath10k/sdio.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index c06d50db40b8..00d0556dafef 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -2487,7 +2487,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
 	if (fast_dump)
 		ath10k_bmi_start(ar);
 
+	mutex_lock(&ar->dump_mutex);
+
+	spin_lock_bh(&ar->data_lock);
 	ar->stats.fw_crash_counter++;
+	spin_unlock_bh(&ar->data_lock);
 
 	ath10k_sdio_disable_intrs(ar);
 
@@ -2505,6 +2509,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
 
 	ath10k_sdio_enable_intrs(ar);
 
+	mutex_unlock(&ar->dump_mutex);
+
 	ath10k_core_start_recovery(ar);
 }
 
-- 
2.34.1


^ permalink raw reply related

* [patch] wifi: mt76: mt7921: fix ROC abort flow interruption in mt7921_roc_work
From: Quan Zhou @ 2026-01-23  2:16 UTC (permalink / raw)
  To: Felix Fietkau, Lorenzo Bianconi
  Cc: Sean Wang, Deren Wu, Ryder Lee, Shayne Chen, Leon Yen,
	Ming Yen Hsieh, Allan Wang, Sarick Jiang, Posh Sun, Shengxi Xu,
	Eric-SY Chang, Michael Lo, CH Yeh, Robin Chiu, linux-wireless,
	linux-mediatek, Quan Zhou, stable

The mt7921_set_roc API may be executed concurrently with mt7921_roc_work,
specifically between the following code paths:

- The check and clear of MT76_STATE_ROC in mt7921_roc_work:
    if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
        return;

- The execution of ieee80211_iterate_active_interfaces.

This race condition can interrupt the ROC abort flow, resulting in
the ROC process failing to abort as expected.

To address this defect, the modification of MT76_STATE_ROC is now
protected by mt792x_mutex_acquire(phy->dev). This ensures that
changes to the ROC state are properly synchronized, preventing
race conditions and ensuring the ROC abort flow is not interrupted.

Fixes: 034ae28b56f1 ("wifi: mt76: mt7921: introduce remain_on_channel support")
Cc: stable@vger.kernel.org
Signed-off-by: Quan Zhou <quan.zhou@mediatek.com>
Reviewed-by: Sean Wang <sean.wang@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt7921/main.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 5fae9a6e273c..021335805acb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -387,10 +387,11 @@ void mt7921_roc_work(struct work_struct *work)
 	phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
 						roc_work);
 
-	if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
-		return;
-
 	mt792x_mutex_acquire(phy->dev);
+	if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) {
+		mt792x_mutex_release(phy->dev);
+		return;
+	}
 	ieee80211_iterate_active_interfaces(phy->mt76->hw,
 					    IEEE80211_IFACE_ITER_RESUME_ALL,
 					    mt7921_roc_iter, phy);
-- 
2.45.2


^ permalink raw reply related

* [PATCH rtw-next 11/11] wifi: rtw89: regd: update regulatory map to R73-R54
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

From: Zong-Zhe Yang <kevin_yang@realtek.com>

Sync Realtek Channel Plan R73 and Realtek Regulatory R54.
Configure 6 GHz field of Realtek regd for the following countries.
PY NA BD ID VN TN GL GP YT EH

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/regd.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c
index c3425ed44732..28466cb35ea2 100644
--- a/drivers/net/wireless/realtek/rtw89/regd.c
+++ b/drivers/net/wireless/realtek/rtw89/regd.c
@@ -38,7 +38,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("MX", RTW89_MEXICO, RTW89_MEXICO, RTW89_FCC, 0x0),
 	COUNTRY_REGD("NI", RTW89_FCC, RTW89_FCC, RTW89_NA, 0x0),
 	COUNTRY_REGD("PA", RTW89_FCC, RTW89_FCC, RTW89_NA, 0x0),
-	COUNTRY_REGD("PY", RTW89_FCC, RTW89_FCC, RTW89_NA, 0x0),
+	COUNTRY_REGD("PY", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
 	COUNTRY_REGD("PE", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
 	COUNTRY_REGD("US", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x1),
 	COUNTRY_REGD("UY", RTW89_FCC, RTW89_FCC, RTW89_NA, 0x0),
@@ -95,7 +95,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("MK", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("MA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("MZ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
-	COUNTRY_REGD("NA", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("NA", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("NG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("OM", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("QA", RTW89_QATAR, RTW89_QATAR, RTW89_QATAR, 0x0),
@@ -111,12 +111,12 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("AE", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("YE", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("ZW", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
-	COUNTRY_REGD("BD", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("BD", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("KH", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("CN", RTW89_CN, RTW89_CN, RTW89_CN, 0x0),
 	COUNTRY_REGD("HK", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("IN", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
-	COUNTRY_REGD("ID", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("ID", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("KR", RTW89_KCC, RTW89_KCC, RTW89_KCC, 0x1),
 	COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
@@ -125,7 +125,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("TH", RTW89_THAILAND, RTW89_THAILAND, RTW89_THAILAND, 0x0),
-	COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA, 0x0),
 	COUNTRY_REGD("NZ", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA, 0x0),
 	COUNTRY_REGD("PG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
@@ -134,7 +134,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("JM", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
 	COUNTRY_REGD("AN", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
 	COUNTRY_REGD("TT", RTW89_FCC, RTW89_FCC, RTW89_NA, 0x0),
-	COUNTRY_REGD("TN", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("TN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("AF", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("DZ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("AS", RTW89_FCC, RTW89_FCC, RTW89_NA, 0x0),
@@ -187,9 +187,9 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("GM", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
-	COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
-	COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
 	COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("GN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
@@ -214,7 +214,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("MQ", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("MR", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("MU", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
-	COUNTRY_REGD("YT", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("YT", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("FM", RTW89_FCC, RTW89_FCC, RTW89_FCC, 0x0),
 	COUNTRY_REGD("MD", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("MN", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
@@ -260,7 +260,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
 	COUNTRY_REGD("UZ", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("VU", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("WF", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
-	COUNTRY_REGD("EH", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
+	COUNTRY_REGD("EH", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI, 0x0),
 	COUNTRY_REGD("ZM", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("CU", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
 	COUNTRY_REGD("IR", RTW89_ETSI, RTW89_ETSI, RTW89_NA, 0x0),
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 10/11] wifi: rtw89: pci: validate release report content before using for RTL8922DE
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

The commit 957eda596c76
("wifi: rtw89: pci: validate sequence number of TX release report")
does validation on existing chips, which somehow a release report of SKB
becomes malformed. As no clear cause found, add rules ahead for RTL8922DE
to avoid crash if it happens.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 093960d7279f..b8135cf15d13 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -604,8 +604,10 @@ static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, void *rpp)
 
 	info->parse_rpp(rtwdev, rpp, &rpp_info);
 
-	if (unlikely(rpp_info.txch == RTW89_TXCH_CH12)) {
-		rtw89_warn(rtwdev, "should no fwcmd release report\n");
+	if (unlikely(rpp_info.txch >= RTW89_TXCH_NUM ||
+		     info->tx_dma_ch_mask & BIT(rpp_info.txch))) {
+		rtw89_warn(rtwdev, "should no release report on txch %d\n",
+			   rpp_info.txch);
 		return;
 	}
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 09/11] wifi: rtw89: get designated link to replace link instance 0
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

From: Zong-Zhe Yang <kevin_yang@realtek.com>

Clean up some places where still to get link instance 0 directly.
Since now MLSR switch is supported, it's not guaranteed to always
run on link instance 0. So, prefer to get designated link in most
cases.

For now, the only exception is MCC (multi-channel concurrency) case.
How to fill content of its H2C command depends on how to choose link
instance, so cannot simply change it as above. Will handle MCC case
separately afterwards.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/chan.c     | 8 ++++----
 drivers/net/wireless/realtek/rtw89/fw.c       | 7 ++-----
 drivers/net/wireless/realtek/rtw89/mac80211.c | 4 ++--
 3 files changed, 8 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c
index c0af61992226..9b2f6f0a00fd 100644
--- a/drivers/net/wireless/realtek/rtw89/chan.c
+++ b/drivers/net/wireless/realtek/rtw89/chan.c
@@ -372,8 +372,8 @@ static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev,
 	if (unlikely(!rtwvif_link->chanctx_assigned))
 		return;
 
-	cur = rtw89_vif_get_link_inst(rtwvif, 0);
-	if (!cur || !cur->chanctx_assigned)
+	cur = rtw89_get_designated_link(rtwvif);
+	if (unlikely(!cur) || !cur->chanctx_assigned)
 		return;
 
 	if (cur == rtwvif_link)
@@ -522,8 +522,8 @@ static void rtw89_entity_recalc_mgnt_roles(struct rtw89_dev *rtwdev)
 	}
 
 	/* To be consistent with legacy behavior, expect the first active role
-	 * which uses RTW89_CHANCTX_0 to put at position 0, and make its first
-	 * link instance take RTW89_CHANCTX_0. (normalizing)
+	 * which uses RTW89_CHANCTX_0 to put at position 0 and its designated
+	 * link take RTW89_CHANCTX_0. (normalizing)
 	 */
 	list_for_each_entry(role, &mgnt->active_list, mgnt_entry) {
 		for (i = 0; i < role->links_inst_valid_num; i++) {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 9e88fd6d735a..f84726f04669 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -9027,12 +9027,9 @@ static void rtw89_hw_scan_set_extra_op_info(struct rtw89_dev *rtwdev,
 		if (tmp == scan_rtwvif)
 			continue;
 
-		tmp_link = rtw89_vif_get_link_inst(tmp, 0);
-		if (unlikely(!tmp_link)) {
-			rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN,
-				    "hw scan: no HW-0 link for extra op\n");
+		tmp_link = rtw89_get_designated_link(tmp);
+		if (unlikely(!tmp_link))
 			continue;
-		}
 
 		tmp_chan = rtw89_chan_get(rtwdev, tmp_link->chanctx_idx);
 		*ext = (struct rtw89_hw_scan_extra_op){
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index ba71709a9bc9..315bb0d0759f 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -1438,9 +1438,9 @@ static void rtw89_ops_channel_switch_beacon(struct ieee80211_hw *hw,
 
 	BUILD_BUG_ON(RTW89_MLD_NON_STA_LINK_NUM != 1);
 
-	rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0);
+	rtwvif_link = rtw89_get_designated_link(rtwvif);
 	if (unlikely(!rtwvif_link)) {
-		rtw89_err(rtwdev, "chsw bcn: find no link on HW-0\n");
+		rtw89_err(rtwdev, "chsw bcn: find no designated link\n");
 		return;
 	}
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 08/11] wifi: rtw89: 8922a: configure FW version for SIM_SER_L0L1_BY_HALT_H2C
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

From: Zong-Zhe Yang <kevin_yang@realtek.com>

After FW version 0.35.97.0, 8922A supports SIM_SER_L0L1_BY_HALT_H2C
FW feature. It allows to simulate FW L0/L1 crash under PS mode.

Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 4c50c0166d4f..9e88fd6d735a 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -922,6 +922,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
 	__DIS_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, WITH_RFK_PRE_NOTIFY, G),
 	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 84, 0, RFK_PRE_NOTIFY_MCC_V1),
 	__CFG_FW_FEAT(RTL8922A, lt, 0, 35, 84, 0, ADDR_CAM_V0),
+	__CFG_FW_FEAT(RTL8922A, ge, 0, 35, 97, 0, SIM_SER_L0L1_BY_HALT_H2C),
 };
 
 static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 07/11] wifi: rtw89: phy: add PHY C2H event dummy handler for func 1-7 and 2-10
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

The two functions aren't implemented and hard necessary by driver.
Implement dummy handler to avoid messages:

  rtw89_8922de 0000:03:00.0: PHY c2h class 1 func 7 not support
  rtw89_8922de 0000:03:00.0: PHY c2h class 2 func 10 not support

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c  | 11 +++++++++++
 drivers/net/wireless/realtek/rtw89/fw.h  |  1 +
 drivers/net/wireless/realtek/rtw89/phy.c |  4 +++-
 drivers/net/wireless/realtek/rtw89/phy.h |  5 ++++-
 4 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 8a33a63619d5..4c50c0166d4f 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -7783,6 +7783,17 @@ void rtw89_fw_free_all_early_h2c(struct rtw89_dev *rtwdev)
 	__rtw89_fw_free_all_early_h2c(rtwdev);
 }
 
+void rtw89_fw_c2h_dummy_handler(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+	struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(c2h);
+	u8 category = attr->category;
+	u8 class = attr->class;
+	u8 func = attr->func;
+
+	rtw89_debug(rtwdev, RTW89_DBG_FW,
+		    "C2H cate=%u cls=%u func=%u is dummy\n", category, class, func);
+}
+
 static void rtw89_fw_c2h_parse_attr(struct sk_buff *c2h)
 {
 	const struct rtw89_c2h_hdr *hdr = (const struct rtw89_c2h_hdr *)c2h->data;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index da802482c47d..d45b6ea6ea1b 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -5249,6 +5249,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v3(struct rtw89_dev *rtwdev,
 void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h);
 void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work);
 void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev);
+void rtw89_fw_c2h_dummy_handler(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len);
 int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
 			       struct rtw89_vif_link *rtwvif_link,
 			       struct rtw89_sta_link *rtwsta_link,
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 41a8ce3aaffc..6c6d5f1da867 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3332,6 +3332,7 @@ void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev,
 	[RTW89_PHY_C2H_FUNC_STS_RPT] = rtw89_phy_c2h_ra_rpt,
 	[RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT] = NULL,
 	[RTW89_PHY_C2H_FUNC_TXSTS] = NULL,
+	[RTW89_PHY_C2H_FUNC_ACCELERATE_EN] = rtw89_fw_c2h_dummy_handler,
 };
 
 static void
@@ -3419,6 +3420,7 @@ void (* const rtw89_phy_c2h_dm_handler[])(struct rtw89_dev *rtwdev,
 	[RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY] = rtw89_phy_c2h_lowrt_rty,
 	[RTW89_PHY_C2H_DM_FUNC_MCC_DIG] = NULL,
 	[RTW89_PHY_C2H_DM_FUNC_LPS] = rtw89_phy_c2h_lps_rpt,
+	[RTW89_PHY_C2H_DM_FUNC_ENV_MNTR] = rtw89_fw_c2h_dummy_handler,
 	[RTW89_PHY_C2H_DM_FUNC_FW_SCAN] = rtw89_phy_c2h_fw_scan_rpt,
 };
 
@@ -4009,7 +4011,7 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
 
 	switch (class) {
 	case RTW89_PHY_C2H_CLASS_RA:
-		if (func < RTW89_PHY_C2H_FUNC_RA_MAX)
+		if (func < ARRAY_SIZE(rtw89_phy_c2h_ra_handler))
 			handler = rtw89_phy_c2h_ra_handler[func];
 		break;
 	case RTW89_PHY_C2H_RFK_LOG:
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index a587f83b8d67..ab263738d212 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -139,7 +139,9 @@ enum rtw89_phy_c2h_ra_func {
 	RTW89_PHY_C2H_FUNC_STS_RPT,
 	RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT,
 	RTW89_PHY_C2H_FUNC_TXSTS,
-	RTW89_PHY_C2H_FUNC_RA_MAX,
+	RTW89_PHY_C2H_FUNC_ACCELERATE_EN = 0x7,
+
+	RTW89_PHY_C2H_FUNC_RA_NUM,
 };
 
 enum rtw89_phy_c2h_rfk_log_func {
@@ -168,6 +170,7 @@ enum rtw89_phy_c2h_dm_func {
 	RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY,
 	RTW89_PHY_C2H_DM_FUNC_MCC_DIG,
 	RTW89_PHY_C2H_DM_FUNC_LPS = 0x9,
+	RTW89_PHY_C2H_DM_FUNC_ENV_MNTR = 0xa,
 	RTW89_PHY_C2H_DM_FUNC_FW_SCAN = 0xc,
 	RTW89_PHY_C2H_DM_FUNC_NUM,
 };
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 06/11] wifi: rtw89: fw: correct content of DACK H2C command
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

The fields of command should be u8 instead of __le32. However, current
firmware doesn't really use the data for now, so this mistake doesn't
impact performance.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c | 6 +++---
 drivers/net/wireless/realtek/rtw89/fw.h | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 4035ec8defa8..8a33a63619d5 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -7503,9 +7503,9 @@ int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 	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);
+	h2c->len = len;
+	h2c->phy = phy_idx;
+	h2c->type = 0;
 
 	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
 			      H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK,
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index e4dbcd899ddb..da802482c47d 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -4912,9 +4912,9 @@ struct rtw89_h2c_rf_txgapk {
 } __packed;
 
 struct rtw89_h2c_rf_dack {
-	__le32 len;
-	__le32 phy;
-	__le32 type;
+	u8 len;
+	u8 phy;
+	u8 type;
 } __packed;
 
 struct rtw89_h2c_rf_rxdck_v0 {
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 05/11] wifi: rtw89: rfk: update RFK report format of IQK, DACK and TXGAPK
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

The report formats of IQK, DACK and TXGAPK are changed. Update them
accordingly.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.h  | 24 ++++++++++++-------
 drivers/net/wireless/realtek/rtw89/phy.c | 30 +++++++++++++++++++-----
 2 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 4fa982cbac49..e4dbcd899ddb 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -5005,12 +5005,16 @@ struct rtw89_c2h_rf_iqk_rpt_log {
 	u8 rsvd;
 	__le32 reload_cnt;
 	__le32 iqk_fail_cnt;
+	__le32 rf_0x18[2];
 	__le32 lok_idac[2];
 	__le32 lok_vbuf[2];
-	__le32 rftxgain[2][4];
-	__le32 rfrxgain[2][4];
-	__le32 tx_xym[2][4];
-	__le32 rx_xym[2][4];
+	__le32 rftxgain[2][6];
+	__le32 rfrxgain[2][6];
+	__le32 tx_xym[2][6];
+	__le32 rx_xym[2][6];
+	__le32 rx_wb_xym[2][32];
+	bool is_radar;
+	u8 rsvd1[3];
 } __packed;
 
 struct rtw89_c2h_rf_dpk_rpt_log {
@@ -5053,6 +5057,7 @@ struct rtw89_c2h_rf_dack_rpt_log {
 	u8 dack_fail;
 	u8 wbdck_d[2];
 	u8 rck_d;
+	u8 adgaink_ex_d;
 } __packed;
 
 struct rtw89_c2h_rf_rxdck_rpt_log {
@@ -5079,12 +5084,14 @@ struct rtw89_c2h_rf_txgapk_rpt_log {
 	u8 is_txgapk_ok;
 	u8 chk_id;
 	u8 ver;
-	u8 rsv1;
+	u8 d_bnd_ok;
+	__le32 stage[2];
+	__le16 failcode[2];
+	u8 rsvd[4];
 } __packed;
 
 struct rtw89_c2h_rf_txiqk_rpt_log {
 	u8 fw_txiqk_ver;
-	u8 rsvd;
 	u8 iqk_band[2];
 	u8 iqk_ch[2];
 	u8 iqk_bw[2];
@@ -5093,13 +5100,14 @@ struct rtw89_c2h_rf_txiqk_rpt_log {
 	bool txiqk_en;
 	bool lok_en;
 	bool lok_fail[2];
-	u8 rsvd2;
+	u8 rsvd[2];
 	__le32 iqk_times;
 	bool txiqk_nctldone[2];
-	u8 rsvd3[2];
+	u8 rsvd2[2];
 	__le32 txgain[2][6];
 	__le32 tx_iqc[2][6];
 	__le32 tx_xym[2][6][14];
+	__le32 kidx[2];
 } __packed;
 
 struct rtw89_c2h_rf_cim3k_rpt_log {
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 11f45e30d76d..41a8ce3aaffc 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3512,6 +3512,8 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 				    i, iqk->iqk_ch[i]);
 			rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_bw[%d] = %x\n",
 				    i, iqk->iqk_bw[i]);
+			rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->rf_0x18[%d] = %x\n",
+				    i, le32_to_cpu(iqk->rf_0x18[i]));
 			rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_idac[%d] = %x\n",
 				    i, le32_to_cpu(iqk->lok_idac[i]));
 			rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->lok_vbuf[%d] = %x\n",
@@ -3520,22 +3522,30 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 				    i, iqk->iqk_tx_fail[i]);
 			rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] iqk->iqk_rx_fail[%d] = %x\n",
 				    i, iqk->iqk_rx_fail[i]);
-			for (j = 0; j < 4; j++)
+			for (j = 0; j < 6; j++)
 				rtw89_debug(rtwdev, RTW89_DBG_RFK,
 					    "[IQK] iqk->rftxgain[%d][%d] = %x\n",
 					    i, j, le32_to_cpu(iqk->rftxgain[i][j]));
-			for (j = 0; j < 4; j++)
+			for (j = 0; j < 6; j++)
 				rtw89_debug(rtwdev, RTW89_DBG_RFK,
 					    "[IQK] iqk->tx_xym[%d][%d] = %x\n",
 					    i, j, le32_to_cpu(iqk->tx_xym[i][j]));
-			for (j = 0; j < 4; j++)
+			for (j = 0; j < 6; j++)
 				rtw89_debug(rtwdev, RTW89_DBG_RFK,
 					    "[IQK] iqk->rfrxgain[%d][%d] = %x\n",
 					    i, j, le32_to_cpu(iqk->rfrxgain[i][j]));
-			for (j = 0; j < 4; j++)
+			for (j = 0; j < 6; j++)
 				rtw89_debug(rtwdev, RTW89_DBG_RFK,
 					    "[IQK] iqk->rx_xym[%d][%d] = %x\n",
 					    i, j, le32_to_cpu(iqk->rx_xym[i][j]));
+
+			if (!iqk->iqk_xym_en)
+				continue;
+
+			for (j = 0; j < 32; j++)
+				rtw89_debug(rtwdev, RTW89_DBG_RFK,
+					    "[IQK] iqk->rx_wb_xym[%d][%d] = %x\n",
+					    i, j, iqk->rx_wb_xym[i][j]);
 		}
 		return;
 	case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK:
@@ -3691,8 +3701,16 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 			    le32_to_cpu(txgapk->chk_cnt));
 		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt ver = 0x%x\n",
 			    txgapk->ver);
-		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt rsv1 = %d\n",
-			    txgapk->rsv1);
+		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt d_bnd_ok = %d\n",
+			    txgapk->d_bnd_ok);
+		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt stage[0] = 0x%x\n",
+			    le32_to_cpu(txgapk->stage[0]));
+		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt stage[1] = 0x%x\n",
+			    le32_to_cpu(txgapk->stage[1]));
+		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]failcode[0] = 0x%x\n",
+			    le16_to_cpu(txgapk->failcode[0]));
+		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]failcode[1] = 0x%x\n",
+			    le16_to_cpu(txgapk->failcode[1]));
 
 		rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[0] = %*ph\n",
 			    (int)sizeof(txgapk->track_d[0]), txgapk->track_d[0]);
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 04/11] wifi: rtw89: rfk: add to print debug log of CIM3K
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

Add calibration report of CIM3K, which does calibration in firmware and
send a C2H event as debug purpose.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.h  | 27 ++++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/phy.c | 13 ++++++++++++
 drivers/net/wireless/realtek/rtw89/phy.h |  1 +
 3 files changed, 41 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 2f04138148b7..4fa982cbac49 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -5102,6 +5102,33 @@ struct rtw89_c2h_rf_txiqk_rpt_log {
 	__le32 tx_xym[2][6][14];
 } __packed;
 
+struct rtw89_c2h_rf_cim3k_rpt_log {
+	u8 cim3k_band[2];
+	u8 cim3k_ch[2];
+	u8 cim3k_bw[2];
+	u8 su_path_ok[2];
+	u8 ru_path_ok[2];
+	u8 txagc_cim3k[2];
+	u8 ther_cim3k[2];
+	u8 cim3k_gs[2];
+	__le16 cim3k_pwsf[2];
+	bool cim3k_nctldone[2];
+	u8 rsvd[2];
+	__le32 cim3k_rxiqc[2];
+	__le32 cim3k_su_coef[2][3];
+	__le16 dc_i[2];
+	__le16 dc_q[2];
+	u8 corr_val[2];
+	u8 corr_idx[2];
+	u8 rxbb_ov[2];
+	u8 cim3k_txiqc[2];
+	u8 kidx[2];
+	u8 fw_cim3k_ver;
+	bool su_cim3k_en[2];
+	bool ru_cim3k_en[2];
+	u8 rsvd1;
+} __packed;
+
 struct rtw89_c2h_rfk_report {
 	struct rtw89_c2h_hdr hdr;
 	u8 state; /* enum rtw89_rfk_report_state */
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 5f6854b7550d..11f45e30d76d 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3457,6 +3457,7 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 	struct rtw89_c2h_rf_txgapk_rpt_log *txgapk;
 	struct rtw89_c2h_rf_rxdck_rpt_log *rxdck;
 	struct rtw89_c2h_rf_txiqk_rpt_log *txiqk;
+	struct rtw89_c2h_rf_cim3k_rpt_log *cim3k;
 	struct rtw89_c2h_rf_dack_rpt_log *dack;
 	struct rtw89_c2h_rf_tssi_rpt_log *tssi;
 	struct rtw89_c2h_rf_dpk_rpt_log *dpk;
@@ -3712,6 +3713,10 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 		if (len != sizeof(*txiqk))
 			goto out;
 		return;
+	case RTW89_PHY_C2H_RFK_LOG_FUNC_CIM3K:
+		if (len != sizeof(*cim3k))
+			goto out;
+		return;
 	default:
 		break;
 	}
@@ -3854,6 +3859,13 @@ rtw89_phy_c2h_rfk_log_txiqk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 l
 			      RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK, "TXIQK");
 }
 
+static void
+rtw89_phy_c2h_rfk_log_cim3k(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+	rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+			      RTW89_PHY_C2H_RFK_LOG_FUNC_CIM3K, "CIM3K");
+}
+
 static
 void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
 					       struct sk_buff *c2h, u32 len) = {
@@ -3865,6 +3877,7 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
 	[RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk,
 	[RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr,
 	[RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK] = rtw89_phy_c2h_rfk_log_txiqk,
+	[RTW89_PHY_C2H_RFK_LOG_FUNC_CIM3K] = rtw89_phy_c2h_rfk_log_cim3k,
 };
 
 static
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 5e04bdcef4e9..a587f83b8d67 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -151,6 +151,7 @@ enum rtw89_phy_c2h_rfk_log_func {
 	RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5,
 	RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR = 9,
 	RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK = 0xc,
+	RTW89_PHY_C2H_RFK_LOG_FUNC_CIM3K = 0xe,
 
 	RTW89_PHY_C2H_RFK_LOG_FUNC_NUM,
 };
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 03/11] wifi: rtw89: rfk: add firmware command to do CIM3K
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

CIM is short for counter intermodulation products 3rd-order. Due to
non-linearity in transmit path, need a calibration to yield performance
for RF system.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c  | 41 ++++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/fw.h  | 15 +++++++++
 drivers/net/wireless/realtek/rtw89/phy.c | 17 ++++++++++
 drivers/net/wireless/realtek/rtw89/phy.h |  4 +++
 4 files changed, 77 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index fed74ad6b4bd..4035ec8defa8 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -7657,6 +7657,47 @@ int rtw89_fw_h2c_rf_txiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 	return ret;
 }
 
+int rtw89_fw_h2c_rf_cim3k(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
+			  const struct rtw89_chan *chan)
+{
+	struct rtw89_h2c_rf_cim3k *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 CIM3K\n");
+		return -ENOMEM;
+	}
+	skb_put(skb, len);
+	h2c = (struct rtw89_h2c_rf_cim3k *)skb->data;
+
+	h2c->len = len;
+	h2c->phy = phy_idx;
+	h2c->kpath = RF_AB;
+	h2c->cur_band = chan->band_type;
+	h2c->cur_bw = chan->band_width;
+	h2c->cur_ch = chan->channel;
+	h2c->cim3k_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_CIM3K_OFFOAD, 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)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index c3ad473a06f2..2f04138148b7 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -4719,6 +4719,7 @@ enum rtw89_rfk_offload_h2c_func {
 	H2C_FUNC_RFK_PRE_NOTIFY = 0x8,
 	H2C_FUNC_RFK_TAS_OFFLOAD = 0x9,
 	H2C_FUNC_RFK_TXIQK_OFFOAD = 0xc,
+	H2C_FUNC_RFK_CIM3K_OFFOAD = 0xe,
 };
 
 struct rtw89_fw_h2c_rf_get_mccch {
@@ -4948,6 +4949,18 @@ struct rtw89_h2c_rf_txiqk {
 	u8 txiqk_dbg_en;
 } __packed;
 
+struct rtw89_h2c_rf_cim3k {
+	u8 len;
+	u8 phy;
+	u8 su_cim3k_enable[2];
+	u8 ru_cim3k_enable[2];
+	u8 kpath;
+	u8 cur_band;
+	u8 cur_bw;
+	u8 cur_ch;
+	u8 cim3k_dbg_en;
+} __packed;
+
 enum rtw89_rf_log_type {
 	RTW89_RF_RUN_LOG = 0,
 	RTW89_RF_RPT_LOG = 1,
@@ -5270,6 +5283,8 @@ int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable);
 int rtw89_fw_h2c_rf_txiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 			  const struct rtw89_chan *chan);
+int rtw89_fw_h2c_rf_cim3k(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
+			  const struct rtw89_chan *chan);
 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);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 215864d1e1c7..5f6854b7550d 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -4149,6 +4149,23 @@ int rtw89_phy_rfk_txiqk_and_wait(struct rtw89_dev *rtwdev,
 }
 EXPORT_SYMBOL(rtw89_phy_rfk_txiqk_and_wait);
 
+int rtw89_phy_rfk_cim3k_and_wait(struct rtw89_dev *rtwdev,
+				 enum rtw89_phy_idx phy_idx,
+				 const struct rtw89_chan *chan,
+				 unsigned int ms)
+{
+	int ret;
+
+	rtw89_phy_rfk_report_prep(rtwdev);
+
+	ret = rtw89_fw_h2c_rf_cim3k(rtwdev, phy_idx, chan);
+	if (ret)
+		return ret;
+
+	return rtw89_phy_rfk_report_wait(rtwdev, "CIM3k", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_cim3k_and_wait);
+
 static u32 phy_tssi_get_cck_group(u8 ch)
 {
 	switch (ch) {
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 89e3bc588494..5e04bdcef4e9 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -1036,6 +1036,10 @@ int rtw89_phy_rfk_txiqk_and_wait(struct rtw89_dev *rtwdev,
 				 enum rtw89_phy_idx phy_idx,
 				 const struct rtw89_chan *chan,
 				 unsigned int ms);
+int rtw89_phy_rfk_cim3k_and_wait(struct rtw89_dev *rtwdev,
+				 enum rtw89_phy_idx phy_idx,
+				 const struct rtw89_chan *chan,
+				 unsigned int ms);
 void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev,
 					       enum rtw89_phy_idx phy,
 					       const struct rtw89_chan *chan,
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 02/11] wifi: rtw89: rfk: add to print debug log of TX IQK
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

Add report format for TX IQK, which do calibration in firmware and send
a C2H event as debug purpose.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.h  | 20 ++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/phy.c | 15 ++++++++++++++-
 drivers/net/wireless/realtek/rtw89/phy.h |  1 +
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 31402667e155..c3ad473a06f2 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -5069,6 +5069,26 @@ struct rtw89_c2h_rf_txgapk_rpt_log {
 	u8 rsv1;
 } __packed;
 
+struct rtw89_c2h_rf_txiqk_rpt_log {
+	u8 fw_txiqk_ver;
+	u8 rsvd;
+	u8 iqk_band[2];
+	u8 iqk_ch[2];
+	u8 iqk_bw[2];
+	bool tx_iqk_fail[2];
+	bool is_iqk_init;
+	bool txiqk_en;
+	bool lok_en;
+	bool lok_fail[2];
+	u8 rsvd2;
+	__le32 iqk_times;
+	bool txiqk_nctldone[2];
+	u8 rsvd3[2];
+	__le32 txgain[2][6];
+	__le32 tx_iqc[2][6];
+	__le32 tx_xym[2][6][14];
+} __packed;
+
 struct rtw89_c2h_rfk_report {
 	struct rtw89_c2h_hdr hdr;
 	u8 state; /* enum rtw89_rfk_report_state */
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index fd2e9a472518..215864d1e1c7 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3456,6 +3456,7 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 {
 	struct rtw89_c2h_rf_txgapk_rpt_log *txgapk;
 	struct rtw89_c2h_rf_rxdck_rpt_log *rxdck;
+	struct rtw89_c2h_rf_txiqk_rpt_log *txiqk;
 	struct rtw89_c2h_rf_dack_rpt_log *dack;
 	struct rtw89_c2h_rf_tssi_rpt_log *tssi;
 	struct rtw89_c2h_rf_dpk_rpt_log *dpk;
@@ -3706,7 +3707,10 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
 			goto out;
 
 		rtw89_phy_c2h_rfk_tas_pwr(rtwdev, content);
-
+		return;
+	case RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK:
+		if (len != sizeof(*txiqk))
+			goto out;
 		return;
 	default:
 		break;
@@ -3843,6 +3847,13 @@ rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32
 			      RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR, "TAS");
 }
 
+static void
+rtw89_phy_c2h_rfk_log_txiqk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+	rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+			      RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK, "TXIQK");
+}
+
 static
 void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
 					       struct sk_buff *c2h, u32 len) = {
@@ -3853,6 +3864,7 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
 	[RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI] = rtw89_phy_c2h_rfk_log_tssi,
 	[RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk,
 	[RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr,
+	[RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK] = rtw89_phy_c2h_rfk_log_txiqk,
 };
 
 static
@@ -3941,6 +3953,7 @@ bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func)
 		case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK:
 		case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI:
 		case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK:
+		case RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK:
 			return true;
 		default:
 			return false;
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 9a15dbf1c318..89e3bc588494 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -150,6 +150,7 @@ enum rtw89_phy_c2h_rfk_log_func {
 	RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI = 4,
 	RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5,
 	RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR = 9,
+	RTW89_PHY_C2H_RFK_LOG_FUNC_TXIQK = 0xc,
 
 	RTW89_PHY_C2H_RFK_LOG_FUNC_NUM,
 };
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 01/11] wifi: rtw89: rfk: add firmware command to do TX IQK
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang
In-Reply-To: <20260123013957.16418-1-pkshih@realtek.com>

TX IQK is a RF calibration, which driver call this H2C command to trigger
the calibration.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c  | 43 ++++++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/fw.h  | 15 +++++++++
 drivers/net/wireless/realtek/rtw89/phy.c | 17 ++++++++++
 drivers/net/wireless/realtek/rtw89/phy.h |  4 +++
 4 files changed, 79 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 5f98ca592a3e..fed74ad6b4bd 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -7614,6 +7614,49 @@ int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable)
 	return ret;
 }
 
+int rtw89_fw_h2c_rf_txiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
+			  const struct rtw89_chan *chan)
+{
+	struct rtw89_h2c_rf_txiqk *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 TXIQK\n");
+		return -ENOMEM;
+	}
+	skb_put(skb, len);
+	h2c = (struct rtw89_h2c_rf_txiqk *)skb->data;
+
+	h2c->len = len;
+	h2c->phy = phy_idx;
+	h2c->txiqk_enable = true;
+	h2c->is_wb_txiqk = true;
+	h2c->kpath = RF_AB;
+	h2c->cur_band = chan->band_type;
+	h2c->cur_bw = chan->band_width;
+	h2c->cur_ch = chan->channel;
+	h2c->txiqk_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_TXIQK_OFFOAD, 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)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 521702f97d50..31402667e155 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -4718,6 +4718,7 @@ enum rtw89_rfk_offload_h2c_func {
 	H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6,
 	H2C_FUNC_RFK_PRE_NOTIFY = 0x8,
 	H2C_FUNC_RFK_TAS_OFFLOAD = 0x9,
+	H2C_FUNC_RFK_TXIQK_OFFOAD = 0xc,
 };
 
 struct rtw89_fw_h2c_rf_get_mccch {
@@ -4935,6 +4936,18 @@ struct rtw89_h2c_rf_rxdck {
 	u8 is_chl_k;
 } __packed;
 
+struct rtw89_h2c_rf_txiqk {
+	u8 len;
+	u8 phy;
+	u8 txiqk_enable;
+	u8 is_wb_txiqk;
+	u8 kpath;
+	u8 cur_band;
+	u8 cur_bw;
+	u8 cur_ch;
+	u8 txiqk_dbg_en;
+} __packed;
+
 enum rtw89_rf_log_type {
 	RTW89_RF_RUN_LOG = 0,
 	RTW89_RF_RPT_LOG = 1,
@@ -5235,6 +5248,8 @@ int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
 			  const struct rtw89_chan *chan, bool is_chl_k);
 int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable);
+int rtw89_fw_h2c_rf_txiqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx,
+			  const struct rtw89_chan *chan);
 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);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index f3ef5673cb6a..fd2e9a472518 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -4119,6 +4119,23 @@ int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev,
 }
 EXPORT_SYMBOL(rtw89_phy_rfk_rxdck_and_wait);
 
+int rtw89_phy_rfk_txiqk_and_wait(struct rtw89_dev *rtwdev,
+				 enum rtw89_phy_idx phy_idx,
+				 const struct rtw89_chan *chan,
+				 unsigned int ms)
+{
+	int ret;
+
+	rtw89_phy_rfk_report_prep(rtwdev);
+
+	ret = rtw89_fw_h2c_rf_txiqk(rtwdev, phy_idx, chan);
+	if (ret)
+		return ret;
+
+	return rtw89_phy_rfk_report_wait(rtwdev, "TX_IQK", ms);
+}
+EXPORT_SYMBOL(rtw89_phy_rfk_txiqk_and_wait);
+
 static u32 phy_tssi_get_cck_group(u8 ch)
 {
 	switch (ch) {
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 0c5224780e84..9a15dbf1c318 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -1031,6 +1031,10 @@ int rtw89_phy_rfk_rxdck_and_wait(struct rtw89_dev *rtwdev,
 				 enum rtw89_phy_idx phy_idx,
 				 const struct rtw89_chan *chan,
 				 bool is_chl_k, unsigned int ms);
+int rtw89_phy_rfk_txiqk_and_wait(struct rtw89_dev *rtwdev,
+				 enum rtw89_phy_idx phy_idx,
+				 const struct rtw89_chan *chan,
+				 unsigned int ms);
 void rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(struct rtw89_dev *rtwdev,
 					       enum rtw89_phy_idx phy,
 					       const struct rtw89_chan *chan,
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 00/11] wifi: rtw89: update RFK command/report and REGD R73-R54
From: Ping-Ke Shih @ 2026-01-23  1:39 UTC (permalink / raw)
  To: linux-wireless; +Cc: kevin_yang

The first 6 patches are related to RFK (RF calibration) in firmware,
including H2C command to trigger certain RFK and print the report.

The last one is to update the latest REGD along internal update.

Others are random patches to this driver.

Ping-Ke Shih (8):
  wifi: rtw89: rfk: add firmware command to do TX IQK
  wifi: rtw89: rfk: add to print debug log of TX IQK
  wifi: rtw89: rfk: add firmware command to do CIM3K
  wifi: rtw89: rfk: add to print debug log of CIM3K
  wifi: rtw89: rfk: update RFK report format of IQK, DACK and TXGAPK
  wifi: rtw89: fw: correct content of DACK H2C command
  wifi: rtw89: phy: add PHY C2H event dummy handler for func 1-7 and
    2-10
  wifi: rtw89: pci: validate release report content before using for
    RTL8922DE

Zong-Zhe Yang (3):
  wifi: rtw89: 8922a: configure FW version for SIM_SER_L0L1_BY_HALT_H2C
  wifi: rtw89: get designated link to replace link instance 0
  wifi: rtw89: regd: update regulatory map to R73-R54

 drivers/net/wireless/realtek/rtw89/chan.c     |   8 +-
 drivers/net/wireless/realtek/rtw89/fw.c       | 109 ++++++++++++++++--
 drivers/net/wireless/realtek/rtw89/fw.h       | 102 ++++++++++++++--
 drivers/net/wireless/realtek/rtw89/mac80211.c |   4 +-
 drivers/net/wireless/realtek/rtw89/pci.c      |   6 +-
 drivers/net/wireless/realtek/rtw89/phy.c      |  96 +++++++++++++--
 drivers/net/wireless/realtek/rtw89/phy.h      |  15 ++-
 drivers/net/wireless/realtek/rtw89/regd.c     |  20 ++--
 8 files changed, 317 insertions(+), 43 deletions(-)


base-commit: 8da7e88682d58a7c2e2c2101e49d3c9c9ac481b0
-- 
2.25.1


^ permalink raw reply

* Re: [PATCH] wifi: mac80211: do not set 320MHz EHT capabilities on non 6GHz band
From: Johannes Berg @ 2026-01-22 16:41 UTC (permalink / raw)
  To: Nicolas Escande, linux-wireless
In-Reply-To: <DFV9KI49QEP2.2TMVJXR5EK0B7@gmail.com>

On Thu, 2026-01-22 at 17:38 +0100, Nicolas Escande wrote:
> For context I initially encountered this problem on an ath12k AP which has a
> single phy with both 5GHz & 6GHz bands available but only had a 5GHz AP started.
> On such a platform, we set this '320MHz in 6G' operation on the 5GHz no matter
> what beacause of the phy's capabilities.

But that's what I'm saying why it's a driver bug - the PHY capabilities
are advertised *per interface type* and *per band* by the driver. It
shouldn't set this one on 2.4/5 GHz bands.

johannes

^ permalink raw reply

* Re: [PATCH] wifi: mac80211: do not set 320MHz EHT capabilities on non 6GHz band
From: Nicolas Escande @ 2026-01-22 16:38 UTC (permalink / raw)
  To: Johannes Berg, Nicolas Escande, linux-wireless
In-Reply-To: <829488acfdbf7ecfe6418bfb2c5669dae18392ed.camel@sipsolutions.net>

On Thu Jan 22, 2026 at 5:05 PM CET, Johannes Berg wrote:
> On Thu, 2026-01-22 at 15:56 +0100, Nicolas Escande wrote:
>> The spec (at least 802.11-be draft7) at section 9.4.2.323.3 says we should
>> not set the 320MHz related fields when not operating on a 6GHz band. It's
>> quite explicit for most of them. For example:
>> 
>> Bit 0 "Support For 320 MHz In 6 GHz" says "Reserved if the EHT
>>       Capabilities element is indicating capabilities for the 2.4 GHz or
>>       5 GHz bands."
>> 
>> Bit 22-24 "Number Of Sounding Dimensions (= 320 MHz)" says "Reserved if
>>           the SU Beamformer subfield is 0 or the Support For 320 MHz In
>>           6 GHz subfield in EHT Capabilities Information field does not
>>           indicate support for a bandwidth of 320 MHz."
>> 
>> Bit 54 "Support Of EHT-MCS 15 In MRU" says about bit 3 "If 320 MHz is not
>>         supported, then B3 is set to 0."
>> 
>> For bit 13-15 "Beamformee SS (= 320 MHz)" it's not explicit, but it makes
>> little sense to special case the handling of this one.
>
> Sure, but ...
>
>> Fixes: 6239da18d2f9 ("wifi: mac80211: adjust EHT capa when lowering bandwidth")
>> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
>> ---
>>  net/mac80211/util.c | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>> 
>> diff --git a/net/mac80211/util.c b/net/mac80211/util.c
>> index 0c46009a3d63..996983f6815b 100644
>> --- a/net/mac80211/util.c
>> +++ b/net/mac80211/util.c
>> @@ -4426,7 +4426,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
>>  			~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ;
>>  	}
>>  
>> -	if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320) {
>> +	if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320 ||
>> +	    sband->band != NL80211_BAND_6GHZ) {
>>  		fixed.phy_cap_info[0] &=
>>  			~IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
>>  		fixed.phy_cap_info[1] &=
>
> How does this make any sense? The driver should just not advertise the
> bit on its 2.4 and 5 GHz sbands?
>
> johannes

Well from a strictly spec point of view yes: "Reserved if the EHT
Capabilities element is indicating capabilities for the 2.4 GHz or 5 GHz bands."
doesn't leave much room for interpretation.

But it kinda of seems counter productive for this name "Support For 320 MHz In 6
GHz" as it seems to have be explicitely chosen to inform people that a colocated
AP exists on the 6Ghz band.

For context I initially encountered this problem on an ath12k AP which has a
single phy with both 5GHz & 6GHz bands available but only had a 5GHz AP started.
On such a platform, we set this '320MHz in 6G' operation on the 5GHz no matter
what beacause of the phy's capabilities.

So not sure how to adress this problem, it seems weird that the driver should
alter the EHT elem by himself to be honest.

Nico,

^ permalink raw reply

* Re: [GIT PULL] wireless-2026-11-22
From: patchwork-bot+netdevbpf @ 2026-01-22 16:10 UTC (permalink / raw)
  To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <20260122110248.15450-3-johannes@sipsolutions.net>

Hello:

This pull request was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Thu, 22 Jan 2026 12:00:15 +0100 you wrote:
> Hi,
> 
> Some more updates from wireless. The only interesting thing here is
> that there's a merge conflict with net-next, see here:
> https://lore.kernel.org/all/98386125-c0bb-495e-b2ba-2765aaed19d8@oss.qualcomm.com/
> 
> Please pull and let us know if there's any problem.
> 
> [...]

Here is the summary with links:
  - [GIT,PULL] wireless-2026-11-22
    https://git.kernel.org/netdev/net/c/9146fe282990

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* Re: [PATCH] wifi: mac80211: do not set 320MHz EHT capabilities on non 6GHz band
From: Johannes Berg @ 2026-01-22 16:05 UTC (permalink / raw)
  To: Nicolas Escande, linux-wireless
In-Reply-To: <20260122145620.861355-1-nico.escande@gmail.com>

On Thu, 2026-01-22 at 15:56 +0100, Nicolas Escande wrote:
> The spec (at least 802.11-be draft7) at section 9.4.2.323.3 says we should
> not set the 320MHz related fields when not operating on a 6GHz band. It's
> quite explicit for most of them. For example:
> 
> Bit 0 "Support For 320 MHz In 6 GHz" says "Reserved if the EHT
>       Capabilities element is indicating capabilities for the 2.4 GHz or
>       5 GHz bands."
> 
> Bit 22-24 "Number Of Sounding Dimensions (= 320 MHz)" says "Reserved if
>           the SU Beamformer subfield is 0 or the Support For 320 MHz In
>           6 GHz subfield in EHT Capabilities Information field does not
>           indicate support for a bandwidth of 320 MHz."
> 
> Bit 54 "Support Of EHT-MCS 15 In MRU" says about bit 3 "If 320 MHz is not
>         supported, then B3 is set to 0."
> 
> For bit 13-15 "Beamformee SS (= 320 MHz)" it's not explicit, but it makes
> little sense to special case the handling of this one.

Sure, but ...

> Fixes: 6239da18d2f9 ("wifi: mac80211: adjust EHT capa when lowering bandwidth")
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
> ---
>  net/mac80211/util.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/net/mac80211/util.c b/net/mac80211/util.c
> index 0c46009a3d63..996983f6815b 100644
> --- a/net/mac80211/util.c
> +++ b/net/mac80211/util.c
> @@ -4426,7 +4426,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
>  			~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ;
>  	}
>  
> -	if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320) {
> +	if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320 ||
> +	    sband->band != NL80211_BAND_6GHZ) {
>  		fixed.phy_cap_info[0] &=
>  			~IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
>  		fixed.phy_cap_info[1] &=

How does this make any sense? The driver should just not advertise the
bit on its 2.4 and 5 GHz sbands?

johannes

^ permalink raw reply

* [PATCH] wifi: mac80211: do not set 320MHz EHT capabilities on non 6GHz band
From: Nicolas Escande @ 2026-01-22 14:56 UTC (permalink / raw)
  To: linux-wireless; +Cc: johannes.berg

The spec (at least 802.11-be draft7) at section 9.4.2.323.3 says we should
not set the 320MHz related fields when not operating on a 6GHz band. It's
quite explicit for most of them. For example:

Bit 0 "Support For 320 MHz In 6 GHz" says "Reserved if the EHT
      Capabilities element is indicating capabilities for the 2.4 GHz or
      5 GHz bands."

Bit 22-24 "Number Of Sounding Dimensions (= 320 MHz)" says "Reserved if
          the SU Beamformer subfield is 0 or the Support For 320 MHz In
          6 GHz subfield in EHT Capabilities Information field does not
          indicate support for a bandwidth of 320 MHz."

Bit 54 "Support Of EHT-MCS 15 In MRU" says about bit 3 "If 320 MHz is not
        supported, then B3 is set to 0."

For bit 13-15 "Beamformee SS (= 320 MHz)" it's not explicit, but it makes
little sense to special case the handling of this one.

Fixes: 6239da18d2f9 ("wifi: mac80211: adjust EHT capa when lowering bandwidth")
Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
---
 net/mac80211/util.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0c46009a3d63..996983f6815b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -4426,7 +4426,8 @@ int ieee80211_put_eht_cap(struct sk_buff *skb,
 			~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ;
 	}
 
-	if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320) {
+	if (conn->bw_limit < IEEE80211_CONN_BW_LIMIT_320 ||
+	    sband->band != NL80211_BAND_6GHZ) {
 		fixed.phy_cap_info[0] &=
 			~IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
 		fixed.phy_cap_info[1] &=
-- 
2.52.0


^ permalink raw reply related

* Re: [RFC PATCH] ath11k: add ath11k_mac_op_flush_sta to properly flush pending packets
From: Nicolas Escande @ 2026-01-22 14:02 UTC (permalink / raw)
  To: Jeff Johnson, ath11k; +Cc: linux-wireless, Florian Maurer
In-Reply-To: <29a30250-137e-429f-91fb-1f509a55746f@oss.qualcomm.com>

On Tue Oct 7, 2025 at 4:29 PM CEST, Jeff Johnson wrote:
[...]
> These are just cosmetic comments. I've asked both the infrastructure and the
> mobile teams to validate this proposal for technical correctness.
>
> /jeff

Hello Jeff,

Just to check if you got any of your guys to check this subject. The final patch
here [0] seems to not have been accepted yet. And the "issue" is also there in
ath12k, so if we could fix it for both driver that would be a plus.

[0]: https://lore.kernel.org/linux-wireless/GV1P250MB1433E723AF90A69AEBB696DAE8CBA@GV1P250MB1433.EURP250.PROD.OUTLOOK.COM/#t

Thanks,

^ permalink raw reply

* [PATCH wireless-next 2/2] wifi: mac80211: Add drv_set_eml_op_mode driver callback
From: Lorenzo Bianconi @ 2026-01-22 13:51 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, Felix Fietkau, Shayne Chen, Lorenzo Bianconi,
	Christian Marangi, linux-mediatek
In-Reply-To: <20260122-mac80211-emlsr-v1-0-f0e43bb6d95a@kernel.org>

Introduce drv_set_eml_op_mode mac80211 callback in order to configure
underlay driver with eMLSR info (control and bitmap). eMLMR is currently
not supported.

Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 include/net/mac80211.h    |  7 +++++++
 net/mac80211/driver-ops.h | 21 +++++++++++++++++++++
 net/mac80211/eht.c        | 26 ++++++++++++++++++++++++--
 net/mac80211/trace.h      | 31 +++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 36ae7fe9ddf35190921f4fee0fe3294418007a56..3920135595c545a4255bf513c2c8b0525a383c71 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4513,6 +4513,9 @@ struct ieee80211_prep_tx_info {
  *      interface with the specified type would be added, and thus drivers that
  *      implement this callback need to handle such cases. The type is the full
  *      &enum nl80211_iftype.
+ * @set_eml_op_mode: Configure eMLSR/eMLMR operation mode in the underlay
+ *	driver according to the parameter received in the EML Operating mode
+ *	notification frame.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw,
@@ -4908,6 +4911,10 @@ struct ieee80211_ops {
 			struct ieee80211_neg_ttlm *ttlm);
 	void (*prep_add_interface)(struct ieee80211_hw *hw,
 				   enum nl80211_iftype type);
+	int (*set_eml_op_mode)(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_link_sta *link_sta,
+			       u8 control, __le16 link_bitmap);
 };
 
 /**
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 55105d238d6bc5963eb2863575805bee72c42399..a3f2a38241edbea62698cb1104a11a80681983a0 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1772,4 +1772,25 @@ drv_prep_add_interface(struct ieee80211_local *local,
 	trace_drv_return_void(local);
 }
 
+static inline int drv_set_eml_op_mode(struct ieee80211_sub_if_data *sdata,
+				      struct ieee80211_link_sta *link_sta,
+				      u8 control, __le16 link_bitmap)
+{
+	struct ieee80211_local *local = sdata->local;
+	int ret = 0;
+
+	might_sleep();
+	lockdep_assert_wiphy(local->hw.wiphy);
+
+	trace_drv_set_eml_op_mode(local, sdata, link_sta, control,
+				  link_bitmap);
+	if (local->ops->set_eml_op_mode)
+		ret = local->ops->set_eml_op_mode(&local->hw, &sdata->vif,
+						  link_sta, control,
+						  link_bitmap);
+	trace_drv_return_int(local, ret);
+
+	return ret;
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index f1f60d41fccfc2da4ecd2961f6a524e94a6bfa6c..cb5d0ca08ac3aa81f928ab4e05107515dc111858 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -5,6 +5,7 @@
  * Copyright(c) 2021-2025 Intel Corporation
  */
 
+#include "driver-ops.h"
 #include "ieee80211_i.h"
 
 void
@@ -136,17 +137,22 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 {
 	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.eml_omn);
 	enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif);
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	const struct wiphy_iftype_ext_capab *ift_ext_capa;
 	struct ieee80211_mgmt *mgmt = (void *)skb->data;
 	struct ieee80211_local *local = sdata->local;
 	u8 control = mgmt->u.action.u.eml_omn.control;
 	u8 *ptr = mgmt->u.action.u.eml_omn.variable;
+	struct wiphy *wiphy = local->hw.wiphy;
+	struct link_sta_info *link_sta;
+	__le16 link_bitmap = 0;
+	struct sta_info *sta;
 	u8 act_len = 3; /* action_code + dialog_token + control */
 
 	if (!ieee80211_vif_is_mld(&sdata->vif))
 		return;
 
-	ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type);
+	ift_ext_capa = cfg80211_get_iftype_ext_capa(wiphy, type);
 	if (!ift_ext_capa)
 		return;
 
@@ -160,8 +166,10 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 		return;
 
 	if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) ||
-	    (control & IEEE80211_EML_CTRL_EMLMR_MODE))
+	    (control & IEEE80211_EML_CTRL_EMLMR_MODE)) {
+		link_bitmap = get_unaligned((__le16 *)ptr);
 		act_len += sizeof(__le16); /* eMLSR/eMLMR link_bitmap */
+	}
 
 	if (control & IEEE80211_EML_CTRL_EMLMR_MODE) {
 		u8 mcs_map_count = ptr[3];
@@ -176,5 +184,19 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 	if (skb->len < hdr_len + act_len)
 		return;
 
+	if (!status->link_valid)
+		return;
+
+	sta = sta_info_get_bss(sdata, mgmt->sa);
+	if (!sta)
+		return;
+
+	link_sta = wiphy_dereference(wiphy, sta->link[status->link_id]);
+	if (!link_sta)
+		return;
+
+	if (drv_set_eml_op_mode(sdata, link_sta->pub, control, link_bitmap))
+		return;
+
 	ieee80211_send_eml_op_mode_notif(sdata, mgmt, act_len);
 }
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 0bfbce1574862b5a6a2ca39794abea7fe9a3f34a..584658bd4640c72aef3199cd9341699924fd5fea 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -3353,6 +3353,37 @@ TRACE_EVENT(drv_prep_add_interface,
 	)
 );
 
+TRACE_EVENT(drv_set_eml_op_mode,
+	    TP_PROTO(struct ieee80211_local *local,
+		     struct ieee80211_sub_if_data *sdata,
+		     struct ieee80211_link_sta *link_sta,
+		     u8 control, __le16 link_bitmap),
+
+	TP_ARGS(local, sdata, link_sta, control, link_bitmap),
+
+	TP_STRUCT__entry(LOCAL_ENTRY
+			 VIF_ENTRY
+			 STA_ENTRY
+			 __field(u32, link_id)
+			 __field(u8, control)
+			 __field(__le16, link_bitmap)),
+
+	TP_fast_assign(LOCAL_ASSIGN;
+		       VIF_ASSIGN;
+		       STA_NAMED_ASSIGN(link_sta->sta);
+		       __entry->link_id = link_sta->link_id;
+		       __entry->control = control;
+		       __entry->link_bitmap = link_bitmap;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT
+		" (link:%d control:%02x link_bitmap:%04x)",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->link_id,
+		__entry->control, __entry->link_bitmap
+	)
+);
+
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH

-- 
2.52.0


^ permalink raw reply related

* [PATCH wireless-next 1/2] wifi: mac80211: Add EMLSR/EMLMR action frame parsing support
From: Lorenzo Bianconi @ 2026-01-22 13:51 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, Felix Fietkau, Shayne Chen, Lorenzo Bianconi,
	Christian Marangi, linux-mediatek
In-Reply-To: <20260122-mac80211-emlsr-v1-0-f0e43bb6d95a@kernel.org>

Introduce support in AP mode for parsing of the Operating Mode Notification
frame sent by the client to enable/disable MLO eMLSR or eMLMR if supported
by both the AP and the client.

Tested-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 include/linux/ieee80211-eht.h |  5 +++
 include/linux/ieee80211.h     |  6 ++++
 net/mac80211/eht.c            | 76 +++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h    |  2 ++
 net/mac80211/iface.c          | 10 +++++-
 net/mac80211/rx.c             |  8 +++++
 6 files changed, 106 insertions(+), 1 deletion(-)

diff --git a/include/linux/ieee80211-eht.h b/include/linux/ieee80211-eht.h
index f9782e46c5e5241bccc84c3bbc18b1cc9ec1879c..f409469d3db87c5714c68f8dada6fa212dff5c55 100644
--- a/include/linux/ieee80211-eht.h
+++ b/include/linux/ieee80211-eht.h
@@ -558,6 +558,11 @@ struct ieee80211_mle_tdls_common_info {
 
 #define IEEE80211_MLC_PRIO_ACCESS_PRES_AP_MLD_MAC_ADDR	0x0010
 
+#define IEEE80211_EML_CTRL_EMLSR_MODE		BIT(0)
+#define IEEE80211_EML_CTRL_EMLMR_MODE		BIT(1)
+#define IEEE80211_EML_CTRL_PARAM_UPDATE		BIT(2)
+#define IEEE80211_EML_CTRL_INDEV_COEX_ACT	BIT(3)
+
 /* no fixed fields in PRIO_ACCESS */
 
 /**
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index fbde215c25aa79efd339aa530896a29dbb1a8ff8..f2c6f34f39f24ce59cbb2650f70e898d24d12901 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1186,6 +1186,12 @@ struct ieee80211_mgmt {
 					u8 action_code;
 					u8 variable[];
 				} __packed epcs;
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 control;
+					u8 variable[];
+				} __packed eml_omn;
 			} u;
 		} __packed action;
 		DECLARE_FLEX_ARRAY(u8, body); /* Generic frame body */
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index fd41046e3b681b753e6cc7ddf82046e4bc5df9b3..f1f60d41fccfc2da4ecd2961f6a524e94a6bfa6c 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -102,3 +102,79 @@ ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
 
 	ieee80211_sta_recalc_aggregates(&link_sta->sta->sta);
 }
+
+static void
+ieee80211_send_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
+				 struct ieee80211_mgmt *req, u8 act_len)
+{
+	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.eml_omn);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_mgmt *mgmt;
+	struct sk_buff *skb;
+
+	skb = dev_alloc_skb(local->tx_headroom + hdr_len + act_len);
+	if (!skb)
+		return;
+
+	skb_reserve(skb, local->tx_headroom);
+	mgmt = skb_put_zero(skb, hdr_len);
+	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					  IEEE80211_STYPE_ACTION);
+	memcpy(mgmt->da, req->sa, ETH_ALEN);
+	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+	memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+
+	mgmt->u.action.category = WLAN_CATEGORY_PROTECTED_EHT;
+	memcpy(&mgmt->u.action.u.eml_omn, &req->u.action.u.eml_omn, act_len);
+	mgmt->u.action.u.eml_omn.control &= ~(IEEE80211_EML_CTRL_PARAM_UPDATE |
+					      IEEE80211_EML_CTRL_INDEV_COEX_ACT);
+	ieee80211_tx_skb(sdata, skb);
+}
+
+void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
+				    struct sk_buff *skb)
+{
+	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.eml_omn);
+	enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif);
+	const struct wiphy_iftype_ext_capab *ift_ext_capa;
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
+	struct ieee80211_local *local = sdata->local;
+	u8 control = mgmt->u.action.u.eml_omn.control;
+	u8 *ptr = mgmt->u.action.u.eml_omn.variable;
+	u8 act_len = 3; /* action_code + dialog_token + control */
+
+	if (!ieee80211_vif_is_mld(&sdata->vif))
+		return;
+
+	ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type);
+	if (!ift_ext_capa)
+		return;
+
+	if (!(ift_ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP) &&
+	    !(ift_ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLMR_SUPPORT))
+		return;
+
+	/* eMLSR and eMLMR can't be enabled at the same time */
+	if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) &&
+	    (control & IEEE80211_EML_CTRL_EMLMR_MODE))
+		return;
+
+	if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) ||
+	    (control & IEEE80211_EML_CTRL_EMLMR_MODE))
+		act_len += sizeof(__le16); /* eMLSR/eMLMR link_bitmap */
+
+	if (control & IEEE80211_EML_CTRL_EMLMR_MODE) {
+		u8 mcs_map_count = ptr[3];
+
+		if (mcs_map_count > 2)
+			return;
+
+		/* mcs_map_count_control and mcs_map_bw */
+		act_len += 2 + mcs_map_count;
+	}
+
+	if (skb->len < hdr_len + act_len)
+		return;
+
+	ieee80211_send_eml_op_mode_notif(sdata, mgmt, act_len);
+}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index dc757cb329740d621f6a9deb4e9ffe258e1b7d67..3ef93cd1fb33e2614c3e06c51d6b1ebcafa4824c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2837,6 +2837,8 @@ void ieee80211_destroy_frag_cache(struct ieee80211_fragment_cache *cache);
 
 u8 ieee80211_ie_len_eht_cap(struct ieee80211_sub_if_data *sdata);
 
+void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
+				    struct sk_buff *skb);
 void
 ieee80211_eht_cap_ie_to_sta_eht_cap(struct ieee80211_sub_if_data *sdata,
 				    struct ieee80211_supported_band *sband,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3ce94b95decd64eea4ea063ae98c111bdfd57e9c..17476fd9259b68b3d9c649eabad10efa42d56cd7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1664,7 +1664,15 @@ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
 		}
 	} else if (ieee80211_is_action(mgmt->frame_control) &&
 		   mgmt->u.action.category == WLAN_CATEGORY_PROTECTED_EHT) {
-		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+		if (sdata->vif.type == NL80211_IFTYPE_AP) {
+			switch (mgmt->u.action.u.eml_omn.action_code) {
+			case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF:
+				ieee80211_rx_eml_op_mode_notif(sdata, skb);
+				break;
+			default:
+				break;
+			}
+		} else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
 			switch (mgmt->u.action.u.ttlm_req.action_code) {
 			case WLAN_PROTECTED_EHT_ACTION_TTLM_REQ:
 				ieee80211_process_neg_ttlm_req(sdata, mgmt,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index ac437256f5d5c4b34601fd4c8a6f6f80469b2522..521e44c9e8dac498122e7a595d1eb8bb5751789d 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3928,6 +3928,14 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 					      u.action.u.epcs))
 				goto invalid;
 			goto queue;
+		case WLAN_PROTECTED_EHT_ACTION_EML_OP_MODE_NOTIF:
+			if (sdata->vif.type != NL80211_IFTYPE_AP)
+				break;
+
+			if (len < offsetofend(typeof(*mgmt),
+					      u.action.u.eml_omn))
+				goto invalid;
+			goto queue;
 		default:
 			break;
 		}

-- 
2.52.0


^ permalink raw reply related

* [PATCH wireless-next 0/2] wifi: mac80211: Introduce eMLSR/eMLMR parsing support in AP mode.
From: Lorenzo Bianconi @ 2026-01-22 13:51 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, Felix Fietkau, Shayne Chen, Lorenzo Bianconi,
	Christian Marangi, linux-mediatek

Introduce support in AP mode for parsing of the Operating Mode Notification
frame sent by the client to enable/disable MLO eMLSR or eMLMR if supported
by both the AP and the client.
Add drv_set_eml_op_mode mac80211 callback in order to configure underlay
driver with eMLSR info (control and bitmap).

---
Lorenzo Bianconi (2):
      wifi: mac80211: Add EMLSR/EMLMR action frame parsing support
      wifi: mac80211: Add drv_set_eml_op_mode driver callback

 include/linux/ieee80211-eht.h |  5 +++
 include/linux/ieee80211.h     |  6 +++
 include/net/mac80211.h        |  7 ++++
 net/mac80211/driver-ops.h     | 21 ++++++++++
 net/mac80211/eht.c            | 98 +++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h    |  2 +
 net/mac80211/iface.c          | 10 ++++-
 net/mac80211/rx.c             |  8 ++++
 net/mac80211/trace.h          | 31 ++++++++++++++
 9 files changed, 187 insertions(+), 1 deletion(-)
---
base-commit: 1e1dd9eeaab3908746d1dce5db6b0c29e0d28d6d
change-id: 20260121-mac80211-emlsr-5774082ff8cc

Best regards,
-- 
Lorenzo Bianconi <lorenzo@kernel.org>


^ permalink raw reply

* Re: [PATCH v3] wifi: p54: Fix memory leak in p54_beacon_update()
From: Christian Lamparter @ 2026-01-22 11:43 UTC (permalink / raw)
  To: Zilin Guan
  Cc: johannes.berg, quic_rdevanat, linux-wireless, linux-kernel,
	jianhao.xu
In-Reply-To: <20260122085945.444955-1-zilin@seu.edu.cn>

On 1/22/26 9:59 AM, Zilin Guan wrote:
> In p54_beacon_update(), beacon is allocated via ieee80211_beacon_get().
> If p54_beacon_format_ie_tim() fails, the function returns immediately
> without freeing the allocated beacon skb, which would lead to a memory
> leak.
> 
> Since no other references to this memory exist, it must be freed locally
> before returning the error. Fix this by freeing the buffer using
> dev_kfree_skb_any() in the error path.
> 
> Note that this error path is unreachable in practice because mac80211
> guarantees a minimum TIM length of 4 bytes for non-S1G devices. This
> change primarily serves to silence static analysis warnings and keep
> the error handling logic complete.
> 
> Compile tested only. Issue found using a prototype static analysis tool
> and code review.
> 
> Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
Acked-by: Christian Lamparter <chunkeey@gmail.com>

This will be picked up automatically, right?

> ---
> Changes in v3:
> - Add a note in the commit message about the code path being unreachable
>    in practice.
> - Remove the Fixes tag as the issue is theoretical and unreachable.
> 
> Changes in v2:
> - Correct the Fixes tag to point to the commit that introduced this issue.
> 
>   drivers/net/wireless/intersil/p54/main.c | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
> index 2ec3655f1a9c..57a62108cbc3 100644
> --- a/drivers/net/wireless/intersil/p54/main.c
> +++ b/drivers/net/wireless/intersil/p54/main.c
> @@ -143,8 +143,10 @@ static int p54_beacon_update(struct p54_common *priv,
>   	if (!beacon)
>   		return -ENOMEM;
>   	ret = p54_beacon_format_ie_tim(beacon);
> -	if (ret)
> +	if (ret) {
> +		dev_kfree_skb_any(beacon);
>   		return ret;
> +	}
>   
>   	/*
>   	 * During operation, the firmware takes care of beaconing.


^ permalink raw reply

* [GIT PULL] wireless-2026-11-22
From: Johannes Berg @ 2026-01-22 11:00 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless

Hi,

Some more updates from wireless. The only interesting thing here is
that there's a merge conflict with net-next, see here:
https://lore.kernel.org/all/98386125-c0bb-495e-b2ba-2765aaed19d8@oss.qualcomm.com/

Please pull and let us know if there's any problem.

Thanks,
johannes



The following changes since commit f2a3b12b305c7bb72467b2a56d19a4587b6007f9:

  Merge tag 'net-6.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-01-08 08:40:35 -1000)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git tags/wireless-2026-11-22

for you to fetch changes up to 50b359896fe55d0443ed550e1fabba71d242031a:

  wifi: cfg80211: ignore link disabled flag from userspace (2026-01-20 10:02:01 +0100)

----------------------------------------------------------------
Another set of updates:
 - various small fixes for ath10k/ath12k/mwifiex/rsi
 - cfg80211 fix for HE bitrate overflow
 - mac80211 fixes
   - S1G beacon handling in scan
   - skb tailroom handling for HW encryption
   - CSA fix for multi-link
   - handling of disabled links during association

----------------------------------------------------------------
Baochen Qiang (2):
      wifi: ath12k: don't force radio frequency check in freq_to_idx()
      wifi: ath12k: fix dead lock while flushing management frames

Benjamin Berg (3):
      wifi: mac80211: parse all TTLM entries
      wifi: mac80211: apply advertised TTLM from association response
      wifi: cfg80211: ignore link disabled flag from userspace

Dan Carpenter (1):
      wifi: mwifiex: Fix a loop in mwifiex_update_ampdu_rxwinsize()

Johannes Berg (1):
      Merge tag 'ath-current-20260113' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath into wireless

Lachlan Hodges (1):
      wifi: mac80211: don't perform DA check on S1G beacon

Manish Dharanenthiran (1):
      wifi: ath12k: cancel scan only on active scan vdev

Marek Vasut (1):
      wifi: rsi: Fix memory corruption due to not set vif driver data size

Miri Korenblit (2):
      wifi: mac80211: correctly check if CSA is active
      wifi: mac80211: don't increment crypto_tx_tailroom_needed_cnt twice

Thomas Fourier (2):
      wifi: ath10k: fix dma_free_coherent() pointer
      wifi: ath12k: fix dma_free_coherent() pointer

Veerendranath Jakkam (1):
      wifi: cfg80211: Fix bitrate calculation overflow for HE rates

Yingying Tang (2):
      wifi: ath12k: Fix scan state stuck in ABORTING after cancel_remain_on_channel
      wifi: ath12k: Fix wrong P2P device link id issue

 drivers/net/wireless/ath/ath10k/ce.c               |  16 +-
 drivers/net/wireless/ath/ath12k/ce.c               |  12 +-
 drivers/net/wireless/ath/ath12k/mac.c              |  16 +-
 drivers/net/wireless/ath/ath12k/wmi.c              |   9 +-
 .../net/wireless/marvell/mwifiex/11n_rxreorder.c   |   6 +-
 drivers/net/wireless/rsi/rsi_91x_mac80211.c        |   1 +
 include/net/cfg80211.h                             |   3 -
 include/uapi/linux/nl80211.h                       |   5 +-
 net/mac80211/ieee80211_i.h                         |   2 -
 net/mac80211/iface.c                               |   8 +-
 net/mac80211/key.c                                 |   3 +-
 net/mac80211/mlme.c                                | 213 ++++++++++++---------
 net/mac80211/scan.c                                |   9 +-
 net/wireless/nl80211.c                             |  10 -
 net/wireless/util.c                                |   8 +-
 15 files changed, 171 insertions(+), 150 deletions(-)

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox