* [PATCH v3 1/2] wifi: ath9k: stop a failed register read from opening the RX filter
2026-09-11 1:46 [PATCH v3 0/2] wifi: ath9k: fix the RX filter handling around spectral scans Nerijus Bendžiūnas
@ 2026-09-11 1:46 ` Nerijus Bendžiūnas
2026-09-11 17:06 ` Jeff Johnson
2026-09-11 1:46 ` [PATCH v3 2/2] wifi: ath9k: clear the PHY error filter when a spectral scan is disabled Nerijus Bendžiūnas
2026-09-11 10:28 ` [PATCH v3 0/2] wifi: ath9k: fix the RX filter handling around spectral scans Toke Høiland-Jørgensen
2 siblings, 1 reply; 6+ messages in thread
From: Nerijus Bendžiūnas @ 2026-09-11 1:46 UTC (permalink / raw)
To: toke; +Cc: linux-wireless, linux-kernel, stable
On USB a register read is a WMI round trip and a timeout returns -1.
The spectral trigger reads AR_RX_FILTER back, ORs in the PHY error
bits and writes it, so a timed-out read stores 0xffffffff and the
device forwards every frame and PHY error to the host.
Add ath9k_hw_enable_rxfilter(), which sets the requested bits with
REG_SET_BIT() and reads nothing back, and use it in the trigger. With
firmware 1.4 and later the read-modify-write is done by the firmware;
older firmware still reads from the host.
Fixes: e93d083f42a1 ("ath9k: add spectral scan feature")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Nerijus Bendžiūnas <nerijus.bendziunas@gmail.com>
---
.../net/wireless/ath/ath9k/common-spectral.c | 7 ++----
drivers/net/wireless/ath/ath9k/hw.c | 23 +++++++++++++++++++
drivers/net/wireless/ath/ath9k/hw.h | 1 +
3 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index ca01a07f6630..73c1eb4ebe0e 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -716,7 +716,6 @@ void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
struct ath_spec_scan_priv *spec_priv)
{
struct ath_hw *ah = spec_priv->ah;
- u32 rxfilter;
if (IS_ENABLED(CONFIG_ATH9K_TX99))
return;
@@ -730,10 +729,8 @@ void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
return;
ath_ps_ops(common)->wakeup(common);
- rxfilter = ath9k_hw_getrxfilter(ah);
- ath9k_hw_setrxfilter(ah, rxfilter |
- ATH9K_RX_FILTER_PHYRADAR |
- ATH9K_RX_FILTER_PHYERR);
+ ath9k_hw_enable_rxfilter(ah, ATH9K_RX_FILTER_PHYRADAR |
+ ATH9K_RX_FILTER_PHYERR);
/* TODO: usually this should not be necessary, but for some reason
* (or in some mode?) the trigger must be called after the
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index e08ab73fcacb..d62b6ff00d41 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2905,6 +2905,29 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
}
EXPORT_SYMBOL(ath9k_hw_setrxfilter);
+/*
+ * Set bits in the RX filter without reading it back: on USB a failed read
+ * returns all ones, and writing that back would open every filter bit.
+ */
+void ath9k_hw_enable_rxfilter(struct ath_hw *ah, u32 bits)
+{
+ u32 phybits = 0;
+
+ if (bits & ATH9K_RX_FILTER_PHYRADAR)
+ phybits |= AR_PHY_ERR_RADAR;
+ if (bits & ATH9K_RX_FILTER_PHYERR)
+ phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+
+ REG_SET_BIT(ah, AR_RX_FILTER, bits);
+
+ if (phybits) {
+ REG_SET_BIT(ah, AR_PHY_ERR, phybits);
+ /* PHY errors are reported in zero length frames. */
+ REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
+ }
+}
+EXPORT_SYMBOL(ath9k_hw_enable_rxfilter);
+
bool ath9k_hw_phy_disable(struct ath_hw *ah)
{
if (ath9k_hw_mci_is_enabled(ah))
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index b942b8303d8f..f102f73a0114 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -1055,6 +1055,7 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
struct chan_centers *centers);
u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
+void ath9k_hw_enable_rxfilter(struct ath_hw *ah, u32 bits);
bool ath9k_hw_phy_disable(struct ath_hw *ah);
bool ath9k_hw_disable(struct ath_hw *ah);
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test);
--
2.55.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v3 1/2] wifi: ath9k: stop a failed register read from opening the RX filter
2026-09-11 1:46 ` [PATCH v3 1/2] wifi: ath9k: stop a failed register read from opening the RX filter Nerijus Bendžiūnas
@ 2026-09-11 17:06 ` Jeff Johnson
2026-09-14 2:25 ` Nerijus Bendžiūnas
0 siblings, 1 reply; 6+ messages in thread
From: Jeff Johnson @ 2026-09-11 17:06 UTC (permalink / raw)
To: Nerijus Bendžiūnas, toke; +Cc: linux-wireless, linux-kernel, stable
On 9/10/2026 6:46 PM, Nerijus Bendžiūnas wrote:
> +/*
> + * Set bits in the RX filter without reading it back: on USB a failed read
> + * returns all ones, and writing that back would open every filter bit.
> + */
> +void ath9k_hw_enable_rxfilter(struct ath_hw *ah, u32 bits)
there is a standard for kernel function documentation
https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html#function-documentation
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 1/2] wifi: ath9k: stop a failed register read from opening the RX filter
2026-09-11 17:06 ` Jeff Johnson
@ 2026-09-14 2:25 ` Nerijus Bendžiūnas
0 siblings, 0 replies; 6+ messages in thread
From: Nerijus Bendžiūnas @ 2026-09-14 2:25 UTC (permalink / raw)
To: Jeff Johnson
Cc: Toke Høiland-Jørgensen, linux-wireless, linux-kernel
On Fri, 11 Sep 2026 10:06:21 -0700, Jeff Johnson wrote:
> On 9/10/2026 6:46 PM, Nerijus Bendžiūnas wrote:
>> +/*
>> + * Set bits in the RX filter without reading it back: on USB a failed read
>> + * returns all ones, and writing that back would open every filter bit.
>> + */
>> +void ath9k_hw_enable_rxfilter(struct ath_hw *ah, u32 bits)
>
> there is a standard for kernel function documentation
>
> https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html#function-documentation
Thanks, I will change this to kernel-doc.
Per Toke's request on the cover letter, this patch and the other ath9k
fixes will come back as one series once, with the dependencies and the
testing explained, rather than as a v4 on this thread.
Nerijus
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 2/2] wifi: ath9k: clear the PHY error filter when a spectral scan is disabled
2026-09-11 1:46 [PATCH v3 0/2] wifi: ath9k: fix the RX filter handling around spectral scans Nerijus Bendžiūnas
2026-09-11 1:46 ` [PATCH v3 1/2] wifi: ath9k: stop a failed register read from opening the RX filter Nerijus Bendžiūnas
@ 2026-09-11 1:46 ` Nerijus Bendžiūnas
2026-09-11 10:28 ` [PATCH v3 0/2] wifi: ath9k: fix the RX filter handling around spectral scans Toke Høiland-Jørgensen
2 siblings, 0 replies; 6+ messages in thread
From: Nerijus Bendžiūnas @ 2026-09-11 1:46 UTC (permalink / raw)
To: toke; +Cc: linux-wireless, linux-kernel, stable
Triggering a spectral scan sets the PHY error bits in AR_RX_FILTER and
AR_PHY_ERR and sets AR_RXCFG_ZLFDMA. Disabling it clears none of them,
and ath9k_htc carries the hardware bits into every later filter update.
An idle AR9271 in monitor mode then keeps forwarding every PHY error
as a zero-length frame.
Clear all three on SPECTRAL_DISABLED unless radar detection is enabled,
which needs the same bits. AR_RXCFG_ZLFDMA must go too: with it set the
frames keep coming after the PHY error mask is cleared. As with the
enable path, firmware older than 1.4 still reads from the host.
Fixes: e93d083f42a1 ("ath9k: add spectral scan feature")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Nerijus Bendžiūnas <nerijus.bendziunas@gmail.com>
---
.../net/wireless/ath/ath9k/common-spectral.c | 6 +++++
drivers/net/wireless/ath/ath9k/hw.c | 23 +++++++++++++++++++
drivers/net/wireless/ath/ath9k/hw.h | 1 +
3 files changed, 30 insertions(+)
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 73c1eb4ebe0e..841075d904f8 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -776,6 +776,12 @@ int ath9k_cmn_spectral_scan_config(struct ath_common *common,
ath_ps_ops(common)->wakeup(common);
ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config);
+
+ /* Radar detection needs the same bits. */
+ if (spectral_mode == SPECTRAL_DISABLED &&
+ !common->hw->conf.radar_enabled)
+ ath9k_hw_disable_rxfilter(ah, ATH9K_RX_FILTER_PHYRADAR |
+ ATH9K_RX_FILTER_PHYERR);
ath_ps_ops(common)->restore(common);
spec_priv->spectral_mode = spectral_mode;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index d62b6ff00d41..6f86a8967548 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2928,6 +2928,29 @@ void ath9k_hw_enable_rxfilter(struct ath_hw *ah, u32 bits)
}
EXPORT_SYMBOL(ath9k_hw_enable_rxfilter);
+/*
+ * Counterpart of ath9k_hw_enable_rxfilter(). AR_RXCFG_ZLFDMA goes with the
+ * PHY error mask or the frames keep coming; callers clear all the PHY error
+ * bits together, as checking for a remaining one would need a read.
+ */
+void ath9k_hw_disable_rxfilter(struct ath_hw *ah, u32 bits)
+{
+ u32 phybits = 0;
+
+ if (bits & ATH9K_RX_FILTER_PHYRADAR)
+ phybits |= AR_PHY_ERR_RADAR;
+ if (bits & ATH9K_RX_FILTER_PHYERR)
+ phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+
+ REG_CLR_BIT(ah, AR_RX_FILTER, bits);
+
+ if (phybits) {
+ REG_CLR_BIT(ah, AR_PHY_ERR, phybits);
+ REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
+ }
+}
+EXPORT_SYMBOL(ath9k_hw_disable_rxfilter);
+
bool ath9k_hw_phy_disable(struct ath_hw *ah)
{
if (ath9k_hw_mci_is_enabled(ah))
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index f102f73a0114..983146208f26 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -1056,6 +1056,7 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
void ath9k_hw_enable_rxfilter(struct ath_hw *ah, u32 bits);
+void ath9k_hw_disable_rxfilter(struct ath_hw *ah, u32 bits);
bool ath9k_hw_phy_disable(struct ath_hw *ah);
bool ath9k_hw_disable(struct ath_hw *ah);
void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test);
--
2.55.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v3 0/2] wifi: ath9k: fix the RX filter handling around spectral scans
2026-09-11 1:46 [PATCH v3 0/2] wifi: ath9k: fix the RX filter handling around spectral scans Nerijus Bendžiūnas
2026-09-11 1:46 ` [PATCH v3 1/2] wifi: ath9k: stop a failed register read from opening the RX filter Nerijus Bendžiūnas
2026-09-11 1:46 ` [PATCH v3 2/2] wifi: ath9k: clear the PHY error filter when a spectral scan is disabled Nerijus Bendžiūnas
@ 2026-09-11 10:28 ` Toke Høiland-Jørgensen
2 siblings, 0 replies; 6+ messages in thread
From: Toke Høiland-Jørgensen @ 2026-09-11 10:28 UTC (permalink / raw)
To: Nerijus Bendžiūnas; +Cc: linux-wireless, linux-kernel
Nerijus Bendžiūnas <nerijus.bendziunas@gmail.com> writes:
> Patch 1 is v2
> (https://lore.kernel.org/linux-wireless/20260904181709.788886-1-nerijus.bendziunas@gmail.com/)
> with a shorter comment and message and the Assisted-by tag in the
> documented form. Patch 2 is new and needs the helper from patch 1.
>
> Tested on an AR9271 (ath9k_htc) together with the pending spectral
> stats fix; ath9k is build-tested.
You're resending new versions of patches faster than anyone has a chance
to look at them, with series boundaries that keep changing and have
weird dependencies between them. Please don't do that. If you're still
working on patches so that they require changes, then you sent them off
too early; this is not a race, don't submit things until you're
confident in them.
I'm dropping all patches from you from patchwork; if you have a series
of dependent patches, please resend as one series, explaining how they
relate to each other and how you tested them, and then *wait for someone
to look at them before resending*.
-Toke
^ permalink raw reply [flat|nested] 6+ messages in thread