This patch leaves the code for ath9k's internal per-node per-tid
queues in place and just modifies the driver to also pull from
the new mac80211 intermediate software queues, and implements
the .wake_tx_queue method, which will cause mac80211 to deliver
packets to be sent via the new intermediate queue.

Signed-off-by: Tim Shepard <s...@alum.mit.edu>
---
 drivers/net/wireless/ath/ath9k/ath9k.h     |   16 +++-
 drivers/net/wireless/ath/ath9k/debug_sta.c |    8 +-
 drivers/net/wireless/ath/ath9k/init.c      |    1 +
 drivers/net/wireless/ath/ath9k/main.c      |    1 +
 drivers/net/wireless/ath/ath9k/xmit.c      |  122 ++++++++++++++++++++++++----
 5 files changed, 129 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h 
b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1118b3d..96cbcad 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -145,8 +145,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct 
ath_descdma *dd,
 #define BAW_WITHIN(_start, _bawsz, _seqno) \
        ((((_seqno) - (_start)) & 4095) < (_bawsz))
 
-#define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
-
 #define IS_HT_RATE(rate)   (rate & 0x80)
 #define IS_CCK_RATE(rate)  ((rate >= 0x18) && (rate <= 0x1e))
 #define IS_OFDM_RATE(rate) ((rate >= 0x8) && (rate <= 0xf))
@@ -232,8 +230,10 @@ struct ath_buf {
 
 struct ath_atx_tid {
        struct list_head list;
+       struct sk_buff_head i_q;
        struct sk_buff_head buf_q;
        struct sk_buff_head retry_q;
+       struct ieee80211_txq *txq;
        struct ath_node *an;
        struct ath_hwq *hwq;
        unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)];
