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. --- 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 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html