mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] wifi: ath11k: initialize CFR locks before capability checks
@ 2026-10-09  6:03 Runyu Xiao
  2026-10-09  6:57 ` Vasanthakumar Thiagarajan
  2026-10-09 22:07 ` Jeff Johnson
  0 siblings, 2 replies; 3+ messages in thread
From: Runyu Xiao @ 2026-10-09  6:03 UTC (permalink / raw)
  To: Jeff Johnson
  Cc: linux-wireless, ath11k, linux-kernel, stable, Runyu Xiao, Jianhao Xu

ath11k_cfr_init() returns before initializing cfr->lock when CFR
capability is absent.  However, station removal still calls
ath11k_cfr_decrement_peer_count(), which unconditionally takes this
lock.  This leaves a production path using an uninitialized spinlock.

Initialize cfr->lock for every radio before the capability check.  Keep
the CFR ring and lookup-table lock initialization conditional, since
those objects are only used after CFR capability setup.

Fixes: 9b2e3b4ebec7 ("wifi: ath11k: Add initialization and deinitialization sequence for CFR module")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
---
 drivers/net/wireless/ath/ath11k/cfr.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c
index a91f25fb6..0708ca28b 100644
--- a/drivers/net/wireless/ath/ath11k/cfr.c
+++ b/drivers/net/wireless/ath/ath11k/cfr.c
@@ -956,6 +956,9 @@ int ath11k_cfr_init(struct ath11k_base *ab)
 	struct ath11k *ar;
 	int i, ret;
 
+	for (i = 0; i < ab->num_radios; i++)
+		spin_lock_init(&ab->pdevs[i].ar->cfr.lock);
+
 	if (!test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, ab->wmi_ab.svc_map) ||
 	    !ab->hw_params.cfr_support)
 		return 0;
@@ -971,7 +974,6 @@ int ath11k_cfr_init(struct ath11k_base *ab)
 
 		idr_init(&cfr->rx_ring.bufs_idr);
 		spin_lock_init(&cfr->rx_ring.idr_lock);
-		spin_lock_init(&cfr->lock);
 		spin_lock_init(&cfr->lut_lock);
 
 		num_lut_entries = min_t(u32, CFR_MAX_LUT_ENTRIES, db_cap.min_elem);
-- 
2.34.1

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

* Re: [PATCH] wifi: ath11k: initialize CFR locks before capability checks
  2026-10-09  6:03 [PATCH] wifi: ath11k: initialize CFR locks before capability checks Runyu Xiao
@ 2026-10-09  6:57 ` Vasanthakumar Thiagarajan
  2026-10-09 22:07 ` Jeff Johnson
  1 sibling, 0 replies; 3+ messages in thread
From: Vasanthakumar Thiagarajan @ 2026-10-09  6:57 UTC (permalink / raw)
  To: Runyu Xiao, Jeff Johnson
  Cc: linux-wireless, ath11k, linux-kernel, stable, Jianhao Xu



On 10/9/2026 11:33 AM, Runyu Xiao wrote:
> ath11k_cfr_init() returns before initializing cfr->lock when CFR
> capability is absent.  However, station removal still calls
> ath11k_cfr_decrement_peer_count(), which unconditionally takes this
> lock.  This leaves a production path using an uninitialized spinlock.
> 
> Initialize cfr->lock for every radio before the capability check.  Keep
> the CFR ring and lookup-table lock initialization conditional, since
> those objects are only used after CFR capability setup.
> 
> Fixes: 9b2e3b4ebec7 ("wifi: ath11k: Add initialization and deinitialization sequence for CFR module")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Runyu Xiao <runyu.xiao@seu.edu.cn>
> ---
>   drivers/net/wireless/ath/ath11k/cfr.c | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/ath11k/cfr.c b/drivers/net/wireless/ath/ath11k/cfr.c
> index a91f25fb6..0708ca28b 100644
> --- a/drivers/net/wireless/ath/ath11k/cfr.c
> +++ b/drivers/net/wireless/ath/ath11k/cfr.c
> @@ -956,6 +956,9 @@ int ath11k_cfr_init(struct ath11k_base *ab)
>   	struct ath11k *ar;
>   	int i, ret;
>   
> +	for (i = 0; i < ab->num_radios; i++)
> +		spin_lock_init(&ab->pdevs[i].ar->cfr.lock);
> +
>   	if (!test_bit(WMI_TLV_SERVICE_CFR_CAPTURE_SUPPORT, ab->wmi_ab.svc_map) ||
>   	    !ab->hw_params.cfr_support)
>   		return 0;
> @@ -971,7 +974,6 @@ int ath11k_cfr_init(struct ath11k_base *ab)
>   
>   		idr_init(&cfr->rx_ring.bufs_idr);
>   		spin_lock_init(&cfr->rx_ring.idr_lock);
> -		spin_lock_init(&cfr->lock);
>   		spin_lock_init(&cfr->lut_lock);
>   
>   		num_lut_entries = min_t(u32, CFR_MAX_LUT_ENTRIES, db_cap.min_elem);


