The branch releng/13.2 has been updated by bz:

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

commit 0b165b1fce848c6c636548d54064eec5a9d82c55
Author:     Bjoern A. Zeeb <[email protected]>
AuthorDate: 2023-01-31 16:17:14 +0000
Commit:     Bjoern A. Zeeb <[email protected]>
CommitDate: 2023-02-23 19:33:01 +0000

    LinuxKPI: 802.11: basic implementation of *queue(s)/*txq*
    LinuxKPI: 802.11: deal with stopped queues
    
    Very basic implementations of ieee80211_{wake,stop}_queue[s],
    as well as ieee80211_txq_schedule_start(), ieee80211_next_txq(),
    and ieee80211_schedule_txq().
    Various combinations of these are used by different wireless
    drivers, incl. iwlwifi.
    
    Following 5a9a0d7803382321b5f9fff1deae5fb08463cf1a initialize the
    queue values explicitly and deal with a stopped queue in
    ieee80211_tx_dequeue().
    
    Sponsored by:   The FreeBSD Foundation (parts of this work)
    Approved by:    re (cperciva)
    
    (cherry picked from commit 5a9a0d7803382321b5f9fff1deae5fb08463cf1a)
    (cherry picked from commit 0cbcfa1964de89cd346ee6f79437c6ab83a3b716)
    (cherry picked from commit 9f9d047405778b2d2aca829a2037532b8ae8ed5d)
---
 sys/compat/linuxkpi/common/include/net/mac80211.h | 124 +++++------
 sys/compat/linuxkpi/common/src/linux_80211.c      | 237 ++++++++++++++++++++++
 sys/compat/linuxkpi/common/src/linux_80211.h      |  14 ++
 3 files changed, 316 insertions(+), 59 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h 
b/sys/compat/linuxkpi/common/include/net/mac80211.h
index b7c6c2d37b90..36e6600f237b 100644
--- a/sys/compat/linuxkpi/common/include/net/mac80211.h
+++ b/sys/compat/linuxkpi/common/include/net/mac80211.h
@@ -1030,6 +1030,14 @@ struct sk_buff *linuxkpi_ieee80211_probereq_get(struct 
ieee80211_hw *,
 void linuxkpi_ieee80211_tx_status(struct ieee80211_hw *, struct sk_buff *);
 void linuxkpi_ieee80211_tx_status_ext(struct ieee80211_hw *,
     struct ieee80211_tx_status *);
+void linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *);
+void linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *);
+void linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *, int);
+void linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *, int);
+void linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *, uint8_t);
+struct ieee80211_txq *linuxkpi_ieee80211_next_txq(struct ieee80211_hw *, 
uint8_t);
+void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *,
+    struct ieee80211_txq *, bool);
 
 /* -------------------------------------------------------------------------- 
*/
 
@@ -1508,6 +1516,63 @@ ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff 
*skb)
 
 /* -------------------------------------------------------------------------- 
*/
 
+static inline void
+ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+       linuxkpi_ieee80211_stop_queues(hw);
+}
+
+static inline void
+ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+       linuxkpi_ieee80211_wake_queues(hw);
+}
+
+static inline void
+ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)
+{
+       linuxkpi_ieee80211_stop_queue(hw, qnum);
+}
+
+static inline void
+ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
+{
+       linuxkpi_ieee80211_wake_queue(hw, qnum);
+}
+
+static inline void
+ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+{
+       linuxkpi_ieee80211_schedule_txq(hw, txq, true);
+}
+
+static inline void
+ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
+    bool withoutpkts)
+{
+       linuxkpi_ieee80211_schedule_txq(hw, txq, true);
+}
+
+static inline void
+ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
+{
+       linuxkpi_ieee80211_txq_schedule_start(hw, ac);
+}
+
+static inline void
+ieee80211_txq_schedule_end(struct ieee80211_hw *hw, uint8_t ac)
+{
+       /* DO_NADA; */
+}
+
+static inline struct ieee80211_txq *
+ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
+{
+       return (linuxkpi_ieee80211_next_txq(hw, ac));
+}
+
+/* -------------------------------------------------------------------------- 
*/
+
 static __inline uint8_t
 ieee80211_get_tid(struct ieee80211_hdr *hdr)
 {
@@ -1819,18 +1884,6 @@ ieee80211_tdls_oper_request(struct ieee80211_vif *vif, 
uint8_t *addr,
        TODO();
 }
 
-static __inline void
-ieee80211_stop_queues(struct ieee80211_hw *hw)
-{
-       TODO();
-}
-
-static __inline void
-ieee80211_wake_queues(struct ieee80211_hw *hw)
-{
-       TODO();
-}
-
 static __inline void
 wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool state)
 {
@@ -2117,18 +2170,6 @@ ieee80211_queue_work(struct ieee80211_hw *hw, struct 
work_struct *w)
        linuxkpi_ieee80211_queue_work(hw, w);
 }
 
