Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH rtw-next 1/9] wifi: rtw89: coex: Add Init info version 10
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601
In-Reply-To: <20260703114311.2609942-1-pkshih@realtek.com>

From: Ching-Te Ku <ku920601@realtek.com>

The version 10 Init info add I/O offload type & variable Bluetooth
function (EX: Zigbee/Thread...etc) into the structure definition.
Firmware need to synchronize these information to do corresponding
setting.

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     | 58 +++++++++++++++++--
 drivers/net/wireless/realtek/rtw89/coex.h     |  6 ++
 drivers/net/wireless/realtek/rtw89/core.h     | 54 ++++++++++++++++-
 drivers/net/wireless/realtek/rtw89/fw.c       | 41 +++++++++++++
 drivers/net/wireless/realtek/rtw89/fw.h       |  6 ++
 drivers/net/wireless/realtek/rtw89/rtw8851b.c |  2 -
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |  1 -
 .../wireless/realtek/rtw89/rtw8852b_common.c  |  1 -
 drivers/net/wireless/realtek/rtw89/rtw8852c.c |  1 -
 drivers/net/wireless/realtek/rtw89/rtw8922a.c |  1 -
 10 files changed, 159 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index 1361d4d54528..43de238c18f8 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -2822,6 +2822,8 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 index)
 	case CXDRVINFO_INIT:
 		if (ver->fcxinit == 7)
 			rtw89_fw_h2c_cxdrv_init_v7(rtwdev, index);
+		else if (ver->fcxinit == 10)
+			rtw89_fw_h2c_cxdrv_init_v10(rtwdev, index);
 		else
 			rtw89_fw_h2c_cxdrv_init(rtwdev, index);
 		break;
@@ -7884,15 +7886,30 @@ void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev)
 	btc->cx.wl.status.map.rf_off_pre = btc->cx.wl.status.map.rf_off;
 }
 