NAK. This can never happen.

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

* Re: [PATCH] wifi: ath11k: initialize CFR locks before capability checks
  2026-10-09  6:03 [PATCH] wifi: ath11k: initialize CFR locks before capability checks Runyu Xiao
  2026-10-09  6:57 ` Vasanthakumar Thiagarajan
@ 2026-10-09 22:07 ` Jeff Johnson
  1 sibling, 0 replies; 3+ messages in thread
From: Jeff Johnson @ 2026-10-09 22:07 UTC (permalink / raw)
  To: Runyu Xiao, Jeff Johnson
  Cc: linux-wireless, ath11k, linux-kernel, stable, Jianhao Xu

On 10/8/2026 11:03 PM, Runyu Xiao wrote:
> ath11k_cfr_init() returns before initializing cfr->lock when CFR
> capability is absent.  However, station removal still calls
> ath11k_cfr_decrement_peer_count(), which unconditionally takes this
> lock.  This leaves a production path using an uninitialized spinlock.

If this is really happening...

> 
> Initialize cfr->lock for every radio before the capability check.  Keep
> the CFR ring and lookup-table lock initialization conditional, since
> those objects are only used after CFR capability setup.

...then this is a poor solution.

And my review agent agreed:

- Initializing the locks unconditionally at the top of ath11k_cfr_init()
before the early-exit check would work mechanically, but it's wrong
semantically — callers should not need to reason about which subset of struct
fields is safe to use at any given time.

It also ruled out:
- Guarding the call site in mac.c with a capability check would duplicate the
firmware/hw-support logic outside cfr.c, and there could be other callers in
the future.
- Moving the locks to ath11k_ar_init() would be over-engineering; cfr->lock
only protects CFR state.

And concluded:

The fix: guard ath11k_cfr_decrement_peer_count() with cfr->enabled

In cfr.c, add an early return at the top of ath11k_cfr_decrement_peer_count():

void ath11k_cfr_decrement_peer_count(struct ath11k *ar,
                                     struct ath11k_sta *arsta)
{
      struct ath11k_cfr *cfr = &ar->cfr;

      if (!cfr->enabled)
              return;

      spin_lock_bh(&cfr->lock);

      if (arsta->cfr_capture.cfr_enable)
              cfr->cfr_enabled_peer_cnt--;

      spin_unlock_bh(&cfr->lock);
}

Why this is the right approach:

- cfr->enabled is set to true only after spin_lock_init(&cfr->lock) succeeds
and the ring allocation succeeds (cfr.c:997). It stays false in all early-exit
paths: the firmware/hardware capability check at line 959, the
ath11k_dbring_get_cap() failure continue at line 970, and the ring alloc
failure at line 991.
- The check is already used analogously at line 937 in the relay flush path,
so it's an established pattern in this file.
- This avoids touching ath11k_cfr_init() or the call site in mac.c, keeping
the fix minimal and localized to the function that has the precondition.

/jeff

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

end of thread, other threads:[~2026-10-09 22:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-09  6:03 [PATCH] wifi: ath11k: initialize CFR locks before capability checks Runyu Xiao
2026-10-09  6:57 ` Vasanthakumar Thiagarajan
2026-10-09 22:07 ` Jeff Johnson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®