@@ -247,13 +247,13 @@ struct ath_atx_tid {
        s8 bar_index;
        bool active;
        bool clear_ps_filter;
+       bool txq_nonempty;
 };
 
 struct ath_node {
        struct ath_softc *sc;
        struct ieee80211_sta *sta; /* station struct we're part of */
        struct ieee80211_vif *vif; /* interface with which we're associated */
-       struct ath_atx_tid tid[IEEE80211_NUM_TIDS];
 
        u16 maxampdu;
        u8 mpdudensity;
@@ -271,6 +271,15 @@ struct ath_node {
        struct list_head list;
 };
 
+static inline
+struct ath_atx_tid *ath_an_2_tid(struct ath_node *an, u8 tidno)
+{
+       struct ieee80211_sta *sta = an->sta;
+       struct ieee80211_vif *vif = an->vif;
+       struct ieee80211_txq *txq = sta? sta->txq[tidno] : vif->txq;
+       return (struct ath_atx_tid *) txq->drv_priv;
+}
+
 struct ath_tx_control {
        struct ath_hwq *hwq;
        struct ath_node *an;
@@ -585,6 +594,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
                                   u16 tids, int nframes,
                                   enum ieee80211_frame_release_type reason,
                                   bool more_data);
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
 
 /********/
 /* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c 
b/drivers/net/wireless/ath/ath9k/debug_sta.c
index a9f4a92..100cbfd 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -25,6 +25,7 @@ static ssize_t read_file_node_aggr(struct file *file, char 
__user *user_buf,
 {
        struct ath_node *an = file->private_data;
        struct ath_softc *sc = an->sc;
+       struct ieee80211_txq *txq;
        struct ath_atx_tid *tid;
        struct ath_hwq *hwq;
        u32 len = 0, size = 4096;
@@ -52,8 +53,11 @@ static ssize_t read_file_node_aggr(struct file *file, char 
__user *user_buf,
                         "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
                         "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
 
-       for (tidno = 0, tid = &an->tid[tidno];
-            tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+       for (tidno = 0;
+            tidno < IEEE80211_NUM_TIDS; tidno++) {
+
+               txq = an->sta->txq[tidno];
+               tid = (struct ath_atx_tid *) txq->drv_priv;
                hwq = tid->hwq;
                ath_hwq_lock(sc, hwq);
                if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c 
b/drivers/net/wireless/ath/ath9k/init.c
index d96055f..7d4427a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -882,6 +882,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct 
ieee80211_hw *hw)
        hw->max_rate_tries = 10;
        hw->sta_data_size = sizeof(struct ath_node);
        hw->vif_data_size = sizeof(struct ath_vif);
+       hw->txq_data_size = sizeof(struct ath_atx_tid);
        hw->extra_tx_headroom = 4;
 
        hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1;
diff --git a/drivers/net/wireless/ath/ath9k/main.c 
b/drivers/net/wireless/ath/ath9k/main.c
index d39eec8..6cb27b2 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2668,4 +2668,5 @@ struct ieee80211_ops ath9k_ops = {
        .sw_scan_start      = ath9k_sw_scan_start,
        .sw_scan_complete   = ath9k_sw_scan_complete,
        .get_txpower        = ath9k_get_txpower,
+       .wake_tx_queue      = ath9k_wake_tx_queue,
 };
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c 
b/drivers/net/wireless/ath/ath9k/xmit.c
index 4732965..01c0f76 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -65,6 +65,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc 
*sc,
                                           struct ath_hwq *hwq,
                                           struct ath_atx_tid *tid,
                                           struct sk_buff *skb);
+static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb,
+                         struct ath_tx_control *txctl);
 
 enum {
        MCS_HT20,
@@ -118,6 +120,21 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct 
ath_hwq *hwq,
                list_add_tail(&tid->list, list);
 }
 
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_atx_tid *tid = (struct ath_atx_tid *) txq->drv_priv;
+       struct ath_hwq *hwq = tid->hwq;
+
+       spin_lock_bh(&hwq->axq_lock);
+
+       tid->txq_nonempty = true;
+       ath_tx_queue_tid(sc, hwq, tid);
+       ath_hwq_schedule(sc, hwq);
+
+       spin_unlock_bh(&hwq->axq_lock);
+}
+
 static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
 {
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -170,12 +187,54 @@ static struct ath_atx_tid *
 ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
 {
        u8 tidno = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
-       return ATH_AN_2_TID(an, tidno);
+       return ath_an_2_tid(an, tidno);
+}
+
+static void ath_txq_pull(struct ath_atx_tid *tid)
+{
+       struct sk_buff *skb;
+       struct ath_tx_control txctl;
+       struct ath_frame_info *fi;
+       int r;
+
+       if (!skb_queue_empty(&tid->i_q))
+               return;
+
+       if (!tid->txq_nonempty)
+               return;
+
+       skb = ieee80211_tx_dequeue(tid->an->sc->hw, tid->txq);
+       if (!skb) {
+               tid->txq_nonempty = false;
+       } else {
+               /* sad to do all this with axq_lock held */
+               memset(&txctl, 0, sizeof txctl);
+               txctl.hwq = tid->hwq;
+               txctl.sta = tid->an->sta;
+               r = ath_tx_prepare(tid->an->sc->hw, skb, &txctl);
+               if (WARN_ON(r != 0)) {
+                       /** should not happen ??? */
+               } else {
+                       /* perhaps not needed here ??? */
+                       fi = get_frame_info(skb);
+                       fi->hwq = skb_get_queue_mapping(skb);
+
+                       __skb_queue_tail(&tid->i_q, skb);
+                       ++tid->hwq->pending_frames;
+               }
+       }
 }
 
 static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
 {
-       return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+       if (!skb_queue_empty(&tid->retry_q))
+               return true;
+       if (!skb_queue_empty(&tid->buf_q))
+               return true;
+       if (!skb_queue_empty(&tid->i_q))
+               return true;
+       ath_txq_pull(tid);
+       return !skb_queue_empty(&tid->i_q);
 }
 
 static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -185,6 +244,12 @@ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid 
*tid)
        skb = __skb_dequeue(&tid->retry_q);
        if (!skb)
                skb = __skb_dequeue(&tid->buf_q);
+       if (!skb)
+               skb = __skb_dequeue(&tid->i_q);
+       if (!skb) {
+               ath_txq_pull(tid);
+               skb = __skb_dequeue(&tid->i_q);
+       }
 
        return skb;
 }
@@ -870,6 +935,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct 
ath_hwq *hwq,
                *q = &tid->retry_q;
                if (skb_queue_empty(*q))
                        *q = &tid->buf_q;
+               if (skb_queue_empty(*q))
+                       *q = &tid->i_q;
+               if (skb_queue_empty(*q))
+                       ath_txq_pull(tid); /* try pull packet onto tid->i_q */
 
                skb = skb_peek(*q);
                if (!skb)
@@ -1482,7 +1551,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct 
ieee80211_sta *sta,
        ath_dbg(common, XMIT, "%s called\n", __func__);
 
        an = (struct ath_node *)sta->drv_priv;
-       txtid = ATH_AN_2_TID(an, tid);
+       txtid = ath_an_2_tid(an, tid);
        hwq = txtid->hwq;
 
        ath_hwq_lock(sc, hwq);
@@ -1517,7 +1586,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct 
ieee80211_sta *sta, u16 tid)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
-       struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
+       struct ath_atx_tid *txtid = ath_an_2_tid(an, tid);
        struct ath_hwq *hwq = txtid->hwq;
 
        ath_dbg(common, XMIT, "%s called\n", __func__);