-static __inline void
-ieee80211_stop_queue(struct ieee80211_hw *hw, uint16_t q)
-{
-       TODO();
-}
-
-static __inline void
-ieee80211_wake_queue(struct ieee80211_hw *hw, uint16_t q)
-{
-       TODO();
-}
-
 static __inline void
 ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
@@ -2259,41 +2300,6 @@ ieee80211_sta_register_airtime(struct ieee80211_sta *sta,
        TODO();
 }
 
-
-static __inline void
-ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
-{
-       TODO();
-}
-
-static __inline void
-ieee80211_txq_schedule_end(struct ieee80211_hw *hw, uint8_t ac)
-{
-       /* DO_NADA; */
-}
-
-static __inline struct ieee80211_txq *
-ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
-{
-
-       TODO();
-       return (NULL);
-}
-
-static __inline void
-ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
-{
-       TODO();
-}
-
-static __inline void
-ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
-    bool withoutpkts)
-{
-       TODO();
-}
-
-
 static __inline void
 ieee80211_beacon_set_cntdwn(struct ieee80211_vif *vif, u8 counter)
 {
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c 
b/sys/compat/linuxkpi/common/src/linux_80211.c
index bcd8ea9d4c6e..d0a3b4b8586a 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -76,6 +76,12 @@ __FBSDID("$FreeBSD$");
 
 static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "LinuxKPI 80211 compat");
 
+/* XXX-BZ really want this and others in queue.h */
+#define        TAILQ_ELEM_INIT(elm, field) do {                                
\
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = NULL;                                   \
+} while (0)
+
 /* -------------------------------------------------------------------------- 
*/
 
 /* Keep public for as long as header files are using it too. */
@@ -238,9 +244,11 @@ lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t 
mac[IEEE80211_ADDR_LEN],
                        ltxq->txq.ac = tid_to_mac80211_ac[tid & 7];
                }
                ltxq->seen_dequeue = false;
+               ltxq->stopped = false;
                ltxq->txq.vif = vif;
                ltxq->txq.tid = tid;
                ltxq->txq.sta = sta;
+               TAILQ_ELEM_INIT(ltxq, txq_entry);
                skb_queue_head_init(&ltxq->skbq);
                sta->txq[tid] = &ltxq->txq;
        }
@@ -2270,6 +2278,9 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char 
name[IFNAMSIZ],
                        vif->hw_queue[i] = i;
                else
                        vif->hw_queue[i] = 0;
+
+               /* Initialize the queue to running. Stopped? */
+               lvif->hw_queue_stopped[i] = false;
        }
        vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
 
@@ -4262,13 +4273,25 @@ linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw,
     struct ieee80211_txq *txq)
 {
        struct lkpi_txq *ltxq;
+       struct lkpi_vif *lvif;
        struct sk_buff *skb;
 
+       skb = NULL;
        ltxq = TXQ_TO_LTXQ(txq);
        ltxq->seen_dequeue = true;
 
+       if (ltxq->stopped)
+               goto stopped;
+
+       lvif = VIF_TO_LVIF(ltxq->txq.vif);
+       if (lvif->hw_queue_stopped[ltxq->txq.ac]) {
+               ltxq->stopped = true;
+               goto stopped;
+       }
+
        skb = skb_dequeue(&ltxq->skbq);
 
+stopped:
        return (skb);
 }
 
@@ -4643,6 +4666,220 @@ linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif 
*vif)
 
 /* -------------------------------------------------------------------------- 
*/
 
