linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] wifi: ath9k_htc: keep WMI commands off the 64-byte packet boundary
@ 2026-09-05  8:58 Nerijus Bendžiūnas
  2026-09-05  8:58 ` [PATCH v3 1/2] wifi: ath9k_htc: fix the byte count of a full RMW buffer flush Nerijus Bendžiūnas
  2026-09-05  8:58 ` [PATCH v3 2/2] wifi: ath9k_htc: refuse a command that fills whole USB packets Nerijus Bendžiūnas
  0 siblings, 2 replies; 3+ messages in thread
From: Nerijus Bendžiūnas @ 2026-09-05  8:58 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless
  Cc: Kalle Valo, Oleksij Rempel, linux-kernel

v2 [1] must not be applied. Its message said no caller fills the RMW
buffer; ar9271_hw_pa_cal() does, on every AR9271 reset. With the size
corrected the flush is a 192-byte command, three full 64-byte USB
packets. The firmware ends a command only on a short packet, so this
one is never delivered: the device stops answering WMI and stays dead
until power is removed. This happens on the first interface open,
with the linux-firmware 1.4.0 blob and with an open-firmware build.

Patch 1 fixes the size and caps MAX_RMW_CMD_NUMBER at 14, so the
buffer can never produce a 192-byte command. With the cap, 120
interface opens ran clean: 60 with this patch, 20 of them on the
linux-firmware blob and 20 on a second AR9271, and 60 with a bench
build of the same wire lengths. A 16-entry, 204-byte command is
delivered while the 15-entry, 192-byte one is not. Patch 2 refuses
any command whose length is a multiple of the endpoint's packet size.

With all 15 writes applied the PA calibration reads offset 30 on 40
of 40 opens, where the truncated command gave 32 on 78 of 80. A
firmware with fixed reassembly, given the full 15-entry command, gave
30 on 19 of 20. The on-air effect is not measured yet.

The firmware rule is usb_reg_out_patch() in open-ath9k-htc-firmware,
target_firmware/magpie_fw_dev/target/hif/usb_api_main_patch.c. A fix
for it exists and goes to the firmware project separately; it does
not reach devices already in the field, so the driver has to stay
clear anyway.

[1] https://lore.kernel.org/linux-wireless/20260904180849.775404-1-nerijus.bendziunas@gmail.com/

Based on ath-next, commit 1d8e73163ef9.

Nerijus Bendžiūnas (2):
  wifi: ath9k_htc: fix the byte count of a full RMW buffer flush
  wifi: ath9k_htc: refuse a command that fills whole USB packets

 drivers/net/wireless/ath/ath9k/hif_usb.c      | 7 +++++++
 drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +-
 drivers/net/wireless/ath/ath9k/wmi.h          | 3 ++-
 3 files changed, 10 insertions(+), 2 deletions(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v3 1/2] wifi: ath9k_htc: fix the byte count of a full RMW buffer flush
  2026-09-05  8:58 [PATCH v3 0/2] wifi: ath9k_htc: keep WMI commands off the 64-byte packet boundary Nerijus Bendžiūnas
@ 2026-09-05  8:58 ` Nerijus Bendžiūnas
  2026-09-05  8:58 ` [PATCH v3 2/2] wifi: ath9k_htc: refuse a command that fills whole USB packets Nerijus Bendžiūnas
  1 sibling, 0 replies; 3+ messages in thread
From: Nerijus Bendžiūnas @ 2026-09-05  8:58 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless
  Cc: Kalle Valo, Oleksij Rempel, linux-kernel

The AR9271 PA calibration has been running with its last five
register writes dropped since the RMW buffer was added.
ar9271_hw_pa_cal() queues exactly 15 read-modify-writes, which fills
the buffer, and ath9k_reg_rmw_buffer() sizes that flush with
sizeof(struct register_write), 8 bytes, instead of
sizeof(struct register_rmw), 12 bytes. The firmware gets 120 of the
180 bytes and applies only the first 10.

Fixing the size alone kills the device. The command becomes
8 (HTC) + 4 (WMI) + 180 = 192 bytes, three full 64-byte USB packets,
and the firmware ends a command only on a short packet
(usb_reg_out_patch() in open-ath9k-htc-firmware). The 192-byte
command is never delivered: the device stops answering WMI and stays
dead through a warm reboot until power is removed. An AR9271 hangs
this way on the first interface open, with the linux-firmware 1.4.0
blob and with an open-firmware build alike.

So cap the buffer at 14 entries as well. A command of n entries is
12 * (n + 1) bytes, a multiple of 64 only at n = 15 within the
buffer's reach. The next largest RMW batch, ath9k_hw_4k_set_gain(),
queues at most 14 entries, 180 bytes, and a register write batch is
8n + 12 bytes, never a multiple of 64. The PA calibration then goes
out as 14 + 1 entries and all 15 writes reach the chip.
AR9271_AN_RF2G6_OFFS then reads 30 on 40 of 40 opens, where the
truncated command gave 32 on 78 of 80; a firmware with fixed
reassembly, given the full 15-entry command, gave 30 on 19 of 20. The
on-air effect is not measured yet. With the cap, 120 interface opens
ran clean: 60 with this patch, 20 of them on the linux-firmware 1.4.0
blob and 20 on a second AR9271, and 60 with a bench build of the same
wire lengths.