+#define BTC_PLATFORM_LITTLE_ENDIAN 0
 static void _set_init_info(struct rtw89_dev *rtwdev)
 {
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	struct rtw89_btc *btc = &rtwdev->btc;
 	const struct rtw89_btc_ver *ver = btc->ver;
 	struct rtw89_btc_dm *dm = &btc->dm;
+	struct rtw89_btc_cx *cx = &btc->cx;
 	struct rtw89_btc_wl_info *wl = &btc->cx.wl;
 
-	if (ver->fcxinit == 7) {
+	if (ver->fcxinit == 10) {
+		dm->init_info.init_v10.init_mode = wl->coex_mode;
+		dm->init_info.init_v10.wl_init_ok = wl->status.map.init_ok;
+		dm->init_info.init_v10.endian_type = BTC_PLATFORM_LITTLE_ENDIAN;
+
+		dm->init_info.init_v10.module = btc->mdinfo.md_v10;
+
+		dm->init_info.init_v10.bt0_function = cx->bt0.func_type;
+		dm->init_info.init_v10.bt1_function = cx->bt1.func_type;
+		dm->init_info.init_v10.bt2_function = cx->bt_ext.func_type;
+
+		dm->init_info.init_v10.pta_mode = RTW89_MAC_AX_COEX_RTK_MODE;
+		dm->init_info.init_v10.pta_direction = RTW89_MAC_AX_COEX_INNER;
+	} else if (ver->fcxinit == 7) {
 		dm->init_info.init_v7.wl_only = (u8)dm->wl_only;
 		dm->init_info.init_v7.bt_only = (u8)dm->bt_only;
 		dm->init_info.init_v7.wl_init_ok = (u8)wl->status.map.init_ok;
@@ -7908,6 +7925,12 @@ static void _set_init_info(struct rtw89_dev *rtwdev)
 		dm->init_info.init.wl_guard_ch = chip->afh_guard_ch;
 		dm->init_info.init.module = btc->mdinfo.md;
 	}
+
+	_fw_set_drv_info(rtwdev, CXDRVINFO_INIT);
+	_fw_set_drv_info(rtwdev, CXDRVINFO_CTRL);
+	rtw89_btc_fw_set_slots(rtwdev);
+	btc_fw_set_monreg(rtwdev);
+	_set_wl_tx_power(rtwdev, RTW89_BTC_WL_DEF_TX_PWR, RTW89_PHY_0);
 }
 
 void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
@@ -7918,13 +7941,18 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
 	const struct rtw89_chip_info *chip = rtwdev->chip;
 	const struct rtw89_btc_ver *ver = btc->ver;
 
+	rtw89_debug(rtwdev, RTW89_DBG_BTC,
+		    "[BTC], %s(): Init %s !!\n", __func__,
+		    chip_id_str(chip->chip_id));
+
 	_reset_btc_var(rtwdev, BTC_RESET_ALL);
 	btc->dm.run_reason = BTC_RSN_NONE;
 	btc->dm.run_action = BTC_ACT_NONE;
-	if (ver->fcxctrl == 7)
+	if (ver->fcxctrl >= 7)
 		btc->ctrl.ctrl_v7.igno_bt = true;
 	else
 		btc->ctrl.ctrl.igno_bt = true;
+	wl->status.map.init_ok = true;
 
 	rtw89_debug(rtwdev, RTW89_DBG_BTC,
 		    "[BTC], %s(): mode=%d\n", __func__, mode);
@@ -7934,9 +7962,11 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
 	dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
 	dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
 	wl->status.map.rf_off = mode == BTC_MODE_WLOFF ? 1 : 0;
-
-	chip->ops->btc_set_rfe(rtwdev);
-	chip->ops->btc_init_cfg(rtwdev);
+	dm->vid = rtwdev->custid;
+	if (ver->fcxctrl >= 7)
+		btc->ctrl.ctrl_v7.always_freerun = mode == BTC_MODE_COTX;
+	else
+		btc->ctrl.ctrl.always_freerun = mode == BTC_MODE_COTX;
 
 	if (!wl->status.map.init_ok) {
 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -7946,8 +7976,26 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
 		return;
 	}
 
+	if (rtwdev->chip->para_ver & BTC_FEAT_DUAL_BT) {
+		btc->cx.bt1.enable.now = 1;
+		btc->cx.bt1.run_patch_code = 1;
+	}
+
+	if (rtwdev->chip->para_ver & BTC_FEAT_H2C_MACRO) {
+		btc->cx.bt0.enable.now = 1;
+		btc->cx.bt0.run_patch_code = 1;
+		btc->io_oflld_type = BTC_IO_OFLD_BTC_H2C;
+	} else {
+		btc->io_oflld_type = BTC_IO_OFLD_NO_SUPPORT;
+		_update_bt_scbd(rtwdev, true);
+	}
+
+	chip->ops->btc_set_rfe(rtwdev);
+	chip->ops->btc_init_cfg(rtwdev);
+
 	_write_scbd(rtwdev,
 		    BTC_WSCB_ACTIVE | BTC_WSCB_ON | BTC_WSCB_BTLOG, true);
+
 	if (rtw89_mac_get_ctrl_path(rtwdev)) {
 		rtw89_debug(rtwdev, RTW89_DBG_BTC,
 			    "[BTC], %s(): PTA owner warning!!\n",
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index 6ac14611607c..259c6e2c0e3c 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -16,6 +16,8 @@ enum btc_mode {
 	BTC_MODE_WL,
 	BTC_MODE_BT,
 	BTC_MODE_WLOFF,
+	BTC_MODE_COTX,
+	BTC_MODE_MECHANISM_INIT,
 	BTC_MODE_MAX
 };
 
@@ -212,6 +214,10 @@ enum btc_chip_feature {
 	BTC_FEAT_NEW_BBAPI_FLOW = BIT(3), /* new btg_ctrl/pre_agc_ctrl */
 	BTC_FEAT_MLO_SUPPORT = BIT(4),
 	BTC_FEAT_H2C_MACRO = BIT(5),
+	BTC_FEAT_DUAL_BT = BIT(6),
+	BTC_FEAT_BT_6G = BIT(7),
+	BTC_FEAT_MULTI_PTA = BIT(8),
+	BTC_FEAT_DUAL_BTGA = BIT(9) /* the future A-Die */
 };
 
 enum btc_wl_mode {
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 5dde620b1e5e..1e72c9b9f3b7 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -1451,6 +1451,12 @@ enum rtw89_btc_bt_rf_band {
 	BTC_BT_BMAX = 0x2
 };
 
+enum rtw89_btc_io_offload_type {
+	BTC_IO_OFLD_NO_SUPPORT = 0,
+	BTC_IO_OFLD_MAC_API = 1,
+	BTC_IO_OFLD_BTC_H2C = 2
+};
+
 enum rtw89_btc_bt_profile {
 	BTC_BT_NOPROFILE = 0,
 	BTC_BT_HFP = BIT(0),
@@ -1483,6 +1489,19 @@ struct rtw89_btc_ant_info_v7 {
 	u8 rsvd;
 } __packed;
 
+struct rtw89_btc_ant_info_v10 {
+	u8 type;  /* shared, dedicated(non-shared) */
+	u8 num;   /* antenna count  */
+	u8 isolation; /* Ant-Iso between WL/BT */
+	u8 single_pos; /* wifi 1ss-1ant at 0:S0 or 1:S1 */
+
+	u8 stream_cnt; /* spatial_stream count: Tx[7:4], Rx[3:0] */
+	u8 btg_pos;    /* BT0 btg-circuit at 0:WL-S0/1:WL-S1 */
+	u8 btg1_pos;   /* BT1 btg-circuit at 0:WL-S0/1:WL-S1 */
+	u8 func[5]; /* function at 1~5 Ant refer to enum btc_bt_func_type */
+	u8 ant_xmap[2][4];
+} __packed;
+
 enum rtw89_tfc_dir {
 	RTW89_TFC_UL,
 	RTW89_TFC_DL,
@@ -2129,9 +2148,24 @@ struct rtw89_btc_module_v7 {
 	struct rtw89_btc_ant_info_v7 ant;
 } __packed;
 
+struct rtw89_btc_module_v10 {
+	u8 rfe_type;
+	u8 wa_type; /* Refer to enum btc_wa_type */
+	u8 kt_ver;
+	u8 kt_ver_adie;
+
+	u8 bt0_pos; /* wl-end view: get from efuse, must compare bt.btg_type*/
+	u8 bt0_sw_type; /* BT Ant-switch: None(non-share), Int(BTG), Ext(SPDT)*/
+	u8 bt1_pos; /* BTC_BT_ALONE or BTC_BT_BTG */
+	u8 bt1_sw_type;
+
+	struct rtw89_btc_ant_info_v10 ant;
+} __packed;
+
 union rtw89_btc_module_info {
 	struct rtw89_btc_module md;
 	struct rtw89_btc_module_v7 md_v7;
+	struct rtw89_btc_module_v10 md_v10;
 };
 
 #define RTW89_BTC_DM_MAXSTEP 30
@@ -2170,9 +2204,24 @@ struct rtw89_btc_init_info_v7 {
 	struct rtw89_btc_module_v7 module;
 } __packed;
 
+struct rtw89_btc_init_info_v10 {
+	u8 endian_type; /* 0: little-endian, 1:big-endian */
+	u8 init_mode; /* refer to enum BTC_MODE_xxx  */
+	u8 wl_init_ok;
+	u8 bt0_function;
+
+	u8 bt1_function;
+	u8 bt2_function;
+	u8 pta_mode;
+	u8 pta_direction;
+
+	struct rtw89_btc_module_v10 module;
+};
+
 union rtw89_btc_init_info_u {
 	struct rtw89_btc_init_info init;
 	struct rtw89_btc_init_info_v7 init_v7;
+	struct rtw89_btc_init_info_v10 init_v10;
 };
 
 struct rtw89_btc_wl_tx_limit_para {
@@ -2253,6 +2302,7 @@ struct rtw89_btc_bt_info {
 	u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
 	u8 txpwr_info[BTC_BTINFO_MAX];
 	u8 rssi_level;
+	u8 func_type;
 
 	u32 scbd;
 	u32 feature;
@@ -3173,6 +3223,7 @@ struct rtw89_btc_dm {
 	u8 run_reason;
 	u8 run_action;
 	u8 wl_tx_pwr_phy_map;
+	u8 vid;
 
 	u8 wl_pre_agc: 2;
 	u8 wl_lna2: 1;
@@ -3203,7 +3254,7 @@ struct rtw89_btc_ctrl_v7 {
 
 union rtw89_btc_ctrl_list {
 	struct rtw89_btc_ctrl ctrl;
-	struct rtw89_btc_ctrl_v7 ctrl_v7;
+	struct rtw89_btc_ctrl_v7 ctrl_v7; /* ver 8, 9 is the same */
 };
 
 struct rtw89_btc_dbg {
@@ -3425,6 +3476,7 @@ struct rtw89_btc {
 	u8 policy[RTW89_BTC_POLICY_MAXLEN];
 	u8 ant_type;
 	u8 btg_pos;
+	u8 io_oflld_type;
 	u16 policy_len;
 	u16 policy_type;
 	u32 hubmsg_cnt;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 9d98805835d6..b97c6e9c18bc 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -5863,6 +5863,47 @@ int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type)
 	return ret;
 }
 
+int rtw89_fw_h2c_cxdrv_init_v10(struct rtw89_dev *rtwdev, u8 type)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_dm *dm = &btc->dm;
+	struct rtw89_btc_init_info_v10 *init_info = &dm->init_info.init_v10;
+	struct rtw89_h2c_cxinit_v10 *h2c;
+	u32 len = sizeof(*h2c);
+	struct sk_buff *skb;
+	int ret;
+
+	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+	if (!skb) {
+		rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_init_v10\n");
+		return -ENOMEM;
+	}
+	skb_put(skb, len);
+	h2c = (struct rtw89_h2c_cxinit_v10 *)skb->data;
+
+	h2c->hdr.type = type;
+	h2c->hdr.ver = btc->ver->fcxinit;
+	h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7;
+	h2c->init = *init_info;
+
+	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+			      H2C_CAT_OUTSRC, BTFC_SET,
+			      SET_DRV_INFO, 0, 0,
+			      len);
+
+	ret = rtw89_h2c_tx(rtwdev, skb, false);
+	if (ret) {
+		rtw89_err(rtwdev, "failed to send h2c\n");
+		goto fail;
+	}
+
+	return 0;
+fail:
+	dev_kfree_skb_any(skb);
+
+	return ret;
+}
+
 #define PORT_DATA_OFFSET 4
 #define H2C_LEN_CXDRVINFO_ROLE_DBCC_LEN 12
 #define H2C_LEN_CXDRVINFO_ROLE_SIZE(max_role_num) \
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 71e8554a7af7..de8b77de8705 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2592,6 +2592,11 @@ struct rtw89_h2c_cxinit_v7 {
 	struct rtw89_btc_init_info_v7 init;
 } __packed;
 
+struct rtw89_h2c_cxinit_v10 {
+	struct rtw89_h2c_cxhdr_v7 hdr;
+	struct rtw89_btc_init_info_v10 init;
+} __packed;
+
 static inline void RTW89_SET_FWCMD_CXROLE_CONNECT_CNT(void *cmd, u8 val)
 {
 	u8p_replace_bits((u8 *)(cmd) + 2, val, GENMASK(7, 0));
@@ -5380,6 +5385,7 @@ int rtw89_fw_h2c_tx_history(struct rtw89_dev *rtwdev, u16 mac_id);
 int rtw89_fw_h2c_drv_ctrl_fw(struct rtw89_dev *rtwdev);
 int rtw89_fw_h2c_cxdrv_init(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_init_v7(struct rtw89_dev *rtwdev, u8 type);
+int rtw89_fw_h2c_cxdrv_init_v10(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type);
 int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index 4caf231c6287..a1a63588cb90 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -2277,8 +2277,6 @@ static void rtw8851b_btc_init_cfg(struct rtw89_dev *rtwdev)
 
 	/* enable BT counter 0xda40[16,2] = 2b'11 */
 	rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN);
-
-	btc->cx.wl.status.map.init_ok = true;
 }
 
 static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 78addc0aef69..055c67a07cea 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -1945,7 +1945,6 @@ static void rtw8852a_btc_init_cfg(struct rtw89_dev *rtwdev)
 	 /* enable BT counter 0xda40[16,2] = 2b'11 */
 	rtw89_write32_set(rtwdev,
 			  R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN);
-	btc->cx.wl.status.map.init_ok = true;
 }
 
 static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
index df5fbae50ff5..7d409a64869f 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c
@@ -1838,7 +1838,6 @@ static void __rtw8852bx_btc_init_cfg(struct rtw89_dev *rtwdev)
 
 	 /* enable BT counter 0xda40[16,2] = 2b'11 */
 	rtw89_write32_set(rtwdev, R_AX_CSR_MODE, B_AX_BT_CNT_RST | B_AX_STATIS_BT_EN);
-	btc->cx.wl.status.map.init_ok = true;
 }
 
 static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 29a3c90021f3..9e630b897986 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2761,7 +2761,6 @@ 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);
-	btc->cx.wl.status.map.init_ok = true;
 }
 
 static
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
index 6d4301661b04..382034eb27d0 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -2828,7 +2828,6 @@ static void rtw8922a_btc_init_cfg(struct rtw89_dev *rtwdev)
 	rtw89_write32(rtwdev, R_BTC_ZB_COEX_TBL_1, 0xda5a5a5a);
 
 	rtw89_write32(rtwdev, R_BTC_ZB_BREAK_TBL, 0xf0ffffff);
-	btc->cx.wl.status.map.init_ok = true;
 }
 
 static void
-- 
2.25.1


^ permalink raw reply related

* [PATCH rtw-next 0/9] wifi: rtw89: coex: implement components for dual Bluetooth
From: Ping-Ke Shih @ 2026-07-03 11:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: ku920601

Extend more components of BT-coexitence to support dual Bluetooth,
including TDMA descriptor, TX power, RX gain, scoreboard and etc.

Ching-Te Ku (9):
  wifi: rtw89: coex: Add Init info version 10
  wifi: rtw89: coex: add rtw89_btc_init() entry for initialization once
  wifi: rtw89: coex: Update TDMA descriptor for dual MAC
  wifi: rtw89: coex: Add Bluetooth binding for Bluetooth TX power
    setting
  wifi: rtw89: coex: Add Bluetooth binding for Bluetooth RX gain setting
  wifi: rtw89: coex: Add WiFi/Bluetooth adapter binding info
  wifi: rtw89: coex: Add TDMA binding for dual MAC
  wifi: rtw89: coex: Update scoreboard related logic for dual Bluetooth
  wifi: rtw89: coex: Add Co-RX logic

 drivers/net/wireless/realtek/rtw89/coex.c     | 1493 +++++++++++------
 drivers/net/wireless/realtek/rtw89/coex.h     |   16 +
 drivers/net/wireless/realtek/rtw89/core.c     |    5 +-
 drivers/net/wireless/realtek/rtw89/core.h     |  241 ++-
 drivers/net/wireless/realtek/rtw89/fw.c       |   41 +
 drivers/net/wireless/realtek/rtw89/fw.h       |    9 +
 drivers/net/wireless/realtek/rtw89/rtw8851b.c |    2 -
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |    1 -
 .../wireless/realtek/rtw89/rtw8852b_common.c  |    1 -
 drivers/net/wireless/realtek/rtw89/rtw8852c.c |    1 -
 drivers/net/wireless/realtek/rtw89/rtw8922a.c |    1 -
 11 files changed, 1298 insertions(+), 513 deletions(-)


base-commit: 2b7858891b100587c10c136cf07205335a897be0
-- 
2.25.1


^ permalink raw reply

* Re: [PATCH] wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get()
From: Rameshkumar Sundaram @ 2026-07-03 10:36 UTC (permalink / raw)
  To: Dmitry Morgun, Jeff Johnson
  Cc: linux-wireless, ath11k, linux-kernel, lvc-project, stable
In-Reply-To: <20260530114252.42615-1-d.morgun@ispras.ru>

On 5/30/2026 5:12 PM, Dmitry Morgun wrote:
> When the first entry in msdu_details has a zero buffer address,
> the code accesses msdu_details[i - 1] with i == 0, causing a
> buffer underflow.
> 
> Fix similarly to ath12k_wifi7_hal_rx_msdu_list_get() by adding
> a separate check for i == 0 before the main condition to prevent
> the out-of-bounds access.
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
> 
> Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
> Signed-off-by: Dmitry Morgun <d.morgun@ispras.ru>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>

^ permalink raw reply

* [PATCH wireless] wifi: cfg80211: convert pmsr_free_wk to wiphy_work to fix deadlock
From: Peddolla Harshavardhan Reddy @ 2026-07-03  8:25 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless

When a netlink socket that owns a PMSR session is closed,
cfg80211_release_pmsr() clears the request's nl_portid and queues
pmsr_free_wk to call cfg80211_pmsr_process_abort() asynchronously.

If the interface tears down concurrently, cfg80211_pmsr_wdev_down()
is called under wiphy_lock and calls cancel_work_sync(&pmsr_free_wk)
to wait for any running work. The work function acquires wiphy_lock
via guard(wiphy) before calling process_abort.

This is a deadlock: wdev_down holds wiphy_lock and blocks inside
cancel_work_sync(); pmsr_free_wk blocks trying to acquire that same
wiphy_lock. Neither thread can proceed.

The same deadlock is reachable from cfg80211_leave_locked(), which
calls cfg80211_pmsr_wdev_down() for all interface types under
wiphy_lock.

Fix this by converting pmsr_free_wk from a plain work_struct to a
wiphy_work. The wiphy_work dispatcher holds wiphy_lock when running
work items, so the explicit guard(wiphy) in the work function is no
longer needed. wiphy_work_cancel() can be called safely while holding
wiphy_lock - since wiphy_lock prevents the work from running
concurrently, wiphy_work_cancel() never blocks, eliminating the
deadlock.

Remove the cancel_work_sync() for pmsr_free_wk from the
NETDEV_GOING_DOWN handler. cfg80211_leave(), called unconditionally
just before it, already cancels any pending work under wiphy_lock
via wiphy_work_cancel() inside cfg80211_pmsr_wdev_down().

Fixes: 6dccbc9f3e1d ("wifi: cfg80211: cancel pmsr_free_wk in cfg80211_pmsr_wdev_down")
Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
---
 include/net/cfg80211.h | 2 +-
 net/wireless/core.c    | 3 +--
 net/wireless/core.h    | 2 +-
 net/wireless/pmsr.c    | 8 +++-----
 4 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8188ad200de5..3751a1d74765 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -7265,7 +7265,7 @@ struct wireless_dev {
 
 	struct list_head pmsr_list;
 	spinlock_t pmsr_lock;
-	struct work_struct pmsr_free_wk;
+	struct wiphy_work pmsr_free_wk;
 
 	unsigned long unprot_beacon_reported;
 
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 3dcf63b04c41..b6bb25ee89cd 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1613,7 +1613,7 @@ void cfg80211_init_wdev(struct wireless_dev *wdev)
 	INIT_LIST_HEAD(&wdev->mgmt_registrations);
 	INIT_LIST_HEAD(&wdev->pmsr_list);
 	spin_lock_init(&wdev->pmsr_lock);
-	INIT_WORK(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
+	wiphy_work_init(&wdev->pmsr_free_wk, cfg80211_pmsr_free_wk);
 
 #ifdef CONFIG_CFG80211_WEXT
 	wdev->wext.default_key = -1;
@@ -1747,7 +1747,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 			cfg80211_remove_links(wdev);
 		/* since we just did cfg80211_leave() nothing to do there */
 		cancel_work_sync(&wdev->disconnect_wk);
-		cancel_work_sync(&wdev->pmsr_free_wk);
 		break;
 	case NETDEV_DOWN:
 		wiphy_lock(&rdev->wiphy);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index df47ed6208a5..f60c66b88677 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -586,7 +586,7 @@ cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len,
 
 void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
 void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
-void cfg80211_pmsr_free_wk(struct work_struct *work);
+void cfg80211_pmsr_free_wk(struct wiphy *wiphy, struct wiphy_work *work);
 
 void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id);
 void cfg80211_remove_links(struct wireless_dev *wdev);
diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c
index c8447448f3a5..2c8db33d9c30 100644
--- a/net/wireless/pmsr.c
+++ b/net/wireless/pmsr.c
@@ -807,13 +807,11 @@ static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev)
 	}
 }
 
-void cfg80211_pmsr_free_wk(struct work_struct *work)
+void cfg80211_pmsr_free_wk(struct wiphy *wiphy, struct wiphy_work *work)
 {
 	struct wireless_dev *wdev = container_of(work, struct wireless_dev,
 						 pmsr_free_wk);
 
-	guard(wiphy)(wdev->wiphy);
-
 	cfg80211_pmsr_process_abort(wdev);
 }
 
@@ -829,7 +827,7 @@ void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
 	}
 	spin_unlock_bh(&wdev->pmsr_lock);
 
