[PATCH ath-next v4 7/8] wifi: ath9k_htc: pass CRC-tagged spectral samples to the FFT parser

From: Nerijus Bendžiūnas

Date: Wed Sep 16 2026 - 13:43:01 EST


The AR9271 firmware reports a frame that failed its CRC as a CRC error
even when the PHY error bit is set too, so spectral samples received
under interference reach the host as CRC errors, and the host passes
only PHY errors to the FFT parser. ath9k reordered the same check in
commit 3a325565c7fa ("ath9k: reorder error codes for spectral"); the
firmware never followed.

While a scan is active, also pass a CRC error frame of FFT report size
to the parser, with the PHY error code it expects. The parser rejects a
frame without the spectral bit in its trailer. A monitor interface with
FIF_FCSFAIL no longer sees those frames.

Fixes: 83fb287ecd8a ("ath9k_htc: process rx spectral packets")
Assisted-by: LLM
Signed-off-by: Nerijus Bendžiūnas <nerijus.bendziunas@xxxxxxxxx>
---
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index bed7ea2425a0..23d1ef2407a4 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -969,6 +969,25 @@ static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats,
convert_htc_flag(rx_stats, rxstatus);
}

+static bool ath9k_htc_is_spectral_sample_len(struct ath9k_htc_priv *priv,
+ u16 len)
+{
+ enum nl80211_channel_type chan_type;
+ u16 fft_len;
+
+ if (priv->spec_priv.spectral_mode == SPECTRAL_DISABLED)
+ return false;
+
+ chan_type = cfg80211_get_chandef_type(&priv->hw->conf.chandef);
+ if (chan_type == NL80211_CHAN_HT40MINUS ||
+ chan_type == NL80211_CHAN_HT40PLUS)
+ fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
+ else
+ fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
+
+ return len >= fft_len - 1 && len <= fft_len + 2;
+}
+
static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
struct ath9k_htc_rxbuf *rxbuf,
struct ieee80211_rx_status *rx_status)
@@ -1052,6 +1071,16 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
goto rx_next;
}

+ if (unlikely(rx_stats.rs_status & ATH9K_RXERR_CRC) &&
+ ath9k_htc_is_spectral_sample_len(priv, rs_datalen)) {
+ struct ath_rx_status sample_rs = rx_stats;
+
+ sample_rs.rs_phyerr = ATH9K_PHYERR_RADAR;
+ if (ath_cmn_process_fft(&priv->spec_priv, hdr, &sample_rs,
+ rx_status->mactime))
+ goto rx_next;
+ }
+
if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats,
&decrypt_error, priv->rxfilter))
goto rx_next;
--
2.55.0