[PATCH ath-next 2/5] wifi: ath11k: count down channel switch announcements in mac80211

From: Andrei-Alexandru Bleortu

Date: Sun Oct 04 2026 - 07:20:36 EST


ath11k handled the CSA switch count event only once the count reached
zero, to finish the switch, and did not ask the firmware for an event at
any other count. mac80211's countdown therefore never moved: Probe
Response frames, which mac80211 fills from it, and every beacon template
uploaded during the switch carried the initial Channel Switch Count,
although IEEE Std 802.11-2024, 9.4.2.17 has it give the number of TBTTs
left until the switch.

Request an event for every count in the beacon template command and
decrement mac80211's countdown on each one that matches the expected
count; a beacon that failed to go out repeats the previous count, which
is then skipped. This is how ath12k handles the same event.

Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.9.0.1-02146-QCAHKSWPL_SILICONZ-1

Assisted-by: LLM
Signed-off-by: Andrei-Alexandru Bleortu <me@xxxxxxxxxxxx>
---
drivers/net/wireless/ath/ath11k/core.h | 2 ++
drivers/net/wireless/ath/ath11k/wmi.c | 23 ++++++++++++++++++-----
2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index a0d725923e..0b10dac706 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -395,6 +395,8 @@ struct ath11k_vif {

bool is_started;
bool is_up;
+ /* CSA countdown value the firmware is expected to report next */
+ u8 current_cntdown_counter;
bool ftm_responder;
bool spectral_enabled;
bool ps;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 08fd6795ed..b7944f98a6 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1806,6 +1806,9 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
if (vif->bss_conf.csa_active) {
cmd->csa_switch_count_offset = offs->cntdwn_counter_offs[0];
cmd->ext_csa_switch_count_offset = offs->cntdwn_counter_offs[1];
+ /* a switch count event for every count, not just the last */
+ cmd->csa_event_bitmap = 0xffffffff;
+ arvif->current_cntdown_counter = bcn->data[offs->cntdwn_counter_offs[0]];
}

cmd->buf_len = bcn->len;
@@ -8385,10 +8388,6 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab,
struct ath11k_vif *arvif;
int i;

- /* Finish CSA once the switch count becomes NULL */
- if (ev->current_switch_count)
- return;
-
if (num_vdevs > vdev_ids_len / sizeof(*vdev_ids)) {
ath11k_warn(ab, "csa switch count num_vdevs %u exceeds tlv array length %u\n",
num_vdevs, vdev_ids_len);
@@ -8405,8 +8404,22 @@ ath11k_wmi_process_csa_switch_count_event(struct ath11k_base *ab,
continue;
}

- if (arvif->is_up && arvif->vif->bss_conf.csa_active)
+ if (!arvif->is_up || !arvif->vif->bss_conf.csa_active)
+ continue;
+
+ if (!ev->current_switch_count) {
ieee80211_csa_finish(arvif->vif, 0);
+ arvif->current_cntdown_counter = 0;
+ } else if (ev->current_switch_count > 1) {
+ /* A beacon that failed to go out repeats the previous
+ * count; mac80211 counts down once per beacon sent.
+ */
+ if (ev->current_switch_count != arvif->current_cntdown_counter)
+ continue;
+
+ arvif->current_cntdown_counter =
+ ieee80211_beacon_update_cntdwn(arvif->vif, 0);
+ }
}
rcu_read_unlock();
}
--
2.47.3