Fixes: 8badb50cfab6 ("ath9k_htc: add new WMI_REG_RMW_CMDID command")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Nerijus Bendžiūnas <nerijus.bendziunas@gmail.com>
---
Changes in v3:
- v2 said no caller fills the buffer; ar9271_hw_pa_cal() does, on
  every AR9271 reset.
- Cap MAX_RMW_CMD_NUMBER at 14 in the same patch: the corrected size
  alone yields a 192-byte command the firmware never delivers.
- Assisted-by in the form Documentation/process/coding-assistants.rst
  now asks for.
Changes in v2:
- Add Assisted-by, rewrite the commit message, rebase onto ath-next.

 drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +-
 drivers/net/wireless/ath/ath9k/wmi.h          | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 6de78ae85726..0b49d2cc99f0 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -405,7 +405,7 @@ static void ath9k_reg_rmw_buffer(void *hw_priv,
 	if (priv->wmi->multi_rmw_idx == MAX_RMW_CMD_NUMBER) {
 		r = ath9k_wmi_cmd(priv->wmi, WMI_REG_RMW_CMDID,
 			  (u8 *) &priv->wmi->multi_rmw,
-			  sizeof(struct register_write) * priv->wmi->multi_rmw_idx,
+			  sizeof(struct register_rmw) * priv->wmi->multi_rmw_idx,
 			  (u8 *) &rsp_status, sizeof(rsp_status),
 			  100);
 		if (unlikely(r)) {
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 5c3b710b8f31..256f46098a6b 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -126,7 +126,8 @@ enum wmi_event_id {
 };
 
 #define MAX_CMD_NUMBER 62
-#define MAX_RMW_CMD_NUMBER 15
+/* 15 entries make 192 bytes, three full USB packets: never delivered. */
+#define MAX_RMW_CMD_NUMBER 14
 
 struct register_write {
 	__be32 reg;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v3 2/2] wifi: ath9k_htc: refuse a command that fills whole USB packets
  2026-09-05  8:58 [PATCH v3 0/2] wifi: ath9k_htc: keep WMI commands off the 64-byte packet boundary Nerijus Bendžiūnas
  2026-09-05  8:58 ` [PATCH v3 1/2] wifi: ath9k_htc: fix the byte count of a full RMW buffer flush Nerijus Bendžiūnas
@ 2026-09-05  8:58 ` Nerijus Bendžiūnas
  1 sibling, 0 replies; 3+ messages in thread
From: Nerijus Bendžiūnas @ 2026-09-05  8:58 UTC (permalink / raw)
  To: Toke Høiland-Jørgensen, linux-wireless
  Cc: Kalle Valo, Oleksij Rempel, linux-kernel

The firmware ends a command on the interrupt OUT endpoint only when a
packet is shorter than 64 bytes (usb_reg_out_patch() in
open-ath9k-htc-firmware). The one such command this driver can
produce, 192 bytes, was never delivered: the device stopped answering
WMI and stayed dead through a warm reboot until power was removed.

Nothing in the driver checks for this. Check the length in
hif_usb_send_regout(), where the packet size is known, and refuse the
command with a warning. The command then fails the way any other WMI
command failure does: ath9k_wmi_cmd() frees the buffer and returns
the error.

Assisted-by: LLM
Signed-off-by: Nerijus Bendžiūnas <nerijus.bendziunas@gmail.com>
---
New in v3.

 drivers/net/wireless/ath/ath9k/hif_usb.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index d3491ff08e6e..49303c7e3fef 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -99,10 +99,17 @@ static void hif_usb_regout_cb(struct urb *urb)
 static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
 			       struct sk_buff *skb)
 {
+	u16 maxpacket = usb_maxpacket(hif_dev->udev,
+				      usb_sndintpipe(hif_dev->udev,
+						     USB_REG_OUT_PIPE));
 	struct urb *urb;
 	struct cmd_buf *cmd;
 	int ret = 0;
 
+	if (WARN_ONCE(maxpacket && skb->len % maxpacket == 0,
+		      "%u-byte command fills whole USB packets\n", skb->len))
+		return -EINVAL;
+
 	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (urb == NULL)
 		return -ENOMEM;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-05  8:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-05  8:58 [PATCH v3 0/2] wifi: ath9k_htc: keep WMI commands off the 64-byte packet boundary Nerijus Bendžiūnas
2026-09-05  8:58 ` [PATCH v3 1/2] wifi: ath9k_htc: fix the byte count of a full RMW buffer flush Nerijus Bendžiūnas
2026-09-05  8:58 ` [PATCH v3 2/2] wifi: ath9k_htc: refuse a command that fills whole USB packets Nerijus Bendžiūnas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).