* [ath9k-devel] [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 16:17 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 16:17 UTC (permalink / raw)
To: ath9k-devel
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
---
Changes since v1:
- Remove the old intermediate queueing logic completely instead of
just disabling it.
- Remove the qlen debug tunables.
- Remove the force_channel parameter from struct txctl (since we just
removed the code path that was using it).
drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 1 +
drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
8 files changed, 130 insertions(+), 214 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5294595..daf972c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
@@ -145,7 +144,9 @@ 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 ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv)
+#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv)
+#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif))
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
@@ -164,7 +165,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +232,6 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +246,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
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;
@@ -276,7 +275,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
@@ -293,7 +291,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
@@ -585,6 +582,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 *queue);
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 319cb5f..a5ce016 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
goto error;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta = sta;
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6de64cf..48b181d 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
ath_txq_unlock(sc, txq);
}
@@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index c2ca57a..d789798 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ 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++) {
+ tid = ATH_STA_2_TID(an->sta, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1c226d6..752cacb 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
}
return 0;
}
@@ -867,6 +866,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 3aed43a..f584e19 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2673,4 +2673,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 fe795fc..4077eeb 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_txq *txq,
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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&tid->list, list);
}
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq = tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued = true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
int q = fi->txq;
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
}
static struct ath_atx_tid *
@@ -173,9 +186,47 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ath_softc *sc = tid->an->sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_control txctl = {
+ .txq = tid->txq,
+ .sta = tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv));
+ if (!skb) {
+ tid->has_queued = false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q = skb_get_queue_mapping(skb);
+ if (tid->txq == sc->tx.txq_map[q]) {
+ fi = get_frame_info(skb);
+ fi->txq = q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +235,11 @@ 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);
+ skb = ath_tid_pull(tid);
return skb;
}
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq = tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->txq;
@@ -858,7 +874,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
@@ -867,11 +883,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
u16 seqno;
while (1) {
- *q = &tid->retry_q;
- if (skb_queue_empty(*q))
- *q = &tid->buf_q;
-
- skb = skb_peek(*q);
+ skb = ath_tid_dequeue(tid);
if (!skb)
break;
@@ -883,7 +895,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.stale = false;
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
seqno = bf->bf_state.seqno;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb))
+ continue;
break;
+ }
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts = {};
@@ -921,7 +940,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +951,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
return NULL;
}
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf = bf_first, *bf_prev = NULL;
@@ -947,12 +964,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed = false;
+
bf = bf_first;
aggr_limit = ath_lookup_rate(sc, bf, tid);
- do {
+ while (bf)
+ {
skb = bf->bf_mpdu;
fi = get_frame_info(skb);
@@ -961,12 +979,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >= h_baw)
- break;
+ goto stop;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
/* add padding for previous frame to aggregation length */
@@ -988,20 +1006,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
bf_prev = bf;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed = true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf = bf_first;
bf->bf_lastbf = bf_prev;
@@ -1012,9 +1028,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- *aggr_len = al;
-
- return closed;
+ return al;
#undef PADBYTES
}
@@ -1391,18 +1405,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf = bf_first, *bf_prev = NULL;
- struct sk_buff *skb;
int nframes = 0;
do {
struct ieee80211_tx_info *tx_info;
- skb = bf->bf_mpdu;
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
@@ -1411,13 +1422,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
if (nframes >= 2)
break;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1441,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len = 0;
- bool aggr, last = true;
+ bool aggr;
if (!ath_tid_has_buffered(tid))
return false;
INIT_LIST_HEAD(&bf_q);
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop = true;
return false;
}
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1510,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density;
}
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active = true;
*ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1;
@@ -1525,7 +1534,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
@@ -1535,14 +1543,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
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++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -1552,13 +1558,9 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
continue;
}
- buffered = ath_tid_has_buffered(tid);
-
list_del_init(&tid->list);
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
@@ -1571,19 +1573,12 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
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++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
tid->clear_ps_filter = true;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
ath_txq_unlock_complete(sc, txq);
}
}
@@ -1606,11 +1601,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
ath_txq_unlock_complete(sc, txq);
}
@@ -1626,7 +1616,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail = NULL, *bf;
- struct sk_buff_head *tid_q;
int sent = 0;
int i;
@@ -1641,11 +1630,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1648,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1875,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq = &sc->tx.txq[i];
- txq->stopped = false;
ath_draintxq(sc, txq);
}
@@ -2293,15 +2275,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false, ps_resp;
+ bool ps_resp;
int q, ret;
if (vif)
avp = (void *)vif->drv_priv;
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel = true;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2295,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
q = skb_get_queue_mapping(skb);
+ if (ps_resp)
+ txq = sc->tx.uapsdq;
+
ath_txq_lock(sc, txq);
if (txq == sc->tx.txq_map[q]) {
fi->txq = q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped = true;
- }
- }
-
- queue = ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue = true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx != sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
- skip_uapsd = true;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
- txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq != txctl->txq);
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter = true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
-
- ath_txq_schedule(sc, txq);
- goto out;
+ ++txq->pending_frames;
}
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2785,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ATH_AN_2_TID(an, tidno);
tid->an = an;
tid->tidno = tidno;
tid->seq_start = tid->seq_next = 0;
@@ -2866,11 +2794,14 @@ 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;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued = false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno = TID_TO_WME_AC(tidno);
tid->txq = sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
@@ -2880,9 +2811,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -2894,6 +2824,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->active = false;
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
--
2.9.0
^ permalink raw reply related [flat|nested] 118+ messages in thread
* Re: [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 16:17 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-06 18:19 ` Sebastian Gottschall
-1 siblings, 0 replies; 118+ messages in thread
From: Sebastian Gottschall @ 2016-07-06 17:57 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, linux-wireless, make-wifi-fast,
ath9k-devel
Cc: Tim Shepard, Felix Fietkau
testing now on my various devices in various operation modes, but looks
good so far. no stability issues
Sebastian
Am 06.07.2016 um 18:16 schrieb Toke Høiland-Jørgensen:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
> ---
> Changes since v1:
> - Remove the old intermediate queueing logic completely instead of
> just disabling it.
> - Remove the qlen debug tunables.
> - Remove the force_channel parameter from struct txctl (since we just
> removed the code path that was using it).
>
> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
> drivers/net/wireless/ath/ath9k/channel.c | 2 -
> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
> drivers/net/wireless/ath/ath9k/debug.h | 2 -
> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
> drivers/net/wireless/ath/ath9k/init.c | 2 +-
> drivers/net/wireless/ath/ath9k/main.c | 1 +
> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
> 8 files changed, 130 insertions(+), 214 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 5294595..daf972c 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
> #define ATH_RXBUF 512
> #define ATH_TXBUF 512
> #define ATH_TXBUF_RESERVE 5
> -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
> #define ATH_TXMAXTRY 13
> #define ATH_MAX_SW_RETRIES 30
>
> @@ -145,7 +144,9 @@ 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 ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv)
> +#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv)
> +#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif))
>
> #define IS_HT_RATE(rate) (rate & 0x80)
> #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
> @@ -164,7 +165,6 @@ struct ath_txq {
> spinlock_t axq_lock;
> u32 axq_depth;
> u32 axq_ampdu_depth;
> - bool stopped;
> bool axq_tx_inprogress;
> struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
> u8 txq_headidx;
> @@ -232,7 +232,6 @@ struct ath_buf {
>
> struct ath_atx_tid {
> struct list_head list;
> - struct sk_buff_head buf_q;
> struct sk_buff_head retry_q;
> struct ath_node *an;
> struct ath_txq *txq;
> @@ -247,13 +246,13 @@ struct ath_atx_tid {
> s8 bar_index;
> bool active;
> bool clear_ps_filter;
> + bool has_queued;
> };
>
> 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;
> @@ -276,7 +275,6 @@ struct ath_tx_control {
> struct ath_node *an;
> struct ieee80211_sta *sta;
> u8 paprd;
> - bool force_channel;
> };
>
>
> @@ -293,7 +291,6 @@ struct ath_tx {
> struct ath_descdma txdma;
> struct ath_txq *txq_map[IEEE80211_NUM_ACS];
> struct ath_txq *uapsdq;
> - u32 txq_max_pending[IEEE80211_NUM_ACS];
> u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
> };
>
> @@ -585,6 +582,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 *queue);
>
> /********/
> /* VIFs */
> diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
> index 319cb5f..a5ce016 100644
> --- a/drivers/net/wireless/ath/ath9k/channel.c
> +++ b/drivers/net/wireless/ath/ath9k/channel.c
> @@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
> goto error;
>
> txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
> - txctl.force_channel = true;
> if (ath_tx_start(sc->hw, skb, &txctl))
> goto error;
>
> @@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
> memset(&txctl, 0, sizeof(txctl));
> txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
> txctl.sta = sta;
> - txctl.force_channel = true;
> if (ath_tx_start(sc->hw, skb, &txctl)) {
> ieee80211_free_txskb(sc->hw, skb);
> return false;
> diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
> index 6de64cf..48b181d 100644
> --- a/drivers/net/wireless/ath/ath9k/debug.c
> +++ b/drivers/net/wireless/ath/ath9k/debug.c
> @@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
> PR("MPDUs XRetried: ", xretries);
> PR("Aggregates: ", a_aggr);
> PR("AMPDUs Queued HW:", a_queued_hw);
> - PR("AMPDUs Queued SW:", a_queued_sw);
> PR("AMPDUs Completed:", a_completed);
> PR("AMPDUs Retried: ", a_retries);
> PR("AMPDUs XRetried: ", a_xretries);
> @@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
> seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
> seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
> seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
> - seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
> - seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
> + seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
>
> ath_txq_unlock(sc, txq);
> }
> @@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
> AMKSTR(d_tx_mpdu_xretries),
> AMKSTR(d_tx_aggregates),
> AMKSTR(d_tx_ampdus_queued_hw),
> - AMKSTR(d_tx_ampdus_queued_sw),
> AMKSTR(d_tx_ampdus_completed),
> AMKSTR(d_tx_ampdu_retries),
> AMKSTR(d_tx_ampdu_xretries),
> @@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
> AWDATA(xretries);
> AWDATA(a_aggr);
> AWDATA(a_queued_hw);
> - AWDATA(a_queued_sw);
> AWDATA(a_completed);
> AWDATA(a_retries);
> AWDATA(a_xretries);
> @@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
> read_file_xmit);
> debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
> read_file_queues);
> - debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
> - debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
> - debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
> - debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
> debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
> read_file_misc);
> debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
> diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
> index cd68c5f..a078cdd 100644
> --- a/drivers/net/wireless/ath/ath9k/debug.h
> +++ b/drivers/net/wireless/ath/ath9k/debug.h
> @@ -147,7 +147,6 @@ struct ath_interrupt_stats {
> * @completed: Total MPDUs (non-aggr) completed
> * @a_aggr: Total no. of aggregates queued
> * @a_queued_hw: Total AMPDUs queued to hardware
> - * @a_queued_sw: Total AMPDUs queued to software queues
> * @a_completed: Total AMPDUs completed
> * @a_retries: No. of AMPDUs retried (SW)
> * @a_xretries: No. of AMPDUs dropped due to xretries
> @@ -174,7 +173,6 @@ struct ath_tx_stats {
> u32 xretries;
> u32 a_aggr;
> u32 a_queued_hw;
> - u32 a_queued_sw;
> u32 a_completed;
> u32 a_retries;
> u32 a_xretries;
> diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
> index c2ca57a..d789798 100644
> --- a/drivers/net/wireless/ath/ath9k/debug_sta.c
> +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
> @@ -52,8 +52,8 @@ 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++) {
> + tid = ATH_STA_2_TID(an->sta, tidno);
> txq = tid->txq;
> ath_txq_lock(sc, txq);
> if (tid->active) {
> diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
> index 1c226d6..752cacb 100644
> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
> for (i = 0; i < IEEE80211_NUM_ACS; i++) {
> sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
> sc->tx.txq_map[i]->mac80211_qnum = i;
> - sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
> }
> return 0;
> }
> @@ -867,6 +866,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 3aed43a..f584e19 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -2673,4 +2673,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 fe795fc..4077eeb 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_txq *txq,
> 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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
> list_add_tail(&tid->list, list);
> }
>
> +void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
> +{
> + struct ath_softc *sc = hw->priv;
> + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
> + struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
> + struct ath_txq *txq = tid->txq;
> +
> + ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
> + queue->sta ? queue->sta->addr : queue->vif->addr,
> + tid->tidno);
> +
> + ath_txq_lock(sc, txq);
> +
> + tid->has_queued = true;
> + ath_tx_queue_tid(sc, txq, tid);
> + ath_txq_schedule(sc, txq);
> +
> + ath_txq_unlock(sc, txq);
> +}
> +
> static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
> {
> struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
> @@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
> static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
> struct sk_buff *skb)
> {
> - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> struct ath_frame_info *fi = get_frame_info(skb);
> int q = fi->txq;
>
> @@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
> if (WARN_ON(--txq->pending_frames < 0))
> txq->pending_frames = 0;
>
> - if (txq->stopped &&
> - txq->pending_frames < sc->tx.txq_max_pending[q]) {
> - if (ath9k_is_chanctx_enabled())
> - ieee80211_wake_queue(sc->hw, info->hw_queue);
> - else
> - ieee80211_wake_queue(sc->hw, q);
> - txq->stopped = false;
> - }
> }
>
> static struct ath_atx_tid *
> @@ -173,9 +186,47 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
> return ATH_AN_2_TID(an, tidno);
> }
>
> +static struct sk_buff *
> +ath_tid_pull(struct ath_atx_tid *tid)
> +{
> + struct ath_softc *sc = tid->an->sc;
> + struct ieee80211_hw *hw = sc->hw;
> + struct ath_tx_control txctl = {
> + .txq = tid->txq,
> + .sta = tid->an->sta,
> + };
> + struct sk_buff *skb;
> + struct ath_frame_info *fi;
> + int q;
> +
> + if (!tid->has_queued)
> + return NULL;
> +
> + skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv));
> + if (!skb) {
> + tid->has_queued = false;
> + return NULL;
> + }
> +
> + if (ath_tx_prepare(hw, skb, &txctl)) {
> + ieee80211_free_txskb(hw, skb);
> + return NULL;
> + }
> +
> + q = skb_get_queue_mapping(skb);
> + if (tid->txq == sc->tx.txq_map[q]) {
> + fi = get_frame_info(skb);
> + fi->txq = q;
> + ++tid->txq->pending_frames;
> + }
> +
> + return skb;
> + }
> +
> +
> static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
> {
> - return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
> + return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
> }
>
> static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
> @@ -184,46 +235,11 @@ 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);
> + skb = ath_tid_pull(tid);
>
> return skb;
> }
>
> -/*
> - * ath_tx_tid_change_state:
> - * - clears a-mpdu flag of previous session
> - * - force sequence number allocation to fix next BlockAck Window
> - */
> -static void
> -ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
> -{
> - struct ath_txq *txq = tid->txq;
> - struct ieee80211_tx_info *tx_info;
> - struct sk_buff *skb, *tskb;
> - struct ath_buf *bf;
> - struct ath_frame_info *fi;
> -
> - skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
> - fi = get_frame_info(skb);
> - bf = fi->bf;
> -
> - tx_info = IEEE80211_SKB_CB(skb);
> - tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
> -
> - if (bf)
> - continue;
> -
> - bf = ath_tx_setup_buffer(sc, txq, tid, skb);
> - if (!bf) {
> - __skb_unlink(skb, &tid->buf_q);
> - ath_txq_skb_done(sc, txq, skb);
> - ieee80211_free_txskb(sc->hw, skb);
> - continue;
> - }
> - }
> -
> -}
> -
> static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
> {
> struct ath_txq *txq = tid->txq;
> @@ -858,7 +874,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
>
> static struct ath_buf *
> ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> - struct ath_atx_tid *tid, struct sk_buff_head **q)
> + struct ath_atx_tid *tid)
> {
> struct ieee80211_tx_info *tx_info;
> struct ath_frame_info *fi;
> @@ -867,11 +883,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> u16 seqno;
>
> while (1) {
> - *q = &tid->retry_q;
> - if (skb_queue_empty(*q))
> - *q = &tid->buf_q;
> -
> - skb = skb_peek(*q);
> + skb = ath_tid_dequeue(tid);
> if (!skb)
> break;
>
> @@ -883,7 +895,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> bf->bf_state.stale = false;
>
> if (!bf) {
> - __skb_unlink(skb, *q);
> ath_txq_skb_done(sc, txq, skb);
> ieee80211_free_txskb(sc->hw, skb);
> continue;
> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> seqno = bf->bf_state.seqno;
>
> /* do not step over block-ack window */
> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
> + __skb_queue_tail(&tid->retry_q, skb);
> +
> + /* If there are other skbs in the retry q, they are
> + * probably within the BAW, so loop immediately to get
> + * one of them. Otherwise the queue can get stuck. */
> + if (!skb_queue_is_first(&tid->retry_q, skb))
> + continue;
> break;
> + }
>
> if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
> struct ath_tx_status ts = {};
> @@ -921,7 +940,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>
> INIT_LIST_HEAD(&bf_head);
> list_add(&bf->list, &bf_head);
> - __skb_unlink(skb, *q);
> ath_tx_update_baw(sc, tid, seqno);
> ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
> continue;
> @@ -933,11 +951,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> return NULL;
> }
>
> -static bool
> +static int
> ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> struct ath_atx_tid *tid, struct list_head *bf_q,
> - struct ath_buf *bf_first, struct sk_buff_head *tid_q,
> - int *aggr_len)
> + struct ath_buf *bf_first)
> {
> #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
> struct ath_buf *bf = bf_first, *bf_prev = NULL;
> @@ -947,12 +964,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> struct ieee80211_tx_info *tx_info;
> struct ath_frame_info *fi;
> struct sk_buff *skb;
> - bool closed = false;
> +
>
> bf = bf_first;
> aggr_limit = ath_lookup_rate(sc, bf, tid);
>
> - do {
> + while (bf)
> + {
> skb = bf->bf_mpdu;
> fi = get_frame_info(skb);
>
> @@ -961,12 +979,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> if (nframes) {
> if (aggr_limit < al + bpad + al_delta ||
> ath_lookup_legacy(bf) || nframes >= h_baw)
> - break;
> + goto stop;
>
> tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
> if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
> !(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
> - break;
> + goto stop;
> }
>
> /* add padding for previous frame to aggregation length */
> @@ -988,20 +1006,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> ath_tx_addto_baw(sc, tid, bf);
> bf->bf_state.ndelim = ndelim;
>
> - __skb_unlink(skb, tid_q);
> list_add_tail(&bf->list, bf_q);
> if (bf_prev)
> bf_prev->bf_next = bf;
>
> bf_prev = bf;
>
> - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
> - if (!bf) {
> - closed = true;
> - break;
> - }
> - } while (ath_tid_has_buffered(tid));
> -
> + bf = ath_tx_get_tid_subframe(sc, txq, tid);
> + }
> + goto finish;
> +stop:
> + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
> +finish:
> bf = bf_first;
> bf->bf_lastbf = bf_prev;
>
> @@ -1012,9 +1028,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> TX_STAT_INC(txq->axq_qnum, a_aggr);
> }
>
> - *aggr_len = al;
> -
> - return closed;
> + return al;
> #undef PADBYTES
> }
>
> @@ -1391,18 +1405,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
> static void
> ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
> struct ath_atx_tid *tid, struct list_head *bf_q,
> - struct ath_buf *bf_first, struct sk_buff_head *tid_q)
> + struct ath_buf *bf_first)
> {
> struct ath_buf *bf = bf_first, *bf_prev = NULL;
> - struct sk_buff *skb;
> int nframes = 0;
>
> do {
> struct ieee80211_tx_info *tx_info;
> - skb = bf->bf_mpdu;
>
> nframes++;
> - __skb_unlink(skb, tid_q);
> list_add_tail(&bf->list, bf_q);
> if (bf_prev)
> bf_prev->bf_next = bf;
> @@ -1411,13 +1422,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
> if (nframes >= 2)
> break;
>
> - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
> + bf = ath_tx_get_tid_subframe(sc, txq, tid);
> if (!bf)
> break;
>
> tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
> - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
> + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
> + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
> break;
> + }
>
> ath_set_rates(tid->an->vif, tid->an->sta, bf);
> } while (1);
> @@ -1428,34 +1441,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
> {
> struct ath_buf *bf;
> struct ieee80211_tx_info *tx_info;
> - struct sk_buff_head *tid_q;
> struct list_head bf_q;
> int aggr_len = 0;
> - bool aggr, last = true;
> + bool aggr;
>
> if (!ath_tid_has_buffered(tid))
> return false;
>
> INIT_LIST_HEAD(&bf_q);
>
> - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
> + bf = ath_tx_get_tid_subframe(sc, txq, tid);
> if (!bf)
> return false;
>
> tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
> aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
> if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
> - (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
> + (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
> + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
> *stop = true;
> return false;
> }
>
> ath_set_rates(tid->an->vif, tid->an->sta, bf);
> if (aggr)
> - last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
> - tid_q, &aggr_len);
> + aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
> else
> - ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
> + ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
>
> if (list_empty(&bf_q))
> return false;
> @@ -1498,9 +1510,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
> an->mpdudensity = density;
> }
>
> - /* force sequence number allocation for pending frames */
> - ath_tx_tid_change_state(sc, txtid);
> -
> txtid->active = true;
> *ssn = txtid->seq_start = txtid->seq_next;
> txtid->bar_index = -1;
> @@ -1525,7 +1534,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
> ath_txq_lock(sc, txq);
> txtid->active = false;
> ath_tx_flush_tid(sc, txtid);
> - ath_tx_tid_change_state(sc, txtid);
> ath_txq_unlock_complete(sc, txq);
> }
>
> @@ -1535,14 +1543,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
> struct ath_common *common = ath9k_hw_common(sc->sc_ah);
> struct ath_atx_tid *tid;
> struct ath_txq *txq;
> - bool buffered;
> 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++) {
> + tid = ATH_AN_2_TID(an, tidno);
> txq = tid->txq;
>
> ath_txq_lock(sc, txq);
> @@ -1552,13 +1558,9 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
> continue;
> }
>
> - buffered = ath_tid_has_buffered(tid);
> -
> list_del_init(&tid->list);
>
> ath_txq_unlock(sc, txq);
> -
> - ieee80211_sta_set_buffered(sta, tidno, buffered);
> }
> }
>
> @@ -1571,19 +1573,12 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
>
> 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++) {
> + tid = ATH_AN_2_TID(an, tidno);
> txq = tid->txq;
>
> ath_txq_lock(sc, txq);
> tid->clear_ps_filter = true;
> -
> - if (ath_tid_has_buffered(tid)) {
> - ath_tx_queue_tid(sc, txq, tid);
> - ath_txq_schedule(sc, txq);
> - }
> -
> ath_txq_unlock_complete(sc, txq);
> }
> }
> @@ -1606,11 +1601,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
>
> tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
>
> - if (ath_tid_has_buffered(tid)) {
> - ath_tx_queue_tid(sc, txq, tid);
> - ath_txq_schedule(sc, txq);
> - }
> -
> ath_txq_unlock_complete(sc, txq);
> }
>
> @@ -1626,7 +1616,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
> struct ieee80211_tx_info *info;
> struct list_head bf_q;
> struct ath_buf *bf_tail = NULL, *bf;
> - struct sk_buff_head *tid_q;
> int sent = 0;
> int i;
>
> @@ -1641,11 +1630,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
>
> ath_txq_lock(sc, tid->txq);
> while (nframes > 0) {
> - bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
> + bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
> if (!bf)
> break;
>
> - __skb_unlink(bf->bf_mpdu, tid_q);
> list_add_tail(&bf->list, &bf_q);
> ath_set_rates(tid->an->vif, tid->an->sta, bf);
> if (bf_isampdu(bf)) {
> @@ -1660,7 +1648,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
> sent++;
> TX_STAT_INC(txq->axq_qnum, a_queued_hw);
>
> - if (an->sta && !ath_tid_has_buffered(tid))
> + if (an->sta && skb_queue_empty(&tid->retry_q))
> ieee80211_sta_set_buffered(an->sta, i, false);
> }
> ath_txq_unlock_complete(sc, tid->txq);
> @@ -1887,13 +1875,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
> if (!ATH_TXQ_SETUP(sc, i))
> continue;
>
> - /*
> - * The caller will resume queues with ieee80211_wake_queues.
> - * Mark the queue as not stopped to prevent ath_tx_complete
> - * from waking the queue too early.
> - */
> txq = &sc->tx.txq[i];
> - txq->stopped = false;
> ath_draintxq(sc, txq);
> }
>
> @@ -2293,15 +2275,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
> struct ath_txq *txq = txctl->txq;
> struct ath_atx_tid *tid = NULL;
> struct ath_buf *bf;
> - bool queue, skip_uapsd = false, ps_resp;
> + bool ps_resp;
> int q, ret;
>
> if (vif)
> avp = (void *)vif->drv_priv;
>
> - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
> - txctl->force_channel = true;
> -
> ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
>
> ret = ath_tx_prepare(hw, skb, txctl);
> @@ -2316,63 +2295,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
>
> q = skb_get_queue_mapping(skb);
>
> + if (ps_resp)
> + txq = sc->tx.uapsdq;
> +
> ath_txq_lock(sc, txq);
> if (txq == sc->tx.txq_map[q]) {
> fi->txq = q;
> - if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
> - !txq->stopped) {
> - if (ath9k_is_chanctx_enabled())
> - ieee80211_stop_queue(sc->hw, info->hw_queue);
> - else
> - ieee80211_stop_queue(sc->hw, q);
> - txq->stopped = true;
> - }
> - }
> -
> - queue = ieee80211_is_data_present(hdr->frame_control);
> -
> - /* If chanctx, queue all null frames while NOA could be there */
> - if (ath9k_is_chanctx_enabled() &&
> - ieee80211_is_nullfunc(hdr->frame_control) &&
> - !txctl->force_channel)
> - queue = true;
> -
> - /* Force queueing of all frames that belong to a virtual interface on
> - * a different channel context, to ensure that they are sent on the
> - * correct channel.
> - */
> - if (((avp && avp->chanctx != sc->cur_chan) ||
> - sc->cur_chan->stopped) && !txctl->force_channel) {
> - if (!txctl->an)
> - txctl->an = &avp->mcast_node;
> - queue = true;
> - skip_uapsd = true;
> - }
> -
> - if (txctl->an && queue)
> - tid = ath_get_skb_tid(sc, txctl->an, skb);
> -
> - if (!skip_uapsd && ps_resp) {
> - ath_txq_unlock(sc, txq);
> - txq = sc->tx.uapsdq;
> - ath_txq_lock(sc, txq);
> - } else if (txctl->an && queue) {
> - WARN_ON(tid->txq != txctl->txq);
> -
> - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
> - tid->clear_ps_filter = true;
> -
> - /*
> - * Add this frame to software queue for scheduling later
> - * for aggregation.
> - */
> - TX_STAT_INC(txq->axq_qnum, a_queued_sw);
> - __skb_queue_tail(&tid->buf_q, skb);
> - if (!txctl->an->sleeping)
> - ath_tx_queue_tid(sc, txq, tid);
> -
> - ath_txq_schedule(sc, txq);
> - goto out;
> + ++txq->pending_frames;
> }
>
> bf = ath_tx_setup_buffer(sc, txq, tid, skb);
> @@ -2856,9 +2785,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
> struct ath_atx_tid *tid;
> int tidno, acno;
>
> - for (tidno = 0, tid = &an->tid[tidno];
> - tidno < IEEE80211_NUM_TIDS;
> - tidno++, tid++) {
> + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
> + tid = ATH_AN_2_TID(an, tidno);
> tid->an = an;
> tid->tidno = tidno;
> tid->seq_start = tid->seq_next = 0;
> @@ -2866,11 +2794,14 @@ 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;
> - __skb_queue_head_init(&tid->buf_q);
> + tid->has_queued = false;
> __skb_queue_head_init(&tid->retry_q);
> INIT_LIST_HEAD(&tid->list);
> acno = TID_TO_WME_AC(tidno);
> tid->txq = sc->tx.txq_map[acno];
> +
> + if (!an->sta)
> + break; /* just one multicast ath_atx_tid */
> }
> }
>
> @@ -2880,9 +2811,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
> struct ath_txq *txq;
> int tidno;
>
> - for (tidno = 0, tid = &an->tid[tidno];
> - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
> -
> + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
> + tid = ATH_AN_2_TID(an, tidno);
> txq = tid->txq;
>
> ath_txq_lock(sc, txq);
> @@ -2894,6 +2824,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
> tid->active = false;
>
> ath_txq_unlock(sc, txq);
> +
> + if (!an->sta)
> + break; /* just one multicast ath_atx_tid */
> }
> }
>
--
Mit freundlichen Grüssen / Regards
Sebastian Gottschall / CTO
NewMedia-NET GmbH - DD-WRT
Firmensitz: Berliner Ring 101, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Geschäftsführer: Peter Steinhäuser, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall@dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 18:19 ` Sebastian Gottschall
0 siblings, 0 replies; 118+ messages in thread
From: Sebastian Gottschall @ 2016-07-06 18:19 UTC (permalink / raw)
To: ath9k-devel
testing now on my various devices in various operation modes, but looks
good so far. no stability issues
Sebastian
Am 06.07.2016 um 18:16 schrieb Toke H?iland-J?rgensen:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
> ---
> Changes since v1:
> - Remove the old intermediate queueing logic completely instead of
> just disabling it.
> - Remove the qlen debug tunables.
> - Remove the force_channel parameter from struct txctl (since we just
> removed the code path that was using it).
>
> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
> drivers/net/wireless/ath/ath9k/channel.c | 2 -
> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
> drivers/net/wireless/ath/ath9k/debug.h | 2 -
> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
> drivers/net/wireless/ath/ath9k/init.c | 2 +-
> drivers/net/wireless/ath/ath9k/main.c | 1 +
> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
> 8 files changed, 130 insertions(+), 214 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 5294595..daf972c 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
> #define ATH_RXBUF 512
> #define ATH_TXBUF 512
> #define ATH_TXBUF_RESERVE 5
> -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
> #define ATH_TXMAXTRY 13
> #define ATH_MAX_SW_RETRIES 30
>
> @@ -145,7 +144,9 @@ 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 ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv)
> +#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv)
> +#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif))
>
> #define IS_HT_RATE(rate) (rate & 0x80)
> #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
> @@ -164,7 +165,6 @@ struct ath_txq {
> spinlock_t axq_lock;
> u32 axq_depth;
> u32 axq_ampdu_depth;
> - bool stopped;
> bool axq_tx_inprogress;
> struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
> u8 txq_headidx;
> @@ -232,7 +232,6 @@ struct ath_buf {
>
> struct ath_atx_tid {
> struct list_head list;
> - struct sk_buff_head buf_q;
> struct sk_buff_head retry_q;
> struct ath_node *an;
> struct ath_txq *txq;
> @@ -247,13 +246,13 @@ struct ath_atx_tid {
> s8 bar_index;
> bool active;
> bool clear_ps_filter;
> + bool has_queued;
> };
>
> 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;
> @@ -276,7 +275,6 @@ struct ath_tx_control {
> struct ath_node *an;
> struct ieee80211_sta *sta;
> u8 paprd;
> - bool force_channel;
> };
>
>
> @@ -293,7 +291,6 @@ struct ath_tx {
> struct ath_descdma txdma;
> struct ath_txq *txq_map[IEEE80211_NUM_ACS];
> struct ath_txq *uapsdq;
> - u32 txq_max_pending[IEEE80211_NUM_ACS];
> u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
> };
>
> @@ -585,6 +582,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 *queue);
>
> /********/
> /* VIFs */
> diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
> index 319cb5f..a5ce016 100644
> --- a/drivers/net/wireless/ath/ath9k/channel.c
> +++ b/drivers/net/wireless/ath/ath9k/channel.c
> @@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
> goto error;
>
> txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
> - txctl.force_channel = true;
> if (ath_tx_start(sc->hw, skb, &txctl))
> goto error;
>
> @@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
> memset(&txctl, 0, sizeof(txctl));
> txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
> txctl.sta = sta;
> - txctl.force_channel = true;
> if (ath_tx_start(sc->hw, skb, &txctl)) {
> ieee80211_free_txskb(sc->hw, skb);
> return false;
> diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
> index 6de64cf..48b181d 100644
> --- a/drivers/net/wireless/ath/ath9k/debug.c
> +++ b/drivers/net/wireless/ath/ath9k/debug.c
> @@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
> PR("MPDUs XRetried: ", xretries);
> PR("Aggregates: ", a_aggr);
> PR("AMPDUs Queued HW:", a_queued_hw);
> - PR("AMPDUs Queued SW:", a_queued_sw);
> PR("AMPDUs Completed:", a_completed);
> PR("AMPDUs Retried: ", a_retries);
> PR("AMPDUs XRetried: ", a_xretries);
> @@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
> seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
> seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
> seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
> - seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
> - seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
> + seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
>
> ath_txq_unlock(sc, txq);
> }
> @@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
> AMKSTR(d_tx_mpdu_xretries),
> AMKSTR(d_tx_aggregates),
> AMKSTR(d_tx_ampdus_queued_hw),
> - AMKSTR(d_tx_ampdus_queued_sw),
> AMKSTR(d_tx_ampdus_completed),
> AMKSTR(d_tx_ampdu_retries),
> AMKSTR(d_tx_ampdu_xretries),
> @@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
> AWDATA(xretries);
> AWDATA(a_aggr);
> AWDATA(a_queued_hw);
> - AWDATA(a_queued_sw);
> AWDATA(a_completed);
> AWDATA(a_retries);
> AWDATA(a_xretries);
> @@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
> read_file_xmit);
> debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
> read_file_queues);
> - debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
> - debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
> - debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
> - debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
> - &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
> debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
> read_file_misc);
> debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
> diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
> index cd68c5f..a078cdd 100644
> --- a/drivers/net/wireless/ath/ath9k/debug.h
> +++ b/drivers/net/wireless/ath/ath9k/debug.h
> @@ -147,7 +147,6 @@ struct ath_interrupt_stats {
> * @completed: Total MPDUs (non-aggr) completed
> * @a_aggr: Total no. of aggregates queued
> * @a_queued_hw: Total AMPDUs queued to hardware
> - * @a_queued_sw: Total AMPDUs queued to software queues
> * @a_completed: Total AMPDUs completed
> * @a_retries: No. of AMPDUs retried (SW)
> * @a_xretries: No. of AMPDUs dropped due to xretries
> @@ -174,7 +173,6 @@ struct ath_tx_stats {
> u32 xretries;
> u32 a_aggr;
> u32 a_queued_hw;
> - u32 a_queued_sw;
> u32 a_completed;
> u32 a_retries;
> u32 a_xretries;
> diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
> index c2ca57a..d789798 100644
> --- a/drivers/net/wireless/ath/ath9k/debug_sta.c
> +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
> @@ -52,8 +52,8 @@ 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++) {
> + tid = ATH_STA_2_TID(an->sta, tidno);
> txq = tid->txq;
> ath_txq_lock(sc, txq);
> if (tid->active) {
> diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
> index 1c226d6..752cacb 100644
> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
> for (i = 0; i < IEEE80211_NUM_ACS; i++) {
> sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
> sc->tx.txq_map[i]->mac80211_qnum = i;
> - sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
> }
> return 0;
> }
> @@ -867,6 +866,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 3aed43a..f584e19 100644
> --- a/drivers/net/wireless/ath/ath9k/main.c
> +++ b/drivers/net/wireless/ath/ath9k/main.c
> @@ -2673,4 +2673,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 fe795fc..4077eeb 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_txq *txq,
> 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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
> list_add_tail(&tid->list, list);
> }
>
> +void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
> +{
> + struct ath_softc *sc = hw->priv;
> + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
> + struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
> + struct ath_txq *txq = tid->txq;
> +
> + ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
> + queue->sta ? queue->sta->addr : queue->vif->addr,
> + tid->tidno);
> +
> + ath_txq_lock(sc, txq);
> +
> + tid->has_queued = true;
> + ath_tx_queue_tid(sc, txq, tid);
> + ath_txq_schedule(sc, txq);
> +
> + ath_txq_unlock(sc, txq);
> +}
> +
> static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
> {
> struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
> @@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
> static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
> struct sk_buff *skb)
> {
> - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> struct ath_frame_info *fi = get_frame_info(skb);
> int q = fi->txq;
>
> @@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
> if (WARN_ON(--txq->pending_frames < 0))
> txq->pending_frames = 0;
>
> - if (txq->stopped &&
> - txq->pending_frames < sc->tx.txq_max_pending[q]) {
> - if (ath9k_is_chanctx_enabled())
> - ieee80211_wake_queue(sc->hw, info->hw_queue);
> - else
> - ieee80211_wake_queue(sc->hw, q);
> - txq->stopped = false;
> - }
> }
>
> static struct ath_atx_tid *
> @@ -173,9 +186,47 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
> return ATH_AN_2_TID(an, tidno);
> }
>
> +static struct sk_buff *
> +ath_tid_pull(struct ath_atx_tid *tid)
> +{
> + struct ath_softc *sc = tid->an->sc;
> + struct ieee80211_hw *hw = sc->hw;
> + struct ath_tx_control txctl = {
> + .txq = tid->txq,
> + .sta = tid->an->sta,
> + };
> + struct sk_buff *skb;
> + struct ath_frame_info *fi;
> + int q;
> +
> + if (!tid->has_queued)
> + return NULL;
> +
> + skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv));
> + if (!skb) {
> + tid->has_queued = false;
> + return NULL;
> + }
> +
> + if (ath_tx_prepare(hw, skb, &txctl)) {
> + ieee80211_free_txskb(hw, skb);
> + return NULL;
> + }
> +
> + q = skb_get_queue_mapping(skb);
> + if (tid->txq == sc->tx.txq_map[q]) {
> + fi = get_frame_info(skb);
> + fi->txq = q;
> + ++tid->txq->pending_frames;
> + }
> +
> + return skb;
> + }
> +
> +
> static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
> {
> - return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
> + return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
> }
>
> static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
> @@ -184,46 +235,11 @@ 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);
> + skb = ath_tid_pull(tid);
>
> return skb;
> }
>
> -/*
> - * ath_tx_tid_change_state:
> - * - clears a-mpdu flag of previous session
> - * - force sequence number allocation to fix next BlockAck Window
> - */
> -static void
> -ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
> -{
> - struct ath_txq *txq = tid->txq;
> - struct ieee80211_tx_info *tx_info;
> - struct sk_buff *skb, *tskb;
> - struct ath_buf *bf;
> - struct ath_frame_info *fi;
> -
> - skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
> - fi = get_frame_info(skb);
> - bf = fi->bf;
> -
> - tx_info = IEEE80211_SKB_CB(skb);
> - tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
> -
> - if (bf)
> - continue;
> -
> - bf = ath_tx_setup_buffer(sc, txq, tid, skb);
> - if (!bf) {
> - __skb_unlink(skb, &tid->buf_q);
> - ath_txq_skb_done(sc, txq, skb);
> - ieee80211_free_txskb(sc->hw, skb);
> - continue;
> - }
> - }
> -
> -}
> -
> static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
> {
> struct ath_txq *txq = tid->txq;
> @@ -858,7 +874,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
>
> static struct ath_buf *
> ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> - struct ath_atx_tid *tid, struct sk_buff_head **q)
> + struct ath_atx_tid *tid)
> {
> struct ieee80211_tx_info *tx_info;
> struct ath_frame_info *fi;
> @@ -867,11 +883,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> u16 seqno;
>
> while (1) {
> - *q = &tid->retry_q;
> - if (skb_queue_empty(*q))
> - *q = &tid->buf_q;
> -
> - skb = skb_peek(*q);
> + skb = ath_tid_dequeue(tid);
> if (!skb)
> break;
>
> @@ -883,7 +895,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> bf->bf_state.stale = false;
>
> if (!bf) {
> - __skb_unlink(skb, *q);
> ath_txq_skb_done(sc, txq, skb);
> ieee80211_free_txskb(sc->hw, skb);
> continue;
> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> seqno = bf->bf_state.seqno;
>
> /* do not step over block-ack window */
> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
> + __skb_queue_tail(&tid->retry_q, skb);
> +
> + /* If there are other skbs in the retry q, they are
> + * probably within the BAW, so loop immediately to get
> + * one of them. Otherwise the queue can get stuck. */
> + if (!skb_queue_is_first(&tid->retry_q, skb))
> + continue;
> break;
> + }
>
> if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
> struct ath_tx_status ts = {};
> @@ -921,7 +940,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>
> INIT_LIST_HEAD(&bf_head);
> list_add(&bf->list, &bf_head);
> - __skb_unlink(skb, *q);
> ath_tx_update_baw(sc, tid, seqno);
> ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
> continue;
> @@ -933,11 +951,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> return NULL;
> }
>
> -static bool
> +static int
> ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> struct ath_atx_tid *tid, struct list_head *bf_q,
> - struct ath_buf *bf_first, struct sk_buff_head *tid_q,
> - int *aggr_len)
> + struct ath_buf *bf_first)
> {
> #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
> struct ath_buf *bf = bf_first, *bf_prev = NULL;
> @@ -947,12 +964,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> struct ieee80211_tx_info *tx_info;
> struct ath_frame_info *fi;
> struct sk_buff *skb;
> - bool closed = false;
> +
>
> bf = bf_first;
> aggr_limit = ath_lookup_rate(sc, bf, tid);
>
> - do {
> + while (bf)
> + {
> skb = bf->bf_mpdu;
> fi = get_frame_info(skb);
>
> @@ -961,12 +979,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> if (nframes) {
> if (aggr_limit < al + bpad + al_delta ||
> ath_lookup_legacy(bf) || nframes >= h_baw)
> - break;
> + goto stop;
>
> tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
> if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
> !(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
> - break;
> + goto stop;
> }
>
> /* add padding for previous frame to aggregation length */
> @@ -988,20 +1006,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> ath_tx_addto_baw(sc, tid, bf);
> bf->bf_state.ndelim = ndelim;
>
> - __skb_unlink(skb, tid_q);
> list_add_tail(&bf->list, bf_q);
> if (bf_prev)
> bf_prev->bf_next = bf;
>
> bf_prev = bf;
>
> - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
> - if (!bf) {
> - closed = true;
> - break;
> - }
> - } while (ath_tid_has_buffered(tid));
> -
> + bf = ath_tx_get_tid_subframe(sc, txq, tid);
> + }
> + goto finish;
> +stop:
> + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
> +finish:
> bf = bf_first;
> bf->bf_lastbf = bf_prev;
>
> @@ -1012,9 +1028,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
> TX_STAT_INC(txq->axq_qnum, a_aggr);
> }
>
> - *aggr_len = al;
> -
> - return closed;
> + return al;
> #undef PADBYTES
> }
>
> @@ -1391,18 +1405,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
> static void
> ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
> struct ath_atx_tid *tid, struct list_head *bf_q,
> - struct ath_buf *bf_first, struct sk_buff_head *tid_q)
> + struct ath_buf *bf_first)
> {
> struct ath_buf *bf = bf_first, *bf_prev = NULL;
> - struct sk_buff *skb;
> int nframes = 0;
>
> do {
> struct ieee80211_tx_info *tx_info;
> - skb = bf->bf_mpdu;
>
> nframes++;
> - __skb_unlink(skb, tid_q);
> list_add_tail(&bf->list, bf_q);
> if (bf_prev)
> bf_prev->bf_next = bf;
> @@ -1411,13 +1422,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
> if (nframes >= 2)
> break;
>
> - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
> + bf = ath_tx_get_tid_subframe(sc, txq, tid);
> if (!bf)
> break;
>
> tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
> - if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
> + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
> + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
> break;
> + }
>
> ath_set_rates(tid->an->vif, tid->an->sta, bf);
> } while (1);
> @@ -1428,34 +1441,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
> {
> struct ath_buf *bf;
> struct ieee80211_tx_info *tx_info;
> - struct sk_buff_head *tid_q;
> struct list_head bf_q;
> int aggr_len = 0;
> - bool aggr, last = true;
> + bool aggr;
>
> if (!ath_tid_has_buffered(tid))
> return false;
>
> INIT_LIST_HEAD(&bf_q);
>
> - bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
> + bf = ath_tx_get_tid_subframe(sc, txq, tid);
> if (!bf)
> return false;
>
> tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
> aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
> if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
> - (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
> + (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
> + __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
> *stop = true;
> return false;
> }
>
> ath_set_rates(tid->an->vif, tid->an->sta, bf);
> if (aggr)
> - last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
> - tid_q, &aggr_len);
> + aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
> else
> - ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
> + ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
>
> if (list_empty(&bf_q))
> return false;
> @@ -1498,9 +1510,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
> an->mpdudensity = density;
> }
>
> - /* force sequence number allocation for pending frames */
> - ath_tx_tid_change_state(sc, txtid);
> -
> txtid->active = true;
> *ssn = txtid->seq_start = txtid->seq_next;
> txtid->bar_index = -1;
> @@ -1525,7 +1534,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
> ath_txq_lock(sc, txq);
> txtid->active = false;
> ath_tx_flush_tid(sc, txtid);
> - ath_tx_tid_change_state(sc, txtid);
> ath_txq_unlock_complete(sc, txq);
> }
>
> @@ -1535,14 +1543,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
> struct ath_common *common = ath9k_hw_common(sc->sc_ah);
> struct ath_atx_tid *tid;
> struct ath_txq *txq;
> - bool buffered;
> 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++) {
> + tid = ATH_AN_2_TID(an, tidno);
> txq = tid->txq;
>
> ath_txq_lock(sc, txq);
> @@ -1552,13 +1558,9 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
> continue;
> }
>
> - buffered = ath_tid_has_buffered(tid);
> -
> list_del_init(&tid->list);
>
> ath_txq_unlock(sc, txq);
> -
> - ieee80211_sta_set_buffered(sta, tidno, buffered);
> }
> }
>
> @@ -1571,19 +1573,12 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
>
> 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++) {
> + tid = ATH_AN_2_TID(an, tidno);
> txq = tid->txq;
>
> ath_txq_lock(sc, txq);
> tid->clear_ps_filter = true;
> -
> - if (ath_tid_has_buffered(tid)) {
> - ath_tx_queue_tid(sc, txq, tid);
> - ath_txq_schedule(sc, txq);
> - }
> -
> ath_txq_unlock_complete(sc, txq);
> }
> }
> @@ -1606,11 +1601,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
>
> tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
>
> - if (ath_tid_has_buffered(tid)) {
> - ath_tx_queue_tid(sc, txq, tid);
> - ath_txq_schedule(sc, txq);
> - }
> -
> ath_txq_unlock_complete(sc, txq);
> }
>
> @@ -1626,7 +1616,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
> struct ieee80211_tx_info *info;
> struct list_head bf_q;
> struct ath_buf *bf_tail = NULL, *bf;
> - struct sk_buff_head *tid_q;
> int sent = 0;
> int i;
>
> @@ -1641,11 +1630,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
>
> ath_txq_lock(sc, tid->txq);
> while (nframes > 0) {
> - bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
> + bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
> if (!bf)
> break;
>
> - __skb_unlink(bf->bf_mpdu, tid_q);
> list_add_tail(&bf->list, &bf_q);
> ath_set_rates(tid->an->vif, tid->an->sta, bf);
> if (bf_isampdu(bf)) {
> @@ -1660,7 +1648,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
> sent++;
> TX_STAT_INC(txq->axq_qnum, a_queued_hw);
>
> - if (an->sta && !ath_tid_has_buffered(tid))
> + if (an->sta && skb_queue_empty(&tid->retry_q))
> ieee80211_sta_set_buffered(an->sta, i, false);
> }
> ath_txq_unlock_complete(sc, tid->txq);
> @@ -1887,13 +1875,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
> if (!ATH_TXQ_SETUP(sc, i))
> continue;
>
> - /*
> - * The caller will resume queues with ieee80211_wake_queues.
> - * Mark the queue as not stopped to prevent ath_tx_complete
> - * from waking the queue too early.
> - */
> txq = &sc->tx.txq[i];
> - txq->stopped = false;
> ath_draintxq(sc, txq);
> }
>
> @@ -2293,15 +2275,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
> struct ath_txq *txq = txctl->txq;
> struct ath_atx_tid *tid = NULL;
> struct ath_buf *bf;
> - bool queue, skip_uapsd = false, ps_resp;
> + bool ps_resp;
> int q, ret;
>
> if (vif)
> avp = (void *)vif->drv_priv;
>
> - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
> - txctl->force_channel = true;
> -
> ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
>
> ret = ath_tx_prepare(hw, skb, txctl);
> @@ -2316,63 +2295,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
>
> q = skb_get_queue_mapping(skb);
>
> + if (ps_resp)
> + txq = sc->tx.uapsdq;
> +
> ath_txq_lock(sc, txq);
> if (txq == sc->tx.txq_map[q]) {
> fi->txq = q;
> - if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
> - !txq->stopped) {
> - if (ath9k_is_chanctx_enabled())
> - ieee80211_stop_queue(sc->hw, info->hw_queue);
> - else
> - ieee80211_stop_queue(sc->hw, q);
> - txq->stopped = true;
> - }
> - }
> -
> - queue = ieee80211_is_data_present(hdr->frame_control);
> -
> - /* If chanctx, queue all null frames while NOA could be there */
> - if (ath9k_is_chanctx_enabled() &&
> - ieee80211_is_nullfunc(hdr->frame_control) &&
> - !txctl->force_channel)
> - queue = true;
> -
> - /* Force queueing of all frames that belong to a virtual interface on
> - * a different channel context, to ensure that they are sent on the
> - * correct channel.
> - */
> - if (((avp && avp->chanctx != sc->cur_chan) ||
> - sc->cur_chan->stopped) && !txctl->force_channel) {
> - if (!txctl->an)
> - txctl->an = &avp->mcast_node;
> - queue = true;
> - skip_uapsd = true;
> - }
> -
> - if (txctl->an && queue)
> - tid = ath_get_skb_tid(sc, txctl->an, skb);
> -
> - if (!skip_uapsd && ps_resp) {
> - ath_txq_unlock(sc, txq);
> - txq = sc->tx.uapsdq;
> - ath_txq_lock(sc, txq);
> - } else if (txctl->an && queue) {
> - WARN_ON(tid->txq != txctl->txq);
> -
> - if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
> - tid->clear_ps_filter = true;
> -
> - /*
> - * Add this frame to software queue for scheduling later
> - * for aggregation.
> - */
> - TX_STAT_INC(txq->axq_qnum, a_queued_sw);
> - __skb_queue_tail(&tid->buf_q, skb);
> - if (!txctl->an->sleeping)
> - ath_tx_queue_tid(sc, txq, tid);
> -
> - ath_txq_schedule(sc, txq);
> - goto out;
> + ++txq->pending_frames;
> }
>
> bf = ath_tx_setup_buffer(sc, txq, tid, skb);
> @@ -2856,9 +2785,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
> struct ath_atx_tid *tid;
> int tidno, acno;
>
> - for (tidno = 0, tid = &an->tid[tidno];
> - tidno < IEEE80211_NUM_TIDS;
> - tidno++, tid++) {
> + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
> + tid = ATH_AN_2_TID(an, tidno);
> tid->an = an;
> tid->tidno = tidno;
> tid->seq_start = tid->seq_next = 0;
> @@ -2866,11 +2794,14 @@ 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;
> - __skb_queue_head_init(&tid->buf_q);
> + tid->has_queued = false;
> __skb_queue_head_init(&tid->retry_q);
> INIT_LIST_HEAD(&tid->list);
> acno = TID_TO_WME_AC(tidno);
> tid->txq = sc->tx.txq_map[acno];
> +
> + if (!an->sta)
> + break; /* just one multicast ath_atx_tid */
> }
> }
>
> @@ -2880,9 +2811,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
> struct ath_txq *txq;
> int tidno;
>
> - for (tidno = 0, tid = &an->tid[tidno];
> - tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
> -
> + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
> + tid = ATH_AN_2_TID(an, tidno);
> txq = tid->txq;
>
> ath_txq_lock(sc, txq);
> @@ -2894,6 +2824,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
> tid->active = false;
>
> ath_txq_unlock(sc, txq);
> +
> + if (!an->sta)
> + break; /* just one multicast ath_atx_tid */
> }
> }
>
--
Mit freundlichen Gr?ssen / Regards
Sebastian Gottschall / CTO
NewMedia-NET GmbH - DD-WRT
Firmensitz: Berliner Ring 101, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Gesch?ftsf?hrer: Peter Steinh?user, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall at dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 16:17 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-06 18:13 ` Felix Fietkau
-1 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-06 18:13 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, linux-wireless, make-wifi-fast,
ath9k-devel
Cc: Tim Shepard
On 2016-07-06 18:16, Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
> ---
> Changes since v1:
> - Remove the old intermediate queueing logic completely instead of
> just disabling it.
> - Remove the qlen debug tunables.
> - Remove the force_channel parameter from struct txctl (since we just
> removed the code path that was using it).
>
> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
> drivers/net/wireless/ath/ath9k/channel.c | 2 -
> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
> drivers/net/wireless/ath/ath9k/debug.h | 2 -
> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
> drivers/net/wireless/ath/ath9k/init.c | 2 +-
> drivers/net/wireless/ath/ath9k/main.c | 1 +
> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
> 8 files changed, 130 insertions(+), 214 deletions(-)
Nice work!
> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
> index fe795fc..4077eeb 100644
> --- a/drivers/net/wireless/ath/ath9k/xmit.c
> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> seqno = bf->bf_state.seqno;
>
> /* do not step over block-ack window */
> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
> + __skb_queue_tail(&tid->retry_q, skb);
> +
> + /* If there are other skbs in the retry q, they are
> + * probably within the BAW, so loop immediately to get
> + * one of them. Otherwise the queue can get stuck. */
> + if (!skb_queue_is_first(&tid->retry_q, skb))
> + continue;
Not sure if this can happen, but if we ever somehow end up with two skbs
in the retry queue that do not fit into the Block-Ack window, there's
potential for an infinite loop here.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 18:13 ` Felix Fietkau
0 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-06 18:13 UTC (permalink / raw)
To: ath9k-devel
On 2016-07-06 18:16, Toke H?iland-J?rgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
> ---
> Changes since v1:
> - Remove the old intermediate queueing logic completely instead of
> just disabling it.
> - Remove the qlen debug tunables.
> - Remove the force_channel parameter from struct txctl (since we just
> removed the code path that was using it).
>
> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
> drivers/net/wireless/ath/ath9k/channel.c | 2 -
> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
> drivers/net/wireless/ath/ath9k/debug.h | 2 -
> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
> drivers/net/wireless/ath/ath9k/init.c | 2 +-
> drivers/net/wireless/ath/ath9k/main.c | 1 +
> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
> 8 files changed, 130 insertions(+), 214 deletions(-)
Nice work!
> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
> index fe795fc..4077eeb 100644
> --- a/drivers/net/wireless/ath/ath9k/xmit.c
> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
> seqno = bf->bf_state.seqno;
>
> /* do not step over block-ack window */
> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
> + __skb_queue_tail(&tid->retry_q, skb);
> +
> + /* If there are other skbs in the retry q, they are
> + * probably within the BAW, so loop immediately to get
> + * one of them. Otherwise the queue can get stuck. */
> + if (!skb_queue_is_first(&tid->retry_q, skb))
> + continue;
Not sure if this can happen, but if we ever somehow end up with two skbs
in the retry queue that do not fit into the Block-Ack window, there's
potential for an infinite loop here.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 18:13 ` [ath9k-devel] " Felix Fietkau
@ 2016-07-06 18:52 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 18:52 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-06 18:16, Toke Høiland-Jørgensen wrote:
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>
>> Based on Tim's original patch set, but reworked quite thoroughly.
>>
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>> ---
>> Changes since v1:
>> - Remove the old intermediate queueing logic completely instead of
>> just disabling it.
>> - Remove the qlen debug tunables.
>> - Remove the force_channel parameter from struct txctl (since we just
>> removed the code path that was using it).
>>
>> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
>> drivers/net/wireless/ath/ath9k/channel.c | 2 -
>> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
>> drivers/net/wireless/ath/ath9k/debug.h | 2 -
>> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
>> drivers/net/wireless/ath/ath9k/init.c | 2 +-
>> drivers/net/wireless/ath/ath9k/main.c | 1 +
>> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
>> 8 files changed, 130 insertions(+), 214 deletions(-)
> Nice work!
Thanks :)
>> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
>> index fe795fc..4077eeb 100644
>> --- a/drivers/net/wireless/ath/ath9k/xmit.c
>> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
>> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>> seqno = bf->bf_state.seqno;
>>
>> /* do not step over block-ack window */
>> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
>> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
>> + __skb_queue_tail(&tid->retry_q, skb);
>> +
>> + /* If there are other skbs in the retry q, they are
>> + * probably within the BAW, so loop immediately to get
>> + * one of them. Otherwise the queue can get stuck. */
>> + if (!skb_queue_is_first(&tid->retry_q, skb))
>> + continue;
> Not sure if this can happen, but if we ever somehow end up with two skbs
> in the retry queue that do not fit into the Block-Ack window, there's
> potential for an infinite loop here.
Yes, I realise that (v1 contained a comment on that). However, I don't
actually think it can happen: The code will only ever put one skb from
the intermediate queues on the retry queue (ath_tid_pull() is only
called if the retry queue is empty). Everything else on there are actual
retries that have been put on there by ath_tx_complete_aggr(). Figure
the latter will always be within the BAW?
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 18:52 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 18:52 UTC (permalink / raw)
To: ath9k-devel
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-06 18:16, Toke H?iland-J?rgensen wrote:
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>
>> Based on Tim's original patch set, but reworked quite thoroughly.
>>
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>> ---
>> Changes since v1:
>> - Remove the old intermediate queueing logic completely instead of
>> just disabling it.
>> - Remove the qlen debug tunables.
>> - Remove the force_channel parameter from struct txctl (since we just
>> removed the code path that was using it).
>>
>> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
>> drivers/net/wireless/ath/ath9k/channel.c | 2 -
>> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
>> drivers/net/wireless/ath/ath9k/debug.h | 2 -
>> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
>> drivers/net/wireless/ath/ath9k/init.c | 2 +-
>> drivers/net/wireless/ath/ath9k/main.c | 1 +
>> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
>> 8 files changed, 130 insertions(+), 214 deletions(-)
> Nice work!
Thanks :)
>> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
>> index fe795fc..4077eeb 100644
>> --- a/drivers/net/wireless/ath/ath9k/xmit.c
>> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
>> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>> seqno = bf->bf_state.seqno;
>>
>> /* do not step over block-ack window */
>> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
>> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
>> + __skb_queue_tail(&tid->retry_q, skb);
>> +
>> + /* If there are other skbs in the retry q, they are
>> + * probably within the BAW, so loop immediately to get
>> + * one of them. Otherwise the queue can get stuck. */
>> + if (!skb_queue_is_first(&tid->retry_q, skb))
>> + continue;
> Not sure if this can happen, but if we ever somehow end up with two skbs
> in the retry queue that do not fit into the Block-Ack window, there's
> potential for an infinite loop here.
Yes, I realise that (v1 contained a comment on that). However, I don't
actually think it can happen: The code will only ever put one skb from
the intermediate queues on the retry queue (ath_tid_pull() is only
called if the retry queue is empty). Everything else on there are actual
retries that have been put on there by ath_tx_complete_aggr(). Figure
the latter will always be within the BAW?
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 18:52 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-06 18:59 ` Felix Fietkau
-1 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-06 18:59 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
On 2016-07-06 20:52, Toke Høiland-Jørgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
>
>> On 2016-07-06 18:16, Toke Høiland-Jørgensen wrote:
>>> This switches ath9k over to using the mac80211 intermediate software
>>> queueing mechanism for data packets. It removes the queueing inside the
>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>> a packet is needed. The retry queue is used to store a packet that was
>>> pulled but can't be sent immediately.
>>>
>>> The old code path in ath_tx_start that would queue packets has been
>>> removed completely, as has the qlen limit tunables (since there's no
>>> longer a queue in the driver to limit).
>>>
>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>
>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>> Cc: Felix Fietkau <nbd@nbd.name>
>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>> ---
>>> Changes since v1:
>>> - Remove the old intermediate queueing logic completely instead of
>>> just disabling it.
>>> - Remove the qlen debug tunables.
>>> - Remove the force_channel parameter from struct txctl (since we just
>>> removed the code path that was using it).
>>>
>>> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
>>> drivers/net/wireless/ath/ath9k/channel.c | 2 -
>>> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
>>> drivers/net/wireless/ath/ath9k/debug.h | 2 -
>>> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
>>> drivers/net/wireless/ath/ath9k/init.c | 2 +-
>>> drivers/net/wireless/ath/ath9k/main.c | 1 +
>>> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
>>> 8 files changed, 130 insertions(+), 214 deletions(-)
>> Nice work!
>
> Thanks :)
>
>>> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
>>> index fe795fc..4077eeb 100644
>>> --- a/drivers/net/wireless/ath/ath9k/xmit.c
>>> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
>>> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>>> seqno = bf->bf_state.seqno;
>>>
>>> /* do not step over block-ack window */
>>> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
>>> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
>>> + __skb_queue_tail(&tid->retry_q, skb);
>>> +
>>> + /* If there are other skbs in the retry q, they are
>>> + * probably within the BAW, so loop immediately to get
>>> + * one of them. Otherwise the queue can get stuck. */
>>> + if (!skb_queue_is_first(&tid->retry_q, skb))
>>> + continue;
>> Not sure if this can happen, but if we ever somehow end up with two skbs
>> in the retry queue that do not fit into the Block-Ack window, there's
>> potential for an infinite loop here.
>
> Yes, I realise that (v1 contained a comment on that). However, I don't
> actually think it can happen: The code will only ever put one skb from
> the intermediate queues on the retry queue (ath_tid_pull() is only
> called if the retry queue is empty). Everything else on there are actual
> retries that have been put on there by ath_tx_complete_aggr(). Figure
> the latter will always be within the BAW?
I think it would be a good idea to have a check there (with WARN_ON), in
case there's some weird corner case with seqno handling, software retry
and aggregation state changes.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 18:59 ` Felix Fietkau
0 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-06 18:59 UTC (permalink / raw)
To: ath9k-devel
On 2016-07-06 20:52, Toke H?iland-J?rgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
>
>> On 2016-07-06 18:16, Toke H?iland-J?rgensen wrote:
>>> This switches ath9k over to using the mac80211 intermediate software
>>> queueing mechanism for data packets. It removes the queueing inside the
>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>> a packet is needed. The retry queue is used to store a packet that was
>>> pulled but can't be sent immediately.
>>>
>>> The old code path in ath_tx_start that would queue packets has been
>>> removed completely, as has the qlen limit tunables (since there's no
>>> longer a queue in the driver to limit).
>>>
>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>
>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>> Cc: Felix Fietkau <nbd@nbd.name>
>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>> ---
>>> Changes since v1:
>>> - Remove the old intermediate queueing logic completely instead of
>>> just disabling it.
>>> - Remove the qlen debug tunables.
>>> - Remove the force_channel parameter from struct txctl (since we just
>>> removed the code path that was using it).
>>>
>>> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
>>> drivers/net/wireless/ath/ath9k/channel.c | 2 -
>>> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
>>> drivers/net/wireless/ath/ath9k/debug.h | 2 -
>>> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
>>> drivers/net/wireless/ath/ath9k/init.c | 2 +-
>>> drivers/net/wireless/ath/ath9k/main.c | 1 +
>>> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
>>> 8 files changed, 130 insertions(+), 214 deletions(-)
>> Nice work!
>
> Thanks :)
>
>>> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
>>> index fe795fc..4077eeb 100644
>>> --- a/drivers/net/wireless/ath/ath9k/xmit.c
>>> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
>>> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>>> seqno = bf->bf_state.seqno;
>>>
>>> /* do not step over block-ack window */
>>> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
>>> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
>>> + __skb_queue_tail(&tid->retry_q, skb);
>>> +
>>> + /* If there are other skbs in the retry q, they are
>>> + * probably within the BAW, so loop immediately to get
>>> + * one of them. Otherwise the queue can get stuck. */
>>> + if (!skb_queue_is_first(&tid->retry_q, skb))
>>> + continue;
>> Not sure if this can happen, but if we ever somehow end up with two skbs
>> in the retry queue that do not fit into the Block-Ack window, there's
>> potential for an infinite loop here.
>
> Yes, I realise that (v1 contained a comment on that). However, I don't
> actually think it can happen: The code will only ever put one skb from
> the intermediate queues on the retry queue (ath_tid_pull() is only
> called if the retry queue is empty). Everything else on there are actual
> retries that have been put on there by ath_tx_complete_aggr(). Figure
> the latter will always be within the BAW?
I think it would be a good idea to have a check there (with WARN_ON), in
case there's some weird corner case with seqno handling, software retry
and aggregation state changes.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 18:59 ` [ath9k-devel] " Felix Fietkau
@ 2016-07-06 19:08 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 19:08 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-06 20:52, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>
>>> On 2016-07-06 18:16, Toke Høiland-Jørgensen wrote:
>>>> This switches ath9k over to using the mac80211 intermediate software
>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>> a packet is needed. The retry queue is used to store a packet that was
>>>> pulled but can't be sent immediately.
>>>>
>>>> The old code path in ath_tx_start that would queue packets has been
>>>> removed completely, as has the qlen limit tunables (since there's no
>>>> longer a queue in the driver to limit).
>>>>
>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>
>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>>> ---
>>>> Changes since v1:
>>>> - Remove the old intermediate queueing logic completely instead of
>>>> just disabling it.
>>>> - Remove the qlen debug tunables.
>>>> - Remove the force_channel parameter from struct txctl (since we just
>>>> removed the code path that was using it).
>>>>
>>>> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
>>>> drivers/net/wireless/ath/ath9k/channel.c | 2 -
>>>> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
>>>> drivers/net/wireless/ath/ath9k/debug.h | 2 -
>>>> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
>>>> drivers/net/wireless/ath/ath9k/init.c | 2 +-
>>>> drivers/net/wireless/ath/ath9k/main.c | 1 +
>>>> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
>>>> 8 files changed, 130 insertions(+), 214 deletions(-)
>>> Nice work!
>>
>> Thanks :)
>>
>>>> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
>>>> index fe795fc..4077eeb 100644
>>>> --- a/drivers/net/wireless/ath/ath9k/xmit.c
>>>> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
>>>> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>>>> seqno = bf->bf_state.seqno;
>>>>
>>>> /* do not step over block-ack window */
>>>> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
>>>> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
>>>> + __skb_queue_tail(&tid->retry_q, skb);
>>>> +
>>>> + /* If there are other skbs in the retry q, they are
>>>> + * probably within the BAW, so loop immediately to get
>>>> + * one of them. Otherwise the queue can get stuck. */
>>>> + if (!skb_queue_is_first(&tid->retry_q, skb))
>>>> + continue;
>>> Not sure if this can happen, but if we ever somehow end up with two skbs
>>> in the retry queue that do not fit into the Block-Ack window, there's
>>> potential for an infinite loop here.
>>
>> Yes, I realise that (v1 contained a comment on that). However, I don't
>> actually think it can happen: The code will only ever put one skb from
>> the intermediate queues on the retry queue (ath_tid_pull() is only
>> called if the retry queue is empty). Everything else on there are actual
>> retries that have been put on there by ath_tx_complete_aggr(). Figure
>> the latter will always be within the BAW?
> I think it would be a good idea to have a check there (with WARN_ON), in
> case there's some weird corner case with seqno handling, software retry
> and aggregation state changes.
Right, can do :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v2] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 19:08 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 19:08 UTC (permalink / raw)
To: ath9k-devel
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-06 20:52, Toke H?iland-J?rgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>
>>> On 2016-07-06 18:16, Toke H?iland-J?rgensen wrote:
>>>> This switches ath9k over to using the mac80211 intermediate software
>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>> a packet is needed. The retry queue is used to store a packet that was
>>>> pulled but can't be sent immediately.
>>>>
>>>> The old code path in ath_tx_start that would queue packets has been
>>>> removed completely, as has the qlen limit tunables (since there's no
>>>> longer a queue in the driver to limit).
>>>>
>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>
>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>>> ---
>>>> Changes since v1:
>>>> - Remove the old intermediate queueing logic completely instead of
>>>> just disabling it.
>>>> - Remove the qlen debug tunables.
>>>> - Remove the force_channel parameter from struct txctl (since we just
>>>> removed the code path that was using it).
>>>>
>>>> drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
>>>> drivers/net/wireless/ath/ath9k/channel.c | 2 -
>>>> drivers/net/wireless/ath/ath9k/debug.c | 14 +-
>>>> drivers/net/wireless/ath/ath9k/debug.h | 2 -
>>>> drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
>>>> drivers/net/wireless/ath/ath9k/init.c | 2 +-
>>>> drivers/net/wireless/ath/ath9k/main.c | 1 +
>>>> drivers/net/wireless/ath/ath9k/xmit.c | 307 +++++++++++------------------
>>>> 8 files changed, 130 insertions(+), 214 deletions(-)
>>> Nice work!
>>
>> Thanks :)
>>
>>>> diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
>>>> index fe795fc..4077eeb 100644
>>>> --- a/drivers/net/wireless/ath/ath9k/xmit.c
>>>> +++ b/drivers/net/wireless/ath/ath9k/xmit.c
>>>> @@ -912,8 +923,16 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
>>>> seqno = bf->bf_state.seqno;
>>>>
>>>> /* do not step over block-ack window */
>>>> - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
>>>> + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
>>>> + __skb_queue_tail(&tid->retry_q, skb);
>>>> +
>>>> + /* If there are other skbs in the retry q, they are
>>>> + * probably within the BAW, so loop immediately to get
>>>> + * one of them. Otherwise the queue can get stuck. */
>>>> + if (!skb_queue_is_first(&tid->retry_q, skb))
>>>> + continue;
>>> Not sure if this can happen, but if we ever somehow end up with two skbs
>>> in the retry queue that do not fit into the Block-Ack window, there's
>>> potential for an infinite loop here.
>>
>> Yes, I realise that (v1 contained a comment on that). However, I don't
>> actually think it can happen: The code will only ever put one skb from
>> the intermediate queues on the retry queue (ath_tid_pull() is only
>> called if the retry queue is empty). Everything else on there are actual
>> retries that have been put on there by ath_tx_complete_aggr(). Figure
>> the latter will always be within the BAW?
> I think it would be a good idea to have a check there (with WARN_ON), in
> case there's some weird corner case with seqno handling, software retry
> and aggregation state changes.
Right, can do :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [PATCH v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 16:17 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-06 19:38 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 19:34 UTC (permalink / raw)
To: linux-wireless, make-wifi-fast, ath9k-devel
Cc: Toke Høiland-Jørgensen, Tim Shepard, Felix Fietkau
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
Changes since v2:
- Add safeguard against looping infinitely in
ath_tx_get_tid_subframe().
drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 1 +
drivers/net/wireless/ath/ath9k/xmit.c | 312 ++++++++++++-----------------
8 files changed, 134 insertions(+), 215 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5294595..daf972c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
@@ -145,7 +144,9 @@ 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 ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv)
+#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv)
+#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif))
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
@@ -164,7 +165,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +232,6 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +246,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
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;
@@ -276,7 +275,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
@@ -293,7 +291,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
@@ -585,6 +582,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 *queue);
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 319cb5f..a5ce016 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
goto error;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta = sta;
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6de64cf..48b181d 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
ath_txq_unlock(sc, txq);
}
@@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index c2ca57a..d789798 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ 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++) {
+ tid = ATH_STA_2_TID(an->sta, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1c226d6..752cacb 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
}
return 0;
}
@@ -867,6 +866,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 3aed43a..f584e19 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2673,4 +2673,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 fe795fc..c2a2dbe 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_txq *txq,
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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&tid->list, list);
}
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq = tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued = true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
int q = fi->txq;
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
}
static struct ath_atx_tid *
@@ -173,9 +186,47 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ath_softc *sc = tid->an->sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_control txctl = {
+ .txq = tid->txq,
+ .sta = tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv));
+ if (!skb) {
+ tid->has_queued = false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q = skb_get_queue_mapping(skb);
+ if (tid->txq == sc->tx.txq_map[q]) {
+ fi = get_frame_info(skb);
+ fi->txq = q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +235,11 @@ 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);
+ skb = ath_tid_pull(tid);
return skb;
}
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq = tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->txq;
@@ -858,20 +874,16 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb = NULL;
struct ath_buf *bf;
u16 seqno;
while (1) {
- *q = &tid->retry_q;
- if (skb_queue_empty(*q))
- *q = &tid->buf_q;
-
- skb = skb_peek(*q);
+ skb = ath_tid_dequeue(tid);
if (!skb)
break;
@@ -883,7 +895,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.stale = false;
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +923,19 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
seqno = bf->bf_state.seqno;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) && skb != first_skb) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb = skb;
+ continue;
+ }
break;
+ }
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts = {};
@@ -921,7 +943,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +954,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
return NULL;
}
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf = bf_first, *bf_prev = NULL;
@@ -947,12 +967,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed = false;
+
bf = bf_first;
aggr_limit = ath_lookup_rate(sc, bf, tid);
- do {
+ while (bf)
+ {
skb = bf->bf_mpdu;
fi = get_frame_info(skb);
@@ -961,12 +982,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >= h_baw)
- break;
+ goto stop;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
/* add padding for previous frame to aggregation length */
@@ -988,20 +1009,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
bf_prev = bf;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed = true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf = bf_first;
bf->bf_lastbf = bf_prev;
@@ -1012,9 +1031,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- *aggr_len = al;
-
- return closed;
+ return al;
#undef PADBYTES
}
@@ -1391,18 +1408,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf = bf_first, *bf_prev = NULL;
- struct sk_buff *skb;
int nframes = 0;
do {
struct ieee80211_tx_info *tx_info;
- skb = bf->bf_mpdu;
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
@@ -1411,13 +1425,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
if (nframes >= 2)
break;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1444,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len = 0;
- bool aggr, last = true;
+ bool aggr;
if (!ath_tid_has_buffered(tid))
return false;
INIT_LIST_HEAD(&bf_q);
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop = true;
return false;
}
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1513,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density;
}
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active = true;
*ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1;
@@ -1525,7 +1537,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
@@ -1535,14 +1546,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
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++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -1552,13 +1561,9 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
continue;
}
- buffered = ath_tid_has_buffered(tid);
-
list_del_init(&tid->list);
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
@@ -1571,19 +1576,12 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
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++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
tid->clear_ps_filter = true;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
ath_txq_unlock_complete(sc, txq);
}
}
@@ -1606,11 +1604,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
ath_txq_unlock_complete(sc, txq);
}
@@ -1626,7 +1619,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail = NULL, *bf;
- struct sk_buff_head *tid_q;
int sent = 0;
int i;
@@ -1641,11 +1633,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1651,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1878,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq = &sc->tx.txq[i];
- txq->stopped = false;
ath_draintxq(sc, txq);
}
@@ -2293,15 +2278,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false, ps_resp;
+ bool ps_resp;
int q, ret;
if (vif)
avp = (void *)vif->drv_priv;
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel = true;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2298,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
q = skb_get_queue_mapping(skb);
+ if (ps_resp)
+ txq = sc->tx.uapsdq;
+
ath_txq_lock(sc, txq);
if (txq == sc->tx.txq_map[q]) {
fi->txq = q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped = true;
- }
- }
-
- queue = ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue = true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx != sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
- skip_uapsd = true;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
- txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq != txctl->txq);
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter = true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
-
- ath_txq_schedule(sc, txq);
- goto out;
+ ++txq->pending_frames;
}
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2788,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ATH_AN_2_TID(an, tidno);
tid->an = an;
tid->tidno = tidno;
tid->seq_start = tid->seq_next = 0;
@@ -2866,11 +2797,14 @@ 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;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued = false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno = TID_TO_WME_AC(tidno);
tid->txq = sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
@@ -2880,9 +2814,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -2894,6 +2827,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->active = false;
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
--
2.9.0
^ permalink raw reply related [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-06 19:38 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-06 19:38 UTC (permalink / raw)
To: ath9k-devel
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
---
Changes since v2:
- Add safeguard against looping infinitely in
ath_tx_get_tid_subframe().
drivers/net/wireless/ath/ath9k/ath9k.h | 12 +-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 1 +
drivers/net/wireless/ath/ath9k/xmit.c | 312 ++++++++++++-----------------
8 files changed, 134 insertions(+), 215 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5294595..daf972c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
@@ -145,7 +144,9 @@ 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 ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv)
+#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv)
+#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif))
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
@@ -164,7 +165,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +232,6 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +246,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
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;
@@ -276,7 +275,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
@@ -293,7 +291,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
@@ -585,6 +582,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 *queue);
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 319cb5f..a5ce016 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
goto error;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta = sta;
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6de64cf..48b181d 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
ath_txq_unlock(sc, txq);
}
@@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index c2ca57a..d789798 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ 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++) {
+ tid = ATH_STA_2_TID(an->sta, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1c226d6..752cacb 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
}
return 0;
}
@@ -867,6 +866,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 3aed43a..f584e19 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2673,4 +2673,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 fe795fc..c2a2dbe 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_txq *txq,
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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&tid->list, list);
}
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq = tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued = true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
int q = fi->txq;
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
}
static struct ath_atx_tid *
@@ -173,9 +186,47 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ath_softc *sc = tid->an->sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_control txctl = {
+ .txq = tid->txq,
+ .sta = tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv));
+ if (!skb) {
+ tid->has_queued = false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q = skb_get_queue_mapping(skb);
+ if (tid->txq == sc->tx.txq_map[q]) {
+ fi = get_frame_info(skb);
+ fi->txq = q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +235,11 @@ 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);
+ skb = ath_tid_pull(tid);
return skb;
}
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq = tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->txq;
@@ -858,20 +874,16 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb = NULL;
struct ath_buf *bf;
u16 seqno;
while (1) {
- *q = &tid->retry_q;
- if (skb_queue_empty(*q))
- *q = &tid->buf_q;
-
- skb = skb_peek(*q);
+ skb = ath_tid_dequeue(tid);
if (!skb)
break;
@@ -883,7 +895,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.stale = false;
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +923,19 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
seqno = bf->bf_state.seqno;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) && skb != first_skb) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb = skb;
+ continue;
+ }
break;
+ }
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts = {};
@@ -921,7 +943,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +954,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
return NULL;
}
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf = bf_first, *bf_prev = NULL;
@@ -947,12 +967,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed = false;
+
bf = bf_first;
aggr_limit = ath_lookup_rate(sc, bf, tid);
- do {
+ while (bf)
+ {
skb = bf->bf_mpdu;
fi = get_frame_info(skb);
@@ -961,12 +982,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >= h_baw)
- break;
+ goto stop;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
/* add padding for previous frame to aggregation length */
@@ -988,20 +1009,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
bf_prev = bf;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed = true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf = bf_first;
bf->bf_lastbf = bf_prev;
@@ -1012,9 +1031,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- *aggr_len = al;
-
- return closed;
+ return al;
#undef PADBYTES
}
@@ -1391,18 +1408,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf = bf_first, *bf_prev = NULL;
- struct sk_buff *skb;
int nframes = 0;
do {
struct ieee80211_tx_info *tx_info;
- skb = bf->bf_mpdu;
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
@@ -1411,13 +1425,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
if (nframes >= 2)
break;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1444,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len = 0;
- bool aggr, last = true;
+ bool aggr;
if (!ath_tid_has_buffered(tid))
return false;
INIT_LIST_HEAD(&bf_q);
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop = true;
return false;
}
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1513,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density;
}
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active = true;
*ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1;
@@ -1525,7 +1537,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
@@ -1535,14 +1546,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
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++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -1552,13 +1561,9 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
continue;
}
- buffered = ath_tid_has_buffered(tid);
-
list_del_init(&tid->list);
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
@@ -1571,19 +1576,12 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
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++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
tid->clear_ps_filter = true;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
ath_txq_unlock_complete(sc, txq);
}
}
@@ -1606,11 +1604,6 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
ath_txq_unlock_complete(sc, txq);
}
@@ -1626,7 +1619,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail = NULL, *bf;
- struct sk_buff_head *tid_q;
int sent = 0;
int i;
@@ -1641,11 +1633,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1651,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1878,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq = &sc->tx.txq[i];
- txq->stopped = false;
ath_draintxq(sc, txq);
}
@@ -2293,15 +2278,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false, ps_resp;
+ bool ps_resp;
int q, ret;
if (vif)
avp = (void *)vif->drv_priv;
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel = true;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2298,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
q = skb_get_queue_mapping(skb);
+ if (ps_resp)
+ txq = sc->tx.uapsdq;
+
ath_txq_lock(sc, txq);
if (txq == sc->tx.txq_map[q]) {
fi->txq = q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped = true;
- }
- }
-
- queue = ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue = true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx != sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
- skip_uapsd = true;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
- txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq != txctl->txq);
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter = true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
-
- ath_txq_schedule(sc, txq);
- goto out;
+ ++txq->pending_frames;
}
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2788,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ATH_AN_2_TID(an, tidno);
tid->an = an;
tid->tidno = tidno;
tid->seq_start = tid->seq_next = 0;
@@ -2866,11 +2797,14 @@ 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;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued = false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno = TID_TO_WME_AC(tidno);
tid->txq = sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
@@ -2880,9 +2814,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ATH_AN_2_TID(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -2894,6 +2827,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->active = false;
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
--
2.9.0
^ permalink raw reply related [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 19:38 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-08 14:26 ` Kalle Valo
-1 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-07-08 14:26 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel,
Toke Høiland-Jørgensen, Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Nice work. Because this is such a significant change, and to maximise testing
time, I'm planning to queue this for 4.9 (so I would apply this to ath-next in
3-4 weeks after the merge window closes). But anyone who wants to test this can
use master-pending branch from my ath.git tree (uses wireless-testing as the
baseline). Sounds good?
Testing and review feedback very welcome!
--
Sent by pwcli
https://patchwork.kernel.org/patch/9216993/
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 14:26 ` Kalle Valo
0 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-07-08 14:26 UTC (permalink / raw)
To: ath9k-devel
Toke H?iland-J?rgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
Nice work. Because this is such a significant change, and to maximise testing
time, I'm planning to queue this for 4.9 (so I would apply this to ath-next in
3-4 weeks after the merge window closes). But anyone who wants to test this can
use master-pending branch from my ath.git tree (uses wireless-testing as the
baseline). Sounds good?
Testing and review feedback very welcome!
--
Sent by pwcli
https://patchwork.kernel.org/patch/9216993/
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 14:26 ` [ath9k-devel] " Kalle Valo
@ 2016-07-08 15:53 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-08 15:53 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@qca.qualcomm.com> writes:
> Toke Høiland-Jørgensen wrote:
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>
>> Based on Tim's original patch set, but reworked quite thoroughly.
>>
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>
> Nice work.
Thanks :)
> Because this is such a significant change, and to maximise testing
> time, I'm planning to queue this for 4.9 (so I would apply this to
> ath-next in 3-4 weeks after the merge window closes). But anyone who
> wants to test this can use master-pending branch from my ath.git tree
> (uses wireless-testing as the baseline). Sounds good?
Sounds good to me. I'm planning on backporting this and Michael's
mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
Hopefully that will get it some more testing as well.
> Testing and review feedback very welcome!
My own evaluation results are here:
https://blog.tohojo.dk/2016/06/fixing-the-wifi-performance-anomaly-on-ath9k.html
-- I see aggregate throughput to multiple stations improve by a factor
of ~3 and latency under load decrease by a factor of ~10 now that we can
take advantage of the mac80211 FQ-CoDel patches.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 15:53 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-08 15:53 UTC (permalink / raw)
To: ath9k-devel
Kalle Valo <kvalo@qca.qualcomm.com> writes:
> Toke H?iland-J?rgensen wrote:
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>
>> Based on Tim's original patch set, but reworked quite thoroughly.
>>
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>
> Nice work.
Thanks :)
> Because this is such a significant change, and to maximise testing
> time, I'm planning to queue this for 4.9 (so I would apply this to
> ath-next in 3-4 weeks after the merge window closes). But anyone who
> wants to test this can use master-pending branch from my ath.git tree
> (uses wireless-testing as the baseline). Sounds good?
Sounds good to me. I'm planning on backporting this and Michael's
mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
Hopefully that will get it some more testing as well.
> Testing and review feedback very welcome!
My own evaluation results are here:
https://blog.tohojo.dk/2016/06/fixing-the-wifi-performance-anomaly-on-ath9k.html
-- I see aggregate throughput to multiple stations improve by a factor
of ~3 and latency under load decrease by a factor of ~10 now that we can
take advantage of the mac80211 FQ-CoDel patches.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 15:53 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-08 16:10 ` Felix Fietkau
-1 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-08 16:10 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
On 2016-07-08 17:53, Toke Høiland-Jørgensen wrote:
> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>
>> Toke Høiland-Jørgensen wrote:
>>> This switches ath9k over to using the mac80211 intermediate software
>>> queueing mechanism for data packets. It removes the queueing inside the
>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>> a packet is needed. The retry queue is used to store a packet that was
>>> pulled but can't be sent immediately.
>>>
>>> The old code path in ath_tx_start that would queue packets has been
>>> removed completely, as has the qlen limit tunables (since there's no
>>> longer a queue in the driver to limit).
>>>
>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>
>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>> Cc: Felix Fietkau <nbd@nbd.name>
>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>
>> Nice work.
>
> Thanks :)
>
>> Because this is such a significant change, and to maximise testing
>> time, I'm planning to queue this for 4.9 (so I would apply this to
>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>> wants to test this can use master-pending branch from my ath.git tree
>> (uses wireless-testing as the baseline). Sounds good?
>
> Sounds good to me. I'm planning on backporting this and Michael's
> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
> Hopefully that will get it some more testing as well.
I've pushed a backport of this into my LEDE staging tree:
https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
I don't have time for testing it myself at the moment, but I'll try to
get some people to do so.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 16:10 ` Felix Fietkau
0 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-08 16:10 UTC (permalink / raw)
To: ath9k-devel
On 2016-07-08 17:53, Toke H?iland-J?rgensen wrote:
> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>
>> Toke H?iland-J?rgensen wrote:
>>> This switches ath9k over to using the mac80211 intermediate software
>>> queueing mechanism for data packets. It removes the queueing inside the
>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>> a packet is needed. The retry queue is used to store a packet that was
>>> pulled but can't be sent immediately.
>>>
>>> The old code path in ath_tx_start that would queue packets has been
>>> removed completely, as has the qlen limit tunables (since there's no
>>> longer a queue in the driver to limit).
>>>
>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>
>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>> Cc: Felix Fietkau <nbd@nbd.name>
>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>
>> Nice work.
>
> Thanks :)
>
>> Because this is such a significant change, and to maximise testing
>> time, I'm planning to queue this for 4.9 (so I would apply this to
>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>> wants to test this can use master-pending branch from my ath.git tree
>> (uses wireless-testing as the baseline). Sounds good?
>
> Sounds good to me. I'm planning on backporting this and Michael's
> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
> Hopefully that will get it some more testing as well.
I've pushed a backport of this into my LEDE staging tree:
https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
I don't have time for testing it myself at the moment, but I'll try to
get some people to do so.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 16:10 ` [ath9k-devel] " Felix Fietkau
@ 2016-07-08 16:28 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-08 16:28 UTC (permalink / raw)
To: Felix Fietkau
Cc: Kalle Valo, linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-08 17:53, Toke Høiland-Jørgensen wrote:
>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>
>>> Toke Høiland-Jørgensen wrote:
>>>> This switches ath9k over to using the mac80211 intermediate software
>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>> a packet is needed. The retry queue is used to store a packet that was
>>>> pulled but can't be sent immediately.
>>>>
>>>> The old code path in ath_tx_start that would queue packets has been
>>>> removed completely, as has the qlen limit tunables (since there's no
>>>> longer a queue in the driver to limit).
>>>>
>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>
>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>>
>>> Nice work.
>>
>> Thanks :)
>>
>>> Because this is such a significant change, and to maximise testing
>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>> wants to test this can use master-pending branch from my ath.git tree
>>> (uses wireless-testing as the baseline). Sounds good?
>>
>> Sounds good to me. I'm planning on backporting this and Michael's
>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>> Hopefully that will get it some more testing as well.
> I've pushed a backport of this into my LEDE staging tree:
> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
tree where I've separated out the needed patches and rebased them on
mainline 4.4.9. Can I post that somewhere (or just email you the series)
and get you to include those as well? Or do I just dump the patch files
into the LEDE patches dir and send that as a patch to LEDE? (I see your
patch also refreshed subsequent patches; is there a script to do that
automatically?)
> I don't have time for testing it myself at the moment, but I'll try to
> get some people to do so.
Awesome :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 16:28 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-08 16:28 UTC (permalink / raw)
To: ath9k-devel
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-08 17:53, Toke H?iland-J?rgensen wrote:
>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>
>>> Toke H?iland-J?rgensen wrote:
>>>> This switches ath9k over to using the mac80211 intermediate software
>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>> a packet is needed. The retry queue is used to store a packet that was
>>>> pulled but can't be sent immediately.
>>>>
>>>> The old code path in ath_tx_start that would queue packets has been
>>>> removed completely, as has the qlen limit tunables (since there's no
>>>> longer a queue in the driver to limit).
>>>>
>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>
>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>>
>>> Nice work.
>>
>> Thanks :)
>>
>>> Because this is such a significant change, and to maximise testing
>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>> wants to test this can use master-pending branch from my ath.git tree
>>> (uses wireless-testing as the baseline). Sounds good?
>>
>> Sounds good to me. I'm planning on backporting this and Michael's
>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>> Hopefully that will get it some more testing as well.
> I've pushed a backport of this into my LEDE staging tree:
> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
tree where I've separated out the needed patches and rebased them on
mainline 4.4.9. Can I post that somewhere (or just email you the series)
and get you to include those as well? Or do I just dump the patch files
into the LEDE patches dir and send that as a patch to LEDE? (I see your
patch also refreshed subsequent patches; is there a script to do that
automatically?)
> I don't have time for testing it myself at the moment, but I'll try to
> get some people to do so.
Awesome :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 16:28 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-08 16:31 ` Felix Fietkau
-1 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-08 16:31 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: Kalle Valo, linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
On 2016-07-08 18:28, Toke Høiland-Jørgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
>
>> On 2016-07-08 17:53, Toke Høiland-Jørgensen wrote:
>>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>>
>>>> Toke Høiland-Jørgensen wrote:
>>>>> This switches ath9k over to using the mac80211 intermediate software
>>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>>> a packet is needed. The retry queue is used to store a packet that was
>>>>> pulled but can't be sent immediately.
>>>>>
>>>>> The old code path in ath_tx_start that would queue packets has been
>>>>> removed completely, as has the qlen limit tunables (since there's no
>>>>> longer a queue in the driver to limit).
>>>>>
>>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>>
>>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>>>
>>>> Nice work.
>>>
>>> Thanks :)
>>>
>>>> Because this is such a significant change, and to maximise testing
>>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>>> wants to test this can use master-pending branch from my ath.git tree
>>>> (uses wireless-testing as the baseline). Sounds good?
>>>
>>> Sounds good to me. I'm planning on backporting this and Michael's
>>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>>> Hopefully that will get it some more testing as well.
>> I've pushed a backport of this into my LEDE staging tree:
>> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
>
> Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
> tree where I've separated out the needed patches and rebased them on
> mainline 4.4.9. Can I post that somewhere (or just email you the series)
> and get you to include those as well? Or do I just dump the patch files
> into the LEDE patches dir and send that as a patch to LEDE? (I see your
> patch also refreshed subsequent patches; is there a script to do that
> automatically?)
You don't need to do anything here. LEDE does not use mac80211 and
drivers from the kernel tree, it's built using backports.
It's currently using a backports snapshot that I built myself from
wireless-testing 2016-06-20, which already includes FQ-Codel.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 16:31 ` Felix Fietkau
0 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-07-08 16:31 UTC (permalink / raw)
To: ath9k-devel
On 2016-07-08 18:28, Toke H?iland-J?rgensen wrote:
> Felix Fietkau <nbd@nbd.name> writes:
>
>> On 2016-07-08 17:53, Toke H?iland-J?rgensen wrote:
>>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>>
>>>> Toke H?iland-J?rgensen wrote:
>>>>> This switches ath9k over to using the mac80211 intermediate software
>>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>>> a packet is needed. The retry queue is used to store a packet that was
>>>>> pulled but can't be sent immediately.
>>>>>
>>>>> The old code path in ath_tx_start that would queue packets has been
>>>>> removed completely, as has the qlen limit tunables (since there's no
>>>>> longer a queue in the driver to limit).
>>>>>
>>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>>
>>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>>>
>>>> Nice work.
>>>
>>> Thanks :)
>>>
>>>> Because this is such a significant change, and to maximise testing
>>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>>> wants to test this can use master-pending branch from my ath.git tree
>>>> (uses wireless-testing as the baseline). Sounds good?
>>>
>>> Sounds good to me. I'm planning on backporting this and Michael's
>>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>>> Hopefully that will get it some more testing as well.
>> I've pushed a backport of this into my LEDE staging tree:
>> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
>
> Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
> tree where I've separated out the needed patches and rebased them on
> mainline 4.4.9. Can I post that somewhere (or just email you the series)
> and get you to include those as well? Or do I just dump the patch files
> into the LEDE patches dir and send that as a patch to LEDE? (I see your
> patch also refreshed subsequent patches; is there a script to do that
> automatically?)
You don't need to do anything here. LEDE does not use mac80211 and
drivers from the kernel tree, it's built using backports.
It's currently using a backports snapshot that I built myself from
wireless-testing 2016-06-20, which already includes FQ-Codel.
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 16:31 ` [ath9k-devel] " Felix Fietkau
@ 2016-07-08 16:38 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-08 16:38 UTC (permalink / raw)
To: Felix Fietkau
Cc: Kalle Valo, linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-08 18:28, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>
>>> On 2016-07-08 17:53, Toke Høiland-Jørgensen wrote:
>>>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>>>
>>>>> Toke Høiland-Jørgensen wrote:
>>>>>> This switches ath9k over to using the mac80211 intermediate software
>>>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>>>> a packet is needed. The retry queue is used to store a packet that was
>>>>>> pulled but can't be sent immediately.
>>>>>>
>>>>>> The old code path in ath_tx_start that would queue packets has been
>>>>>> removed completely, as has the qlen limit tunables (since there's no
>>>>>> longer a queue in the driver to limit).
>>>>>>
>>>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>>>
>>>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>>>>
>>>>> Nice work.
>>>>
>>>> Thanks :)
>>>>
>>>>> Because this is such a significant change, and to maximise testing
>>>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>>>> wants to test this can use master-pending branch from my ath.git tree
>>>>> (uses wireless-testing as the baseline). Sounds good?
>>>>
>>>> Sounds good to me. I'm planning on backporting this and Michael's
>>>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>>>> Hopefully that will get it some more testing as well.
>>> I've pushed a backport of this into my LEDE staging tree:
>>> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
>>
>> Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
>> tree where I've separated out the needed patches and rebased them on
>> mainline 4.4.9. Can I post that somewhere (or just email you the series)
>> and get you to include those as well? Or do I just dump the patch files
>> into the LEDE patches dir and send that as a patch to LEDE? (I see your
>> patch also refreshed subsequent patches; is there a script to do that
>> automatically?)
> You don't need to do anything here. LEDE does not use mac80211 and
> drivers from the kernel tree, it's built using backports.
> It's currently using a backports snapshot that I built myself from
> wireless-testing 2016-06-20, which already includes FQ-Codel.
Ah, didn't know that. Cool; and thanks for taking care of the
backporting :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 16:38 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-08 16:38 UTC (permalink / raw)
To: ath9k-devel
Felix Fietkau <nbd@nbd.name> writes:
> On 2016-07-08 18:28, Toke H?iland-J?rgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>
>>> On 2016-07-08 17:53, Toke H?iland-J?rgensen wrote:
>>>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>>>
>>>>> Toke H?iland-J?rgensen wrote:
>>>>>> This switches ath9k over to using the mac80211 intermediate software
>>>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>>>> a packet is needed. The retry queue is used to store a packet that was
>>>>>> pulled but can't be sent immediately.
>>>>>>
>>>>>> The old code path in ath_tx_start that would queue packets has been
>>>>>> removed completely, as has the qlen limit tunables (since there's no
>>>>>> longer a queue in the driver to limit).
>>>>>>
>>>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>>>
>>>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>>>>
>>>>> Nice work.
>>>>
>>>> Thanks :)
>>>>
>>>>> Because this is such a significant change, and to maximise testing
>>>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>>>> wants to test this can use master-pending branch from my ath.git tree
>>>>> (uses wireless-testing as the baseline). Sounds good?
>>>>
>>>> Sounds good to me. I'm planning on backporting this and Michael's
>>>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>>>> Hopefully that will get it some more testing as well.
>>> I've pushed a backport of this into my LEDE staging tree:
>>> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
>>
>> Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
>> tree where I've separated out the needed patches and rebased them on
>> mainline 4.4.9. Can I post that somewhere (or just email you the series)
>> and get you to include those as well? Or do I just dump the patch files
>> into the LEDE patches dir and send that as a patch to LEDE? (I see your
>> patch also refreshed subsequent patches; is there a script to do that
>> automatically?)
> You don't need to do anything here. LEDE does not use mac80211 and
> drivers from the kernel tree, it's built using backports.
> It's currently using a backports snapshot that I built myself from
> wireless-testing 2016-06-20, which already includes FQ-Codel.
Ah, didn't know that. Cool; and thanks for taking care of the
backporting :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 16:31 ` [ath9k-devel] " Felix Fietkau
@ 2016-07-08 18:24 ` Sebastian Gottschall
-1 siblings, 0 replies; 118+ messages in thread
From: Sebastian Gottschall @ 2016-07-08 18:24 UTC (permalink / raw)
To: Felix Fietkau, Toke Høiland-Jørgensen
Cc: Kalle Valo, linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard
for me it crashes on wds sta on 3.18 kernels. need to solder a serial to
get more logs
Am 08.07.2016 um 18:31 schrieb Felix Fietkau:
> On 2016-07-08 18:28, Toke Høiland-Jørgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>
>>> On 2016-07-08 17:53, Toke Høiland-Jørgensen wrote:
>>>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>>>
>>>>> Toke Høiland-Jørgensen wrote:
>>>>>> This switches ath9k over to using the mac80211 intermediate software
>>>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>>>> a packet is needed. The retry queue is used to store a packet that was
>>>>>> pulled but can't be sent immediately.
>>>>>>
>>>>>> The old code path in ath_tx_start that would queue packets has been
>>>>>> removed completely, as has the qlen limit tunables (since there's no
>>>>>> longer a queue in the driver to limit).
>>>>>>
>>>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>>>
>>>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>>>> Nice work.
>>>> Thanks :)
>>>>
>>>>> Because this is such a significant change, and to maximise testing
>>>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>>>> wants to test this can use master-pending branch from my ath.git tree
>>>>> (uses wireless-testing as the baseline). Sounds good?
>>>> Sounds good to me. I'm planning on backporting this and Michael's
>>>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>>>> Hopefully that will get it some more testing as well.
>>> I've pushed a backport of this into my LEDE staging tree:
>>> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
>> Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
>> tree where I've separated out the needed patches and rebased them on
>> mainline 4.4.9. Can I post that somewhere (or just email you the series)
>> and get you to include those as well? Or do I just dump the patch files
>> into the LEDE patches dir and send that as a patch to LEDE? (I see your
>> patch also refreshed subsequent patches; is there a script to do that
>> automatically?)
> You don't need to do anything here. LEDE does not use mac80211 and
> drivers from the kernel tree, it's built using backports.
> It's currently using a backports snapshot that I built myself from
> wireless-testing 2016-06-20, which already includes FQ-Codel.
>
> - Felix
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Mit freundlichen Grüssen / Regards
Sebastian Gottschall / CTO
NewMedia-NET GmbH - DD-WRT
Firmensitz: Berliner Ring 101, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Geschäftsführer: Peter Steinhäuser, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall@dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 18:24 ` Sebastian Gottschall
0 siblings, 0 replies; 118+ messages in thread
From: Sebastian Gottschall @ 2016-07-08 18:24 UTC (permalink / raw)
To: ath9k-devel
for me it crashes on wds sta on 3.18 kernels. need to solder a serial to
get more logs
Am 08.07.2016 um 18:31 schrieb Felix Fietkau:
> On 2016-07-08 18:28, Toke H?iland-J?rgensen wrote:
>> Felix Fietkau <nbd@nbd.name> writes:
>>
>>> On 2016-07-08 17:53, Toke H?iland-J?rgensen wrote:
>>>> Kalle Valo <kvalo@qca.qualcomm.com> writes:
>>>>
>>>>> Toke H?iland-J?rgensen wrote:
>>>>>> This switches ath9k over to using the mac80211 intermediate software
>>>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>>>> a packet is needed. The retry queue is used to store a packet that was
>>>>>> pulled but can't be sent immediately.
>>>>>>
>>>>>> The old code path in ath_tx_start that would queue packets has been
>>>>>> removed completely, as has the qlen limit tunables (since there's no
>>>>>> longer a queue in the driver to limit).
>>>>>>
>>>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>>>
>>>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>>>> Nice work.
>>>> Thanks :)
>>>>
>>>>> Because this is such a significant change, and to maximise testing
>>>>> time, I'm planning to queue this for 4.9 (so I would apply this to
>>>>> ath-next in 3-4 weeks after the merge window closes). But anyone who
>>>>> wants to test this can use master-pending branch from my ath.git tree
>>>>> (uses wireless-testing as the baseline). Sounds good?
>>>> Sounds good to me. I'm planning on backporting this and Michael's
>>>> mac80211 FQ-CoDel patches to 4.4 and post them for inclusion in LEDE.
>>>> Hopefully that will get it some more testing as well.
>>> I've pushed a backport of this into my LEDE staging tree:
>>> https://git.lede-project.org/?p=lede/nbd/staging.git;a=summary
>> Awesome! What about the FQ-CoDel mac80211 patches themselves? I have a
>> tree where I've separated out the needed patches and rebased them on
>> mainline 4.4.9. Can I post that somewhere (or just email you the series)
>> and get you to include those as well? Or do I just dump the patch files
>> into the LEDE patches dir and send that as a patch to LEDE? (I see your
>> patch also refreshed subsequent patches; is there a script to do that
>> automatically?)
> You don't need to do anything here. LEDE does not use mac80211 and
> drivers from the kernel tree, it's built using backports.
> It's currently using a backports snapshot that I built myself from
> wireless-testing 2016-06-20, which already includes FQ-Codel.
>
> - Felix
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Mit freundlichen Gr?ssen / Regards
Sebastian Gottschall / CTO
NewMedia-NET GmbH - DD-WRT
Firmensitz: Berliner Ring 101, 64625 Bensheim
Registergericht: Amtsgericht Darmstadt, HRB 25473
Gesch?ftsf?hrer: Peter Steinh?user, Christian Scheele
http://www.dd-wrt.com
email: s.gottschall at dd-wrt.com
Tel.: +496251-582650 / Fax: +496251-5826565
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 18:24 ` [ath9k-devel] " Sebastian Gottschall
@ 2016-07-09 12:00 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-09 12:00 UTC (permalink / raw)
To: Sebastian Gottschall
Cc: Felix Fietkau, Kalle Valo, linux-wireless, make-wifi-fast,
ath9k-devel, Tim Shepard
Sebastian Gottschall <s.gottschall@dd-wrt.com> writes:
> for me it crashes on wds sta on 3.18 kernels.
Bugger :/
> need to solder a serial to get more logs
That would be helpful :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 19:38 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-07-08 16:38 ` Tim Shepard
-1 siblings, 0 replies; 118+ messages in thread
From: Tim Shepard @ 2016-07-08 16:38 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Felix Fietkau
> The old code path in ath_tx_start that would queue packets has been
> removed completely,
It seems to me that this breaks the ath9k driver when non-data packets
which mac80211 will not queue on the new intermediate queues, see
ieee80211_drv_tx( ) in mac80211/tx.c where it says
if (!ieee80211_is_data(hdr->frame_control))
goto tx_normal;
This means that non-data packets can come down from mac80211 via
ath_tx --> ath_tx_start which might be for a vif that is not on the
same channel, and so cannot be sent straight away but must be queued.
Maybe this problem should be fixed in mac80211, but as of now this is
a problem. It appears to me that your new patch just sends them on
the wrong channel.
Maybe I'm confused about something, hints appreciated.
> as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 5294595..daf972c 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
> #define ATH_RXBUF 512
> #define ATH_TXBUF 512
> #define ATH_TXBUF_RESERVE 5
> -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
> #define ATH_TXMAXTRY 13
> #define ATH_MAX_SW_RETRIES 30
I thought the purpose of ATH_MAX_QDEPTH was due to a limit on the
depth of a hardware FIFO. Not all packets that get handed to the
hardware come through a software queue (e.g. those that bypass the
intermediate queueing in mac80211 now) and (it seems to me) there
needs to be a limit to prevent overflowing a hardware fifo. Yes,
normal data packets are (much) further limited as you taught me a few
weeks ago, but not all packets are subject to that constraint (as far
as I can understand at the moment). I'm not entirely sure of the
details, but I think it is the sorts of packets sent directly by
hostapd and wpa_supplicant that bypass all the queueing. And maybe
those things aren't likely to be sending a burst of hundreds of
packets in a very short period of time (where it could overrun the
FIFO), but there may be other tools that send raw 802.11 non-data
packets which could then overflow the above limit, and it seems you
are removing the check. Actually I think my original version of
this patch may have had a flaw in that some combination of non-data
and data packets could be combined to overflow this limit (since I
failed to check overflowing this limit where I pulled from the
mac80211 intermediate queue).
My hope is that I'm just confused and you all understand what's really
going on better than I do and have an explanation why all the above
doesn't matter and is handled in some other way. But in case you
don't, I don't want these issues to be overlooked.
(I'm not testing using vifs on multiple channels. But even if I was,
I'm not sure if normal operation of wpa_supplicant or hostapd would
be enough to trigger these problems.)
-Tim Shepard
shep@alum.mit.edu
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-08 16:38 ` Tim Shepard
0 siblings, 0 replies; 118+ messages in thread
From: Tim Shepard @ 2016-07-08 16:38 UTC (permalink / raw)
To: ath9k-devel
> The old code path in ath_tx_start that would queue packets has been
> removed completely,
It seems to me that this breaks the ath9k driver when non-data packets
which mac80211 will not queue on the new intermediate queues, see
ieee80211_drv_tx( ) in mac80211/tx.c where it says
if (!ieee80211_is_data(hdr->frame_control))
goto tx_normal;
This means that non-data packets can come down from mac80211 via
ath_tx --> ath_tx_start which might be for a vif that is not on the
same channel, and so cannot be sent straight away but must be queued.
Maybe this problem should be fixed in mac80211, but as of now this is
a problem. It appears to me that your new patch just sends them on
the wrong channel.
Maybe I'm confused about something, hints appreciated.
> as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 5294595..daf972c 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
> #define ATH_RXBUF 512
> #define ATH_TXBUF 512
> #define ATH_TXBUF_RESERVE 5
> -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
> #define ATH_TXMAXTRY 13
> #define ATH_MAX_SW_RETRIES 30
I thought the purpose of ATH_MAX_QDEPTH was due to a limit on the
depth of a hardware FIFO. Not all packets that get handed to the
hardware come through a software queue (e.g. those that bypass the
intermediate queueing in mac80211 now) and (it seems to me) there
needs to be a limit to prevent overflowing a hardware fifo. Yes,
normal data packets are (much) further limited as you taught me a few
weeks ago, but not all packets are subject to that constraint (as far
as I can understand at the moment). I'm not entirely sure of the
details, but I think it is the sorts of packets sent directly by
hostapd and wpa_supplicant that bypass all the queueing. And maybe
those things aren't likely to be sending a burst of hundreds of
packets in a very short period of time (where it could overrun the
FIFO), but there may be other tools that send raw 802.11 non-data
packets which could then overflow the above limit, and it seems you
are removing the check. Actually I think my original version of
this patch may have had a flaw in that some combination of non-data
and data packets could be combined to overflow this limit (since I
failed to check overflowing this limit where I pulled from the
mac80211 intermediate queue).
My hope is that I'm just confused and you all understand what's really
going on better than I do and have an explanation why all the above
doesn't matter and is handled in some other way. But in case you
don't, I don't want these issues to be overlooked.
(I'm not testing using vifs on multiple channels. But even if I was,
I'm not sure if normal operation of wpa_supplicant or hostapd would
be enough to trigger these problems.)
-Tim Shepard
shep at alum.mit.edu
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v3] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-08 16:38 ` [ath9k-devel] " Tim Shepard
@ 2016-07-09 15:45 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-09 15:44 UTC (permalink / raw)
To: Tim Shepard; +Cc: linux-wireless, make-wifi-fast, ath9k-devel, Felix Fietkau
Tim Shepard <shep@alum.mit.edu> writes:
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely,
>
> It seems to me that this breaks the ath9k driver when non-data packets
> which mac80211 will not queue on the new intermediate queues, see
> ieee80211_drv_tx( ) in mac80211/tx.c where it says
>
> if (!ieee80211_is_data(hdr->frame_control))
> goto tx_normal;
>
> This means that non-data packets can come down from mac80211 via
> ath_tx --> ath_tx_start which might be for a vif that is not on the
> same channel, and so cannot be sent straight away but must be queued.
> Maybe this problem should be fixed in mac80211, but as of now this is
> a problem. It appears to me that your new patch just sends them on
> the wrong channel.
Well, the idea is that the chanctx code will call ieee80211_stop_queue()
to make sure that packets for the wrong context are not pushed down to
the driver.
>> as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>
>> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
>> index 5294595..daf972c 100644
>> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
>> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
>> @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
>> #define ATH_RXBUF 512
>> #define ATH_TXBUF 512
>> #define ATH_TXBUF_RESERVE 5
>> -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
>> #define ATH_TXMAXTRY 13
>> #define ATH_MAX_SW_RETRIES 30
>
> I thought the purpose of ATH_MAX_QDEPTH was due to a limit on the
> depth of a hardware FIFO.
It's not. The limit is way too high for that. I'm a little fuzzy on the
details, but the hardware queue depth is somewhat lower:
#define ATH_TXFIFO_DEPTH 8
The ATH_MAX_QDEPTH was supposed to keep the number of packets queued in
the driver under control. And since we're no longer queueing in the
driver, there's no longer a need for it.
> Not all packets that get handed to the hardware come through a
> software queue (e.g. those that bypass the intermediate queueing in
> mac80211 now) and (it seems to me) there needs to be a limit to
> prevent overflowing a hardware fifo. Yes, normal data packets are
> (much) further limited as you taught me a few weeks ago, but not all
> packets are subject to that constraint (as far as I can understand at
> the moment). I'm not entirely sure of the details, but I think it is
> the sorts of packets sent directly by hostapd and wpa_supplicant that
> bypass all the queueing. And maybe those things aren't likely to be
> sending a burst of hundreds of packets in a very short period of time
> (where it could overrun the FIFO), but there may be other tools that
> send raw 802.11 non-data packets which could then overflow the above
> limit, and it seems you are removing the check. Actually I think my
> original version of this patch may have had a flaw in that some
> combination of non-data and data packets could be combined to overflow
> this limit (since I failed to check overflowing this limit where I
> pulled from the mac80211 intermediate queue).
Hmm, I'm not sure I can confidently say that what you describe would
never happen. But I'm pretty sure that ATH_MAX_QDEPTH wasn't what was
keeping it from happening...
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v3] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-07-09 15:45 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-07-09 15:45 UTC (permalink / raw)
To: ath9k-devel
Tim Shepard <shep@alum.mit.edu> writes:
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely,
>
> It seems to me that this breaks the ath9k driver when non-data packets
> which mac80211 will not queue on the new intermediate queues, see
> ieee80211_drv_tx( ) in mac80211/tx.c where it says
>
> if (!ieee80211_is_data(hdr->frame_control))
> goto tx_normal;
>
> This means that non-data packets can come down from mac80211 via
> ath_tx --> ath_tx_start which might be for a vif that is not on the
> same channel, and so cannot be sent straight away but must be queued.
> Maybe this problem should be fixed in mac80211, but as of now this is
> a problem. It appears to me that your new patch just sends them on
> the wrong channel.
Well, the idea is that the chanctx code will call ieee80211_stop_queue()
to make sure that packets for the wrong context are not pushed down to
the driver.
>> as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>
>> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
>> index 5294595..daf972c 100644
>> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
>> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
>> @@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
>> #define ATH_RXBUF 512
>> #define ATH_TXBUF 512
>> #define ATH_TXBUF_RESERVE 5
>> -#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
>> #define ATH_TXMAXTRY 13
>> #define ATH_MAX_SW_RETRIES 30
>
> I thought the purpose of ATH_MAX_QDEPTH was due to a limit on the
> depth of a hardware FIFO.
It's not. The limit is way too high for that. I'm a little fuzzy on the
details, but the hardware queue depth is somewhat lower:
#define ATH_TXFIFO_DEPTH 8
The ATH_MAX_QDEPTH was supposed to keep the number of packets queued in
the driver under control. And since we're no longer queueing in the
driver, there's no longer a need for it.
> Not all packets that get handed to the hardware come through a
> software queue (e.g. those that bypass the intermediate queueing in
> mac80211 now) and (it seems to me) there needs to be a limit to
> prevent overflowing a hardware fifo. Yes, normal data packets are
> (much) further limited as you taught me a few weeks ago, but not all
> packets are subject to that constraint (as far as I can understand at
> the moment). I'm not entirely sure of the details, but I think it is
> the sorts of packets sent directly by hostapd and wpa_supplicant that
> bypass all the queueing. And maybe those things aren't likely to be
> sending a burst of hundreds of packets in a very short period of time
> (where it could overrun the FIFO), but there may be other tools that
> send raw 802.11 non-data packets which could then overflow the above
> limit, and it seems you are removing the check. Actually I think my
> original version of this patch may have had a flaw in that some
> combination of non-data and data packets could be combined to overflow
> this limit (since I failed to check overflowing this limit where I
> pulled from the mac80211 intermediate queue).
Hmm, I'm not sure I can confidently say that what you describe would
never happen. But I'm pretty sure that ATH_MAX_QDEPTH wasn't what was
keeping it from happening...
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-07-06 19:38 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-08-05 16:05 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-08-05 16:03 UTC (permalink / raw)
To: linux-wireless, make-wifi-fast, ath9k-devel
Cc: Toke Høiland-Jørgensen, Tim Shepard, Felix Fietkau
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
Changes since v3 (most due to Felix; thanks!):
- Correctly notify mac80211 when there are packets in the retry queue
on powersave start/stop.
- Get rid of ath_tx_aggr_resume().
- Some readability changes and additional WARN_ON/BUG_ON in
appropriate places.
drivers/net/wireless/ath/ath9k/ath9k.h | 27 ++-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 9 +-
drivers/net/wireless/ath/ath9k/xmit.c | 332 +++++++++++------------------
8 files changed, 157 insertions(+), 235 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5294595..7e0a976 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
@@ -145,7 +144,7 @@ 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 ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno)
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
@@ -164,7 +163,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +230,6 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +244,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
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;
@@ -276,7 +273,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
@@ -293,7 +289,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
@@ -421,6 +416,22 @@ struct ath_offchannel {
int duration;
};
+static inline struct ath_atx_tid *
+ath_node_to_tid(struct ath_node *an, u8 tidno)
+{
+ struct ieee80211_sta *sta = an->sta;
+ struct ieee80211_vif *vif = an->vif;
+ struct ieee80211_txq *txq;
+
+ BUG_ON(!vif);
+ if (sta)
+ txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)];
+ else
+ txq = vif->txq;
+
+ return (struct ath_atx_tid *) txq->drv_priv;
+}
+
#define case_rtn_string(val) case val: return #val
#define ath_for_each_chanctx(_sc, _ctx) \
@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@@ -585,6 +595,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 *queue);
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 319cb5f..a5ce016 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
goto error;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta = sta;
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6de64cf..48b181d 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
ath_txq_unlock(sc, txq);
}
@@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index c2ca57a..2e8371a 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ 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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1c226d6..752cacb 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
}
return 0;
}
@@ -867,6 +866,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 3aed43a..eb48f91 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1874,9 +1874,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
bool flush = false;
int ret = 0;
struct ieee80211_sta *sta = params->sta;
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
enum ieee80211_ampdu_mlme_action action = params->action;
u16 tid = params->tid;
u16 *ssn = ¶ms->ssn;
+ struct ath_atx_tid *atid;
mutex_lock(&sc->mutex);
@@ -1909,9 +1911,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- ath9k_ps_wakeup(sc);
- ath_tx_aggr_resume(sc, sta, tid);
- ath9k_ps_restore(sc);
+ atid = ath_node_to_tid(an, tid);
+ atid->baw_size = IEEE80211_MIN_AMPDU_BUF <<
+ sta->ht_cap.ampdu_factor;
break;
default:
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
@@ -2673,4 +2675,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 fe795fc..8103954 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_txq *txq,
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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&tid->list, list);
}
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq = tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued = true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
int q = fi->txq;
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
}
static struct ath_atx_tid *
@@ -173,9 +186,48 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv);
+ struct ath_softc *sc = tid->an->sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_control txctl = {
+ .txq = tid->txq,
+ .sta = tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb = ieee80211_tx_dequeue(hw, txq);
+ if (!skb) {
+ tid->has_queued = false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q = skb_get_queue_mapping(skb);
+ if (tid->txq == sc->tx.txq_map[q]) {
+ fi = get_frame_info(skb);
+ fi->txq = q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +236,11 @@ 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);
+ skb = ath_tid_pull(tid);
return skb;
}
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq = tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->txq;
@@ -858,20 +875,16 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb = NULL;
struct ath_buf *bf;
u16 seqno;
while (1) {
- *q = &tid->retry_q;
- if (skb_queue_empty(*q))
- *q = &tid->buf_q;
-
- skb = skb_peek(*q);
+ skb = ath_tid_dequeue(tid);
if (!skb)
break;
@@ -883,7 +896,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.stale = false;
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +924,20 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
seqno = bf->bf_state.seqno;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) &&
+ !WARN_ON(skb == first_skb)) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb = skb;
+ continue;
+ }
break;
+ }
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts = {};
@@ -921,7 +945,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +956,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
return NULL;
}
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf = bf_first, *bf_prev = NULL;
@@ -947,12 +969,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed = false;
+
bf = bf_first;
aggr_limit = ath_lookup_rate(sc, bf, tid);
- do {
+ while (bf)
+ {
skb = bf->bf_mpdu;
fi = get_frame_info(skb);
@@ -961,12 +984,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >= h_baw)
- break;
+ goto stop;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
/* add padding for previous frame to aggregation length */
@@ -988,20 +1011,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
bf_prev = bf;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed = true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf = bf_first;
bf->bf_lastbf = bf_prev;
@@ -1012,9 +1033,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- *aggr_len = al;
-
- return closed;
+ return al;
#undef PADBYTES
}
@@ -1391,18 +1410,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf = bf_first, *bf_prev = NULL;
- struct sk_buff *skb;
int nframes = 0;
do {
struct ieee80211_tx_info *tx_info;
- skb = bf->bf_mpdu;
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
@@ -1411,13 +1427,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
if (nframes >= 2)
break;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1446,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len = 0;
- bool aggr, last = true;
+ bool aggr;
if (!ath_tid_has_buffered(tid))
return false;
INIT_LIST_HEAD(&bf_q);
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop = true;
return false;
}
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1515,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density;
}
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active = true;
*ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1;
@@ -1525,7 +1539,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
@@ -1535,14 +1548,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -1552,13 +1563,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
continue;
}
- buffered = ath_tid_has_buffered(tid);
+ if (!skb_queue_empty(&tid->retry_q))
+ ieee80211_sta_set_buffered(sta, tid->tidno, true);
list_del_init(&tid->list);
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
@@ -1571,49 +1581,20 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
tid->clear_ps_filter = true;
-
if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq);
}
-
ath_txq_unlock_complete(sc, txq);
}
}
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tidno)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_atx_tid *tid;
- struct ath_node *an;
- struct ath_txq *txq;
-
- ath_dbg(common, XMIT, "%s called\n", __func__);
-
- an = (struct ath_node *)sta->drv_priv;
- tid = ATH_AN_2_TID(an, tidno);
- txq = tid->txq;
-
- ath_txq_lock(sc, txq);
-
- tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
- ath_txq_unlock_complete(sc, txq);
-}
-
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@@ -1626,7 +1607,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail = NULL, *bf;
- struct sk_buff_head *tid_q;
int sent = 0;
int i;
@@ -1641,11 +1621,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1639,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1866,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq = &sc->tx.txq[i];
- txq->stopped = false;
ath_draintxq(sc, txq);
}
@@ -2293,15 +2266,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false, ps_resp;
+ bool ps_resp;
int q, ret;
if (vif)
avp = (void *)vif->drv_priv;
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel = true;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2286,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
q = skb_get_queue_mapping(skb);
+ if (ps_resp)
+ txq = sc->tx.uapsdq;
+
ath_txq_lock(sc, txq);
if (txq == sc->tx.txq_map[q]) {
fi->txq = q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped = true;
- }
- }
-
- queue = ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue = true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx != sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
- skip_uapsd = true;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
- txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq != txctl->txq);
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter = true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
-
- ath_txq_schedule(sc, txq);
- goto out;
+ ++txq->pending_frames;
}
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2776,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ath_node_to_tid(an, tidno);
tid->an = an;
tid->tidno = tidno;
tid->seq_start = tid->seq_next = 0;
@@ -2866,11 +2785,14 @@ 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;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued = false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno = TID_TO_WME_AC(tidno);
tid->txq = sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
@@ -2880,9 +2802,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -2894,6 +2815,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->active = false;
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
--
2.9.2
^ permalink raw reply related [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-05 16:05 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-08-05 16:05 UTC (permalink / raw)
To: ath9k-devel
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
---
Changes since v3 (most due to Felix; thanks!):
- Correctly notify mac80211 when there are packets in the retry queue
on powersave start/stop.
- Get rid of ath_tx_aggr_resume().
- Some readability changes and additional WARN_ON/BUG_ON in
appropriate places.
drivers/net/wireless/ath/ath9k/ath9k.h | 27 ++-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 9 +-
drivers/net/wireless/ath/ath9k/xmit.c | 332 +++++++++++------------------
8 files changed, 157 insertions(+), 235 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5294595..7e0a976 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
@@ -145,7 +144,7 @@ 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 ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno)
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
@@ -164,7 +163,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +230,6 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +244,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
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;
@@ -276,7 +273,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
@@ -293,7 +289,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
@@ -421,6 +416,22 @@ struct ath_offchannel {
int duration;
};
+static inline struct ath_atx_tid *
+ath_node_to_tid(struct ath_node *an, u8 tidno)
+{
+ struct ieee80211_sta *sta = an->sta;
+ struct ieee80211_vif *vif = an->vif;
+ struct ieee80211_txq *txq;
+
+ BUG_ON(!vif);
+ if (sta)
+ txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)];
+ else
+ txq = vif->txq;
+
+ return (struct ath_atx_tid *) txq->drv_priv;
+}
+
#define case_rtn_string(val) case val: return #val
#define ath_for_each_chanctx(_sc, _ctx) \
@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@@ -585,6 +595,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 *queue);
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 319cb5f..a5ce016 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
goto error;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta = sta;
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6de64cf..48b181d 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
ath_txq_unlock(sc, txq);
}
@@ -1190,7 +1188,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1270,7 +1267,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1328,14 +1324,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index c2ca57a..2e8371a 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ 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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 1c226d6..752cacb 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -354,7 +354,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
}
return 0;
}
@@ -867,6 +866,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 3aed43a..eb48f91 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1874,9 +1874,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
bool flush = false;
int ret = 0;
struct ieee80211_sta *sta = params->sta;
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
enum ieee80211_ampdu_mlme_action action = params->action;
u16 tid = params->tid;
u16 *ssn = ¶ms->ssn;
+ struct ath_atx_tid *atid;
mutex_lock(&sc->mutex);
@@ -1909,9 +1911,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- ath9k_ps_wakeup(sc);
- ath_tx_aggr_resume(sc, sta, tid);
- ath9k_ps_restore(sc);
+ atid = ath_node_to_tid(an, tid);
+ atid->baw_size = IEEE80211_MIN_AMPDU_BUF <<
+ sta->ht_cap.ampdu_factor;
break;
default:
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
@@ -2673,4 +2675,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 fe795fc..8103954 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_txq *txq,
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,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&tid->list, list);
}
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq = tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued = true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
int q = fi->txq;
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
}
static struct ath_atx_tid *
@@ -173,9 +186,48 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv);
+ struct ath_softc *sc = tid->an->sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_control txctl = {
+ .txq = tid->txq,
+ .sta = tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb = ieee80211_tx_dequeue(hw, txq);
+ if (!skb) {
+ tid->has_queued = false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q = skb_get_queue_mapping(skb);
+ if (tid->txq == sc->tx.txq_map[q]) {
+ fi = get_frame_info(skb);
+ fi->txq = q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +236,11 @@ 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);
+ skb = ath_tid_pull(tid);
return skb;
}
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq = tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->txq;
@@ -858,20 +875,16 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb = NULL;
struct ath_buf *bf;
u16 seqno;
while (1) {
- *q = &tid->retry_q;
- if (skb_queue_empty(*q))
- *q = &tid->buf_q;
-
- skb = skb_peek(*q);
+ skb = ath_tid_dequeue(tid);
if (!skb)
break;
@@ -883,7 +896,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.stale = false;
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +924,20 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
seqno = bf->bf_state.seqno;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) &&
+ !WARN_ON(skb == first_skb)) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb = skb;
+ continue;
+ }
break;
+ }
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts = {};
@@ -921,7 +945,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +956,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
return NULL;
}
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf = bf_first, *bf_prev = NULL;
@@ -947,12 +969,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed = false;
+
bf = bf_first;
aggr_limit = ath_lookup_rate(sc, bf, tid);
- do {
+ while (bf)
+ {
skb = bf->bf_mpdu;
fi = get_frame_info(skb);
@@ -961,12 +984,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >= h_baw)
- break;
+ goto stop;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
/* add padding for previous frame to aggregation length */
@@ -988,20 +1011,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
bf_prev = bf;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed = true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf = bf_first;
bf->bf_lastbf = bf_prev;
@@ -1012,9 +1033,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- *aggr_len = al;
-
- return closed;
+ return al;
#undef PADBYTES
}
@@ -1391,18 +1410,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf = bf_first, *bf_prev = NULL;
- struct sk_buff *skb;
int nframes = 0;
do {
struct ieee80211_tx_info *tx_info;
- skb = bf->bf_mpdu;
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
@@ -1411,13 +1427,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
if (nframes >= 2)
break;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1446,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len = 0;
- bool aggr, last = true;
+ bool aggr;
if (!ath_tid_has_buffered(tid))
return false;
INIT_LIST_HEAD(&bf_q);
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop = true;
return false;
}
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1515,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density;
}
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active = true;
*ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1;
@@ -1525,7 +1539,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
@@ -1535,14 +1548,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -1552,13 +1563,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
continue;
}
- buffered = ath_tid_has_buffered(tid);
+ if (!skb_queue_empty(&tid->retry_q))
+ ieee80211_sta_set_buffered(sta, tid->tidno, true);
list_del_init(&tid->list);
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
@@ -1571,49 +1581,20 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
tid->clear_ps_filter = true;
-
if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq);
}
-
ath_txq_unlock_complete(sc, txq);
}
}
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tidno)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_atx_tid *tid;
- struct ath_node *an;
- struct ath_txq *txq;
-
- ath_dbg(common, XMIT, "%s called\n", __func__);
-
- an = (struct ath_node *)sta->drv_priv;
- tid = ATH_AN_2_TID(an, tidno);
- txq = tid->txq;
-
- ath_txq_lock(sc, txq);
-
- tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
- ath_txq_unlock_complete(sc, txq);
-}
-
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@@ -1626,7 +1607,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail = NULL, *bf;
- struct sk_buff_head *tid_q;
int sent = 0;
int i;
@@ -1641,11 +1621,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1639,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1866,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq = &sc->tx.txq[i];
- txq->stopped = false;
ath_draintxq(sc, txq);
}
@@ -2293,15 +2266,12 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false, ps_resp;
+ bool ps_resp;
int q, ret;
if (vif)
avp = (void *)vif->drv_priv;
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel = true;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2286,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
q = skb_get_queue_mapping(skb);
+ if (ps_resp)
+ txq = sc->tx.uapsdq;
+
ath_txq_lock(sc, txq);
if (txq == sc->tx.txq_map[q]) {
fi->txq = q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped = true;
- }
- }
-
- queue = ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue = true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx != sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
- skip_uapsd = true;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
- txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq != txctl->txq);
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter = true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
-
- ath_txq_schedule(sc, txq);
- goto out;
+ ++txq->pending_frames;
}
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2776,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ath_node_to_tid(an, tidno);
tid->an = an;
tid->tidno = tidno;
tid->seq_start = tid->seq_next = 0;
@@ -2866,11 +2785,14 @@ 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;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued = false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno = TID_TO_WME_AC(tidno);
tid->txq = sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
@@ -2880,9 +2802,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -2894,6 +2815,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->active = false;
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
--
2.9.2
^ permalink raw reply related [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-05 16:05 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-08-22 15:43 ` Kalle Valo
-1 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-08-22 15:43 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen <toke@toke.dk> writes:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
> ---
> Changes since v3 (most due to Felix; thanks!):
> - Correctly notify mac80211 when there are packets in the retry queue
> on powersave start/stop.
> - Get rid of ath_tx_aggr_resume().
> - Some readability changes and additional WARN_ON/BUG_ON in
> appropriate places.
This is great work but due to the regressions I'm not sure if this will
be ready for 4.9. To get more testing time I wonder if we should wait
for 4.10? IMHO applying this in the end of the cycle is too risky and we
should try to maximise the time linux-next by applying this just after
-rc1 is released.
Thoughts?
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-22 15:43 ` Kalle Valo
0 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-08-22 15:43 UTC (permalink / raw)
To: ath9k-devel
Toke H?iland-J?rgensen <toke@toke.dk> writes:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
> ---
> Changes since v3 (most due to Felix; thanks!):
> - Correctly notify mac80211 when there are packets in the retry queue
> on powersave start/stop.
> - Get rid of ath_tx_aggr_resume().
> - Some readability changes and additional WARN_ON/BUG_ON in
> appropriate places.
This is great work but due to the regressions I'm not sure if this will
be ready for 4.9. To get more testing time I wonder if we should wait
for 4.10? IMHO applying this in the end of the cycle is too risky and we
should try to maximise the time linux-next by applying this just after
-rc1 is released.
Thoughts?
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-22 15:43 ` [ath9k-devel] " Kalle Valo
@ 2016-08-22 16:16 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-08-22 16:16 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>
>> Based on Tim's original patch set, but reworked quite thoroughly.
>>
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
>> ---
>> Changes since v3 (most due to Felix; thanks!):
>> - Correctly notify mac80211 when there are packets in the retry queue
>> on powersave start/stop.
>> - Get rid of ath_tx_aggr_resume().
>> - Some readability changes and additional WARN_ON/BUG_ON in
>> appropriate places.
>
> This is great work but due to the regressions I'm not sure if this
> will be ready for 4.9. To get more testing time I wonder if we should
> wait for 4.10? IMHO applying this in the end of the cycle is too risky
> and we should try to maximise the time linux-next by applying this
> just after -rc1 is released.
>
> Thoughts?
Well, now that we understand what is causing the throughput regressions,
fixing them should be fairly straight forward (yeah, famous last words,
but still...). I already have a patch for the fast path and will go poke
at the slow path next. It'll probably require another workaround or two,
so I guess it won't be the architecturally clean ideal solution; but it
would make it possible to have something that works for 4.9 and then
iterate for a cleaner design for 4.10.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-22 16:16 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-08-22 16:16 UTC (permalink / raw)
To: ath9k-devel
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>
>> Based on Tim's original patch set, but reworked quite thoroughly.
>>
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>> ---
>> Changes since v3 (most due to Felix; thanks!):
>> - Correctly notify mac80211 when there are packets in the retry queue
>> on powersave start/stop.
>> - Get rid of ath_tx_aggr_resume().
>> - Some readability changes and additional WARN_ON/BUG_ON in
>> appropriate places.
>
> This is great work but due to the regressions I'm not sure if this
> will be ready for 4.9. To get more testing time I wonder if we should
> wait for 4.10? IMHO applying this in the end of the cycle is too risky
> and we should try to maximise the time linux-next by applying this
> just after -rc1 is released.
>
> Thoughts?
Well, now that we understand what is causing the throughput regressions,
fixing them should be fairly straight forward (yeah, famous last words,
but still...). I already have a patch for the fast path and will go poke
at the slow path next. It'll probably require another workaround or two,
so I guess it won't be the architecturally clean ideal solution; but it
would make it possible to have something that works for 4.9 and then
iterate for a cleaner design for 4.10.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-22 16:16 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-08-22 17:02 ` Kalle Valo
-1 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-08-22 17:02 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen <toke@toke.dk> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>
>> Toke Høiland-Jørgensen <toke@toke.dk> writes:
>>
>>> This switches ath9k over to using the mac80211 intermediate software
>>> queueing mechanism for data packets. It removes the queueing inside the
>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>> a packet is needed. The retry queue is used to store a packet that was
>>> pulled but can't be sent immediately.
>>>
>>> The old code path in ath_tx_start that would queue packets has been
>>> removed completely, as has the qlen limit tunables (since there's no
>>> longer a queue in the driver to limit).
>>>
>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>
>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>> Cc: Felix Fietkau <nbd@nbd.name>
>>> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
>>> ---
>>> Changes since v3 (most due to Felix; thanks!):
>>> - Correctly notify mac80211 when there are packets in the retry queue
>>> on powersave start/stop.
>>> - Get rid of ath_tx_aggr_resume().
>>> - Some readability changes and additional WARN_ON/BUG_ON in
>>> appropriate places.
>>
>> This is great work but due to the regressions I'm not sure if this
>> will be ready for 4.9. To get more testing time I wonder if we should
>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>> and we should try to maximise the time linux-next by applying this
>> just after -rc1 is released.
>>
>> Thoughts?
>
> Well, now that we understand what is causing the throughput regressions,
> fixing them should be fairly straight forward (yeah, famous last words,
> but still...). I already have a patch for the fast path and will go poke
> at the slow path next. It'll probably require another workaround or two,
> so I guess it won't be the architecturally clean ideal solution; but it
> would make it possible to have something that works for 4.9 and then
> iterate for a cleaner design for 4.10.
But if we try to rush this to 4.9 it won't be in linux-next for long. We
are now in -rc3 and let's say that the patches are ready to apply in two
weeks. That would leave us only two weeks of -next time before the merge
window, which I think is not enough for a controversial patch like this
one. There might be other bugs lurking which haven't been found yet.
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-22 17:02 ` Kalle Valo
0 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-08-22 17:02 UTC (permalink / raw)
To: ath9k-devel
Toke H?iland-J?rgensen <toke@toke.dk> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>
>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>
>>> This switches ath9k over to using the mac80211 intermediate software
>>> queueing mechanism for data packets. It removes the queueing inside the
>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>> a packet is needed. The retry queue is used to store a packet that was
>>> pulled but can't be sent immediately.
>>>
>>> The old code path in ath_tx_start that would queue packets has been
>>> removed completely, as has the qlen limit tunables (since there's no
>>> longer a queue in the driver to limit).
>>>
>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>
>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>> Cc: Felix Fietkau <nbd@nbd.name>
>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>> ---
>>> Changes since v3 (most due to Felix; thanks!):
>>> - Correctly notify mac80211 when there are packets in the retry queue
>>> on powersave start/stop.
>>> - Get rid of ath_tx_aggr_resume().
>>> - Some readability changes and additional WARN_ON/BUG_ON in
>>> appropriate places.
>>
>> This is great work but due to the regressions I'm not sure if this
>> will be ready for 4.9. To get more testing time I wonder if we should
>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>> and we should try to maximise the time linux-next by applying this
>> just after -rc1 is released.
>>
>> Thoughts?
>
> Well, now that we understand what is causing the throughput regressions,
> fixing them should be fairly straight forward (yeah, famous last words,
> but still...). I already have a patch for the fast path and will go poke
> at the slow path next. It'll probably require another workaround or two,
> so I guess it won't be the architecturally clean ideal solution; but it
> would make it possible to have something that works for 4.9 and then
> iterate for a cleaner design for 4.10.
But if we try to rush this to 4.9 it won't be in linux-next for long. We
are now in -rc3 and let's say that the patches are ready to apply in two
weeks. That would leave us only two weeks of -next time before the merge
window, which I think is not enough for a controversial patch like this
one. There might be other bugs lurking which haven't been found yet.
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-22 17:02 ` [ath9k-devel] " Kalle Valo
@ 2016-08-22 17:13 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-08-22 17:13 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>
>>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>>
>>>> This switches ath9k over to using the mac80211 intermediate software
>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>> driver, except for the retry queue, and instead pulls from mac80211 wh=
en
>>>> a packet is needed. The retry queue is used to store a packet that was
>>>> pulled but can't be sent immediately.
>>>>
>>>> The old code path in ath_tx_start that would queue packets has been
>>>> removed completely, as has the qlen limit tunables (since there's no
>>>> longer a queue in the driver to limit).
>>>>
>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>
>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>> Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
>>>> ---
>>>> Changes since v3 (most due to Felix; thanks!):
>>>> - Correctly notify mac80211 when there are packets in the retry queue
>>>> on powersave start/stop.
>>>> - Get rid of ath_tx_aggr_resume().
>>>> - Some readability changes and additional WARN_ON/BUG_ON in
>>>> appropriate places.
>>>
>>> This is great work but due to the regressions I'm not sure if this
>>> will be ready for 4.9. To get more testing time I wonder if we should
>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>> and we should try to maximise the time linux-next by applying this
>>> just after -rc1 is released.
>>>
>>> Thoughts?
>>
>> Well, now that we understand what is causing the throughput regressions,
>> fixing them should be fairly straight forward (yeah, famous last words,
>> but still...). I already have a patch for the fast path and will go poke
>> at the slow path next. It'll probably require another workaround or two,
>> so I guess it won't be the architecturally clean ideal solution; but it
>> would make it possible to have something that works for 4.9 and then
>> iterate for a cleaner design for 4.10.
>
> But if we try to rush this to 4.9 it won't be in linux-next for long. We
> are now in -rc3 and let's say that the patches are ready to apply in two
> weeks. That would leave us only two weeks of -next time before the merge
> window, which I think is not enough for a controversial patch like this
> one. There might be other bugs lurking which haven't been found yet.
What, other hidden bugs? Unpossible! :)
Would it be possible to merge the partial solution (which is ready now,
basically) and fix the slow path in a separate patch later?
(Just spit-balling here; I'm still fairly new to this process. But I am
concerned that we'll hit a catch-22 where we can't get wider testing
before it's "ready" and we can't prove that it's "ready" until we've had
wider testing...)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-22 17:13 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-08-22 17:13 UTC (permalink / raw)
To: ath9k-devel
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>
>>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>>
>>>> This switches ath9k over to using the mac80211 intermediate software
>>>> queueing mechanism for data packets. It removes the queueing inside the
>>>> driver, except for the retry queue, and instead pulls from mac80211 when
>>>> a packet is needed. The retry queue is used to store a packet that was
>>>> pulled but can't be sent immediately.
>>>>
>>>> The old code path in ath_tx_start that would queue packets has been
>>>> removed completely, as has the qlen limit tunables (since there's no
>>>> longer a queue in the driver to limit).
>>>>
>>>> Based on Tim's original patch set, but reworked quite thoroughly.
>>>>
>>>> Cc: Tim Shepard <shep@alum.mit.edu>
>>>> Cc: Felix Fietkau <nbd@nbd.name>
>>>> Signed-off-by: Toke H?iland-J?rgensen <toke@toke.dk>
>>>> ---
>>>> Changes since v3 (most due to Felix; thanks!):
>>>> - Correctly notify mac80211 when there are packets in the retry queue
>>>> on powersave start/stop.
>>>> - Get rid of ath_tx_aggr_resume().
>>>> - Some readability changes and additional WARN_ON/BUG_ON in
>>>> appropriate places.
>>>
>>> This is great work but due to the regressions I'm not sure if this
>>> will be ready for 4.9. To get more testing time I wonder if we should
>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>> and we should try to maximise the time linux-next by applying this
>>> just after -rc1 is released.
>>>
>>> Thoughts?
>>
>> Well, now that we understand what is causing the throughput regressions,
>> fixing them should be fairly straight forward (yeah, famous last words,
>> but still...). I already have a patch for the fast path and will go poke
>> at the slow path next. It'll probably require another workaround or two,
>> so I guess it won't be the architecturally clean ideal solution; but it
>> would make it possible to have something that works for 4.9 and then
>> iterate for a cleaner design for 4.10.
>
> But if we try to rush this to 4.9 it won't be in linux-next for long. We
> are now in -rc3 and let's say that the patches are ready to apply in two
> weeks. That would leave us only two weeks of -next time before the merge
> window, which I think is not enough for a controversial patch like this
> one. There might be other bugs lurking which haven't been found yet.
What, other hidden bugs? Unpossible! :)
Would it be possible to merge the partial solution (which is ready now,
basically) and fix the slow path in a separate patch later?
(Just spit-balling here; I'm still fairly new to this process. But I am
concerned that we'll hit a catch-22 where we can't get wider testing
before it's "ready" and we can't prove that it's "ready" until we've had
wider testing...)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-22 17:13 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-08-23 6:59 ` Kalle Valo
-1 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-08-23 6:59 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen <toke@toke.dk> writes:
>>>> This is great work but due to the regressions I'm not sure if this
>>>> will be ready for 4.9. To get more testing time I wonder if we should
>>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>>> and we should try to maximise the time linux-next by applying this
>>>> just after -rc1 is released.
>>>>
>>>> Thoughts?
>>>
>>> Well, now that we understand what is causing the throughput regressions,
>>> fixing them should be fairly straight forward (yeah, famous last words,
>>> but still...). I already have a patch for the fast path and will go poke
>>> at the slow path next. It'll probably require another workaround or two,
>>> so I guess it won't be the architecturally clean ideal solution; but it
>>> would make it possible to have something that works for 4.9 and then
>>> iterate for a cleaner design for 4.10.
>>
>> But if we try to rush this to 4.9 it won't be in linux-next for long. We
>> are now in -rc3 and let's say that the patches are ready to apply in two
>> weeks. That would leave us only two weeks of -next time before the merge
>> window, which I think is not enough for a controversial patch like this
>> one. There might be other bugs lurking which haven't been found yet.
>
> What, other hidden bugs? Unpossible! :)
Yeah, right ;)
> Would it be possible to merge the partial solution (which is ready now,
> basically) and fix the slow path in a separate patch later?
What do you mean with partial solution? You mean ath9k users would
suffer from regressions until they are fixed? We can't do that.
> (Just spit-balling here; I'm still fairly new to this process. But I am
> concerned that we'll hit a catch-22 where we can't get wider testing
> before it's "ready" and we can't prove that it's "ready" until we've had
> wider testing...)
I understand your point, but I don't want to rush this to 4.9 and then
start getting lots of bug reports and eventually forced to revert it. If
we just found a new serious regression the chances are that there are
more lurking somewhere and this patch is just not ready yet.
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-23 6:59 ` Kalle Valo
0 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-08-23 6:59 UTC (permalink / raw)
To: ath9k-devel
Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>>> This is great work but due to the regressions I'm not sure if this
>>>> will be ready for 4.9. To get more testing time I wonder if we should
>>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>>> and we should try to maximise the time linux-next by applying this
>>>> just after -rc1 is released.
>>>>
>>>> Thoughts?
>>>
>>> Well, now that we understand what is causing the throughput regressions,
>>> fixing them should be fairly straight forward (yeah, famous last words,
>>> but still...). I already have a patch for the fast path and will go poke
>>> at the slow path next. It'll probably require another workaround or two,
>>> so I guess it won't be the architecturally clean ideal solution; but it
>>> would make it possible to have something that works for 4.9 and then
>>> iterate for a cleaner design for 4.10.
>>
>> But if we try to rush this to 4.9 it won't be in linux-next for long. We
>> are now in -rc3 and let's say that the patches are ready to apply in two
>> weeks. That would leave us only two weeks of -next time before the merge
>> window, which I think is not enough for a controversial patch like this
>> one. There might be other bugs lurking which haven't been found yet.
>
> What, other hidden bugs? Unpossible! :)
Yeah, right ;)
> Would it be possible to merge the partial solution (which is ready now,
> basically) and fix the slow path in a separate patch later?
What do you mean with partial solution? You mean ath9k users would
suffer from regressions until they are fixed? We can't do that.
> (Just spit-balling here; I'm still fairly new to this process. But I am
> concerned that we'll hit a catch-22 where we can't get wider testing
> before it's "ready" and we can't prove that it's "ready" until we've had
> wider testing...)
I understand your point, but I don't want to rush this to 4.9 and then
start getting lots of bug reports and eventually forced to revert it. If
we just found a new serious regression the chances are that there are
more lurking somewhere and this patch is just not ready yet.
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-23 6:59 ` [ath9k-devel] " Kalle Valo
@ 2016-08-23 8:58 ` Arend van Spriel
-1 siblings, 0 replies; 118+ messages in thread
From: Arend van Spriel @ 2016-08-23 8:52 UTC (permalink / raw)
To: Kalle Valo, Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
On 23-08-16 08:59, Kalle Valo wrote:
> Toke Høiland-Jørgensen <toke@toke.dk> writes:
>
>>>>> This is great work but due to the regressions I'm not sure if this
>>>>> will be ready for 4.9. To get more testing time I wonder if we should
>>>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>>>> and we should try to maximise the time linux-next by applying this
>>>>> just after -rc1 is released.
>>>>>
>>>>> Thoughts?
>>>>
>>>> Well, now that we understand what is causing the throughput regressions,
>>>> fixing them should be fairly straight forward (yeah, famous last words,
>>>> but still...). I already have a patch for the fast path and will go poke
>>>> at the slow path next. It'll probably require another workaround or two,
>>>> so I guess it won't be the architecturally clean ideal solution; but it
>>>> would make it possible to have something that works for 4.9 and then
>>>> iterate for a cleaner design for 4.10.
>>>
>>> But if we try to rush this to 4.9 it won't be in linux-next for long. We
>>> are now in -rc3 and let's say that the patches are ready to apply in two
>>> weeks. That would leave us only two weeks of -next time before the merge
>>> window, which I think is not enough for a controversial patch like this
>>> one. There might be other bugs lurking which haven't been found yet.
>>
>> What, other hidden bugs? Unpossible! :)
>
> Yeah, right ;)
>
>> Would it be possible to merge the partial solution (which is ready now,
>> basically) and fix the slow path in a separate patch later?
>
> What do you mean with partial solution? You mean ath9k users would
> suffer from regressions until they are fixed? We can't do that.
>
>> (Just spit-balling here; I'm still fairly new to this process. But I am
>> concerned that we'll hit a catch-22 where we can't get wider testing
>> before it's "ready" and we can't prove that it's "ready" until we've had
>> wider testing...)
So could the wider testing be accomplished by working on a branch in the
wireless-testing repo and make its availability known on wireless-list,
ath?k-list, LWN or whatever.
Regards,
Arend
> I understand your point, but I don't want to rush this to 4.9 and then
> start getting lots of bug reports and eventually forced to revert it. If
> we just found a new serious regression the chances are that there are
> more lurking somewhere and this patch is just not ready yet.
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-08-23 8:58 ` Arend van Spriel
0 siblings, 0 replies; 118+ messages in thread
From: Arend van Spriel @ 2016-08-23 8:58 UTC (permalink / raw)
To: ath9k-devel
On 23-08-16 08:59, Kalle Valo wrote:
> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>
>>>>> This is great work but due to the regressions I'm not sure if this
>>>>> will be ready for 4.9. To get more testing time I wonder if we should
>>>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>>>> and we should try to maximise the time linux-next by applying this
>>>>> just after -rc1 is released.
>>>>>
>>>>> Thoughts?
>>>>
>>>> Well, now that we understand what is causing the throughput regressions,
>>>> fixing them should be fairly straight forward (yeah, famous last words,
>>>> but still...). I already have a patch for the fast path and will go poke
>>>> at the slow path next. It'll probably require another workaround or two,
>>>> so I guess it won't be the architecturally clean ideal solution; but it
>>>> would make it possible to have something that works for 4.9 and then
>>>> iterate for a cleaner design for 4.10.
>>>
>>> But if we try to rush this to 4.9 it won't be in linux-next for long. We
>>> are now in -rc3 and let's say that the patches are ready to apply in two
>>> weeks. That would leave us only two weeks of -next time before the merge
>>> window, which I think is not enough for a controversial patch like this
>>> one. There might be other bugs lurking which haven't been found yet.
>>
>> What, other hidden bugs? Unpossible! :)
>
> Yeah, right ;)
>
>> Would it be possible to merge the partial solution (which is ready now,
>> basically) and fix the slow path in a separate patch later?
>
> What do you mean with partial solution? You mean ath9k users would
> suffer from regressions until they are fixed? We can't do that.
>
>> (Just spit-balling here; I'm still fairly new to this process. But I am
>> concerned that we'll hit a catch-22 where we can't get wider testing
>> before it's "ready" and we can't prove that it's "ready" until we've had
>> wider testing...)
So could the wider testing be accomplished by working on a branch in the
wireless-testing repo and make its availability known on wireless-list,
ath?k-list, LWN or whatever.
Regards,
Arend
> I understand your point, but I don't want to rush this to 4.9 and then
> start getting lots of bug reports and eventually forced to revert it. If
> we just found a new serious regression the chances are that there are
> more lurking somewhere and this patch is just not ready yet.
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-23 6:59 ` [ath9k-devel] " Kalle Valo
@ 2016-10-05 14:09 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-10-05 14:02 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>
>>>>> This is great work but due to the regressions I'm not sure if this
>>>>> will be ready for 4.9. To get more testing time I wonder if we should
>>>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>>>> and we should try to maximise the time linux-next by applying this
>>>>> just after -rc1 is released.
>>>>>
>>>>> Thoughts?
>>>>
>>>> Well, now that we understand what is causing the throughput regression=
s,
>>>> fixing them should be fairly straight forward (yeah, famous last words,
>>>> but still...). I already have a patch for the fast path and will go po=
ke
>>>> at the slow path next. It'll probably require another workaround or tw=
o,
>>>> so I guess it won't be the architecturally clean ideal solution; but it
>>>> would make it possible to have something that works for 4.9 and then
>>>> iterate for a cleaner design for 4.10.
>>>
>>> But if we try to rush this to 4.9 it won't be in linux-next for long. We
>>> are now in -rc3 and let's say that the patches are ready to apply in two
>>> weeks. That would leave us only two weeks of -next time before the merge
>>> window, which I think is not enough for a controversial patch like this
>>> one. There might be other bugs lurking which haven't been found yet.
>>
>> What, other hidden bugs? Unpossible! :)
>
> Yeah, right ;)
>
>> Would it be possible to merge the partial solution (which is ready now,
>> basically) and fix the slow path in a separate patch later?
>
> What do you mean with partial solution? You mean ath9k users would
> suffer from regressions until they are fixed? We can't do that.
>
>> (Just spit-balling here; I'm still fairly new to this process. But I am
>> concerned that we'll hit a catch-22 where we can't get wider testing
>> before it's "ready" and we can't prove that it's "ready" until we've had
>> wider testing...)
>
> I understand your point, but I don't want to rush this to 4.9 and then
> start getting lots of bug reports and eventually forced to revert it. If
> we just found a new serious regression the chances are that there are
> more lurking somewhere and this patch is just not ready yet.
So, the changes to mac80211 that fixes the known regressions of this
patch have gone in. Any chance of seeing this merged during the current
merge window? :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-10-05 14:09 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-10-05 14:09 UTC (permalink / raw)
To: ath9k-devel
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>
>>>>> This is great work but due to the regressions I'm not sure if this
>>>>> will be ready for 4.9. To get more testing time I wonder if we should
>>>>> wait for 4.10? IMHO applying this in the end of the cycle is too risky
>>>>> and we should try to maximise the time linux-next by applying this
>>>>> just after -rc1 is released.
>>>>>
>>>>> Thoughts?
>>>>
>>>> Well, now that we understand what is causing the throughput regressions,
>>>> fixing them should be fairly straight forward (yeah, famous last words,
>>>> but still...). I already have a patch for the fast path and will go poke
>>>> at the slow path next. It'll probably require another workaround or two,
>>>> so I guess it won't be the architecturally clean ideal solution; but it
>>>> would make it possible to have something that works for 4.9 and then
>>>> iterate for a cleaner design for 4.10.
>>>
>>> But if we try to rush this to 4.9 it won't be in linux-next for long. We
>>> are now in -rc3 and let's say that the patches are ready to apply in two
>>> weeks. That would leave us only two weeks of -next time before the merge
>>> window, which I think is not enough for a controversial patch like this
>>> one. There might be other bugs lurking which haven't been found yet.
>>
>> What, other hidden bugs? Unpossible! :)
>
> Yeah, right ;)
>
>> Would it be possible to merge the partial solution (which is ready now,
>> basically) and fix the slow path in a separate patch later?
>
> What do you mean with partial solution? You mean ath9k users would
> suffer from regressions until they are fixed? We can't do that.
>
>> (Just spit-balling here; I'm still fairly new to this process. But I am
>> concerned that we'll hit a catch-22 where we can't get wider testing
>> before it's "ready" and we can't prove that it's "ready" until we've had
>> wider testing...)
>
> I understand your point, but I don't want to rush this to 4.9 and then
> start getting lots of bug reports and eventually forced to revert it. If
> we just found a new serious regression the chances are that there are
> more lurking somewhere and this patch is just not ready yet.
So, the changes to mac80211 that fixes the known regressions of this
patch have gone in. Any chance of seeing this merged during the current
merge window? :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-10-05 14:09 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-10-05 15:50 ` Kalle Valo
-1 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-10-05 15:50 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>
>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>
>> I understand your point, but I don't want to rush this to 4.9 and then
>> start getting lots of bug reports and eventually forced to revert it. If
>> we just found a new serious regression the chances are that there are
>> more lurking somewhere and this patch is just not ready yet.
>
> So, the changes to mac80211 that fixes the known regressions of this
> patch have gone in.
I guess you mean this commit:
bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequ=
eue
(Just making sure that I have the same commit in my tree when I apply this)
> Any chance of seeing this merged during the current merge window? :)
I sent last new feature ("-next") patches for 4.9 last week, sorry. So
this has to wait for 4.10.
And I assume I need to take v5:
https://patchwork.kernel.org/patch/9311037/
--=20
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-10-05 15:50 ` Kalle Valo
0 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-10-05 15:50 UTC (permalink / raw)
To: ath9k-devel
Toke H?iland-J?rgensen <toke@toke.dk> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>
>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>
>> I understand your point, but I don't want to rush this to 4.9 and then
>> start getting lots of bug reports and eventually forced to revert it. If
>> we just found a new serious regression the chances are that there are
>> more lurking somewhere and this patch is just not ready yet.
>
> So, the changes to mac80211 that fixes the known regressions of this
> patch have gone in.
I guess you mean this commit:
bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue
(Just making sure that I have the same commit in my tree when I apply this)
> Any chance of seeing this merged during the current merge window? :)
I sent last new feature ("-next") patches for 4.9 last week, sorry. So
this has to wait for 4.10.
And I assume I need to take v5:
https://patchwork.kernel.org/patch/9311037/
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-10-05 15:50 ` [ath9k-devel] " Kalle Valo
@ 2016-10-05 16:55 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-10-05 16:55 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>
>>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>>
>>> I understand your point, but I don't want to rush this to 4.9 and then
>>> start getting lots of bug reports and eventually forced to revert it. If
>>> we just found a new serious regression the chances are that there are
>>> more lurking somewhere and this patch is just not ready yet.
>>
>> So, the changes to mac80211 that fixes the known regressions of this
>> patch have gone in.
>
> I guess you mean this commit:
>
> bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ de=
queue
>
> (Just making sure that I have the same commit in my tree when I apply
> this)
Yup, that's the one :)
>> Any chance of seeing this merged during the current merge window? :)
>
> I sent last new feature ("-next") patches for 4.9 last week, sorry. So
> this has to wait for 4.10.
Ah, right, I think I got my merge windows confused. You already said you
wouldn't take it for 4.9. So I guess what I'm asking is for you to put
it into the appropriate -next tree so it can get some wider exposure
ahead of the *next* merge window...
> And I assume I need to take v5:
>
> https://patchwork.kernel.org/patch/9311037/
Yes. Haven't noticed anything that changed since that might conflict
with it, but let me know if I missed something and you want a refreshed
version.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-10-05 16:55 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-10-05 16:55 UTC (permalink / raw)
To: ath9k-devel
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>
>>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>>
>>> I understand your point, but I don't want to rush this to 4.9 and then
>>> start getting lots of bug reports and eventually forced to revert it. If
>>> we just found a new serious regression the chances are that there are
>>> more lurking somewhere and this patch is just not ready yet.
>>
>> So, the changes to mac80211 that fixes the known regressions of this
>> patch have gone in.
>
> I guess you mean this commit:
>
> bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue
>
> (Just making sure that I have the same commit in my tree when I apply
> this)
Yup, that's the one :)
>> Any chance of seeing this merged during the current merge window? :)
>
> I sent last new feature ("-next") patches for 4.9 last week, sorry. So
> this has to wait for 4.10.
Ah, right, I think I got my merge windows confused. You already said you
wouldn't take it for 4.9. So I guess what I'm asking is for you to put
it into the appropriate -next tree so it can get some wider exposure
ahead of the *next* merge window...
> And I assume I need to take v5:
>
> https://patchwork.kernel.org/patch/9311037/
Yes. Haven't noticed anything that changed since that might conflict
with it, but let me know if I missed something and you want a refreshed
version.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-10-05 16:55 ` [ath9k-devel] " Toke Høiland-Jørgensen
@ 2016-10-05 17:54 ` Kalle Valo
-1 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-10-05 17:54 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>
>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>
>>> Kalle Valo <kvalo@codeaurora.org> writes:
>>>
>>>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>>>
>>>> I understand your point, but I don't want to rush this to 4.9 and then
>>>> start getting lots of bug reports and eventually forced to revert it. =
If
>>>> we just found a new serious regression the chances are that there are
>>>> more lurking somewhere and this patch is just not ready yet.
>>>
>>> So, the changes to mac80211 that fixes the known regressions of this
>>> patch have gone in.
>>
>> I guess you mean this commit:
>>
>> bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ d=
equeue
>>
>> (Just making sure that I have the same commit in my tree when I apply
>> this)
>
> Yup, that's the one :)
>
>>> Any chance of seeing this merged during the current merge window? :)
>>
>> I sent last new feature ("-next") patches for 4.9 last week, sorry. So
>> this has to wait for 4.10.
>
> Ah, right, I think I got my merge windows confused. You already said you
> wouldn't take it for 4.9. So I guess what I'm asking is for you to put
> it into the appropriate -next tree so it can get some wider exposure
> ahead of the *next* merge window...
Yeah, we have plenty of time for 4.10 :) So my plan is to apply this
after I open wireless-drivers-next in 2-3 weeks or so. That would mean
that the patch would hit Linus' tree when 4.10-rc1 is released
(estimated to happen on 2017-01-01). The timing is actually perfect as
now we get maximal testing time on -next.
>> And I assume I need to take v5:
>>
>> https://patchwork.kernel.org/patch/9311037/
>
> Yes. Haven't noticed anything that changed since that might conflict
> with it, but let me know if I missed something and you want a refreshed
> version.
Thanks, I'll let you know if there are any problems.
--=20
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-10-05 17:54 ` Kalle Valo
0 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-10-05 17:54 UTC (permalink / raw)
To: ath9k-devel
Toke H?iland-J?rgensen <toke@toke.dk> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>
>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>
>>> Kalle Valo <kvalo@codeaurora.org> writes:
>>>
>>>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>>>
>>>> I understand your point, but I don't want to rush this to 4.9 and then
>>>> start getting lots of bug reports and eventually forced to revert it. If
>>>> we just found a new serious regression the chances are that there are
>>>> more lurking somewhere and this patch is just not ready yet.
>>>
>>> So, the changes to mac80211 that fixes the known regressions of this
>>> patch have gone in.
>>
>> I guess you mean this commit:
>>
>> bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue
>>
>> (Just making sure that I have the same commit in my tree when I apply
>> this)
>
> Yup, that's the one :)
>
>>> Any chance of seeing this merged during the current merge window? :)
>>
>> I sent last new feature ("-next") patches for 4.9 last week, sorry. So
>> this has to wait for 4.10.
>
> Ah, right, I think I got my merge windows confused. You already said you
> wouldn't take it for 4.9. So I guess what I'm asking is for you to put
> it into the appropriate -next tree so it can get some wider exposure
> ahead of the *next* merge window...
Yeah, we have plenty of time for 4.10 :) So my plan is to apply this
after I open wireless-drivers-next in 2-3 weeks or so. That would mean
that the patch would hit Linus' tree when 4.10-rc1 is released
(estimated to happen on 2017-01-01). The timing is actually perfect as
now we get maximal testing time on -next.
>> And I assume I need to take v5:
>>
>> https://patchwork.kernel.org/patch/9311037/
>
> Yes. Haven't noticed anything that changed since that might conflict
> with it, but let me know if I missed something and you want a refreshed
> version.
Thanks, I'll let you know if there are any problems.
--
Kalle Valo
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
2016-10-05 17:54 ` [ath9k-devel] " Kalle Valo
@ 2016-10-05 19:56 ` Toke Høiland-Jørgensen
-1 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-10-05 19:56 UTC (permalink / raw)
To: Kalle Valo
Cc: linux-wireless, make-wifi-fast, ath9k-devel, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>
>>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>>
>>>> Kalle Valo <kvalo@codeaurora.org> writes:
>>>>
>>>>> Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk> writes:
>>>>>
>>>>> I understand your point, but I don't want to rush this to 4.9 and then
>>>>> start getting lots of bug reports and eventually forced to revert it.=
If
>>>>> we just found a new serious regression the chances are that there are
>>>>> more lurking somewhere and this patch is just not ready yet.
>>>>
>>>> So, the changes to mac80211 that fixes the known regressions of this
>>>> patch have gone in.
>>>
>>> I guess you mean this commit:
>>>
>>> bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ =
dequeue
>>>
>>> (Just making sure that I have the same commit in my tree when I apply
>>> this)
>>
>> Yup, that's the one :)
>>
>>>> Any chance of seeing this merged during the current merge window? :)
>>>
>>> I sent last new feature ("-next") patches for 4.9 last week, sorry. So
>>> this has to wait for 4.10.
>>
>> Ah, right, I think I got my merge windows confused. You already said you
>> wouldn't take it for 4.9. So I guess what I'm asking is for you to put
>> it into the appropriate -next tree so it can get some wider exposure
>> ahead of the *next* merge window...
>
> Yeah, we have plenty of time for 4.10 :) So my plan is to apply this
> after I open wireless-drivers-next in 2-3 weeks or so. That would mean
> that the patch would hit Linus' tree when 4.10-rc1 is released
> (estimated to happen on 2017-01-01). The timing is actually perfect as
> now we get maximal testing time on -next.
So the -next trees are those that are open outside the merge window.
Right, got it; thanks :)
>>> And I assume I need to take v5:
>>>
>>> https://patchwork.kernel.org/patch/9311037/
>>
>> Yes. Haven't noticed anything that changed since that might conflict
>> with it, but let me know if I missed something and you want a refreshed
>> version.
>
> Thanks, I'll let you know if there are any problems.
Cool.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [ath9k-devel] [PATCH v4] ath9k: Switch to using mac80211 intermediate software queues.
@ 2016-10-05 19:56 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-10-05 19:56 UTC (permalink / raw)
To: ath9k-devel
Kalle Valo <kvalo@codeaurora.org> writes:
> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>
>>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>>
>>>> Kalle Valo <kvalo@codeaurora.org> writes:
>>>>
>>>>> Toke H?iland-J?rgensen <toke@toke.dk> writes:
>>>>>
>>>>> I understand your point, but I don't want to rush this to 4.9 and then
>>>>> start getting lots of bug reports and eventually forced to revert it. If
>>>>> we just found a new serious regression the chances are that there are
>>>>> more lurking somewhere and this patch is just not ready yet.
>>>>
>>>> So, the changes to mac80211 that fixes the known regressions of this
>>>> patch have gone in.
>>>
>>> I guess you mean this commit:
>>>
>>> bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue
>>>
>>> (Just making sure that I have the same commit in my tree when I apply
>>> this)
>>
>> Yup, that's the one :)
>>
>>>> Any chance of seeing this merged during the current merge window? :)
>>>
>>> I sent last new feature ("-next") patches for 4.9 last week, sorry. So
>>> this has to wait for 4.10.
>>
>> Ah, right, I think I got my merge windows confused. You already said you
>> wouldn't take it for 4.9. So I guess what I'm asking is for you to put
>> it into the appropriate -next tree so it can get some wider exposure
>> ahead of the *next* merge window...
>
> Yeah, we have plenty of time for 4.10 :) So my plan is to apply this
> after I open wireless-drivers-next in 2-3 weeks or so. That would mean
> that the patch would hit Linus' tree when 4.10-rc1 is released
> (estimated to happen on 2017-01-01). The timing is actually perfect as
> now we get maximal testing time on -next.
So the -next trees are those that are open outside the merge window.
Right, got it; thanks :)
>>> And I assume I need to take v5:
>>>
>>> https://patchwork.kernel.org/patch/9311037/
>>
>> Yes. Haven't noticed anything that changed since that might conflict
>> with it, but let me know if I missed something and you want a refreshed
>> version.
>
> Thanks, I'll let you know if there are any problems.
Cool.
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* [PATCH v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-08-05 16:05 ` [ath9k-devel] " Toke Høiland-Jørgensen
(?)
(?)
@ 2016-09-02 14:00 ` Toke Høiland-Jørgensen
2016-09-03 10:16 ` Felix Fietkau
` (3 more replies)
-1 siblings, 4 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-09-02 14:00 UTC (permalink / raw)
To: make-wifi-fast, linux-wireless
Cc: Toke Høiland-Jørgensen, Tim Shepard, Felix Fietkau
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
Based on Tim's original patch set, but reworked quite thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
---
Changes since v4:
- Fix regression where PS response frames (which go through the old TX
path) would not get assigned a seqno because the tid variable was not
assigned correctly. Many thanks to Felix for debugging this and coming
up with a fix.
Hopefully that is the last regression (apart from the ongoing mac80211
restructure). :)
drivers/net/wireless/ath/ath9k/ath9k.h | 27 ++-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 9 +-
drivers/net/wireless/ath/ath9k/xmit.c | 338 ++++++++++++-----------=
------
8 files changed, 163 insertions(+), 235 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireles=
s/ath/ath9k/ath9k.h
index 26fc8ec..378d345 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_=
descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
=20
@@ -145,7 +144,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct at=
h_descdma *dd,
#define BAW_WITHIN(_start, _bawsz, _seqno) \
((((_seqno) - (_start)) & 4095) < (_bawsz))
=20
-#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
+#define ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno)
=20
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >=3D 0x18) && (rate <=3D 0x1e))
@@ -164,7 +163,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +230,6 @@ struct ath_buf {
=20
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +244,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
=20
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];
=20
u16 maxampdu;
u8 mpdudensity;
@@ -276,7 +273,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
=20
=20
@@ -293,7 +289,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
=20
@@ -421,6 +416,22 @@ struct ath_offchannel {
int duration;
};
=20
+static inline struct ath_atx_tid *
+ath_node_to_tid(struct ath_node *an, u8 tidno)
+{
+ struct ieee80211_sta *sta =3D an->sta;
+ struct ieee80211_vif *vif =3D an->vif;
+ struct ieee80211_txq *txq;
+
+ BUG_ON(!vif);
+ if (sta)
+ txq =3D sta->txq[tidno % ARRAY_SIZE(sta->txq)];
+ else
+ txq =3D vif->txq;
+
+ return (struct ath_atx_tid *) txq->drv_priv;
+}
+
#define case_rtn_string(val) case val: return #val
=20
#define ath_for_each_chanctx(_sc, _ctx) \
@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u=
16 tid);
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,=
u16 tid);
=20
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@@ -585,6 +595,7 @@ void ath9k_release_buffered_frames(struct ieee80211_h=
w *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 *=
queue);
=20
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wirel=
ess/ath/ath9k/channel.c
index 57e26a6..929dd70 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1010,7 +1010,6 @@ static void ath_scan_send_probe(struct ath_softc *s=
c,
goto error;
=20
txctl.txq =3D sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel =3D true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
=20
@@ -1133,7 +1132,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc,=
struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq =3D sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta =3D sta;
- txctl.force_channel =3D true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireles=
s/ath/ath9k/debug.c
index c56e40f..89a94dd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void=
*data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct =
ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
=20
ath_txq_unlock(sc, txq);
}
@@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRIN=
G_LEN] =3D {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireles=
s/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wir=
eless/ath/ath9k/debug_sta.c
index b66cfa9..2a3a3c4 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ static ssize_t read_file_node_aggr(struct file *file, c=
har __user *user_buf,
"TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless=
/ath/ath9k/init.c
index cfa3fe8..96bba17 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i =3D 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] =3D ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum =3D i;
- sc->tx.txq_max_pending[i] =3D ATH_MAX_QDEPTH;
}
return 0;
}
@@ -877,6 +876,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, =
struct ieee80211_hw *hw)
hw->max_rate_tries =3D 10;
hw->sta_data_size =3D sizeof(struct ath_node);
hw->vif_data_size =3D sizeof(struct ath_vif);
+ hw->txq_data_size =3D sizeof(struct ath_atx_tid);
hw->extra_tx_headroom =3D 4;
=20
hw->wiphy->available_antennas_rx =3D 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 a394622..1dedf13 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1896,9 +1896,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw =
*hw,
bool flush =3D false;
int ret =3D 0;
struct ieee80211_sta *sta =3D params->sta;
+ struct ath_node *an =3D (struct ath_node *)sta->drv_priv;
enum ieee80211_ampdu_mlme_action action =3D params->action;
u16 tid =3D params->tid;
u16 *ssn =3D ¶ms->ssn;
+ struct ath_atx_tid *atid;
=20
mutex_lock(&sc->mutex);
=20
@@ -1931,9 +1933,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *=
hw,
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- ath9k_ps_wakeup(sc);
- ath_tx_aggr_resume(sc, sta, tid);
- ath9k_ps_restore(sc);
+ atid =3D ath_node_to_tid(an, tid);
+ atid->baw_size =3D IEEE80211_MIN_AMPDU_BUF <<
+ sta->ht_cap.ampdu_factor;
break;
default:
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
@@ -2695,4 +2697,5 @@ struct ieee80211_ops ath9k_ops =3D {
.sw_scan_start =3D ath9k_sw_scan_start,
.sw_scan_complete =3D ath9k_sw_scan_complete,
.get_txpower =3D ath9k_get_txpower,
+ .wake_tx_queue =3D ath9k_wake_tx_queue,
};
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless=
/ath/ath9k/xmit.c
index 8ddd604..c074747 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_s=
oftc *sc,
struct ath_txq *txq,
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);
=20
enum {
MCS_HT20,
@@ -118,6 +120,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, s=
truct ath_txq *txq,
list_add_tail(&tid->list, list);
}
=20
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *=
queue)
+{
+ struct ath_softc *sc =3D hw->priv;
+ struct ath_common *common =3D ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid =3D (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq =3D tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued =3D true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info =3D IEEE80211_SKB_CB(skb);
@@ -145,7 +167,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, =
struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info =3D IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi =3D get_frame_info(skb);
int q =3D fi->txq;
=20
@@ -156,14 +177,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, s=
truct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames =3D 0;
=20
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped =3D false;
- }
}
=20
static struct ath_atx_tid *
@@ -173,9 +186,48 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_nod=
e *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
=20
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ieee80211_txq *txq =3D container_of((void*)tid, struct ieee80211=
_txq, drv_priv);
+ struct ath_softc *sc =3D tid->an->sc;
+ struct ieee80211_hw *hw =3D sc->hw;
+ struct ath_tx_control txctl =3D {
+ .txq =3D tid->txq,
+ .sta =3D tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb =3D ieee80211_tx_dequeue(hw, txq);
+ if (!skb) {
+ tid->has_queued =3D false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q =3D skb_get_queue_mapping(skb);
+ if (tid->txq =3D=3D sc->tx.txq_map[q]) {
+ fi =3D get_frame_info(skb);
+ fi->txq =3D q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q)=
;
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
=20
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -184,46 +236,11 @@ static struct sk_buff *ath_tid_dequeue(struct ath_a=
tx_tid *tid)
=20
skb =3D __skb_dequeue(&tid->retry_q);
if (!skb)
- skb =3D __skb_dequeue(&tid->buf_q);
+ skb =3D ath_tid_pull(tid);
=20
return skb;
}
=20
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq =3D tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi =3D get_frame_info(skb);
- bf =3D fi->bf;
-
- tx_info =3D IEEE80211_SKB_CB(skb);
- tx_info->flags &=3D ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf =3D ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *t=
id)
{
struct ath_txq *txq =3D tid->txq;
@@ -858,20 +875,16 @@ static int ath_compute_num_delims(struct ath_softc =
*sc, struct ath_atx_tid *tid,
=20
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb =3D NULL;
struct ath_buf *bf;
u16 seqno;
=20
while (1) {
- *q =3D &tid->retry_q;
- if (skb_queue_empty(*q))
- *q =3D &tid->buf_q;
-
- skb =3D skb_peek(*q);
+ skb =3D ath_tid_dequeue(tid);
if (!skb)
break;
=20
@@ -883,7 +896,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct =
ath_txq *txq,
bf->bf_state.stale =3D false;
=20
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -912,8 +924,20 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct=
ath_txq *txq,
seqno =3D bf->bf_state.seqno;
=20
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) &&
+ !WARN_ON(skb =3D=3D first_skb)) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb =3D skb;
+ continue;
+ }
break;
+ }
=20
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts =3D {};
@@ -921,7 +945,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct =
ath_txq *txq,
=20
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
continue;
@@ -933,11 +956,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struc=
t ath_txq *txq,
return NULL;
}
=20
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf =3D bf_first, *bf_prev =3D NULL;
@@ -947,12 +969,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_t=
xq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed =3D false;
+
=20
bf =3D bf_first;
aggr_limit =3D ath_lookup_rate(sc, bf, tid);
=20
- do {
+ while (bf)
+ {
skb =3D bf->bf_mpdu;
fi =3D get_frame_info(skb);
=20
@@ -961,12 +984,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_t=
xq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >=3D h_baw)
- break;
+ goto stop;
=20
tx_info =3D IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
=20
/* add padding for previous frame to aggregation length */
@@ -988,20 +1011,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_=
txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim =3D ndelim;
=20
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next =3D bf;
=20
bf_prev =3D bf;
=20
- bf =3D ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed =3D true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf =3D ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf =3D bf_first;
bf->bf_lastbf =3D bf_prev;
=20
@@ -1012,9 +1033,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_t=
xq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
=20
- *aggr_len =3D al;
-
- return closed;
+ return al;
#undef PADBYTES
}
=20
@@ -1391,18 +1410,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc=
, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf =3D bf_first, *bf_prev =3D NULL;
- struct sk_buff *skb;
int nframes =3D 0;
=20
do {
struct ieee80211_tx_info *tx_info;
- skb =3D bf->bf_mpdu;
=20
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next =3D bf;
@@ -1411,13 +1427,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct at=
h_txq *txq,
if (nframes >=3D 2)
break;
=20
- bf =3D ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf =3D ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
=20
tx_info =3D IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
=20
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1428,34 +1446,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *s=
c, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len =3D 0;
- bool aggr, last =3D true;
+ bool aggr;
=20
if (!ath_tid_has_buffered(tid))
return false;
=20
INIT_LIST_HEAD(&bf_q);
=20
- bf =3D ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf =3D ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
=20
tx_info =3D IEEE80211_SKB_CB(bf->bf_mpdu);
aggr =3D !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >=3D ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >=3D ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >=3D ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop =3D true;
return false;
}
=20
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last =3D ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len =3D ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
=20
if (list_empty(&bf_q))
return false;
@@ -1498,9 +1515,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct =
ieee80211_sta *sta,
an->mpdudensity =3D density;
}
=20
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active =3D true;
*ssn =3D txtid->seq_start =3D txtid->seq_next;
txtid->bar_index =3D -1;
@@ -1525,7 +1539,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct =
ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active =3D false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
=20
@@ -1535,14 +1548,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta,=
struct ath_softc *sc,
struct ath_common *common =3D ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
int tidno;
=20
ath_dbg(common, XMIT, "%s called\n", __func__);
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
=20
ath_txq_lock(sc, txq);
@@ -1552,13 +1563,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta,=
struct ath_softc *sc,
continue;
}
=20
- buffered =3D ath_tid_has_buffered(tid);
+ if (!skb_queue_empty(&tid->retry_q))
+ ieee80211_sta_set_buffered(sta, tid->tidno, true);
=20
list_del_init(&tid->list);
=20
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
=20
@@ -1571,49 +1581,20 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, str=
uct ath_node *an)
=20
ath_dbg(common, XMIT, "%s called\n", __func__);
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
=20
ath_txq_lock(sc, txq);
tid->clear_ps_filter =3D true;
-
if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq);
}
-
ath_txq_unlock_complete(sc, txq);
}
}
=20
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tidno)
-{
- struct ath_common *common =3D ath9k_hw_common(sc->sc_ah);
- struct ath_atx_tid *tid;
- struct ath_node *an;
- struct ath_txq *txq;
-
- ath_dbg(common, XMIT, "%s called\n", __func__);
-
- an =3D (struct ath_node *)sta->drv_priv;
- tid =3D ATH_AN_2_TID(an, tidno);
- txq =3D tid->txq;
-
- ath_txq_lock(sc, txq);
-
- tid->baw_size =3D IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
- ath_txq_unlock_complete(sc, txq);
-}
-
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@@ -1626,7 +1607,6 @@ void ath9k_release_buffered_frames(struct ieee80211=
_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail =3D NULL, *bf;
- struct sk_buff_head *tid_q;
int sent =3D 0;
int i;
=20
@@ -1641,11 +1621,10 @@ void ath9k_release_buffered_frames(struct ieee802=
11_hw *hw,
=20
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf =3D ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf =3D ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
=20
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1660,7 +1639,7 @@ void ath9k_release_buffered_frames(struct ieee80211=
_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
=20
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1887,13 +1866,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
=20
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq =3D &sc->tx.txq[i];
- txq->stopped =3D false;
ath_draintxq(sc, txq);
}
=20
@@ -2292,16 +2265,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct =
sk_buff *skb,
struct ath_softc *sc =3D hw->priv;
struct ath_txq *txq =3D txctl->txq;
struct ath_atx_tid *tid =3D NULL;
+ struct ath_node *an =3D NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd =3D false, ps_resp;
+ bool ps_resp;
int q, ret;
=20
if (vif)
avp =3D (void *)vif->drv_priv;
=20
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel =3D true;
-
ps_resp =3D !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
=20
ret =3D ath_tx_prepare(hw, skb, txctl);
@@ -2316,63 +2287,18 @@ int ath_tx_start(struct ieee80211_hw *hw, struct =
sk_buff *skb,
=20
q =3D skb_get_queue_mapping(skb);
=20
- ath_txq_lock(sc, txq);
- if (txq =3D=3D sc->tx.txq_map[q]) {
- fi->txq =3D q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped =3D true;
- }
- }
-
- queue =3D ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue =3D true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx !=3D sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an =3D &avp->mcast_node;
- queue =3D true;
- skip_uapsd =3D true;
- }
-
- if (txctl->an && queue)
- tid =3D ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
+ if (ps_resp)
txq =3D sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq !=3D txctl->txq);
=20
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter =3D true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
+ if (txctl->sta) {
+ an =3D (struct ath_node *) sta->drv_priv;
+ tid =3D ath_get_skb_tid(sc, an, skb);
+ }
=20
- ath_txq_schedule(sc, txq);
- goto out;
+ ath_txq_lock(sc, txq);
+ if (txq =3D=3D sc->tx.txq_map[q]) {
+ fi->txq =3D q;
+ ++txq->pending_frames;
}
=20
bf =3D ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2856,9 +2782,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct =
ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
tid->an =3D an;
tid->tidno =3D tidno;
tid->seq_start =3D tid->seq_next =3D 0;
@@ -2866,11 +2791,14 @@ void ath_tx_node_init(struct ath_softc *sc, struc=
t ath_node *an)
tid->baw_head =3D tid->baw_tail =3D 0;
tid->active =3D false;
tid->clear_ps_filter =3D true;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued =3D false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno =3D TID_TO_WME_AC(tidno);
tid->txq =3D sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
=20
@@ -2880,9 +2808,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, stru=
ct ath_node *an)
struct ath_txq *txq;
int tidno;
=20
- for (tidno =3D 0, tid =3D &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno =3D 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid =3D ath_node_to_tid(an, tidno);
txq =3D tid->txq;
=20
ath_txq_lock(sc, txq);
@@ -2894,6 +2821,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, stru=
ct ath_node *an)
tid->active =3D false;
=20
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
=20
--=20
2.9.3
^ permalink raw reply related [flat|nested] 118+ messages in thread
* Re: [PATCH v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-09-02 14:00 ` [PATCH v5] " Toke Høiland-Jørgensen
@ 2016-09-03 10:16 ` Felix Fietkau
2016-10-07 11:43 ` [v5] " Kalle Valo
` (2 subsequent siblings)
3 siblings, 0 replies; 118+ messages in thread
From: Felix Fietkau @ 2016-09-03 10:16 UTC (permalink / raw)
To: Toke Høiland-Jørgensen, make-wifi-fast, linux-wireless
Cc: Tim Shepard
On 2016-09-02 16:00, Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
You can add:
Signed-off-by: Felix Fietkau <nbd@nbd.name>
- Felix
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-09-02 14:00 ` [PATCH v5] " Toke Høiland-Jørgensen
2016-09-03 10:16 ` Felix Fietkau
@ 2016-10-07 11:43 ` Kalle Valo
2016-11-09 2:22 ` Kalle Valo
2016-11-09 11:31 ` [PATCH v6] " Toke Høiland-Jørgensen
3 siblings, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-10-07 11:43 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: make-wifi-fast, linux-wireless, Toke Høiland-Jørgensen,
Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
Depends on:
bb42f2d13ffc mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue
Patch set to Awaiting Upstream.
--
https://patchwork.kernel.org/patch/9311037/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-09-02 14:00 ` [PATCH v5] " Toke Høiland-Jørgensen
2016-09-03 10:16 ` Felix Fietkau
2016-10-07 11:43 ` [v5] " Kalle Valo
@ 2016-11-09 2:22 ` Kalle Valo
2016-11-09 2:44 ` Tim Shepard
2016-11-09 11:31 ` [PATCH v6] " Toke Høiland-Jørgensen
3 siblings, 1 reply; 118+ messages in thread
From: Kalle Valo @ 2016-11-09 2:22 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: make-wifi-fast, linux-wireless, Toke Høiland-Jørgensen,
Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> Based on Tim's original patch set, but reworked quite thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
> Signed-off-by: Felix Fietkau <nbd@nbd.name>
All dependencies have trickled down to ath.git but unfortunately doesn't apply
anymore, so please rebase. Hopefully the last time :)
While at it, could you also add to the commit log some info how awesome this
patch is from user's point of view and how it helps. For example, before and
and after numbers and other results.
error: patch failed: drivers/net/wireless/ath/ath9k/xmit.c:921
error: drivers/net/wireless/ath/ath9k/xmit.c: patch does not apply
stg import: Diff does not apply cleanly
Patch set to Changes Requested.
--
https://patchwork.kernel.org/patch/9311037/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-11-09 2:22 ` Kalle Valo
@ 2016-11-09 2:44 ` Tim Shepard
2016-11-09 10:42 ` Toke Høiland-Jørgensen
0 siblings, 1 reply; 118+ messages in thread
From: Tim Shepard @ 2016-11-09 2:44 UTC (permalink / raw)
To: Kalle Valo
Cc: Toke Høiland-Jørgensen, make-wifi-fast, linux-wireless,
Felix Fietkau
> While at it, could you also add to the commit log some info how awesome this
> patch is from user's point of view and how it helps. For example, before and
> and after numbers and other results.
That varies wildly, depending on many details of the scenario
(including the wireless capabilities of the clients connected to the
AP using this patch, and how far away those clients are). There's
really not enough room in a commit message to explain enough to make
any such claimed numbers reproducible.
And, BTW, this patch alone is not really where the big improvement
comes from. This just cuts ath9k over to use the new
transmit-a-packet interface between the mac80211 layer and the
wireless device driver. All the good work to improve latency is being
done on the new mac80211 interface to the driver to transmit a packet.
If you want numbers in a commit message, those numbers belong over on
those commits, not on this ath9k commit, IMHO.
And there's different patches that taken together achieve the best
improvement, and in various subsets differing amounts of improvement,
which again all depends on the scenarios.
And all this is complicated by how often real users are involved in
scenarios where this matters (hard to say).
This mainly improves things when you have an ath9k interface with
packets queued simultaneously to different wireless destinations,
which is typically when the ath9k interface is serving as an AP.
And I would expect similar improvements for any wireless driver cut
over to use the new mac80211 interface. (This patch might be a
helpful guide to other wireless driver maintainers wishing to see the
same improvements other wireless drivers.)
I hope that the above paragraphs were helpful.
-Tim Shepard
shep@alum.mit.edu
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-11-09 2:44 ` Tim Shepard
@ 2016-11-09 10:42 ` Toke Høiland-Jørgensen
2016-11-09 20:07 ` Valo, Kalle
0 siblings, 1 reply; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-11-09 10:42 UTC (permalink / raw)
To: Tim Shepard; +Cc: Kalle Valo, make-wifi-fast, linux-wireless, Felix Fietkau
Tim Shepard <shep@alum.mit.edu> writes:
>> While at it, could you also add to the commit log some info how awesome this
>> patch is from user's point of view and how it helps. For example, before and
>> and after numbers and other results.
>
> That varies wildly, depending on many details of the scenario
> (including the wireless capabilities of the clients connected to the
> AP using this patch, and how far away those clients are). There's
> really not enough room in a commit message to explain enough to make
> any such claimed numbers reproducible.
I disagree; it's quite straightforward to demonstrate a gain from this
on an ath9k access point. And while of course the mac80211 queues is the
reason for this, the commit that uses it (i.e. this one) can explain
that and include some numbers. I'll add that and resend :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v5] ath9k: Switch to using mac80211 intermediate software queues.
2016-11-09 10:42 ` Toke Høiland-Jørgensen
@ 2016-11-09 20:07 ` Valo, Kalle
0 siblings, 0 replies; 118+ messages in thread
From: Valo, Kalle @ 2016-11-09 20:07 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: Tim Shepard, make-wifi-fast, linux-wireless, nbd
VG9rZSBIw7hpbGFuZC1Kw7hyZ2Vuc2VuIDx0b2tlQHRva2UuZGs+IHdyaXRlczoNCg0KPiBUaW0g
U2hlcGFyZCA8c2hlcEBhbHVtLm1pdC5lZHU+IHdyaXRlczoNCj4NCj4+PiBXaGlsZSBhdCBpdCwg
Y291bGQgeW91IGFsc28gYWRkIHRvIHRoZSBjb21taXQgbG9nIHNvbWUgaW5mbyBob3cgYXdlc29t
ZSB0aGlzDQo+Pj4gcGF0Y2ggaXMgZnJvbSB1c2VyJ3MgcG9pbnQgb2YgdmlldyBhbmQgaG93IGl0
IGhlbHBzLiBGb3IgZXhhbXBsZSwgYmVmb3JlIGFuZA0KPj4+IGFuZCBhZnRlciBudW1iZXJzIGFu
ZCBvdGhlciByZXN1bHRzLg0KPj4NCj4+IFRoYXQgdmFyaWVzIHdpbGRseSwgZGVwZW5kaW5nIG9u
IG1hbnkgZGV0YWlscyBvZiB0aGUgc2NlbmFyaW8NCj4+IChpbmNsdWRpbmcgdGhlIHdpcmVsZXNz
IGNhcGFiaWxpdGllcyBvZiB0aGUgY2xpZW50cyBjb25uZWN0ZWQgdG8gdGhlDQo+PiBBUCB1c2lu
ZyB0aGlzIHBhdGNoLCBhbmQgaG93IGZhciBhd2F5IHRob3NlIGNsaWVudHMgYXJlKS4gVGhlcmUn
cw0KPj4gcmVhbGx5IG5vdCBlbm91Z2ggcm9vbSBpbiBhIGNvbW1pdCBtZXNzYWdlIHRvIGV4cGxh
aW4gZW5vdWdoIHRvIG1ha2UNCj4+IGFueSBzdWNoIGNsYWltZWQgbnVtYmVycyByZXByb2R1Y2li
bGUuDQo+DQo+IEkgZGlzYWdyZWU7IGl0J3MgcXVpdGUgc3RyYWlnaHRmb3J3YXJkIHRvIGRlbW9u
c3RyYXRlIGEgZ2FpbiBmcm9tIHRoaXMNCj4gb24gYW4gYXRoOWsgYWNjZXNzIHBvaW50LiBBbmQg
d2hpbGUgb2YgY291cnNlIHRoZSBtYWM4MDIxMSBxdWV1ZXMgaXMgdGhlDQo+IHJlYXNvbiBmb3Ig
dGhpcywgdGhlIGNvbW1pdCB0aGF0IHVzZXMgaXQgKGkuZS4gdGhpcyBvbmUpIGNhbiBleHBsYWlu
DQo+IHRoYXQgYW5kIGluY2x1ZGUgc29tZSBudW1iZXJzLg0KDQpZZWFoLCBzbyB3aXRoIHRoYXQg
eW91IGFyZSBiYXNpY2FsbHkgYW5zd2VyaW5nICJXaHk/IiBwYXJ0IGluIHRoZSBjb21taXQNCmxv
ZyBzbyB0aGF0IG90aGVycyBjYW4gYWxzbyB1bmRlcnN0YW5kIHRoZSBtb3RpdmF0aW9uIGJlaGlu
ZCBhbGwgdGhpcy4NCg0KPiBJJ2xsIGFkZCB0aGF0IGFuZCByZXNlbmQgOikNCg0KVGhhbmtzLiBB
bmQgc29ycnkgZm9yIHRha2luZyBzbyBsb25nIHdpdGggdGhpcywgSSBoYXZlIGJlZW4gYmFzaWNh
bGx5DQp0cmF2ZWxsaW5nIG1vc3Qgb2YgdGhlIGxhc3QgbW9udGguIEkgc2hvdWxkIGdldCBiYWNr
IGhvbWUgb24gRnJpZGF5IGFuZA0KdGhpbmdzIHNob3VsZCBnZXQgbm9ybWFsIHNvb24uDQoNCi0t
IA0KS2FsbGUgVmFsbw==
^ permalink raw reply [flat|nested] 118+ messages in thread
* [PATCH v6] ath9k: Switch to using mac80211 intermediate software queues.
2016-09-02 14:00 ` [PATCH v5] " Toke Høiland-Jørgensen
` (2 preceding siblings ...)
2016-11-09 2:22 ` Kalle Valo
@ 2016-11-09 11:31 ` Toke Høiland-Jørgensen
2016-11-09 22:42 ` [v6] " Kalle Valo
2016-11-15 15:00 ` Kalle Valo
3 siblings, 2 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-11-09 11:31 UTC (permalink / raw)
To: make-wifi-fast, linux-wireless
Cc: Toke Høiland-Jørgensen, Tim Shepard, Felix Fietkau
This switches ath9k over to using the mac80211 intermediate software
queueing mechanism for data packets. It removes the queueing inside the
driver, except for the retry queue, and instead pulls from mac80211 when
a packet is needed. The retry queue is used to store a packet that was
pulled but can't be sent immediately.
The old code path in ath_tx_start that would queue packets has been
removed completely, as has the qlen limit tunables (since there's no
longer a queue in the driver to limit).
The mac80211 intermediate software queues offer significant latency
reductions, and this patch allows ath9k to realise them. The exact gains
from this varies with the test scenario, but in an access point scenario
we have seen latency reductions ranging from 1/3 to as much as an order
of magnitude. We also achieve slightly better aggregation.
Median latency (ping) figures with this patch applied at the access point,
with two high-rate stations and one low-rate station (HT20 5Ghz), running
a Flent rtt_fair_var_up test with one TCP flow and one ping flow going to
each station:
Fast station Slow station
Default pfifo_fast qdisc: 430.4 ms 638.7 ms
fq_codel qdisc on iface: 35.5 ms 211.8 ms
This patch set: 22.4 ms 38.2 ms
Median aggregation sizes over the same test:
Default pfifo_fast qdisc: 9.5 pkts 1.9 pkts
fq_codel qdisc on iface: 11.2 pkts 1.9 pkts
This patch set: 13.9 pkts 1.9 pkts
This patch is based on Tim's original patch set, but reworked quite
thoroughly.
Cc: Tim Shepard <shep@alum.mit.edu>
Cc: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
---
Changes since v5:
- Rebase on ath-next, add performance numbers to commit message
drivers/net/wireless/ath/ath9k/ath9k.h | 27 ++-
drivers/net/wireless/ath/ath9k/channel.c | 2 -
drivers/net/wireless/ath/ath9k/debug.c | 14 +-
drivers/net/wireless/ath/ath9k/debug.h | 2 -
drivers/net/wireless/ath/ath9k/debug_sta.c | 4 +-
drivers/net/wireless/ath/ath9k/init.c | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 9 +-
drivers/net/wireless/ath/ath9k/xmit.c | 338 ++++++++++++-----------------
8 files changed, 163 insertions(+), 235 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 26fc8ec..378d345 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_RXBUF 512
#define ATH_TXBUF 512
#define ATH_TXBUF_RESERVE 5
-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MAX_SW_RETRIES 30
@@ -145,7 +144,7 @@ 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 ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno)
#define IS_HT_RATE(rate) (rate & 0x80)
#define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e))
@@ -164,7 +163,6 @@ struct ath_txq {
spinlock_t axq_lock;
u32 axq_depth;
u32 axq_ampdu_depth;
- bool stopped;
bool axq_tx_inprogress;
struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
u8 txq_headidx;
@@ -232,7 +230,6 @@ struct ath_buf {
struct ath_atx_tid {
struct list_head list;
- struct sk_buff_head buf_q;
struct sk_buff_head retry_q;
struct ath_node *an;
struct ath_txq *txq;
@@ -247,13 +244,13 @@ struct ath_atx_tid {
s8 bar_index;
bool active;
bool clear_ps_filter;
+ bool has_queued;
};
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;
@@ -276,7 +273,6 @@ struct ath_tx_control {
struct ath_node *an;
struct ieee80211_sta *sta;
u8 paprd;
- bool force_channel;
};
@@ -293,7 +289,6 @@ struct ath_tx {
struct ath_descdma txdma;
struct ath_txq *txq_map[IEEE80211_NUM_ACS];
struct ath_txq *uapsdq;
- u32 txq_max_pending[IEEE80211_NUM_ACS];
u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
};
@@ -421,6 +416,22 @@ struct ath_offchannel {
int duration;
};
+static inline struct ath_atx_tid *
+ath_node_to_tid(struct ath_node *an, u8 tidno)
+{
+ struct ieee80211_sta *sta = an->sta;
+ struct ieee80211_vif *vif = an->vif;
+ struct ieee80211_txq *txq;
+
+ BUG_ON(!vif);
+ if (sta)
+ txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)];
+ else
+ txq = vif->txq;
+
+ return (struct ath_atx_tid *) txq->drv_priv;
+}
+
#define case_rtn_string(val) case val: return #val
#define ath_for_each_chanctx(_sc, _ctx) \
@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_softc *sc);
int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
@@ -585,6 +595,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 *queue);
/********/
/* VIFs */
diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c
index 57e26a6..929dd70 100644
--- a/drivers/net/wireless/ath/ath9k/channel.c
+++ b/drivers/net/wireless/ath/ath9k/channel.c
@@ -1010,7 +1010,6 @@ static void ath_scan_send_probe(struct ath_softc *sc,
goto error;
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl))
goto error;
@@ -1133,7 +1132,6 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
memset(&txctl, 0, sizeof(txctl));
txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
txctl.sta = sta;
- txctl.force_channel = true;
if (ath_tx_start(sc->hw, skb, &txctl)) {
ieee80211_free_txskb(sc->hw, skb);
return false;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index c56e40f..89a94dd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_file *file, void *data)
PR("MPDUs XRetried: ", xretries);
PR("Aggregates: ", a_aggr);
PR("AMPDUs Queued HW:", a_queued_hw);
- PR("AMPDUs Queued SW:", a_queued_sw);
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum);
seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth);
seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth);
- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames);
- seq_printf(file, "%s: %d\n", "stopped", txq->stopped);
+ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames);
ath_txq_unlock(sc, txq);
}
@@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_mpdu_xretries),
AMKSTR(d_tx_aggregates),
AMKSTR(d_tx_ampdus_queued_hw),
- AMKSTR(d_tx_ampdus_queued_sw),
AMKSTR(d_tx_ampdus_completed),
AMKSTR(d_tx_ampdu_retries),
AMKSTR(d_tx_ampdu_xretries),
@@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(xretries);
AWDATA(a_aggr);
AWDATA(a_queued_hw);
- AWDATA(a_queued_sw);
AWDATA(a_completed);
AWDATA(a_retries);
AWDATA(a_xretries);
@@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah)
read_file_xmit);
debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
read_file_queues);
- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
- &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
read_file_misc);
debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index cd68c5f..a078cdd 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -147,7 +147,6 @@ struct ath_interrupt_stats {
* @completed: Total MPDUs (non-aggr) completed
* @a_aggr: Total no. of aggregates queued
* @a_queued_hw: Total AMPDUs queued to hardware
- * @a_queued_sw: Total AMPDUs queued to software queues
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
@@ -174,7 +173,6 @@ struct ath_tx_stats {
u32 xretries;
u32 a_aggr;
u32 a_queued_hw;
- u32 a_queued_sw;
u32 a_completed;
u32 a_retries;
u32 a_xretries;
diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c
index b66cfa9..2a3a3c4 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -52,8 +52,8 @@ 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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
if (tid->active) {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index cfa3fe8..96bba17 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
sc->tx.txq_map[i]->mac80211_qnum = i;
- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
}
return 0;
}
@@ -877,6 +876,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 e9f32b5..59e3bd0 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1902,9 +1902,11 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
bool flush = false;
int ret = 0;
struct ieee80211_sta *sta = params->sta;
+ struct ath_node *an = (struct ath_node *)sta->drv_priv;
enum ieee80211_ampdu_mlme_action action = params->action;
u16 tid = params->tid;
u16 *ssn = ¶ms->ssn;
+ struct ath_atx_tid *atid;
mutex_lock(&sc->mutex);
@@ -1937,9 +1939,9 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
ath9k_ps_restore(sc);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
- ath9k_ps_wakeup(sc);
- ath_tx_aggr_resume(sc, sta, tid);
- ath9k_ps_restore(sc);
+ atid = ath_node_to_tid(an, tid);
+ atid->baw_size = IEEE80211_MIN_AMPDU_BUF <<
+ sta->ht_cap.ampdu_factor;
break;
default:
ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n");
@@ -2701,4 +2703,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 52bfbb9..486afa9 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -67,6 +67,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
struct ath_txq *txq,
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,
@@ -137,6 +139,26 @@ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq,
list_add_tail(&tid->list, list);
}
+void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
+ struct ath_txq *txq = tid->txq;
+
+ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
+ queue->sta ? queue->sta->addr : queue->vif->addr,
+ tid->tidno);
+
+ ath_txq_lock(sc, txq);
+
+ tid->has_queued = true;
+ ath_tx_queue_tid(sc, txq, tid);
+ ath_txq_schedule(sc, txq);
+
+ ath_txq_unlock(sc, txq);
+}
+
static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -164,7 +186,6 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
struct sk_buff *skb)
{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_frame_info *fi = get_frame_info(skb);
int q = fi->txq;
@@ -175,14 +196,6 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
if (WARN_ON(--txq->pending_frames < 0))
txq->pending_frames = 0;
- if (txq->stopped &&
- txq->pending_frames < sc->tx.txq_max_pending[q]) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_wake_queue(sc->hw, info->hw_queue);
- else
- ieee80211_wake_queue(sc->hw, q);
- txq->stopped = false;
- }
}
static struct ath_atx_tid *
@@ -192,9 +205,48 @@ ath_get_skb_tid(struct ath_softc *sc, struct ath_node *an, struct sk_buff *skb)
return ATH_AN_2_TID(an, tidno);
}
+static struct sk_buff *
+ath_tid_pull(struct ath_atx_tid *tid)
+{
+ struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv);
+ struct ath_softc *sc = tid->an->sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_control txctl = {
+ .txq = tid->txq,
+ .sta = tid->an->sta,
+ };
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ int q;
+
+ if (!tid->has_queued)
+ return NULL;
+
+ skb = ieee80211_tx_dequeue(hw, txq);
+ if (!skb) {
+ tid->has_queued = false;
+ return NULL;
+ }
+
+ if (ath_tx_prepare(hw, skb, &txctl)) {
+ ieee80211_free_txskb(hw, skb);
+ return NULL;
+ }
+
+ q = skb_get_queue_mapping(skb);
+ if (tid->txq == sc->tx.txq_map[q]) {
+ fi = get_frame_info(skb);
+ fi->txq = q;
+ ++tid->txq->pending_frames;
+ }
+
+ return skb;
+ }
+
+
static bool ath_tid_has_buffered(struct ath_atx_tid *tid)
{
- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q);
+ return !skb_queue_empty(&tid->retry_q) || tid->has_queued;
}
static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid)
@@ -203,46 +255,11 @@ 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);
+ skb = ath_tid_pull(tid);
return skb;
}
-/*
- * ath_tx_tid_change_state:
- * - clears a-mpdu flag of previous session
- * - force sequence number allocation to fix next BlockAck Window
- */
-static void
-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid)
-{
- struct ath_txq *txq = tid->txq;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb, *tskb;
- struct ath_buf *bf;
- struct ath_frame_info *fi;
-
- skb_queue_walk_safe(&tid->buf_q, skb, tskb) {
- fi = get_frame_info(skb);
- bf = fi->bf;
-
- tx_info = IEEE80211_SKB_CB(skb);
- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-
- if (bf)
- continue;
-
- bf = ath_tx_setup_buffer(sc, txq, tid, skb);
- if (!bf) {
- __skb_unlink(skb, &tid->buf_q);
- ath_txq_skb_done(sc, txq, skb);
- ieee80211_free_txskb(sc->hw, skb);
- continue;
- }
- }
-
-}
-
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->txq;
@@ -883,20 +900,16 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
static struct ath_buf *
ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
- struct ath_atx_tid *tid, struct sk_buff_head **q)
+ struct ath_atx_tid *tid)
{
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
- struct sk_buff *skb;
+ struct sk_buff *skb, *first_skb = NULL;
struct ath_buf *bf;
u16 seqno;
while (1) {
- *q = &tid->retry_q;
- if (skb_queue_empty(*q))
- *q = &tid->buf_q;
-
- skb = skb_peek(*q);
+ skb = ath_tid_dequeue(tid);
if (!skb)
break;
@@ -908,7 +921,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_state.stale = false;
if (!bf) {
- __skb_unlink(skb, *q);
ath_txq_skb_done(sc, txq, skb);
ieee80211_free_txskb(sc->hw, skb);
continue;
@@ -937,8 +949,20 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
seqno = bf->bf_state.seqno;
/* do not step over block-ack window */
- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno))
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) {
+ __skb_queue_tail(&tid->retry_q, skb);
+
+ /* If there are other skbs in the retry q, they are
+ * probably within the BAW, so loop immediately to get
+ * one of them. Otherwise the queue can get stuck. */
+ if (!skb_queue_is_first(&tid->retry_q, skb) &&
+ !WARN_ON(skb == first_skb)) {
+ if(!first_skb) /* infinite loop prevention */
+ first_skb = skb;
+ continue;
+ }
break;
+ }
if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) {
struct ath_tx_status ts = {};
@@ -946,7 +970,6 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
- __skb_unlink(skb, *q);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
continue;
@@ -958,11 +981,10 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
return NULL;
}
-static bool
+static int
ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q,
- int *aggr_len)
+ struct ath_buf *bf_first)
{
#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
struct ath_buf *bf = bf_first, *bf_prev = NULL;
@@ -972,12 +994,13 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ieee80211_tx_info *tx_info;
struct ath_frame_info *fi;
struct sk_buff *skb;
- bool closed = false;
+
bf = bf_first;
aggr_limit = ath_lookup_rate(sc, bf, tid);
- do {
+ while (bf)
+ {
skb = bf->bf_mpdu;
fi = get_frame_info(skb);
@@ -986,12 +1009,12 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (nframes) {
if (aggr_limit < al + bpad + al_delta ||
ath_lookup_legacy(bf) || nframes >= h_baw)
- break;
+ goto stop;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
!(tx_info->flags & IEEE80211_TX_CTL_AMPDU))
- break;
+ goto stop;
}
/* add padding for previous frame to aggregation length */
@@ -1013,20 +1036,18 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
bf_prev = bf;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
- if (!bf) {
- closed = true;
- break;
- }
- } while (ath_tid_has_buffered(tid));
-
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
+ }
+ goto finish;
+stop:
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
+finish:
bf = bf_first;
bf->bf_lastbf = bf_prev;
@@ -1037,9 +1058,7 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
TX_STAT_INC(txq->axq_qnum, a_aggr);
}
- *aggr_len = al;
-
- return closed;
+ return al;
#undef PADBYTES
}
@@ -1416,18 +1435,15 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
static void
ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct list_head *bf_q,
- struct ath_buf *bf_first, struct sk_buff_head *tid_q)
+ struct ath_buf *bf_first)
{
struct ath_buf *bf = bf_first, *bf_prev = NULL;
- struct sk_buff *skb;
int nframes = 0;
do {
struct ieee80211_tx_info *tx_info;
- skb = bf->bf_mpdu;
nframes++;
- __skb_unlink(skb, tid_q);
list_add_tail(&bf->list, bf_q);
if (bf_prev)
bf_prev->bf_next = bf;
@@ -1436,13 +1452,15 @@ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq,
if (nframes >= 2)
break;
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
break;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
break;
+ }
ath_set_rates(tid->an->vif, tid->an->sta, bf);
} while (1);
@@ -1453,34 +1471,33 @@ static bool ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{
struct ath_buf *bf;
struct ieee80211_tx_info *tx_info;
- struct sk_buff_head *tid_q;
struct list_head bf_q;
int aggr_len = 0;
- bool aggr, last = true;
+ bool aggr;
if (!ath_tid_has_buffered(tid))
return false;
INIT_LIST_HEAD(&bf_q);
- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, txq, tid);
if (!bf)
return false;
tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) ||
- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) {
+ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu);
*stop = true;
return false;
}
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (aggr)
- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf,
- tid_q, &aggr_len);
+ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf);
else
- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q);
+ ath_tx_form_burst(sc, txq, tid, &bf_q, bf);
if (list_empty(&bf_q))
return false;
@@ -1523,9 +1540,6 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
an->mpdudensity = density;
}
- /* force sequence number allocation for pending frames */
- ath_tx_tid_change_state(sc, txtid);
-
txtid->active = true;
*ssn = txtid->seq_start = txtid->seq_next;
txtid->bar_index = -1;
@@ -1550,7 +1564,6 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_txq_lock(sc, txq);
txtid->active = false;
ath_tx_flush_tid(sc, txtid);
- ath_tx_tid_change_state(sc, txtid);
ath_txq_unlock_complete(sc, txq);
}
@@ -1560,14 +1573,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_atx_tid *tid;
struct ath_txq *txq;
- bool buffered;
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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -1577,13 +1588,12 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
continue;
}
- buffered = ath_tid_has_buffered(tid);
+ if (!skb_queue_empty(&tid->retry_q))
+ ieee80211_sta_set_buffered(sta, tid->tidno, true);
list_del_init(&tid->list);
ath_txq_unlock(sc, txq);
-
- ieee80211_sta_set_buffered(sta, tidno, buffered);
}
}
@@ -1596,49 +1606,20 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
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++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
tid->clear_ps_filter = true;
-
if (ath_tid_has_buffered(tid)) {
ath_tx_queue_tid(sc, txq, tid);
ath_txq_schedule(sc, txq);
}
-
ath_txq_unlock_complete(sc, txq);
}
}
-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta,
- u16 tidno)
-{
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- struct ath_atx_tid *tid;
- struct ath_node *an;
- struct ath_txq *txq;
-
- ath_dbg(common, XMIT, "%s called\n", __func__);
-
- an = (struct ath_node *)sta->drv_priv;
- tid = ATH_AN_2_TID(an, tidno);
- txq = tid->txq;
-
- ath_txq_lock(sc, txq);
-
- tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor;
-
- if (ath_tid_has_buffered(tid)) {
- ath_tx_queue_tid(sc, txq, tid);
- ath_txq_schedule(sc, txq);
- }
-
- ath_txq_unlock_complete(sc, txq);
-}
-
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@@ -1651,7 +1632,6 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
struct list_head bf_q;
struct ath_buf *bf_tail = NULL, *bf;
- struct sk_buff_head *tid_q;
int sent = 0;
int i;
@@ -1666,11 +1646,10 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
ath_txq_lock(sc, tid->txq);
while (nframes > 0) {
- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q);
+ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid);
if (!bf)
break;
- __skb_unlink(bf->bf_mpdu, tid_q);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
@@ -1685,7 +1664,7 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
sent++;
TX_STAT_INC(txq->axq_qnum, a_queued_hw);
- if (an->sta && !ath_tid_has_buffered(tid))
+ if (an->sta && skb_queue_empty(&tid->retry_q))
ieee80211_sta_set_buffered(an->sta, i, false);
}
ath_txq_unlock_complete(sc, tid->txq);
@@ -1914,13 +1893,7 @@ bool ath_drain_all_txq(struct ath_softc *sc)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- /*
- * The caller will resume queues with ieee80211_wake_queues.
- * Mark the queue as not stopped to prevent ath_tx_complete
- * from waking the queue too early.
- */
txq = &sc->tx.txq[i];
- txq->stopped = false;
ath_draintxq(sc, txq);
}
@@ -2319,16 +2292,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
+ struct ath_node *an = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false, ps_resp;
+ bool ps_resp;
int q, ret;
if (vif)
avp = (void *)vif->drv_priv;
- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
- txctl->force_channel = true;
-
ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
ret = ath_tx_prepare(hw, skb, txctl);
@@ -2343,63 +2314,18 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
q = skb_get_queue_mapping(skb);
- ath_txq_lock(sc, txq);
- if (txq == sc->tx.txq_map[q]) {
- fi->txq = q;
- if (++txq->pending_frames > sc->tx.txq_max_pending[q] &&
- !txq->stopped) {
- if (ath9k_is_chanctx_enabled())
- ieee80211_stop_queue(sc->hw, info->hw_queue);
- else
- ieee80211_stop_queue(sc->hw, q);
- txq->stopped = true;
- }
- }
-
- queue = ieee80211_is_data_present(hdr->frame_control);
-
- /* If chanctx, queue all null frames while NOA could be there */
- if (ath9k_is_chanctx_enabled() &&
- ieee80211_is_nullfunc(hdr->frame_control) &&
- !txctl->force_channel)
- queue = true;
-
- /* Force queueing of all frames that belong to a virtual interface on
- * a different channel context, to ensure that they are sent on the
- * correct channel.
- */
- if (((avp && avp->chanctx != sc->cur_chan) ||
- sc->cur_chan->stopped) && !txctl->force_channel) {
- if (!txctl->an)
- txctl->an = &avp->mcast_node;
- queue = true;
- skip_uapsd = true;
- }
-
- if (txctl->an && queue)
- tid = ath_get_skb_tid(sc, txctl->an, skb);
-
- if (!skip_uapsd && ps_resp) {
- ath_txq_unlock(sc, txq);
+ if (ps_resp)
txq = sc->tx.uapsdq;
- ath_txq_lock(sc, txq);
- } else if (txctl->an && queue) {
- WARN_ON(tid->txq != txctl->txq);
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- tid->clear_ps_filter = true;
-
- /*
- * Add this frame to software queue for scheduling later
- * for aggregation.
- */
- TX_STAT_INC(txq->axq_qnum, a_queued_sw);
- __skb_queue_tail(&tid->buf_q, skb);
- if (!txctl->an->sleeping)
- ath_tx_queue_tid(sc, txq, tid);
+ if (txctl->sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ tid = ath_get_skb_tid(sc, an, skb);
+ }
- ath_txq_schedule(sc, txq);
- goto out;
+ ath_txq_lock(sc, txq);
+ if (txq == sc->tx.txq_map[q]) {
+ fi->txq = q;
+ ++txq->pending_frames;
}
bf = ath_tx_setup_buffer(sc, txq, tid, skb);
@@ -2892,9 +2818,8 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
struct ath_atx_tid *tid;
int tidno, acno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS;
- tidno++, tid++) {
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ath_node_to_tid(an, tidno);
tid->an = an;
tid->tidno = tidno;
tid->seq_start = tid->seq_next = 0;
@@ -2902,11 +2827,14 @@ 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;
- __skb_queue_head_init(&tid->buf_q);
+ tid->has_queued = false;
__skb_queue_head_init(&tid->retry_q);
INIT_LIST_HEAD(&tid->list);
acno = TID_TO_WME_AC(tidno);
tid->txq = sc->tx.txq_map[acno];
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
@@ -2916,9 +2844,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq;
int tidno;
- for (tidno = 0, tid = &an->tid[tidno];
- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
-
+ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
+ tid = ath_node_to_tid(an, tidno);
txq = tid->txq;
ath_txq_lock(sc, txq);
@@ -2930,6 +2857,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->active = false;
ath_txq_unlock(sc, txq);
+
+ if (!an->sta)
+ break; /* just one multicast ath_atx_tid */
}
}
--
2.10.1
^ permalink raw reply related [flat|nested] 118+ messages in thread
* Re: [v6] ath9k: Switch to using mac80211 intermediate software queues.
2016-11-09 11:31 ` [PATCH v6] " Toke Høiland-Jørgensen
@ 2016-11-09 22:42 ` Kalle Valo
2016-11-09 23:10 ` Toke Høiland-Jørgensen
2016-11-15 15:00 ` Kalle Valo
1 sibling, 1 reply; 118+ messages in thread
From: Kalle Valo @ 2016-11-09 22:42 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: make-wifi-fast, linux-wireless, Toke Høiland-Jørgensen,
Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> The mac80211 intermediate software queues offer significant latency
> reductions, and this patch allows ath9k to realise them. The exact gains
> from this varies with the test scenario, but in an access point scenario
> we have seen latency reductions ranging from 1/3 to as much as an order
> of magnitude. We also achieve slightly better aggregation.
>
> Median latency (ping) figures with this patch applied at the access point,
> with two high-rate stations and one low-rate station (HT20 5Ghz), running
> a Flent rtt_fair_var_up test with one TCP flow and one ping flow going to
> each station:
>
> Fast station Slow station
> Default pfifo_fast qdisc: 430.4 ms 638.7 ms
> fq_codel qdisc on iface: 35.5 ms 211.8 ms
> This patch set: 22.4 ms 38.2 ms
>
> Median aggregation sizes over the same test:
>
> Default pfifo_fast qdisc: 9.5 pkts 1.9 pkts
> fq_codel qdisc on iface: 11.2 pkts 1.9 pkts
> This patch set: 13.9 pkts 1.9 pkts
>
> This patch is based on Tim's original patch set, but reworked quite
> thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Perfect, just what I was hoping to see :) Unless something really
surprising comes up I should apply this within the next few days.
--
https://patchwork.kernel.org/patch/9419029/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v6] ath9k: Switch to using mac80211 intermediate software queues.
2016-11-09 22:42 ` [v6] " Kalle Valo
@ 2016-11-09 23:10 ` Toke Høiland-Jørgensen
0 siblings, 0 replies; 118+ messages in thread
From: Toke Høiland-Jørgensen @ 2016-11-09 23:10 UTC (permalink / raw)
To: Kalle Valo; +Cc: make-wifi-fast, linux-wireless, Tim Shepard, Felix Fietkau
Kalle Valo <kvalo@qca.qualcomm.com> writes:
> Toke H=C3=B8iland-J=C3=B8rgensen wrote:
>> This switches ath9k over to using the mac80211 intermediate software
>> queueing mechanism for data packets. It removes the queueing inside the
>> driver, except for the retry queue, and instead pulls from mac80211 when
>> a packet is needed. The retry queue is used to store a packet that was
>> pulled but can't be sent immediately.
>>=20
>> The old code path in ath_tx_start that would queue packets has been
>> removed completely, as has the qlen limit tunables (since there's no
>> longer a queue in the driver to limit).
>>=20
>> The mac80211 intermediate software queues offer significant latency
>> reductions, and this patch allows ath9k to realise them. The exact gains
>> from this varies with the test scenario, but in an access point scenario
>> we have seen latency reductions ranging from 1/3 to as much as an order
>> of magnitude. We also achieve slightly better aggregation.
>>=20
>> Median latency (ping) figures with this patch applied at the access poin=
t,
>> with two high-rate stations and one low-rate station (HT20 5Ghz), running
>> a Flent rtt_fair_var_up test with one TCP flow and one ping flow going to
>> each station:
>>=20
>> Fast station Slow station
>> Default pfifo_fast qdisc: 430.4 ms 638.7 ms
>> fq_codel qdisc on iface: 35.5 ms 211.8 ms
>> This patch set: 22.4 ms 38.2 ms
>>=20
>> Median aggregation sizes over the same test:
>>=20
>> Default pfifo_fast qdisc: 9.5 pkts 1.9 pkts
>> fq_codel qdisc on iface: 11.2 pkts 1.9 pkts
>> This patch set: 13.9 pkts 1.9 pkts
>>=20
>> This patch is based on Tim's original patch set, but reworked quite
>> thoroughly.
>>=20
>> Cc: Tim Shepard <shep@alum.mit.edu>
>> Cc: Felix Fietkau <nbd@nbd.name>
>> Signed-off-by: Toke H=C3=B8iland-J=C3=B8rgensen <toke@toke.dk>
>
> Perfect, just what I was hoping to see :) Unless something really
> surprising comes up I should apply this within the next few days.
Awesome, thanks! :)
-Toke
^ permalink raw reply [flat|nested] 118+ messages in thread
* Re: [v6] ath9k: Switch to using mac80211 intermediate software queues.
2016-11-09 11:31 ` [PATCH v6] " Toke Høiland-Jørgensen
2016-11-09 22:42 ` [v6] " Kalle Valo
@ 2016-11-15 15:00 ` Kalle Valo
1 sibling, 0 replies; 118+ messages in thread
From: Kalle Valo @ 2016-11-15 15:00 UTC (permalink / raw)
To: Toke Høiland-Jørgensen
Cc: make-wifi-fast, linux-wireless, Toke Høiland-Jørgensen,
Tim Shepard, Felix Fietkau
Toke Høiland-Jørgensen wrote:
> This switches ath9k over to using the mac80211 intermediate software
> queueing mechanism for data packets. It removes the queueing inside the
> driver, except for the retry queue, and instead pulls from mac80211 when
> a packet is needed. The retry queue is used to store a packet that was
> pulled but can't be sent immediately.
>
> The old code path in ath_tx_start that would queue packets has been
> removed completely, as has the qlen limit tunables (since there's no
> longer a queue in the driver to limit).
>
> The mac80211 intermediate software queues offer significant latency
> reductions, and this patch allows ath9k to realise them. The exact gains
> from this varies with the test scenario, but in an access point scenario
> we have seen latency reductions ranging from 1/3 to as much as an order
> of magnitude. We also achieve slightly better aggregation.
>
> Median latency (ping) figures with this patch applied at the access point,
> with two high-rate stations and one low-rate station (HT20 5Ghz), running
> a Flent rtt_fair_var_up test with one TCP flow and one ping flow going to
> each station:
>
> Fast station Slow station
> Default pfifo_fast qdisc: 430.4 ms 638.7 ms
> fq_codel qdisc on iface: 35.5 ms 211.8 ms
> This patch set: 22.4 ms 38.2 ms
>
> Median aggregation sizes over the same test:
>
> Default pfifo_fast qdisc: 9.5 pkts 1.9 pkts
> fq_codel qdisc on iface: 11.2 pkts 1.9 pkts
> This patch set: 13.9 pkts 1.9 pkts
>
> This patch is based on Tim's original patch set, but reworked quite
> thoroughly.
>
> Cc: Tim Shepard <shep@alum.mit.edu>
> Cc: Felix Fietkau <nbd@nbd.name>
> Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Patch applied to ath-next branch of ath.git, thanks.
50f08edf9809 ath9k: Switch to using mac80211 intermediate software queues.
--
https://patchwork.kernel.org/patch/9419029/
Documentation about submitting wireless patches and checking status
from patchwork:
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
^ permalink raw reply [flat|nested] 118+ messages in thread