@@ -1533,6 +1602,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct 
ath_softc *sc,
                       struct ath_node *an)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_txq *txq;
        struct ath_atx_tid *tid;
        struct ath_hwq *hwq;
        bool buffered;
@@ -1540,9 +1610,11 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct 
ath_softc *sc,
 
        ath_dbg(common, XMIT, "%s called\n", __func__);
 
-       for (tidno = 0, tid = &an->tid[tidno];
-            tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+       for (tidno = 0;
+            tidno < IEEE80211_NUM_TIDS; tidno++) {
 
+               txq = an->sta->txq[tidno];
+               tid = (struct ath_atx_tid *) txq->drv_priv;
                hwq = tid->hwq;
 
                ath_hwq_lock(sc, hwq);
@@ -1565,15 +1637,18 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, 
struct ath_softc *sc,
 void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_txq *txq;
        struct ath_atx_tid *tid;
        struct ath_hwq *hwq;
        int tidno;
 
        ath_dbg(common, XMIT, "%s called\n", __func__);
 
-       for (tidno = 0, tid = &an->tid[tidno];
-            tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+       for (tidno = 0;
+            tidno < IEEE80211_NUM_TIDS; tidno++) {
 
+               txq = an->sta->txq[tidno];
+               tid = (struct ath_atx_tid *) txq->drv_priv;
                hwq = tid->hwq;
 
                ath_hwq_lock(sc, hwq);
@@ -1599,7 +1674,7 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct 
ieee80211_sta *sta,
        ath_dbg(common, XMIT, "%s called\n", __func__);
 
        an = (struct ath_node *)sta->drv_priv;
-       tid = ATH_AN_2_TID(an, tidno);
+       tid = ath_an_2_tid(an, tidno);
        hwq = tid->hwq;
 
        ath_hwq_lock(sc, hwq);
@@ -1637,7 +1712,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw 
*hw,
                if (!(tids & 1))
                        continue;
 
-               tid = ATH_AN_2_TID(an, i);
+               tid = ath_an_2_tid(an, i);
 
                ath_hwq_lock(sc, tid->hwq);
                while (nframes > 0) {
@@ -2853,12 +2928,18 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
 
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
 {
+       struct ieee80211_txq *txq;
+       struct ieee80211_sta *sta = an->sta;
+       struct ieee80211_vif *vif = an->vif;
        struct ath_atx_tid *tid;
        int tidno, acno;
 
-       for (tidno = 0, tid = &an->tid[tidno];
+       for (tidno = 0;
             tidno < IEEE80211_NUM_TIDS;
-            tidno++, tid++) {
+            tidno++) {
+               txq = sta? sta->txq[tidno] : vif->txq;
+               tid = (struct ath_atx_tid *) txq->drv_priv;
+               tid->txq       = txq;
                tid->an        = an;
                tid->tidno     = tidno;
                tid->seq_start = tid->seq_next = 0;
@@ -2866,23 +2947,33 @@ void ath_tx_node_init(struct ath_softc *sc, struct 
ath_node *an)
                tid->baw_head  = tid->baw_tail = 0;
                tid->active        = false;
                tid->clear_ps_filter = true;
+               tid->txq_nonempty = false;
+               __skb_queue_head_init(&tid->i_q);
                __skb_queue_head_init(&tid->buf_q);
                __skb_queue_head_init(&tid->retry_q);
                INIT_LIST_HEAD(&tid->list);
                acno = TID_TO_WME_AC(tidno);
                tid->hwq = sc->tx.hwq_map[acno];
+
+               if (!sta)
+                       break; /* just one multicast ath_atx_tid */
        }
 }
 
 void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
 {
+       struct ieee80211_txq *txq;
+       struct ieee80211_sta *sta = an->sta;
+       struct ieee80211_vif *vif = an->vif;
        struct ath_atx_tid *tid;
        struct ath_hwq *hwq;
        int tidno;
 
-       for (tidno = 0, tid = &an->tid[tidno];
-            tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+       for (tidno = 0;
+            tidno < IEEE80211_NUM_TIDS; tidno++) {
 
+               txq = sta? sta->txq[tidno] : vif->txq;
+               tid = (struct ath_atx_tid *) txq->drv_priv;
                hwq = tid->hwq;
 
                ath_hwq_lock(sc, hwq);
@@ -2894,6 +2985,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct 
ath_node *an)
                tid->active = false;
 
                ath_hwq_unlock(sc, hwq);
+
+               if (!sta)
+                       break; /* just one multicast ath_atx_tid */
        }
 }
 
-- 
1.7.10.4

Reply via email to