-	cancel_work_sync(&wdev->pmsr_free_wk);
+	wiphy_work_cancel(wdev->wiphy, &wdev->pmsr_free_wk);
 	if (found)
 		cfg80211_pmsr_process_abort(wdev);
 
@@ -844,7 +842,7 @@ void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid)
 	list_for_each_entry(req, &wdev->pmsr_list, list) {
 		if (req->nl_portid == portid) {
 			req->nl_portid = 0;
-			schedule_work(&wdev->pmsr_free_wk);
+			wiphy_work_queue(wdev->wiphy, &wdev->pmsr_free_wk);
 		}
 	}
 	spin_unlock_bh(&wdev->pmsr_lock);

base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v2] wifi: ath12k: fix scan command endianness on big endian
From: Baochen Qiang @ 2026-07-03  8:18 UTC (permalink / raw)
  To: Alexander Wilhelm, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260703-fix-channel-list-copy-v2-1-372c39306d79@westermo.com>



On 7/3/2026 3:35 PM, Alexander Wilhelm wrote:
> ath12k_wmi_scan_req_arg stores scan parameters in CPU-native byte order,
> while ath12k_wmi_send_scan_start_cmd() writes them into a WMI command
> buffer whose contents must be in little-endian format. The existing code
> copies the channel list and writes s_ssid and hint_bssid related values to
> the command buffer without endian conversion. As a result, scan requests
> contain invalid parameters on big-endian systems and fail.
> 
> Convert the channel list as well as the s_ssid and hint_bssid related
> values to little-endian before writing them to the WMI command buffer. This
> preserves the existing behaviour on little-endian systems while fixing scan
> requests on big-endian architectures.
> 
> Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
> ---
> Changes in v2:
> - Rebase on latest ath/master
> - Use additional __le32 conversion for s_ssid and hint_bssid related values
> - Reword commit message and description
> - Link to v1: https://lore.kernel.org/r/20260629-fix-channel-list-copy-v1-1-5ab826c46d7c@westermo.com
> ---
>  drivers/net/wireless/ath/ath12k/wmi.c | 20 ++++++++++++--------
>  drivers/net/wireless/ath/ath12k/wmi.h | 10 ++++++++++
>  2 files changed, 22 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index ad739bffcf88..4dab6eee80a1 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2637,9 +2637,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>  	struct wmi_tlv *tlv;
>  	void *ptr;
>  	int i, ret, len;
> -	u32 *tmp_ptr, extraie_len_with_pad = 0;
> -	struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
> -	struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
> +	__le32 *tmp_ptr;
> +	u32 extraie_len_with_pad = 0;
> +	struct ath12k_wmi_hint_short_ssid_params *s_ssid = NULL;
> +	struct ath12k_wmi_hint_bssid_params *hint_bssid = NULL;
>  
>  	len = sizeof(*cmd);
>  
> @@ -2722,9 +2723,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>  	tlv = ptr;
>  	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
>  	ptr += TLV_HDR_SIZE;
> -	tmp_ptr = (u32 *)ptr;
> +	tmp_ptr = (__le32 *)ptr;
>  
> -	memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
> +	for (i = 0; i < arg->num_chan; i++)
> +		tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
>  
>  	ptr += len;
>  
> @@ -2780,8 +2782,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>  		ptr += TLV_HDR_SIZE;
>  		s_ssid = ptr;
>  		for (i = 0; i < arg->num_hint_s_ssid; ++i) {
> -			s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;
> -			s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;
> +			s_ssid->freq_flags =
> +				cpu_to_le32(arg->hint_s_ssid[i].freq_flags);
> +			s_ssid->short_ssid =
> +				cpu_to_le32(arg->hint_s_ssid[i].short_ssid);
>  			s_ssid++;
>  		}
>  		ptr += len;
> @@ -2795,7 +2799,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>  		hint_bssid = ptr;
>  		for (i = 0; i < arg->num_hint_bssid; ++i) {
>  			hint_bssid->freq_flags =
> -				arg->hint_bssid[i].freq_flags;
> +				cpu_to_le32(arg->hint_bssid[i].freq_flags);
>  			ether_addr_copy(&arg->hint_bssid[i].bssid.addr[0],
>  					&hint_bssid->bssid.addr[0]);

the src and dst are wrongly swapped, should be

ether_addr_copy(&hint_bssid->bssid.addr[0], &arg->hint_bssid[i].bssid.addr[0]);

However since this is a pre-exising issue and not related to endian handling, not sure if
we should fix it as well in the same patch.

Jeff, your thought?

>  			hint_bssid++;
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 51f3426e1fcd..52e6068d9a64 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -3556,6 +3556,16 @@ struct ath12k_wmi_hint_bssid_arg {
>  	struct ath12k_wmi_mac_addr_params bssid;
>  };
>  
> +struct ath12k_wmi_hint_short_ssid_params {
> +	__le32 freq_flags;
> +	__le32 short_ssid;
> +};
> +
> +struct ath12k_wmi_hint_bssid_params {
> +	__le32 freq_flags;
> +	struct ath12k_wmi_mac_addr_params bssid;
> +};
> +
>  struct ath12k_wmi_scan_req_arg {
>  	u32 scan_id;
>  	u32 scan_req_id;
> 
> ---
> base-commit: fa1b1469f1c5f0f54ed9dab80106a117e7736bfd
> change-id: 20260317-fix-channel-list-copy-cef5cad24fb6
> 
> Best regards,


^ permalink raw reply

* Re: [PATCH RESEND] wifi: ath12k: fix MAC address copy on big endian
From: Alexander Wilhelm @ 2026-07-03  7:48 UTC (permalink / raw)
  To: Baochen Qiang; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <606bc37c-45ff-41d3-8f0f-942c3009c4b4@oss.qualcomm.com>

On Fri, Jul 03, 2026 at 03:10:23PM +0800, Baochen Qiang wrote:
> 
> 
> On 7/3/2026 2:36 PM, Alexander Wilhelm wrote:
> > On Fri, Jul 03, 2026 at 12:04:10PM +0800, Baochen Qiang wrote:
> >>
> >>
> >> On 7/2/2026 8:06 PM, Alexander Wilhelm wrote:
> >>> On Thu, Jul 02, 2026 at 05:56:01PM +0800, Baochen Qiang wrote:
> >>>>
> >>>>
> >>>> On 7/2/2026 5:17 PM, Alexander Wilhelm wrote:
> >>>>> On Thu, Jul 02, 2026 at 10:41:25AM +0200, Alexander Wilhelm wrote:
> >>>>>> On Thu, Jul 02, 2026 at 04:12:00PM +0800, Baochen Qiang wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>> On 6/29/2026 3:55 PM, Alexander Wilhelm wrote:
> >>>>>>>> The ath12k_dp_get_mac_addr function performs a simple memcpy from a
> >>>>>>>> CPU-native data types into an u8 array. On a big-endian architecture, this
> >>>>>>>> later results in a null‑pointer dereference. Convert the data to
> >>>>>>>
> >>>>>>> Alex, did you find a time to investigate the root cause of the null pointer?
> >>>>>
> >>>>> Hi Baochen,
> >>>>>
> >>>>> I am now running kernel v6.18.26, and it looks like the null-pointer issue is
> >>>>> gone. I only see the following log messages:
> >>>>>
> >>>>>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
> >>>>
> >>>> what is the actual mac addr reported from firmware in the PEER MAP event? My understanding
> >>>> is that, without this patch (if we really need it) we get a wrong mac addr, then in
> >>>> ath12k_dp_link_peer_map_event() we are more likely to fail the peer look up hence would
> >>>> create a new peer and wakeup the waiting thread. But the log here clearly indicates that
> >>>> the wait timeout, which does not make sense to me.
> >>
> >> I think I can understand the behavior here: even if wakeup happens, the waiter in
> >> ath12k_wait_for_dp_link_peer_common() checks the map result by calling
> >> ath12k_dp_link_peer_find_by_vdev_and_addr(). Since the mac addr of the newly created peer
> >> does not match, check failed. Finally we get timeout.
> >>
> >>>
> >>> I have now added the following debug output for `peer_map_ev` inside of
> >>> `ath12k_dp_htt_htc_t2h_msg_handler`:
> >>>
> >>>     /* DEBUG */
> >>>     switch (type) {
> >>>     case HTT_T2H_MSG_TYPE_PEER_MAP:
> >>>     case HTT_T2H_MSG_TYPE_PEER_MAP2:
> >>>     case HTT_T2H_MSG_TYPE_PEER_MAP3:
> >>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info: %08X\n", le32_to_cpu(resp->peer_map_ev.info));
> >>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.mac_addr_l32: %08X\n", le32_to_cpu(resp->peer_map_ev.mac_addr_l32));
> >>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info1: %08X\n", le32_to_cpu(resp->peer_map_ev.info1));
> >>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info2: %08X\n", le32_to_cpu(resp->peer_map_ev.info2));
> >>>         break;
> >>>     default:
> >>>         break;
> >>>     }
> >>>
> >>> Here is the result:
> >>>
> >>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
> >>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
> >>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
> >>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
> >>>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
> >>>     ath12k_pci 0001:01:00.0: failed to create vdev 04:f0:21:c9:e0:0e ret -110
> >>>     ath12k_pci 0001:01:00.0: failed to assign chanctx for vif 04:f0:21:c9:e0:0e link id 0 link vif is already started
> >>>     ath12k_pci 0001:01:00.0: invalid vdev id in vdev delete resp ev 0
> >>>
> >>> Let me know if you see anything suspicious or if you need additional debug
> >>> information.
> >>
> >> I am not really sure about the final mac addr and vdev id passed to
> >> ath12k_dp_link_peer_map_event(), so can you also add print below?
> >>
> >> diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c
> >> b/drivers/net/wireless/ath/ath12k/dp_peer.c
> >> index 47d009a0d61f..3e8201d536a5 100644
> >> --- a/drivers/net/wireless/ath/ath12k/dp_peer.c
> >> +++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
> >> @@ -162,6 +162,9 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id,
> >> u16 peer_
> >>         struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
> >>         struct ath12k *ar;
> >>
> >> +       pr_info("peer map event: vdev_id %u peer_id %u mac_addr %pM ast_hash %u hw_peer_id
> >> %u\n",
> >> +               vdev_id, peer_id, mac_addr, ast_hash, hw_peer_id);
> >> +
> >>         spin_lock_bh(&dp->dp_lock);
> >>         peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
> >>         if (!peer) {
> > 
> > Sure, here is the output:
> > 
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
> >     peer map event: vdev_id 0 peer_id 2 mac_addr d902298bM ast_hash 5 hw_peer_id 757
> 
> what is d902298bM? are you using Linux? seems %pM is not properly formatted in your
> environment.

Sory. I got a typo while copy-and-paste. Here's the output:

    peer map event: vdev_id 0 peer_id 2 mac_addr c9:21:f0:04:0e:e0 ast_hash 5 hw_peer_id 757


Best regards
Alexander Wilhelm

^ permalink raw reply

* Re: [PATCH v2] wifi: ath12k: fix scan command endianness on big endian
From: Baochen Qiang @ 2026-07-03  7:46 UTC (permalink / raw)
  To: Alexander Wilhelm, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260703-fix-channel-list-copy-v2-1-372c39306d79@westermo.com>



On 7/3/2026 3:35 PM, Alexander Wilhelm wrote:
> ath12k_wmi_scan_req_arg stores scan parameters in CPU-native byte order,
> while ath12k_wmi_send_scan_start_cmd() writes them into a WMI command
> buffer whose contents must be in little-endian format. The existing code
> copies the channel list and writes s_ssid and hint_bssid related values to
> the command buffer without endian conversion. As a result, scan requests
> contain invalid parameters on big-endian systems and fail.
> 
> Convert the channel list as well as the s_ssid and hint_bssid related
> values to little-endian before writing them to the WMI command buffer. This
> preserves the existing behaviour on little-endian systems while fixing scan
> requests on big-endian architectures.
> 
> Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>


^ permalink raw reply

* [PATCH v2] wifi: ath12k: fix scan command endianness on big endian
From: Alexander Wilhelm @ 2026-07-03  7:35 UTC (permalink / raw)
  To: Jeff Johnson, Baochen Qiang; +Cc: linux-wireless, ath12k, linux-kernel

ath12k_wmi_scan_req_arg stores scan parameters in CPU-native byte order,
while ath12k_wmi_send_scan_start_cmd() writes them into a WMI command
buffer whose contents must be in little-endian format. The existing code
copies the channel list and writes s_ssid and hint_bssid related values to
the command buffer without endian conversion. As a result, scan requests
contain invalid parameters on big-endian systems and fail.

Convert the channel list as well as the s_ssid and hint_bssid related
values to little-endian before writing them to the WMI command buffer. This
preserves the existing behaviour on little-endian systems while fixing scan
requests on big-endian architectures.

Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
---
Changes in v2:
- Rebase on latest ath/master
- Use additional __le32 conversion for s_ssid and hint_bssid related values
- Reword commit message and description
- Link to v1: https://lore.kernel.org/r/20260629-fix-channel-list-copy-v1-1-5ab826c46d7c@westermo.com
---
 drivers/net/wireless/ath/ath12k/wmi.c | 20 ++++++++++++--------
 drivers/net/wireless/ath/ath12k/wmi.h | 10 ++++++++++
 2 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index ad739bffcf88..4dab6eee80a1 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2637,9 +2637,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	struct wmi_tlv *tlv;
 	void *ptr;
 	int i, ret, len;
-	u32 *tmp_ptr, extraie_len_with_pad = 0;
-	struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
-	struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
+	__le32 *tmp_ptr;
+	u32 extraie_len_with_pad = 0;
+	struct ath12k_wmi_hint_short_ssid_params *s_ssid = NULL;
+	struct ath12k_wmi_hint_bssid_params *hint_bssid = NULL;
 
 	len = sizeof(*cmd);
 
@@ -2722,9 +2723,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	tlv = ptr;
 	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
 	ptr += TLV_HDR_SIZE;
-	tmp_ptr = (u32 *)ptr;
+	tmp_ptr = (__le32 *)ptr;
 
-	memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
+	for (i = 0; i < arg->num_chan; i++)
+		tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
 
 	ptr += len;
 
@@ -2780,8 +2782,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 		ptr += TLV_HDR_SIZE;
 		s_ssid = ptr;
 		for (i = 0; i < arg->num_hint_s_ssid; ++i) {
-			s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;
-			s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;
+			s_ssid->freq_flags =
+				cpu_to_le32(arg->hint_s_ssid[i].freq_flags);
+			s_ssid->short_ssid =
+				cpu_to_le32(arg->hint_s_ssid[i].short_ssid);
 			s_ssid++;
 		}
 		ptr += len;
@@ -2795,7 +2799,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 		hint_bssid = ptr;
 		for (i = 0; i < arg->num_hint_bssid; ++i) {
 			hint_bssid->freq_flags =
-				arg->hint_bssid[i].freq_flags;
+				cpu_to_le32(arg->hint_bssid[i].freq_flags);
 			ether_addr_copy(&arg->hint_bssid[i].bssid.addr[0],
 					&hint_bssid->bssid.addr[0]);
 			hint_bssid++;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 51f3426e1fcd..52e6068d9a64 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3556,6 +3556,16 @@ struct ath12k_wmi_hint_bssid_arg {
 	struct ath12k_wmi_mac_addr_params bssid;
 };
 
+struct ath12k_wmi_hint_short_ssid_params {
+	__le32 freq_flags;
+	__le32 short_ssid;
+};
+
+struct ath12k_wmi_hint_bssid_params {
+	__le32 freq_flags;
+	struct ath12k_wmi_mac_addr_params bssid;
+};
+
 struct ath12k_wmi_scan_req_arg {
 	u32 scan_id;
 	u32 scan_req_id;

---
base-commit: fa1b1469f1c5f0f54ed9dab80106a117e7736bfd
change-id: 20260317-fix-channel-list-copy-cef5cad24fb6

Best regards,
-- 
Alexander Wilhelm <alexander.wilhelm@westermo.com>


^ permalink raw reply related

* Re: [PATCH v2 ath-current] wifi: ath12k: avoid flushing scan timeout under the wiphy lock
From: Johannes Berg @ 2026-07-03  7:15 UTC (permalink / raw)
  To: Runyu Xiao, Jeff Johnson
  Cc: Wen Gong, Carl Huang, Karthikeyan Periyasamy, P Praneesh,
	Ramya Gnanasekar, linux-wireless, ath12k, linux-kernel, stable
In-Reply-To: <20260703060219.2998148-1-runyu.xiao@seu.edu.cn>

On Fri, 2026-07-03 at 14:02 +0800, Runyu Xiao wrote:
> 
> @@ -9975,6 +9974,15 @@ void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
>  
>  	lockdep_assert_wiphy(hw->wiphy);
>  
> +	/*
> +	 * scan.timeout takes the wiphy lock before aborting the scan, so do
> +	 * not wait for it from the locked stop path below.
> +	 */
> +	wiphy_unlock(hw->wiphy);
> 

No. Don't drop locks in the middle of someone else's (mac80211 here)
process.

If that work requires wiphy mutex anyway, better just convert it to a
wiphy work.

johannes

^ permalink raw reply

* Re: [PATCH RESEND] wifi: ath12k: fix MAC address copy on big endian
From: Baochen Qiang @ 2026-07-03  7:10 UTC (permalink / raw)
  To: Alexander Wilhelm; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <akdYU_Lejd2FZeIN@FUE-ALEWI-WINX>



On 7/3/2026 2:36 PM, Alexander Wilhelm wrote:
> On Fri, Jul 03, 2026 at 12:04:10PM +0800, Baochen Qiang wrote:
>>
>>
>> On 7/2/2026 8:06 PM, Alexander Wilhelm wrote:
>>> On Thu, Jul 02, 2026 at 05:56:01PM +0800, Baochen Qiang wrote:
>>>>
>>>>
>>>> On 7/2/2026 5:17 PM, Alexander Wilhelm wrote:
>>>>> On Thu, Jul 02, 2026 at 10:41:25AM +0200, Alexander Wilhelm wrote:
>>>>>> On Thu, Jul 02, 2026 at 04:12:00PM +0800, Baochen Qiang wrote:
>>>>>>>
>>>>>>>
>>>>>>> On 6/29/2026 3:55 PM, Alexander Wilhelm wrote:
>>>>>>>> The ath12k_dp_get_mac_addr function performs a simple memcpy from a
>>>>>>>> CPU-native data types into an u8 array. On a big-endian architecture, this
>>>>>>>> later results in a null‑pointer dereference. Convert the data to
>>>>>>>
>>>>>>> Alex, did you find a time to investigate the root cause of the null pointer?
>>>>>
>>>>> Hi Baochen,
>>>>>
>>>>> I am now running kernel v6.18.26, and it looks like the null-pointer issue is
>>>>> gone. I only see the following log messages:
>>>>>
>>>>>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
>>>>
>>>> what is the actual mac addr reported from firmware in the PEER MAP event? My understanding
>>>> is that, without this patch (if we really need it) we get a wrong mac addr, then in
>>>> ath12k_dp_link_peer_map_event() we are more likely to fail the peer look up hence would
>>>> create a new peer and wakeup the waiting thread. But the log here clearly indicates that
>>>> the wait timeout, which does not make sense to me.
>>
>> I think I can understand the behavior here: even if wakeup happens, the waiter in
>> ath12k_wait_for_dp_link_peer_common() checks the map result by calling
>> ath12k_dp_link_peer_find_by_vdev_and_addr(). Since the mac addr of the newly created peer
>> does not match, check failed. Finally we get timeout.
>>
>>>
>>> I have now added the following debug output for `peer_map_ev` inside of
>>> `ath12k_dp_htt_htc_t2h_msg_handler`:
>>>
>>>     /* DEBUG */
>>>     switch (type) {
>>>     case HTT_T2H_MSG_TYPE_PEER_MAP:
>>>     case HTT_T2H_MSG_TYPE_PEER_MAP2:
>>>     case HTT_T2H_MSG_TYPE_PEER_MAP3:
>>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info: %08X\n", le32_to_cpu(resp->peer_map_ev.info));
>>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.mac_addr_l32: %08X\n", le32_to_cpu(resp->peer_map_ev.mac_addr_l32));
>>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info1: %08X\n", le32_to_cpu(resp->peer_map_ev.info1));
>>>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info2: %08X\n", le32_to_cpu(resp->peer_map_ev.info2));
>>>         break;
>>>     default:
>>>         break;
>>>     }
>>>
>>> Here is the result:
>>>
>>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
>>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
>>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
>>>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
>>>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
>>>     ath12k_pci 0001:01:00.0: failed to create vdev 04:f0:21:c9:e0:0e ret -110
>>>     ath12k_pci 0001:01:00.0: failed to assign chanctx for vif 04:f0:21:c9:e0:0e link id 0 link vif is already started
>>>     ath12k_pci 0001:01:00.0: invalid vdev id in vdev delete resp ev 0
>>>
>>> Let me know if you see anything suspicious or if you need additional debug
>>> information.
>>
>> I am not really sure about the final mac addr and vdev id passed to
>> ath12k_dp_link_peer_map_event(), so can you also add print below?
>>
>> diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c
>> b/drivers/net/wireless/ath/ath12k/dp_peer.c
>> index 47d009a0d61f..3e8201d536a5 100644
>> --- a/drivers/net/wireless/ath/ath12k/dp_peer.c
>> +++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
>> @@ -162,6 +162,9 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id,
>> u16 peer_
>>         struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
>>         struct ath12k *ar;
>>
>> +       pr_info("peer map event: vdev_id %u peer_id %u mac_addr %pM ast_hash %u hw_peer_id
>> %u\n",
>> +               vdev_id, peer_id, mac_addr, ast_hash, hw_peer_id);
>> +
>>         spin_lock_bh(&dp->dp_lock);
>>         peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
>>         if (!peer) {
> 
> Sure, here is the output:
> 
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
>     peer map event: vdev_id 0 peer_id 2 mac_addr d902298bM ast_hash 5 hw_peer_id 757

what is d902298bM? are you using Linux? seems %pM is not properly formatted in your
environment.

>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
>     ath12k_pci 0001:01:00.0: failed to create vdev 04:f0:21:c9:e0:0e ret -110
>     ath12k_pci 0001:01:00.0: failed to assign chanctx for vif 04:f0:21:c9:e0:0e link id 0 link vif is already started
>     ath12k_pci 0001:01:00.0: invalid vdev id in vdev delete resp ev 0
> 
> 
> Best regards
> Alexander Wilhelm


^ permalink raw reply

* Re: [PATCH v2] wifi: ath12k: fix survey indexing across bands
From: Matthew Leach @ 2026-07-03  7:06 UTC (permalink / raw)
  To: Nicolas Escande
  Cc: Jeff Johnson, Vasanthakumar Thiagarajan, Baochen Qiang,
	Ramya Gnanasekar, Karthikeyan Periyasamy, Pradeep Kumar Chitrapu,
	P Praneesh, Sriram R, linux-wireless, ath12k, linux-kernel,
	kernel, Rameshkumar Sundaram, Rameshkumar Sundaram, Jeff Johnson
In-Reply-To: <DJOE9Y6P3ZOV.371FAU647MOYR@gmail.com>

"Nicolas Escande" <nico.escande@gmail.com> writes:

> On Thu Jul 2, 2026 at 12:50 PM CEST, Matthew Leach wrote:
>> When running 'iw dev wlan0 survey dump' the values for the channel busy
>> time have the same sequence across bands. This is caused by indexing
>> into the ath12k survey array using a band-local index rather than the
>> global index passed by mac80211. This results in surveys for 5 GHz and 6
>> GHz channels returning values from 2.4 GHz slots, making the survey
>> unusable on those bands. Further, there are redundant survey slots for
>> multi-radio/single-phy instances.
>>
>> Fix by moving the survey data into ath12k_hw so multiple radios under a
>> single wiphy share one table, and index into it using the global
>> mac80211 index. A new spinlock in ath12k_hw serialises access to the
>> survey array, which is now shared across all radios under a single hw.
>>
>> Band busy-times Before this fix:
>>
>> 2.4 GHz: 9, 2, 2, 2, 4, 2, 10, 16, 4, 12, 5
>> 5 GHz:   9, 2, 2, 2, 4, 2, 10, 16, 4, 12, 5
>> 6 GHz:   9, 2, 2, 2, 4, 2, 10, 16, 4, 12, 5
>>
>> After this fix, times are independent:
>>
>> 2.4 GHz: 23, 5,  5,  12, 2,   12,  26,  5,   3,  1,  27
>> 5 GHz:   30, 40, 29, 27, 118, 118, 112, 120, 11, 11, 11
>> 6 GHz:   1,  0,  0,  0,  0,   0,   0,   0,   0,  0,  1
>>
>> Tested-on: wcn7850 hw2.0 PCI WLAN.IOE_HMT.1.1-00018-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1
>>
>
> Hello,

Hi Nicolas,

> I see that this is supposed to work on single phy device, but could someone
> do a proper test to ensure that it will work on QCN9274 split phy ?
>
> I know this is a big ask, and usually I would do it, but I do not have a setup
> with a new enough kernel running to test this right now.

If you're looking at getting this tested on a split-phy, I'll get v3
pushed out asap which incorporates Rameshkumar's comment.

Thanks,
-- 
Matt

^ permalink raw reply

* Re: [PATCH ath-current] wifi: ath12k: Fix low MLO RX throughput on WCN7850
From: Baochen Qiang @ 2026-07-03  7:04 UTC (permalink / raw)
  To: Yingying Tang, ath12k; +Cc: linux-wireless, yintang
In-Reply-To: <20260610053315.2249912-1-yingying.tang@oss.qualcomm.com>



On 6/10/2026 1:33 PM, Yingying Tang wrote:
> Commit [1] introduced a regression causing severely degraded MLO RX
> throughput on WCN7850.
> 
> On WCN7850, there is only a single ar instance, but MLO uses two
> link IDs. ath12k_dp_peer->hw_links[] is indexed using ar->hw_link_id,
> which causes both MLO link IDs to be stored at the same index.
> 
> As a result, an incorrect link ID is assigned to MSDUs in
> ath12k_dp_rx_deliver_msdu(), leading to severe MLO RX throughput loss.
> 
> Different chipsets identify the per-MSDU link differently:
> 
>   - On QCN9274 / IPQ5332, the host owns multiple ar instances and the
>     per-MSDU hw_link_id from the RX descriptor maps cleanly through
>     dp_peer->hw_links[hw_link_id] to the IEEE link_id.
> 
>   - On single-ar chipsets like WCN7850 / QCC2072, there is only one ar
>     instance for both MLO links, so dp_peer->hw_links[] has just one
>     valid slot and cannot be used to distinguish the two links. To
>     resolve the link, walk dp_peer->link_peers[] and match by
>     rxcb->peer_id, which on the link_peer side identifies the link
>     peer for the MSDU.
> 
> Add a new hw_op set_rx_link_id() so each chipset resolves the link
> on the RX fast path using whatever signal it actually has, and let
> the op itself decide whether to populate rx_status::link_valid and
> rx_status::link_id:
> 
>   QCN9274 / IPQ5332 : always derive link_id from
>                       dp_peer->hw_links[rxcb->hw_link_id] and set
>                       link_valid.
>   WCN7850 / QCC2072 : walk the link_peers[] of dp_peer to find the
>                       link_peer whose peer_id matches rxcb->peer_id,
>                       and set link_valid only when a match is found.
>                       Otherwise leave link_valid clear so that
>                       mac80211 can fall back to its own link
>                       resolution path (via addr2 / deflink).
> 
> For WCN7850 / QCC2072, walking dp_peer->link_peers[] is bounded by
> the number of links actually populated, so introduce a link_peers_map
> bitmap (unsigned long) in struct ath12k_dp_peer that tracks populated
> slots and use for_each_set_bit() to iterate. Non-MLO clients hit one
> slot, current MLO clients hit two; the full ATH12K_NUM_MAX_LINKS
> array is never scanned. The bitmap is maintained with WRITE_ONCE() on
> the write side (under dp_hw->peer_lock) paired with READ_ONCE() on
> both the lockless RX read side and the write-side RMW for KCSAN
> correctness.
> 
> Also guard the dp_peer dereference in ath12k_mac_peer_cleanup_all()
> with a NULL check, since peer->dp_peer can be NULL for self-peers or
> peers not yet fully assigned, the pre-existing rcu_assign_pointer()
> call there had the same latent issue.
> 
> This restores the correct link ID on WCN7850 without changing the
> QCN9274 / IPQ5332 data path, which keeps its O(1) hw_links[]
> indexing.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
> 
> Fixes: 11157e0910fd ("wifi: ath12k: Use ath12k_dp_peer in per packet Tx & Rx paths") # [1]
> Signed-off-by: Yingying Tang <yingying.tang@oss.qualcomm.com>

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>


^ permalink raw reply

* Re: [PATCH 2/2] wifi: ath12k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
From: Baochen Qiang @ 2026-07-03  7:03 UTC (permalink / raw)
  To: Manivannan Sadhasivam, jjohnson
  Cc: linux-wireless, ath12k, ath11k, linux-kernel, mani,
	Alex Williamson
In-Reply-To: <20260623141649.41087-2-manivannan.sadhasivam@oss.qualcomm.com>



On 6/23/2026 10:16 PM, Manivannan Sadhasivam wrote:
> ath12k_pci_soc_global_reset() tries to reset the device by writing to the
> PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure
> that the write gets flushed to the device before the delay.
> 
> This may lead to the delay on the host to be insufficient, if the posted
> write doesn't reach the device before the delay.
> 
> So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and
> before the delay.
> 
> Compile tested only.
> 
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Reported-by: Alex Williamson <alex@shazbot.org>
> Closes: https://lore.kernel.org/linux-pci/20260622160822.09350246@shazbot.org
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH 1/2] wifi: ath11k: Flush the posted write after writing to PCIE_SOC_GLOBAL_RESET
From: Baochen Qiang @ 2026-07-03  7:03 UTC (permalink / raw)
  To: Manivannan Sadhasivam, jjohnson
  Cc: linux-wireless, ath12k, ath11k, linux-kernel, mani,
	Alex Williamson
In-Reply-To: <20260623141649.41087-1-manivannan.sadhasivam@oss.qualcomm.com>



On 6/23/2026 10:16 PM, Manivannan Sadhasivam wrote:
> ath11k_pci_soc_global_reset() tries to reset the device by writing to the
> PCIE_SOC_GLOBAL_RESET register. But it doesn't do a read-back to ensure
> that the write gets flushed to the device before the delay.
> 
> This may lead to the delay on the host to be insufficient, if the posted
> write doesn't reach the device before the delay.
> 
> So add a read-back after writing to the PCIE_SOC_GLOBAL_RESET register and
> before the delay.
> 
> Compile tested only.
> 
> Fixes: f3c603d412b3 ("ath11k: reset MHI during power down and power up")
> Reported-by: Alex Williamson <alex@shazbot.org>
> Closes: https://lore.kernel.org/linux-pci/20260622160822.09350246@shazbot.org
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH] wifi: ath11k: fix potential buffer underflow in ath11k_hal_rx_msdu_list_get()
From: Baochen Qiang @ 2026-07-03  6:45 UTC (permalink / raw)
  To: Dmitry Morgun, Jeff Johnson
  Cc: linux-wireless, ath11k, linux-kernel, lvc-project, stable
In-Reply-To: <20260530114252.42615-1-d.morgun@ispras.ru>



On 5/30/2026 7:42 PM, Dmitry Morgun wrote:
> When the first entry in msdu_details has a zero buffer address,
> the code accesses msdu_details[i - 1] with i == 0, causing a
> buffer underflow.
> 
> Fix similarly to ath12k_wifi7_hal_rx_msdu_list_get() by adding
> a separate check for i == 0 before the main condition to prevent
> the out-of-bounds access.
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
> 
> Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
> Signed-off-by: Dmitry Morgun <d.morgun@ispras.ru>

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH RESEND] wifi: ath12k: fix MAC address copy on big endian
From: Alexander Wilhelm @ 2026-07-03  6:36 UTC (permalink / raw)
  To: Baochen Qiang; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <980e1f5c-a845-4180-970d-02f6496f2956@oss.qualcomm.com>

On Fri, Jul 03, 2026 at 12:04:10PM +0800, Baochen Qiang wrote:
> 
> 
> On 7/2/2026 8:06 PM, Alexander Wilhelm wrote:
> > On Thu, Jul 02, 2026 at 05:56:01PM +0800, Baochen Qiang wrote:
> >>
> >>
> >> On 7/2/2026 5:17 PM, Alexander Wilhelm wrote:
> >>> On Thu, Jul 02, 2026 at 10:41:25AM +0200, Alexander Wilhelm wrote:
> >>>> On Thu, Jul 02, 2026 at 04:12:00PM +0800, Baochen Qiang wrote:
> >>>>>
> >>>>>
> >>>>> On 6/29/2026 3:55 PM, Alexander Wilhelm wrote:
> >>>>>> The ath12k_dp_get_mac_addr function performs a simple memcpy from a
> >>>>>> CPU-native data types into an u8 array. On a big-endian architecture, this
> >>>>>> later results in a null‑pointer dereference. Convert the data to
> >>>>>
> >>>>> Alex, did you find a time to investigate the root cause of the null pointer?
> >>>
> >>> Hi Baochen,
> >>>
> >>> I am now running kernel v6.18.26, and it looks like the null-pointer issue is
> >>> gone. I only see the following log messages:
> >>>
> >>>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
> >>
> >> what is the actual mac addr reported from firmware in the PEER MAP event? My understanding
> >> is that, without this patch (if we really need it) we get a wrong mac addr, then in
> >> ath12k_dp_link_peer_map_event() we are more likely to fail the peer look up hence would
> >> create a new peer and wakeup the waiting thread. But the log here clearly indicates that
> >> the wait timeout, which does not make sense to me.
> 
> I think I can understand the behavior here: even if wakeup happens, the waiter in
> ath12k_wait_for_dp_link_peer_common() checks the map result by calling
> ath12k_dp_link_peer_find_by_vdev_and_addr(). Since the mac addr of the newly created peer
> does not match, check failed. Finally we get timeout.
> 
> > 
> > I have now added the following debug output for `peer_map_ev` inside of
> > `ath12k_dp_htt_htc_t2h_msg_handler`:
> > 
> >     /* DEBUG */
> >     switch (type) {
> >     case HTT_T2H_MSG_TYPE_PEER_MAP:
> >     case HTT_T2H_MSG_TYPE_PEER_MAP2:
> >     case HTT_T2H_MSG_TYPE_PEER_MAP3:
> >         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info: %08X\n", le32_to_cpu(resp->peer_map_ev.info));
> >         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.mac_addr_l32: %08X\n", le32_to_cpu(resp->peer_map_ev.mac_addr_l32));
> >         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info1: %08X\n", le32_to_cpu(resp->peer_map_ev.info1));
> >         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info2: %08X\n", le32_to_cpu(resp->peer_map_ev.info2));
> >         break;
> >     default:
> >         break;
> >     }
> > 
> > Here is the result:
> > 
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
> >     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
> >     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
> >     ath12k_pci 0001:01:00.0: failed to create vdev 04:f0:21:c9:e0:0e ret -110
> >     ath12k_pci 0001:01:00.0: failed to assign chanctx for vif 04:f0:21:c9:e0:0e link id 0 link vif is already started
> >     ath12k_pci 0001:01:00.0: invalid vdev id in vdev delete resp ev 0
> > 
> > Let me know if you see anything suspicious or if you need additional debug
> > information.
> 
> I am not really sure about the final mac addr and vdev id passed to
> ath12k_dp_link_peer_map_event(), so can you also add print below?
> 
> diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c
> b/drivers/net/wireless/ath/ath12k/dp_peer.c
> index 47d009a0d61f..3e8201d536a5 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_peer.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
> @@ -162,6 +162,9 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id,
> u16 peer_
>         struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
>         struct ath12k *ar;
> 
> +       pr_info("peer map event: vdev_id %u peer_id %u mac_addr %pM ast_hash %u hw_peer_id
> %u\n",
> +               vdev_id, peer_id, mac_addr, ast_hash, hw_peer_id);
> +
>         spin_lock_bh(&dp->dp_lock);
>         peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
>         if (!peer) {

Sure, here is the output:

    ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
    ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
    ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
    ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
    peer map event: vdev_id 0 peer_id 2 mac_addr d902298bM ast_hash 5 hw_peer_id 757
    ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
    ath12k_pci 0001:01:00.0: failed to create vdev 04:f0:21:c9:e0:0e ret -110
    ath12k_pci 0001:01:00.0: failed to assign chanctx for vif 04:f0:21:c9:e0:0e link id 0 link vif is already started
    ath12k_pci 0001:01:00.0: invalid vdev id in vdev delete resp ev 0


Best regards
Alexander Wilhelm

^ permalink raw reply

* Re: [PATCH RESEND] wifi: ath12k: fix channel list copy on big endian
From: Baochen Qiang @ 2026-07-03  6:31 UTC (permalink / raw)
  To: Alexander Wilhelm; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <akdNdQPM2jdbMvgf@FUE-ALEWI-WINX>



On 7/3/2026 1:49 PM, Alexander Wilhelm wrote:
> On Fri, Jul 03, 2026 at 10:48:11AM +0800, Baochen Qiang wrote:
>>
>>
>> On 7/2/2026 8:18 PM, Alexander Wilhelm wrote:
>>> On Thu, Jul 02, 2026 at 10:44:46AM +0200, Alexander Wilhelm wrote:
>>>> On Thu, Jul 02, 2026 at 04:27:44PM +0800, Baochen Qiang wrote:
>>>>>
>>>>>
>>>>> On 6/29/2026 3:46 PM, Alexander Wilhelm wrote:
>>>>>> The ath12k_wmi_scan_req_arg structure defines the channel list in
>>>>>> CPU-native order, while wmi_start_scan_cmd expects the values in
>>>>>> little-endian format. The simple memcpy causes the hardware scan to fail on
>>>>>> big-endian architectures. Set __le32* type for the tmp_ptr and swap channel
>>>>>> values to support both architectures correctly.
>>>>>>
>>>>>> Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
>>>>>> ---
>>>>>>  drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++---
>>>>>>  1 file changed, 5 insertions(+), 3 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
>>>>>> index 65a05a9520ff..9e1d3c662852 100644
>>>>>> --- a/drivers/net/wireless/ath/ath12k/wmi.c
>>>>>> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
>>>>>> @@ -2571,7 +2571,8 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>>>>>>  	struct wmi_tlv *tlv;
>>>>>>  	void *ptr;
>>>>>>  	int i, ret, len;
>>>>>> -	u32 *tmp_ptr, extraie_len_with_pad = 0;
>>>>>> +	__le32 *tmp_ptr;
>>>>>> +	u32 extraie_len_with_pad = 0;
>>>>>>  	struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
>>>>>>  	struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
>>>>>>  
>>>>>> @@ -2656,9 +2657,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>>>>>>  	tlv = ptr;
>>>>>>  	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
>>>>>>  	ptr += TLV_HDR_SIZE;
>>>>>> -	tmp_ptr = (u32 *)ptr;
>>>>>> +	tmp_ptr = (__le32 *)ptr;
>>>>>>  
>>>>>> -	memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
>>>>>> +	for (i = 0; i < arg->num_chan; i++)
>>>>>> +		tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
>>>>>>  
>>>>>>  	ptr += len;
>>>>>>  
>>>>>>
>>>>>
>>>>> seems hint_s_ssid and hint_bssid at the last also need the endian conversion?
>>>
>>> `hist_s_ssid` and `hint_bssid` are both structs within
>>> `ath12k_wmi_scan_req_arg`, and the remaining member variables are also stored in
>>> CPU order. Therefore, it seems wrong to me to perform byte swapping at this
>>> point. What I actually need to swap is the data written through `ptr`, not the
>>> structure members themselves. For that reason, I could also use the `__le32
>>> *tmp_ptr` approach. What do you think about that?
>>
>> Maybe I was not clear. I intended to mean the ptr:
>>
>> @@ -2728,8 +2728,8 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>>                 ptr += TLV_HDR_SIZE;
>>                 s_ssid = ptr;
>>                 for (i = 0; i < arg->num_hint_s_ssid; ++i) {
>> -                       s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;
>> -                       s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;
>> +                       s_ssid->freq_flags = cpu_to_le32(arg->hint_s_ssid[i].freq_flags);
>> +                       s_ssid->short_ssid = cpu_to_le32(arg->hint_s_ssid[i].short_ssid);
> 
> No, I understood what you meant. The issue is that the upper two lines will
> trigger sparse warnings. The member variables `freq_flags` and `short_ssid` are
> used on both the left-hand side and the right-hand side as members of the same
> `struct ath12k_wmi_hint_short_ssid_arg`. I would keep these fields as `u32` and
> use `tmp_ptr` on the left-hand side instead of `s_ssid` to keep things
> consistent. Alternatively, I could introduce a separate structure specifically
> for this use case.

Ah, I get your point. You are right, the issue is both the WMI cmd member and the arg use
the same definition.

Please introduce new structures for this. Note ath12k has a guidance on WMI interface
naming: for those interfacing with firmware, use the _params as the suffix:

e.g.:
	struct ath12k_wmi_hint_short_ssid_params
	struct ath12k_wmi_hint_bssid_params

for those host-used only use the _arg suffix, like the existing ones:

	struct ath12k_wmi_hint_short_ssid_arg;
	struct ath12k_wmi_hint_bssid_arg;

> 
>>                         s_ssid++;
>>                 }
>>                 ptr += len;
>> @@ -2743,7 +2743,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>>                 hint_bssid = ptr;
>>                 for (i = 0; i < arg->num_hint_bssid; ++i) {
>>                         hint_bssid->freq_flags =
>> -                               arg->hint_bssid[i].freq_flags;
>> +                               cpu_to_le32(arg->hint_bssid[i].freq_flags);
>>                         ether_addr_copy(&arg->hint_bssid[i].bssid.addr[0],
>>                                         &hint_bssid->bssid.addr[0]);
>>
>>>
>>> One thing I am still unsure about is the use of `ether_addr_copy()`. Can I
>>> simply copy the bytes as-is here, or does the address also need to be
>>> byte-swapped? I could not find any place where this address is being populated,
>>> so I am not sure what byte order it is expected to be in.
>>
>> I think you are talking about ath12k_wmi_hint_bssid_arg::bssid, right? For now ath12k does
>> not populate hint_bssid or hint_s_ssid members, so bssid always remain empty. But if we
>> are going to populate it I think the address originates from userspace and there it is
>> passed in byte steams, so byte-swapping not required I think.
> 
> Okay, sounds good. I'll keep the `memcpy()` at this location and prepare the
> next patch version.
> 
> 
> Best regards
> Alexander Wilhelm


^ permalink raw reply

* Re: [PATCH ath-current] wifi: ath12k: Fix low MLO RX throughput on WCN7850
From: Rameshkumar Sundaram @ 2026-07-03  6:10 UTC (permalink / raw)
  To: Yingying Tang, ath12k; +Cc: linux-wireless, yintang
In-Reply-To: <20260610053315.2249912-1-yingying.tang@oss.qualcomm.com>

On 6/10/2026 11:03 AM, Yingying Tang wrote:
> Commit [1] introduced a regression causing severely degraded MLO RX
> throughput on WCN7850.
> 
> On WCN7850, there is only a single ar instance, but MLO uses two
> link IDs. ath12k_dp_peer->hw_links[] is indexed using ar->hw_link_id,
> which causes both MLO link IDs to be stored at the same index.
> 
> As a result, an incorrect link ID is assigned to MSDUs in
> ath12k_dp_rx_deliver_msdu(), leading to severe MLO RX throughput loss.
> 
> Different chipsets identify the per-MSDU link differently:
> 
>    - On QCN9274 / IPQ5332, the host owns multiple ar instances and the
>      per-MSDU hw_link_id from the RX descriptor maps cleanly through
>      dp_peer->hw_links[hw_link_id] to the IEEE link_id.
> 
>    - On single-ar chipsets like WCN7850 / QCC2072, there is only one ar
>      instance for both MLO links, so dp_peer->hw_links[] has just one
>      valid slot and cannot be used to distinguish the two links. To
>      resolve the link, walk dp_peer->link_peers[] and match by
>      rxcb->peer_id, which on the link_peer side identifies the link
>      peer for the MSDU.
> 
> Add a new hw_op set_rx_link_id() so each chipset resolves the link
> on the RX fast path using whatever signal it actually has, and let
> the op itself decide whether to populate rx_status::link_valid and
> rx_status::link_id:
> 
>    QCN9274 / IPQ5332 : always derive link_id from
>                        dp_peer->hw_links[rxcb->hw_link_id] and set
>                        link_valid.
>    WCN7850 / QCC2072 : walk the link_peers[] of dp_peer to find the
>                        link_peer whose peer_id matches rxcb->peer_id,
>                        and set link_valid only when a match is found.
>                        Otherwise leave link_valid clear so that
>                        mac80211 can fall back to its own link
>                        resolution path (via addr2 / deflink).
> 
> For WCN7850 / QCC2072, walking dp_peer->link_peers[] is bounded by
> the number of links actually populated, so introduce a link_peers_map
> bitmap (unsigned long) in struct ath12k_dp_peer that tracks populated
> slots and use for_each_set_bit() to iterate. Non-MLO clients hit one
> slot, current MLO clients hit two; the full ATH12K_NUM_MAX_LINKS
> array is never scanned. The bitmap is maintained with WRITE_ONCE() on
> the write side (under dp_hw->peer_lock) paired with READ_ONCE() on
> both the lockless RX read side and the write-side RMW for KCSAN
> correctness.
> 
> Also guard the dp_peer dereference in ath12k_mac_peer_cleanup_all()
> with a NULL check, since peer->dp_peer can be NULL for self-peers or
> peers not yet fully assigned, the pre-existing rcu_assign_pointer()
> call there had the same latent issue.
> 
> This restores the correct link ID on WCN7850 without changing the
> QCN9274 / IPQ5332 data path, which keeps its O(1) hw_links[]
> indexing.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
> 
> Fixes: 11157e0910fd ("wifi: ath12k: Use ath12k_dp_peer in per packet Tx & Rx paths") # [1]
> Signed-off-by: Yingying Tang <yingying.tang@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>

^ permalink raw reply

* [PATCH v2 ath-current] wifi: ath12k: avoid flushing scan timeout under the wiphy lock
From: Runyu Xiao @ 2026-07-03  6:02 UTC (permalink / raw)
  To: Jeff Johnson
  Cc: Wen Gong, Carl Huang, Karthikeyan Periyasamy, P Praneesh,
	Ramya Gnanasekar, linux-wireless, ath12k, linux-kernel,
	Runyu Xiao, stable

ath12k_mac_op_stop() is called with the wiphy lock held. It then takes
ah->hw_mutex and calls ath12k_mac_stop(), which synchronously cancels
ar->scan.timeout.

That can deadlock if the delayed work has started. The timeout worker
ath12k_scan_timeout_work() takes the same wiphy lock before aborting the
scan, so stop waits for a worker that cannot make progress until the
wiphy lock is released.

Drain ar->scan.timeout before entering the locked stop teardown, and
remove the synchronous cancel from ath12k_mac_stop(). This preserves the
stop-time drain while avoiding the wait-under-wiphy lock ordering.

Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Cc: stable@vger.kernel.org
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
Changes in v2:
  - Rebase on ath.git ath-current.
  - Use ath-current subject tag as requested.
  - Move the synchronous scan timeout drain out of the locked stop path
    instead of adding it in the wrong start-path context.
  - Update Fixes to the ath12k commit that introduced the stop-time
    scan.timeout drain.

 drivers/net/wireless/ath/ath12k/mac.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index af354bef5c0d..6da9a2bda9fe 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -9931,7 +9931,6 @@ static void ath12k_mac_stop(struct ath12k *ar)
 
 	clear_bit(ATH12K_FLAG_CAC_RUNNING, &ar->dev_flags);
 
-	cancel_delayed_work_sync(&ar->scan.timeout);
 	wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk);
 	cancel_work_sync(&ar->regd_channel_update_work);
 	cancel_work_sync(&ar->regd_update_work);
@@ -9975,6 +9974,15 @@ void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
 
 	lockdep_assert_wiphy(hw->wiphy);
 
+	/*
+	 * scan.timeout takes the wiphy lock before aborting the scan, so do
+	 * not wait for it from the locked stop path below.
+	 */
+	wiphy_unlock(hw->wiphy);
+	for_each_ar(ah, ar, i)
+		cancel_delayed_work_sync(&ar->scan.timeout);
+	wiphy_lock(hw->wiphy);
+
 	ath12k_drain_tx(ah);
 
 	mutex_lock(&ah->hw_mutex);
-- 
2.34.1

^ permalink raw reply related

* Re: [PATCH RESEND] wifi: ath12k: fix channel list copy on big endian
From: Alexander Wilhelm @ 2026-07-03  5:49 UTC (permalink / raw)
  To: Baochen Qiang; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <bf545855-6568-44ad-95eb-ac9c55827e89@oss.qualcomm.com>

On Fri, Jul 03, 2026 at 10:48:11AM +0800, Baochen Qiang wrote:
> 
> 
> On 7/2/2026 8:18 PM, Alexander Wilhelm wrote:
> > On Thu, Jul 02, 2026 at 10:44:46AM +0200, Alexander Wilhelm wrote:
> >> On Thu, Jul 02, 2026 at 04:27:44PM +0800, Baochen Qiang wrote:
> >>>
> >>>
> >>> On 6/29/2026 3:46 PM, Alexander Wilhelm wrote:
> >>>> The ath12k_wmi_scan_req_arg structure defines the channel list in
> >>>> CPU-native order, while wmi_start_scan_cmd expects the values in
> >>>> little-endian format. The simple memcpy causes the hardware scan to fail on
> >>>> big-endian architectures. Set __le32* type for the tmp_ptr and swap channel
> >>>> values to support both architectures correctly.
> >>>>
> >>>> Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
> >>>> ---
> >>>>  drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++---
> >>>>  1 file changed, 5 insertions(+), 3 deletions(-)
> >>>>
> >>>> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> >>>> index 65a05a9520ff..9e1d3c662852 100644
> >>>> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> >>>> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> >>>> @@ -2571,7 +2571,8 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
> >>>>  	struct wmi_tlv *tlv;
> >>>>  	void *ptr;
> >>>>  	int i, ret, len;
> >>>> -	u32 *tmp_ptr, extraie_len_with_pad = 0;
> >>>> +	__le32 *tmp_ptr;
> >>>> +	u32 extraie_len_with_pad = 0;
> >>>>  	struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
> >>>>  	struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
> >>>>  
> >>>> @@ -2656,9 +2657,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
> >>>>  	tlv = ptr;
> >>>>  	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
> >>>>  	ptr += TLV_HDR_SIZE;
> >>>> -	tmp_ptr = (u32 *)ptr;
> >>>> +	tmp_ptr = (__le32 *)ptr;
> >>>>  
> >>>> -	memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
> >>>> +	for (i = 0; i < arg->num_chan; i++)
> >>>> +		tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
> >>>>  
> >>>>  	ptr += len;
> >>>>  
> >>>>
> >>>
> >>> seems hint_s_ssid and hint_bssid at the last also need the endian conversion?
> > 
> > `hist_s_ssid` and `hint_bssid` are both structs within
> > `ath12k_wmi_scan_req_arg`, and the remaining member variables are also stored in
> > CPU order. Therefore, it seems wrong to me to perform byte swapping at this
> > point. What I actually need to swap is the data written through `ptr`, not the
> > structure members themselves. For that reason, I could also use the `__le32
> > *tmp_ptr` approach. What do you think about that?
> 
> Maybe I was not clear. I intended to mean the ptr:
> 
> @@ -2728,8 +2728,8 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>                 ptr += TLV_HDR_SIZE;
>                 s_ssid = ptr;
>                 for (i = 0; i < arg->num_hint_s_ssid; ++i) {
> -                       s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;
> -                       s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;
> +                       s_ssid->freq_flags = cpu_to_le32(arg->hint_s_ssid[i].freq_flags);
> +                       s_ssid->short_ssid = cpu_to_le32(arg->hint_s_ssid[i].short_ssid);

No, I understood what you meant. The issue is that the upper two lines will
trigger sparse warnings. The member variables `freq_flags` and `short_ssid` are
used on both the left-hand side and the right-hand side as members of the same
`struct ath12k_wmi_hint_short_ssid_arg`. I would keep these fields as `u32` and
use `tmp_ptr` on the left-hand side instead of `s_ssid` to keep things
consistent. Alternatively, I could introduce a separate structure specifically
for this use case.

>                         s_ssid++;
>                 }
>                 ptr += len;
> @@ -2743,7 +2743,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>                 hint_bssid = ptr;
>                 for (i = 0; i < arg->num_hint_bssid; ++i) {
>                         hint_bssid->freq_flags =
> -                               arg->hint_bssid[i].freq_flags;
> +                               cpu_to_le32(arg->hint_bssid[i].freq_flags);
>                         ether_addr_copy(&arg->hint_bssid[i].bssid.addr[0],
>                                         &hint_bssid->bssid.addr[0]);
> 
> > 
> > One thing I am still unsure about is the use of `ether_addr_copy()`. Can I
> > simply copy the bytes as-is here, or does the address also need to be
> > byte-swapped? I could not find any place where this address is being populated,
> > so I am not sure what byte order it is expected to be in.
> 
> I think you are talking about ath12k_wmi_hint_bssid_arg::bssid, right? For now ath12k does
> not populate hint_bssid or hint_s_ssid members, so bssid always remain empty. But if we
> are going to populate it I think the address originates from userspace and there it is
> passed in byte steams, so byte-swapping not required I think.

Okay, sounds good. I'll keep the `memcpy()` at this location and prepare the
next patch version.


Best regards
Alexander Wilhelm

^ permalink raw reply

* Re: [PATCH v9 00/14] firmware: qcom: Add OP-TEE PAS service support
From: Sumit Garg @ 2026-07-03  4:13 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
	freedreno, linux-media, netdev, linux-wireless, ath12k,
	linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
	akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
	airlied, simona, vikash.garodia, bod, mchehab, elder,
	andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
	trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
	tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
	jenswi, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <CANLsYkyFJ+CbUJpwWAy28KHvmNz6rJRtM5KrEzHjyAha-7grTQ@mail.gmail.com>

Hey Mathieu,

On Thu, Jul 02, 2026 at 01:14:03PM -0600, Mathieu Poirier wrote:
> Hey Sumit - nice hearing from you...
> 

Good to hear from you too.

> Is there some kind of overarching design harminisation between what
> you are proposing here and what Arnaud posted back in April [1] ?

The design here for remoteproc bringup on Qcom platforms for OP-TEE is
carried forward from whatever existed earlier with QTEE. This patch-set
just adds OP-TEE backend and replicate the same co-processor bringup
design as QTEE.

Co-processor bringup using a TEE is very different on Qcom platforms as
compared to what ST did. The image formats for Qcom are custom ones
using MBN format over ELF for which the MDT loader exists in the kernel
only. Similarly the firmware image authentication is very tightly
coupled with Qcom secure boot chain.

The ST framework rather uses an ELF loader in OP-TEE for image loading
and have an authentication mechanism similar to TAs. Also, the OP-TEE
ABI is altogether different from the PAS ABI that Qcom has for the TEE.

-Sumit

> 
> [1]. https://lists.trustedfirmware.org/archives/list/op-tee@lists.trustedfirmware.org/thread/VMKTRATYUFWL2TP7NHN5KJ37MSVZZMPK/
> 
> On Thu, 2 Jul 2026 at 05:59, Sumit Garg <sumit.garg@kernel.org> wrote:
> >
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Qcom platforms has the legacy of using non-standard SCM calls
> > splintered over the various kernel drivers. These SCM calls aren't
> > compliant with the standard SMC calling conventions which is a
> > prerequisite to enable migration to the FF-A specifications from Arm.
> >
> > OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
> > support these non-standard SCM calls. And even for newer architectures
> > using S-EL2 with Hafnium support, QTEE won't be able to support SCM
> > calls either with FF-A requirements coming in. And with both OP-TEE
> > and QTEE drivers well integrated in the TEE subsystem, it makes further
> > sense to reuse the TEE bus client drivers infrastructure.
> >
> > The added benefit of TEE bus infrastructure is that there is support
> > for discoverable/enumerable services. With that client drivers don't
> > have to manually invoke a special SCM call to know the service status.
> >
> > So enable the generic Peripheral Authentication Service (PAS) provided
> > by the firmware. It acts as the common layer with different TZ
> > backends plugged in whether it's an SCM implementation or a proper
> > TEE bus based PAS service implementation.
> >
> > The TEE PAS service ABI is designed to be extensible with additional API
> > as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future
> > extensions of the PAS service needed while still maintaining backwards
> > compatibility.
> >
> > Currently OP-TEE support is being added to provide the backend PAS
> > service implementation which can be found as part of this PR [1].
> > This implementation has been tested on Kodiak/RB3Gen2 and lemans
> > EVK boards. In addition to that WIN/IPQ targets tested OP-TEE with
> > this service too. Surely the backwards compatibility is maintained and
> > tested for SCM backend.
> >
> > Note that kernel PAS service support while running in EL2 is at parity
> > among OP-TEE vs QTEE. Especially the media (venus/iris) support depends
> > on proper IOMMU support being worked out on the PAS client end.
> >
> > Patch summary:
> > - Patch #1: adds generic PAS service.
> > - Patch #2: migrates SCM backend to generic PAS service.
> > - Patch #3: adds TEE/OP-TEE backend for generic PAS service.
> > - Patch #4-#12: migrates all client drivers to generic PAS service.
> > - Patch #13: drops legacy PAS SCM exported APIs.
> >
> > The patch-set is based on v7.2-rc1 and can be found in git tree
> > here [2].
> >
> > Merge strategy:
> >
> > It is expected due to APIs dependency, the entire patch-set to go via
> > the Qcom tree. All other subsystem maintainers, it will be great if I
> > can get acks for the corresponding subsystem patches.
> >
> > [1] https://github.com/OP-TEE/optee_os/pull/7721 (already merged)
> > [2] https://git.kernel.org/pub/scm/linux/kernel/git/sumit.garg/linux.git/log/?h=qcom-pas-v9
> >
> > ---
> > Changes in v9:
> > - Rebased to 7.2-rc1.
> > - Enable SCM backend similar to TEE if ARCH_QCOM is set.
> > - Address misc. comments from Konrad.
> > - Add checks for corner cases (although not reachable as per OP-TEE ABI)
> >   reported by Shashiko on patch #3.
> > - Picked up review tags from Konrad.
> >
> > Changes in v8:
> > - Rebased on mainline tip (no functional changes).
> > - Now Lemans EVK is also tested to support OP-TEE PAS here:
> >   https://github.com/OP-TEE/optee_os/pull/7845
> > - Drop Kodiak DT patch as it is carried independently by Mukesh here:
> >   https://lore.kernel.org/lkml/20260624063952.2242702-1-mukesh.ojha@oss.qualcomm.com/
> > - Regarding Sashiko comments, I have already replied in v6 the ones that
> >   don't apply but in v7 I got the same comments again. Specific context
> >   reasoning which Shashiko ignores:
> >     - ABI contract between Linux and TZ
> >     - No support for multiple concurrent backends
> >     - The TZ backend doesn’t detach during the entire boot cycle
> >
> > Changes in v7:
> > - Rebased to qcom tree (for-next branch) tip.
> > - Merged patch #5 and #7 due to build dependency.
> > - Disabled modem for kodiak EL2 as it isn't tested yet.
> > - Fix an issue found out by sashiko-bot for patch #4.
> >
> > Changes in v6:
> > - Rebased to v7.1-rc4 tag.
> > - Patch #14: fixed ret error print.
> > - Add Kconfig descriptions for PAS symbols such that they are visible
> >   in menuconfig to update.
> >
> > Changes in v5:
> > - Incorporated misc. comments from Mukesh.
> > - Split up patch #11 into 2 to add an independent commit for passing
> >   proper PAS ID to set_remote_state API.
> > - Picked up tags.
> >
> > Changes in v4:
> > - Incorporate misc. comments on patch #4.
> > - Picked up an ack for patch #10.
> > - Clarify in cover letter about state of media support.
> >
> > Changes in v3:
> > - Incorporated some style and misc. comments for patch #2, #3 and #4.
> > - Add QCOM_PAS Kconfig dependency for various subsystems.
> > - Switch from pseudo TA to proper TA invoke commands.
> >
> > Changes in v2:
> > - Fixed kernel doc warnings.
> > - Polish commit message and comments for patch #2.
> > - Pass proper PAS ID in set_remote_state API for media firmware drivers.
> > - Added Maintainer entry and dropped MODULE_AUTHOR.
> >
> > Sumit Garg (14):
> >   firmware: qcom: Add a generic PAS service
> >   firmware: qcom_scm: Migrate to generic PAS service
> >   firmware: qcom: Add a PAS TEE service
> >   remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
> >   remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
> >   remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs
> >   remoteproc: qcom: Select QCOM_PAS generic service
> >   drm/msm: Switch to generic PAS TZ APIs
> >   media: qcom: Switch to generic PAS TZ APIs
> >   media: qcom: Pass proper PAS ID to set_remote_state API
> >   net: ipa: Switch to generic PAS TZ APIs
> >   wifi: ath12k: Switch to generic PAS TZ APIs
> >   firmware: qcom_scm: Remove SCM PAS wrappers
> >   MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service
> >
> >  MAINTAINERS                                   |   9 +
> >  drivers/firmware/qcom/Kconfig                 |  22 +-
> >  drivers/firmware/qcom/Makefile                |   2 +
> >  drivers/firmware/qcom/qcom_pas.c              | 299 +++++++++++
> >  drivers/firmware/qcom/qcom_pas.h              |  50 ++
> >  drivers/firmware/qcom/qcom_pas_tee.c          | 479 ++++++++++++++++++
> >  drivers/firmware/qcom/qcom_scm.c              | 302 ++++-------
> >  drivers/gpu/drm/msm/Kconfig                   |   1 +
> >  drivers/gpu/drm/msm/adreno/a5xx_gpu.c         |   4 +-
> >  drivers/gpu/drm/msm/adreno/adreno_gpu.c       |  11 +-
> >  drivers/media/platform/qcom/iris/Kconfig      |  27 +-
> >  .../media/platform/qcom/iris/iris_firmware.c  |   9 +-
> >  drivers/media/platform/qcom/venus/Kconfig     |   1 +
> >  drivers/media/platform/qcom/venus/firmware.c  |  11 +-
> >  drivers/net/ipa/Kconfig                       |   2 +-
> >  drivers/net/ipa/ipa_main.c                    |  13 +-
> >  drivers/net/wireless/ath/ath12k/Kconfig       |   2 +-
> >  drivers/net/wireless/ath/ath12k/ahb.c         |  10 +-
> >  drivers/remoteproc/Kconfig                    |   4 +-
> >  drivers/remoteproc/qcom_q6v5_mss.c            |   5 +-
> >  drivers/remoteproc/qcom_q6v5_pas.c            |  51 +-
> >  drivers/remoteproc/qcom_wcnss.c               |  12 +-
> >  drivers/soc/qcom/mdt_loader.c                 |  12 +-
> >  include/linux/firmware/qcom/qcom_pas.h        |  43 ++
> >  include/linux/firmware/qcom/qcom_scm.h        |  29 --
> >  include/linux/soc/qcom/mdt_loader.h           |   6 +-
> >  26 files changed, 1095 insertions(+), 321 deletions(-)
> >  create mode 100644 drivers/firmware/qcom/qcom_pas.c
> >  create mode 100644 drivers/firmware/qcom/qcom_pas.h
> >  create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
> >  create mode 100644 include/linux/firmware/qcom/qcom_pas.h
> >
> > --
> > 2.53.0
> >
> 

^ permalink raw reply

* Re: [PATCH rtw-next v4 1/3] wifi: rtlwifi: fix disabling of ASPM for RTL8723BE with AER flooding
From: Ping-Ke Shih @ 2026-07-03  4:07 UTC (permalink / raw)
  To: William Hansen-Baird, pkshih
  Cc: linux-wireless, linux-kernel, William Hansen-Baird
In-Reply-To: <20260630141553.785769-2-william.hansen.baird@gmail.com>

William Hansen-Baird <william.hansen.baird@gmail.com> wrote:

> commit 77a6407c6ab2 ("wifi: rtlwifi: disable ASPM for RTL8723BE with subsystem ID 11ad:1723")
> adds code which sets ppsc->support_aspm to false in
> _rtl_pci_update_default_setting() in order to disable ASPM.
> This does not, however, disable ASPM. Rather, it disables driver
> control of ASPM, and blocks calls to rtl_pci_enable_aspm()
> and rtl_pci_disable_aspm().
> 
> In some cases, the pci device supplied to the probe function has
> ASPM enabled. The code would therefore not disable ASPM, as it means to,
> but rather just leave it enabled.
> This was discovered through testing on a Razer Blade 14 2017.
> 
> Implement a new __rtl_pci_disable_aspm(hw) function which does not check
> ppsc->support_aspm before disabling and call it from
> rtl_pci_disable_aspm().
> 
> Then move the code added in the previous commit to rtl_pci_init_aspm() to
> allow adding a call to __rtl_pci_disable_aspm(hw).
> This makes sure ASPM is disabled while still disabling
> driver control of ASPM to block it from being enabled later.
> 
> Signed-off-by: William Hansen-Baird <william.hansen.baird@gmail.com>
> Acked-by: Ping-Ke Shih <pkshih@realtek.com>

3 patch(es) applied to rtw-next branch of rtw.git, thanks.

04a46c2dbf3b wifi: rtlwifi: fix disabling of ASPM for RTL8723BE with AER flooding
676e59a3825c wifi: rtlwifi: convert pci if-statement to ID table
2b7858891b10 wifi: rtlwifi: disable ASPM for RTL8723BE with subsystem ID 17aa:b736

---
https://github.com/pkshih/rtw.git


^ permalink raw reply

* Re: [PATCH RESEND] wifi: ath12k: fix MAC address copy on big endian
From: Baochen Qiang @ 2026-07-03  4:04 UTC (permalink / raw)
  To: Alexander Wilhelm; +Cc: Jeff Johnson, linux-wireless, ath12k, linux-kernel
In-Reply-To: <akZUUhopfdxb3VTX@FUE-ALEWI-WINX>



On 7/2/2026 8:06 PM, Alexander Wilhelm wrote:
> On Thu, Jul 02, 2026 at 05:56:01PM +0800, Baochen Qiang wrote:
>>
>>
>> On 7/2/2026 5:17 PM, Alexander Wilhelm wrote:
>>> On Thu, Jul 02, 2026 at 10:41:25AM +0200, Alexander Wilhelm wrote:
>>>> On Thu, Jul 02, 2026 at 04:12:00PM +0800, Baochen Qiang wrote:
>>>>>
>>>>>
>>>>> On 6/29/2026 3:55 PM, Alexander Wilhelm wrote:
>>>>>> The ath12k_dp_get_mac_addr function performs a simple memcpy from a
>>>>>> CPU-native data types into an u8 array. On a big-endian architecture, this
>>>>>> later results in a null‑pointer dereference. Convert the data to
>>>>>
>>>>> Alex, did you find a time to investigate the root cause of the null pointer?
>>>
>>> Hi Baochen,
>>>
>>> I am now running kernel v6.18.26, and it looks like the null-pointer issue is
>>> gone. I only see the following log messages:
>>>
>>>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
>>
>> what is the actual mac addr reported from firmware in the PEER MAP event? My understanding
>> is that, without this patch (if we really need it) we get a wrong mac addr, then in
>> ath12k_dp_link_peer_map_event() we are more likely to fail the peer look up hence would
>> create a new peer and wakeup the waiting thread. But the log here clearly indicates that
>> the wait timeout, which does not make sense to me.

I think I can understand the behavior here: even if wakeup happens, the waiter in
ath12k_wait_for_dp_link_peer_common() checks the map result by calling
ath12k_dp_link_peer_find_by_vdev_and_addr(). Since the mac addr of the newly created peer
does not match, check failed. Finally we get timeout.

> 
> I have now added the following debug output for `peer_map_ev` inside of
> `ath12k_dp_htt_htc_t2h_msg_handler`:
> 
>     /* DEBUG */
>     switch (type) {
>     case HTT_T2H_MSG_TYPE_PEER_MAP:
>     case HTT_T2H_MSG_TYPE_PEER_MAP2:
>     case HTT_T2H_MSG_TYPE_PEER_MAP3:
>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info: %08X\n", le32_to_cpu(resp->peer_map_ev.info));
>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.mac_addr_l32: %08X\n", le32_to_cpu(resp->peer_map_ev.mac_addr_l32));
>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info1: %08X\n", le32_to_cpu(resp->peer_map_ev.info1));
>         ath12k_err(ab, "[DEBUG]: resp->peer_map_ev.info2: %08X\n", le32_to_cpu(resp->peer_map_ev.info2));
>         break;
>     default:
>         break;
>     }
> 
> Here is the result:
> 
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info: 0002002B
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.mac_addr_l32: C921F004
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info1: FFFF0EE0
>     ath12k_pci 0001:01:00.0: [DEBUG]: resp->peer_map_ev.info2: 000502F5
>     ath12k_pci 0001:01:00.0: failed to vdev 0 create peer for AP: -110
>     ath12k_pci 0001:01:00.0: failed to create vdev 04:f0:21:c9:e0:0e ret -110
>     ath12k_pci 0001:01:00.0: failed to assign chanctx for vif 04:f0:21:c9:e0:0e link id 0 link vif is already started
>     ath12k_pci 0001:01:00.0: invalid vdev id in vdev delete resp ev 0
> 
> Let me know if you see anything suspicious or if you need additional debug
> information.

I am not really sure about the final mac addr and vdev id passed to
ath12k_dp_link_peer_map_event(), so can you also add print below?

diff --git a/drivers/net/wireless/ath/ath12k/dp_peer.c
b/drivers/net/wireless/ath/ath12k/dp_peer.c
index 47d009a0d61f..3e8201d536a5 100644
--- a/drivers/net/wireless/ath/ath12k/dp_peer.c
+++ b/drivers/net/wireless/ath/ath12k/dp_peer.c
@@ -162,6 +162,9 @@ void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id,
u16 peer_
        struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
        struct ath12k *ar;

+       pr_info("peer map event: vdev_id %u peer_id %u mac_addr %pM ast_hash %u hw_peer_id
%u\n",
+               vdev_id, peer_id, mac_addr, ast_hash, hw_peer_id);
+
        spin_lock_bh(&dp->dp_lock);
        peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
        if (!peer) {


> 
> 
> Best regards
> Alexander Wilhelm


^ permalink raw reply related

* Re: [PATCH] wifi: rtw89: fix HE extended capability length check
From: Ping-Ke Shih @ 2026-07-03  3:58 UTC (permalink / raw)
  To: Pengpeng Hou, Ping-Ke Shih; +Cc: linux-wireless, linux-kernel, Pengpeng Hou
In-Reply-To: <2026063009025530.2-ccfa108-0024-wifi-rtw89-fix-HE-extended--pengpeng@iscas.ac.cn>

Pengpeng Hou <pengpeng@iscas.ac.cn> wrote:

> rtw89_mac_check_he_obss_narrow_bw_ru_iter() reads extended capability
> byte 10, but rejects only datalen values below 10.  Byte 10 requires at
> least 11 bytes.
> 
> Require datalen >= 11 before reading data[10].
> 
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> Acked-by: Ping-Ke Shih <pkshih@realtek.com>

1 patch(es) applied to rtw-next branch of rtw.git, thanks.

2aba608a86e9 wifi: rtw89: fix HE extended capability length check

---
https://github.com/pkshih/rtw.git


^ permalink raw reply

* Re: [PATCH rtw-next v3] wifi: rtw89: check return values in rtw89_ops_start_ap()
From: Ping-Ke Shih @ 2026-07-03  3:51 UTC (permalink / raw)
  To: Dmitry Morgun, Ping-Ke Shih
  Cc: Dmitry Morgun, linux-wireless, linux-kernel, lvc-project
In-Reply-To: <20260629094452.8709-1-d.morgun@ispras.ru>

Dmitry Morgun <d.morgun@ispras.ru> wrote:

> Several functions called in rtw89_ops_start_ap() may fail to allocate
> skb or fail to send H2C command to firmware, returning -ENOMEM or an
> error code. Their return values are ignored, so subsequent commands
> are executed with incorrect state.
> 
> Check the return values and propagate errors.
> 
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
> 
> Fixes: a52e4f2ce0f5 ("wifi: rtw89: implement ieee80211_ops::start_ap and stop_ap")
> Signed-off-by: Dmitry Morgun <d.morgun@ispras.ru>
> Acked-by: Ping-Ke Shih <pkshih@realtek.com>

1 patch(es) applied to rtw-next branch of rtw.git, thanks.

a8cddb62c573 wifi: rtw89: check return values in rtw89_ops_start_ap()

---
https://github.com/pkshih/rtw.git


^ 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