git: a8a47a41775b - main - LinuxKPI: 802.11: add a lchanctx list to lhw

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Fri, 11 Apr 2025 21:26:24 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=a8a47a41775b0320606f90b3ac2048bc23494615

commit a8a47a41775b0320606f90b3ac2048bc23494615
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-08 23:05:43 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-11 21:26:05 +0000

    LinuxKPI: 802.11: add a lchanctx list to lhw
    
    While we are currently only supporting a single VAP (vif) it is
    less of a trouble but in order to get locking and rcu accesses
    [from drivers] more right add a list for all chanctx_conf we have
    for one hw.  Use that list in the iterator function to avoid
    having to lock the vif but not protecting the chanctx list
    (against a parallel removal) due to different locking.
    
    Sponsored by:   The FreeBSD Foundation
    PR:             280546
    MFC after:      3 days
    Tested by:      Oleksandr Kryvulia (shuriku shurik.kiev.ua)
    Tested by:      Oleg Nauman (oleg.nauman gmail.com) [rtw88]
    Differential Revision: https://reviews.freebsd.org/D49734
---
 sys/compat/linuxkpi/common/src/linux_80211.c | 39 ++++++++++++++++++----------
 sys/compat/linuxkpi/common/src/linux_80211.h |  5 ++++
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 891714fb75db..65f203c0eec9 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -1757,6 +1757,7 @@ lkpi_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 	/* Cleanup. */
 	rcu_assign_pointer(vif->bss_conf.chanctx_conf, NULL);
 	lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
+	list_del(&lchanctx->entry);
 	free(lchanctx, M_LKPI80211);
 }
 
@@ -1943,6 +1944,7 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 			goto out;
 		}
 
+		list_add_rcu(&lchanctx->entry, &lhw->lchanctx_list);
 		rcu_assign_pointer(vif->bss_conf.chanctx_conf, chanctx_conf);
 
 		/* Assign vif chanctx. */
@@ -1957,6 +1959,7 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
 			lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);
 			rcu_assign_pointer(vif->bss_conf.chanctx_conf, NULL);
 			lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
+			list_del(&lchanctx->entry);
 			free(lchanctx, M_LKPI80211);
 			goto out;
 		}
@@ -5458,6 +5461,9 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops)
 		TAILQ_INIT(&lhw->scheduled_txqs[ac]);
 	}
 
+	/* Chanctx_conf */
+	INIT_LIST_HEAD(&lhw->lchanctx_list);
+
 	/* Deferred RX path. */
 	LKPI_80211_LHW_RXQ_LOCK_INIT(lhw);
 	TASK_INIT(&lhw->rxq_task, 0, lkpi_80211_lhw_rxq_task, lhw);
@@ -5521,6 +5527,22 @@ linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw)
 	    __func__, lhw, mbufq_len(&lhw->rxq)));
 	LKPI_80211_LHW_RXQ_LOCK_DESTROY(lhw);
 
+	/* Chanctx_conf. */
+	if (!list_empty_careful(&lhw->lchanctx_list)) {
+		struct lkpi_chanctx *lchanctx, *next;
+		struct ieee80211_chanctx_conf *chanctx_conf;
+
+		list_for_each_entry_safe(lchanctx, next, &lhw->lchanctx_list, entry) {
+			if (lchanctx->added_to_drv) {
+				/* In reality we should panic? */
+				chanctx_conf = &lchanctx->chanctx_conf;
+				lkpi_80211_mo_remove_chanctx(hw, chanctx_conf);
+			}
+			list_del(&lchanctx->entry);
+			free(lchanctx, M_LKPI80211);
+		}
+	}
+
 	/* Cleanup more of lhw here or in wiphy_free()? */
 	LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw);
 	LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw);
@@ -5955,8 +5977,6 @@ linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *hw,
     void *arg)
 {
 	struct lkpi_hw *lhw;
-	struct lkpi_vif *lvif;
-	struct ieee80211_vif *vif;
 	struct lkpi_chanctx *lchanctx;
 
 	KASSERT(hw != NULL && iterfunc != NULL,
@@ -5964,22 +5984,13 @@ linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *hw,
 
 	lhw = HW_TO_LHW(hw);
 
-	IMPROVE("lchanctx should be its own list somewhere");
-
-	LKPI_80211_LHW_LVIF_LOCK(lhw);
-	TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
-
-		vif = LVIF_TO_VIF(lvif);
-		if (vif->bss_conf.chanctx_conf == NULL)			/* XXX-BZ; FIXME see IMPROVE above. */
-			continue;
-
-		lchanctx = CHANCTX_CONF_TO_LCHANCTX(vif->bss_conf.chanctx_conf);
+	rcu_read_lock();
+	list_for_each_entry_rcu(lchanctx, &lhw->lchanctx_list, entry) {
 		if (!lchanctx->added_to_drv)
 			continue;
-
 		iterfunc(hw, &lchanctx->chanctx_conf, arg);
 	}
-	LKPI_80211_LHW_LVIF_UNLOCK(lhw);
+	rcu_read_unlock();
 }
 
 void
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h
index 7028e05e9b20..da377280b1c0 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -216,6 +216,8 @@ struct lkpi_hw {	/* name it mac80211_sc? */
 	TAILQ_HEAD(, lkpi_vif)		lvif_head;
 	struct sx			lvif_sx;
 
+	struct list_head		lchanctx_list;
+
 	struct mtx			txq_mtx;
 	uint32_t			txq_generation[IEEE80211_NUM_ACS];
 	TAILQ_HEAD(, lkpi_txq)		scheduled_txqs[IEEE80211_NUM_ACS];
@@ -282,7 +284,10 @@ struct lkpi_hw {	/* name it mac80211_sc? */
 #define	HW_TO_LHW(_hw)		container_of(_hw, struct lkpi_hw, hw)
 
 struct lkpi_chanctx {
+	struct list_head		entry;
+
 	bool				added_to_drv;	/* Managed by MO */
+
 	struct ieee80211_chanctx_conf	chanctx_conf __aligned(CACHE_LINE_SIZE);
 };
 #define	LCHANCTX_TO_CHANCTX_CONF(_lchanctx)		\