+void
+linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)
+{
+       struct lkpi_hw *lhw;
+       struct lkpi_vif *lvif;
+       struct ieee80211_vif *vif;
+       int ac_count, ac;
+
+       KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
+           __func__, qnum, hw->queues, hw));
+
+       lhw = wiphy_priv(hw->wiphy);
+
+       /* See lkpi_ic_vap_create(). */
+       if (hw->queues >= IEEE80211_NUM_ACS)
+               ac_count = IEEE80211_NUM_ACS;
+       else
+               ac_count = 1;
+
+       LKPI_80211_LHW_LVIF_LOCK(lhw);
+       TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
+
+               vif = LVIF_TO_VIF(lvif);
+               for (ac = 0; ac < ac_count; ac++) {
+                       IMPROVE_TXQ("LOCKING");
+                       if (qnum == vif->hw_queue[ac]) {
+                               /*
+                                * For now log this to better understand
+                                * how this is supposed to work.
+                                */
+                               if (lvif->hw_queue_stopped[ac])
+                                       ic_printf(lhw->ic, "%s:%d: lhw %p hw %p 
"
+                                           "lvif %p vif %p ac %d qnum %d 
already "
+                                           "stopped\n", __func__, __LINE__,
+                                           lhw, hw, lvif, vif, ac, qnum);
+                               lvif->hw_queue_stopped[ac] = true;
+                       }
+               }
+       }
+       LKPI_80211_LHW_LVIF_UNLOCK(lhw);
+}
+
+void
+linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+       int i;
+
+       IMPROVE_TXQ("Locking; do we need further info?");
+       for (i = 0; i < hw->queues; i++)
+               linuxkpi_ieee80211_stop_queue(hw, i);
+}
+
+
+static void
+lkpi_ieee80211_wake_queues(struct ieee80211_hw *hw, int hwq)
+{
+       struct lkpi_hw *lhw;
+       struct lkpi_vif *lvif;
+       struct lkpi_sta *lsta;
+       int ac_count, ac, tid;
+
+       /* See lkpi_ic_vap_create(). */
+       if (hw->queues >= IEEE80211_NUM_ACS)
+               ac_count = IEEE80211_NUM_ACS;
+       else
+               ac_count = 1;
+
+       lhw = wiphy_priv(hw->wiphy);
+
+       IMPROVE_TXQ("Locking");
+       LKPI_80211_LHW_LVIF_LOCK(lhw);
+       TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
+               struct ieee80211_vif *vif;
+
+               vif = LVIF_TO_VIF(lvif);
+               for (ac = 0; ac < ac_count; ac++) {
+
+                       if (hwq == vif->hw_queue[ac]) {
+
+                               /* XXX-BZ what about software scan? */
+
+                               /*
+                                * For now log this to better understand
+                                * how this is supposed to work.
+                                */
+                               if (!lvif->hw_queue_stopped[ac])
+                                       ic_printf(lhw->ic, "%s:%d: lhw %p hw %p 
"
+                                           "lvif %p vif %p ac %d hw_q not 
stopped\n",
+                                           __func__, __LINE__,
+                                           lhw, hw, lvif, vif, ac);
+                               lvif->hw_queue_stopped[ac] = false;
+
+                               LKPI_80211_LVIF_LOCK(lvif);
+                               TAILQ_FOREACH(lsta, &lvif->lsta_head, 
lsta_entry) {
+                                       struct ieee80211_sta *sta;
+
+                                       sta = LSTA_TO_STA(lsta);
+                                       for (tid = 0; tid < nitems(sta->txq); 
tid++) {
+                                               struct lkpi_txq *ltxq;
+
+                                               if (sta->txq[tid] == NULL)
+                                                       continue;
+
+                                               if (sta->txq[tid]->ac != ac)
+                                                       continue;
+
+                                               ltxq = 
TXQ_TO_LTXQ(sta->txq[tid]);
+                                               if (!ltxq->stopped)
+                                                       continue;
+
+                                               ltxq->stopped = false;
+
+                                               /* XXX-BZ see when this 
explodes with all the locking. taskq? */
+                                               lkpi_80211_mo_wake_tx_queue(hw, 
sta->txq[tid]);
+                                       }
+                               }
+                               LKPI_80211_LVIF_UNLOCK(lvif);
+                       }
+               }
+       }
+       LKPI_80211_LHW_LVIF_UNLOCK(lhw);
+}
+
+void
+linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+       int i;
+
+       IMPROVE_TXQ("Is this all/enough here?");
+       for (i = 0; i < hw->queues; i++)
+               lkpi_ieee80211_wake_queues(hw, i);
+}
+
+void
+linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
+{
+
+       KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
+           __func__, qnum, hw->queues, hw));
+
+       lkpi_ieee80211_wake_queues(hw, qnum);
+}
+
+/* This is just hardware queues. */
+void
+linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
+{
+       struct lkpi_hw *lhw;
+
+       lhw = HW_TO_LHW(hw);
+
+       IMPROVE_TXQ("Are there reasons why we wouldn't schedule?");
+       IMPROVE_TXQ("LOCKING");
+       if (++lhw->txq_generation[ac] == 0)
+               lhw->txq_generation[ac]++;
+}
+
+struct ieee80211_txq *
+linuxkpi_ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
+{
+       struct lkpi_hw *lhw;
+       struct ieee80211_txq *txq;
+       struct lkpi_txq *ltxq;
+
+       lhw = HW_TO_LHW(hw);
+       txq = NULL;
+
+       IMPROVE_TXQ("LOCKING");
+
+       /* Check that we are scheduled. */
+       if (lhw->txq_generation[ac] == 0)
+               goto out;
+
+       ltxq = TAILQ_FIRST(&lhw->scheduled_txqs[ac]);
+       if (ltxq == NULL)
+               goto out;
+       if (ltxq->txq_generation == lhw->txq_generation[ac])
+               goto out;
+
+       ltxq->txq_generation = lhw->txq_generation[ac];
+       TAILQ_REMOVE(&lhw->scheduled_txqs[ac], ltxq, txq_entry);
+       txq = &ltxq->txq;
+       TAILQ_ELEM_INIT(ltxq, txq_entry);
+
+out:
+       return (txq);
+}
+
+void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *hw,
+    struct ieee80211_txq *txq, bool withoutpkts)
+{
+       struct lkpi_hw *lhw;
+       struct lkpi_txq *ltxq;
+
+       ltxq = TXQ_TO_LTXQ(txq);
+
+       IMPROVE_TXQ("LOCKING");
+
+       /* Only schedule if work to do or asked to anyway. */
+       if (!withoutpkts && skb_queue_empty(&ltxq->skbq))
+               goto out;
+
+       /* Make sure we do not double-schedule. */
+       if (ltxq->txq_entry.tqe_next != NULL)
+               goto out;
+
+       lhw = HW_TO_LHW(hw);
+       TAILQ_INSERT_TAIL(&lhw->scheduled_txqs[txq->ac], ltxq, txq_entry);
+out:
+       return;
+}
+
+/* -------------------------------------------------------------------------- 
*/
+
 struct lkpi_cfg80211_bss {
        u_int refcnt;
        struct cfg80211_bss bss;
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h 
b/sys/compat/linuxkpi/common/src/linux_80211.h
index d9f2ce68f4f1..4d44ca07948e 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -50,6 +50,7 @@
 #ifndef D80211_IMPROVE
 #define        D80211_IMPROVE          0x2
 #endif
+#define        D80211_IMPROVE_TXQ      0x4
 #define        D80211_TRACE            0x10
 #define        D80211_TRACEOK          0x20
 #define        D80211_TRACE_TX         0x100
@@ -62,6 +63,10 @@
 #define        D80211_TRACE_STA        0x10000
 #define        D80211_TRACE_MO         0x100000
 
+#define        IMPROVE_TXQ(...)                                                
\
+    if (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ)                     \
+       printf("%s:%d: XXX LKPI80211 IMPROVE_TXQ\n", __func__, __LINE__)
+
 struct lkpi_radiotap_tx_hdr {
        struct ieee80211_radiotap_header wt_ihdr;
        uint8_t         wt_flags;
@@ -93,7 +98,11 @@ struct lkpi_radiotap_rx_hdr {
         (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE))
 
 struct lkpi_txq {
+       TAILQ_ENTRY(lkpi_txq)   txq_entry;
+
        bool                    seen_dequeue;
+       bool                    stopped;
+       uint32_t                txq_generation;
        struct sk_buff_head     skbq;
 
        /* Must be last! */
@@ -139,6 +148,8 @@ struct lkpi_vif {
        TAILQ_HEAD(, lkpi_sta)  lsta_head;
        bool                    added_to_drv;                   /* Driver 
knows; i.e. we called add_interface(). */
 
+       bool                    hw_queue_stopped[IEEE80211_NUM_ACS];
+
        /* Must be last! */
        struct ieee80211_vif    vif __aligned(CACHE_LINE_SIZE);
 };
@@ -164,6 +175,9 @@ struct lkpi_hw {    /* name it mac80211_sc? */
 
        struct mtx                      mtx;
 
+       uint32_t                        txq_generation[IEEE80211_NUM_ACS];
+       TAILQ_HEAD(, lkpi_txq)          scheduled_txqs[IEEE80211_NUM_ACS];
+
        /* Scan functions we overload to handle depending on scan mode. */
        void                    (*ic_scan_curchan)(struct ieee80211_scan_state 
*,
                                    unsigned long);

Reply via email to