ath9k: Resend all my pending patches.
Here is my current ath9k patch queue. These have all been posted before, but this should make it easier to apply them.
The final 'copy-break' patch still needs some work to function properly on non PCI busses it seems, and maybe disable copybreak on larger packets.
PATCH RESEND 1/11 ath9k: Show some live tx-queue values in debugfs.
From: Ben Greear <[email protected]>
I thought this might help track down stuck queues, etc.
---
:100644 100644 3586c43... 5075faa... M drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.c | 16 ++++++++++++++++ 1 files changed, 16 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/debug.c +16 -0
@@ -589,6 +589,16 @@ static const struct file_operations fops_wiphy = { sc->debug.stats.txstats[WME_AC_VO].elem); \ } while(0) +#define PRX (str, elem) \ +do { \ + len += snprintf(buf + len, size - len, \ + "%s%13u%11u%10u%10u\n", str, \ + (unsigned int)(sc->tx.txq[WME_AC_BE].elem), \ + (unsigned int)(sc->tx.txq[WME_AC_BK].elem), \ + (unsigned int)(sc->tx.txq[WME_AC_VI].elem), \ + (unsigned int)(sc->tx.txq[WME_AC_VO].elem)); \ +} while(0) +static ssize_t read_file_xmit (struct file *file,char __user *user_buf,size_t count,loff_t *ppos) {
@@ -619,6 +629,12 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,PR ("TX-Pkts-All: " , tx_pkts_all);PR ("TX-Bytes-All: " , tx_bytes_all); +PRX ("axq-qnum: " , axq_qnum); +PRX ("axq-depth: " , axq_depth); +PRX ("axq-stopped " , stopped); +PRX ("tx-in-progress " , axq_tx_inprogress); +PRX ("pending-frames " , pending_frames); +if (len > size) len = size;
Signature · 1 line
1.7.2.3
PATCH RESEND 2/11 ath9k: Initialize ah->hw
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
Previous code left it NULL.
---
:100644 100644 767d8b8... 23b2998... M drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/init.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/init.c +1 -0
@@ -537,6 +537,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,if (!ah)return -ENOMEM ; + ah->hw = sc->hw; ah->hw_version.devid = devid; ah->hw_version.subsysid = subsysid; sc->sc_ah = ah;
Signature · 1 line
1.7.2.3
PATCH RESEND 3/11 ath9k: Add more information to debugfs xmit file.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
Should help debug strange tx lockup type issues.
---
:100644 100644 5075faa... 577bc5a... M drivers/net/wireless/ath/ath9k/debug.c
:100644 100644 1e5078b... cd2db3f... M drivers/net/wireless/ath/ath9k/debug.h
:100644 100644 180170d... 99ce6f1... M drivers/net/wireless/ath/ath9k/mac.c
:100644 100644 332d1fe... c769037... M drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/ath9k/debug.c | 29 +++++++++++++++++++++++++++-- drivers/net/wireless/ath/ath9k/debug.h | 6 ++++++ drivers/net/wireless/ath/ath9k/mac.c | 8 ++++++++ drivers/net/wireless/ath/ath9k/xmit.c | 1 + 4 files changed, 42 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/ath9k/debug.c +27 -2
@@ -599,13 +599,25 @@ do { \ (unsigned int)(sc->tx.txq[WME_AC_VO].elem)); \ } while(0) +#define PRQLE (str, elem) \ +do { \ + len += snprintf(buf + len, size - len, \ + "%s%13i%11i%10i%10i\n", str, \ + list_empty(&sc->tx.txq[WME_AC_BE].elem), \ + list_empty(&sc->tx.txq[WME_AC_BK].elem), \ + list_empty(&sc->tx.txq[WME_AC_VI].elem), \ + list_empty(&sc->tx.txq[WME_AC_VO].elem)); \ +} while (0) +static ssize_t read_file_xmit (struct file *file,char __user *user_buf,size_t count,loff_t *ppos) {struct ath_softc *sc = file->private_data;char *buf; -unsigned int len =0 , size =2048 ; +unsigned int len =0 , size =4000 ; +int i;ssize_t retval =0 ; +char tmp[32 ]; buf =kzalloc (size,GFP_KERNEL );if (buf ==NULL )
@@ -628,13 +640,26 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,PR ("DELIM Underrun: " , delim_underrun);PR ("TX-Pkts-All: " , tx_pkts_all);PR ("TX-Bytes-All: " , tx_bytes_all); +PR ("hw-put-tx-buf: " , puttxbuf); +PR ("hw-tx-start: " , txstart); +PR ("hw-tx-proc-desc: " , txprocdesc);PRX ("axq-qnum: " , axq_qnum);PRX ("axq-depth: " , axq_depth); +PRX ("axq-ampdu_depth: " , axq_ampdu_depth);PRX ("axq-stopped " , stopped);PRX ("tx-in-progress " , axq_tx_inprogress);PRX ("pending-frames " , pending_frames); - +PRX ("txq_headidx: " , txq_headidx); +PRX ("txq_tailidx: " , txq_headidx); + +PRQLE ("axq_q empty: " , axq_q); +PRQLE ("axq_acq empty: " , axq_acq); +PRQLE ("txq_fifo_pending: " , txq_fifo_pending); +for (i =0 ; i <ATH_TXFIFO_DEPTH ; i++) { +snprintf (tmp,sizeof (tmp) -1 ,"txq_fifo[%i] empty: " , i); +PRQLE (tmp, txq_fifo[i]); + }if (len > size) len = size;
drivers/net/wireless/ath/ath9k/debug.h +6 -0
@@ -102,6 +102,9 @@ struct ath_interrupt_stats {* @desc_cfg_err: Descriptor configuration errors * @data_urn: TX data underrun errors * @delim_urn: TX delimiter underrun errors +* @puttxbuf: Number of times hardware was given txbuf to write. +* @txstart: Number of times hardware was told to start tx. +* @txprocdesc: Number of times tx descriptor was processed */ struct ath_tx_stats {u32 tx_pkts_all;
@@ -119,6 +122,9 @@ struct ath_tx_stats {u32 desc_cfg_err;u32 data_underrun;u32 delim_underrun; +u32 puttxbuf; +u32 txstart; +u32 txprocdesc; };/**
drivers/net/wireless/ath/ath9k/mac.c +8 -0
@@ -16,6 +16,8 @@#include "hw.h" #include "hw-ops.h" +#include "debug.h" +#include "ath9k.h" static void ath9k_hw_set_txq_interrupts (struct ath_hw *ah,struct ath9k_tx_queue_info *qi)
@@ -50,12 +52,18 @@ EXPORT_SYMBOL(ath9k_hw_gettxbuf);void ath9k_hw_puttxbuf (struct ath_hw *ah,u32 q,u32 txdp) { +struct ath_wiphy *aphy = ah->hw->priv; +struct ath_softc *sc = aphy->sc; +TX_STAT_INC (q, puttxbuf);REG_WRITE (ah,AR_QTXDP (q), txdp); }EXPORT_SYMBOL (ath9k_hw_puttxbuf);void ath9k_hw_txstart (struct ath_hw *ah,u32 q) { +struct ath_wiphy *aphy = ah->hw->priv; +struct ath_softc *sc = aphy->sc; +TX_STAT_INC (q, txstart);ath_dbg (ath9k_hw_common (ah),ATH_DBG_QUEUE ,"Enable TXE on queue: %u\n" , q);REG_WRITE (ah,AR_Q_TXE ,1 << q);
drivers/net/wireless/ath/ath9k/xmit.c +1 -0
@@ -2033,6 +2033,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)spin_unlock_bh (&txq->axq_lock);break ; } +TX_STAT_INC (txq->axq_qnum, txprocdesc);/* * Remove ath_buf's of the same transmit unit from txq,
Signature · 1 line
1.7.2.3
PATCH RESEND 4/11 ath9k: Remove un-used member from ath_node.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
---
:100644 100644 3681caf5.. deda815... M drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/ath9k.h | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/net/wireless/ath/ath9k/ath9k.h +0 -1
@@ -342,7 +342,6 @@ struct ath_vif {__le64 tsf_adjust;/* TSF adjustment for staggered beacons */ enum nl80211_iftype av_opmode;struct ath_buf *av_bcbuf; -struct ath_tx_control av_btxctl;u8 bssid[ETH_ALEN ];/* current BSSID from config_interface */ };
Signature · 1 line
1.7.2.3
PATCH RESEND 5/11 ath9k: Ensure xmit makes progress.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
If the txq->axq_q is empty, the code was breaking out of the tx_processq logic without checking to see if it should transmit other queued AMPDU frames (txq->axq_acq).
This patches ensures ath_txq_schedule is called.
This needs review.
---
:100644 100644 c769037... 2248e47... M drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/ath9k/xmit.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/xmit.c +2 -0
@@ -1999,6 +1999,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)spin_lock_bh (&txq->axq_lock);if (list_empty (&txq->axq_q)) { txq->axq_link =NULL ; +if (sc->sc_flags &SC_OP_TXAGGR ) +ath_txq_schedule (sc, txq);spin_unlock_bh (&txq->axq_lock);break ; }
Signature · 1 line
1.7.2.3
PATCH RESEND 6/11 ath9k: Add counters to distinquish AMPDU enqueues.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
Show counters for pkts sent directly to hardware and those queued in software.
---
:100644 100644 577bc5a... faf84e4... M drivers/net/wireless/ath/ath9k/debug.c
:100644 100644 cd2db3f... 980c9fa... M drivers/net/wireless/ath/ath9k/debug.h
:100644 100644 2248e47... 3aae523... M drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/ath9k/debug.c | 3 ++- drivers/net/wireless/ath/ath9k/debug.h | 6 ++++-- drivers/net/wireless/ath/ath9k/xmit.c | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-)
drivers/net/wireless/ath/ath9k/debug.c +2 -1
@@ -628,7 +628,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,PR ("MPDUs Queued: " , queued);PR ("MPDUs Completed: " , completed);PR ("Aggregates: " , a_aggr); -PR ("AMPDUs Queued: " , a_queued); +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);
drivers/net/wireless/ath/ath9k/debug.h +4 -2
@@ -89,7 +89,8 @@ struct ath_interrupt_stats {* @queued: Total MPDUs (non-aggr) queued * @completed: Total MPDUs (non-aggr) completed * @a_aggr: Total no. of aggregates queued -* @a_queued: Total AMPDUs 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
@@ -112,7 +113,8 @@ struct ath_tx_stats {u32 queued;u32 completed;u32 a_aggr; -u32 a_queued; +u32 a_queued_hw; +u32 a_queued_sw;u32 a_completed;u32 a_retries;u32 a_xretries;
drivers/net/wireless/ath/ath9k/xmit.c +2 -1
@@ -1335,7 +1335,6 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,struct list_head bf_head; bf->bf_state.bf_type |=BUF_AMPDU ; -TX_STAT_INC (txctl->txq->axq_qnum, a_queued);/* * Do not queue to h/w when any of the following conditions is true:
@@ -1351,6 +1350,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,* Add this frame to software queue for scheduling later * for aggregation. */ +TX_STAT_INC (txctl->txq->axq_qnum, a_queued_sw);list_add_tail (&bf->list, &tid->buf_q);ath_tx_queue_tid (txctl->txq, tid);return ;
@@ -1364,6 +1364,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,ath_tx_addto_baw (sc, tid, fi->seqno);/* Queue to h/w without aggregation */ +TX_STAT_INC (txctl->txq->axq_qnum, a_queued_hw); bf->bf_lastbf = bf;ath_buf_set_rate (sc, bf, fi->framelen);ath_tx_txqaddbuf (sc, txctl->txq, &bf_head);
Signature · 1 line
1.7.2.3
PATCH RESEND 7/11 ath9k: Keep track of stations for debugfs.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
The stations hold the ath_node, which holds the tid and other xmit logic structures. In order to debug stuck xmit logic, we need a way to print out the tid state for the stations.
---
:100644 100644 deda815... 3f5c513... M drivers/net/wireless/ath/ath9k/ath9k.h
:100644 100644 faf84e4... 650f00f... M drivers/net/wireless/ath/ath9k/debug.c
:100644 100644 23b2998... 59c01ca... M drivers/net/wireless/ath/ath9k/init.c
:100644 100644 16eb891... cb9940b... M drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/ath9k.h | 7 ++- drivers/net/wireless/ath/ath9k/debug.c | 94 +++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath9k/init.c | 4 ++ drivers/net/wireless/ath/ath9k/main.c | 13 +++++ 4 files changed, 115 insertions(+), 3 deletions(-)
drivers/net/wireless/ath/ath9k/ath9k.h +6 -1
@@ -254,7 +254,10 @@ struct ath_atx_tid { };struct ath_node { -struct ath_common *common; +#ifdef CONFIG_ATH9K_DEBUGFS +struct list_head list;/* for sc->nodes */ +struct ieee80211_sta *sta;/* station struct we're part of */ +#endif struct ath_atx_tid tid[WME_NUM_TID ];struct ath_atx_ac ac[WME_NUM_AC ];u16 maxampdu;
@@ -624,6 +627,8 @@ struct ath_softc {#ifdef CONFIG_ATH9K_DEBUGFS struct ath9k_debug debug; +spinlock_t nodes_lock; +struct list_head nodes;/* basically, stations */ #endif struct ath_beacon_config cur_beacon_conf;struct delayed_work tx_complete_work;
drivers/net/wireless/ath/ath9k/debug.c +92 -2
148 lines not on this page · raw message
drivers/net/wireless/ath/ath9k/init.c +4 -0
@@ -559,6 +559,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,spin_lock_init (&sc->sc_serial_rw);spin_lock_init (&sc->sc_pm_lock);mutex_init (&sc->mutex); +#ifdef CONFIG_ATH9K_DEBUGFS +spin_lock_init (&sc->nodes_lock); +INIT_LIST_HEAD (&sc->nodes); +#endif tasklet_init (&sc->intr_tq, ath9k_tasklet, (unsigned long )sc);tasklet_init (&sc->bcon_tasklet, ath_beacon_tasklet, (unsigned long )sc);
drivers/net/wireless/ath/ath9k/main.c +13 -0
@@ -545,6 +545,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)struct ath_hw *ah = sc->sc_ah; an = (struct ath_node *)sta->drv_priv; +#ifdef CONFIG_ATH9K_DEBUGFS +spin_lock (&sc->nodes_lock); +list_add (&an->list, &sc->nodes); +spin_unlock (&sc->nodes_lock); + an->sta = sta; +#endif if ((ah->caps.hw_caps) &ATH9K_HW_CAP_APM ) sc->sc_flags |=SC_OP_ENABLE_APM ;
@@ -560,6 +566,13 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) {struct ath_node *an = (struct ath_node *)sta->drv_priv; +#ifdef CONFIG_ATH9K_DEBUGFS +spin_lock (&sc->nodes_lock); +list_del (&an->list); +spin_unlock (&sc->nodes_lock); + an->sta =NULL ; +#endif +if (sc->sc_flags &SC_OP_TXAGGR )ath_tx_node_cleanup (sc, an); }
Signature · 1 line
1.7.2.3
PATCH RESEND 8/11 ath9k: More xmit queue debugfs information.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
To try to figure out why xmit logic hangs.
---
:100644 100644 650f00f... 9e009cc... M drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.c | 26 ++++++++++++++++++++++++++ 1 files changed, 26 insertions(+), 0 deletions(-)
drivers/net/wireless/ath/ath9k/debug.c +26 -0
@@ -679,6 +679,32 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,PRQLE (tmp, txq_fifo[i]); } +/* Print out more detailed queue-info */ +for (i =0 ; i <=WME_AC_BK ; i++) { +struct ath_txq *txq = &(sc->tx.txq[i]); +struct ath_atx_ac *ac; +struct ath_atx_tid *tid; +if (len >= size) + goto done; +spin_lock_bh (&txq->axq_lock); +if (!list_empty (&txq->axq_acq)) { + ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, + list); + len +=snprintf (buf + len, size - len, +"txq[%i] first-ac: %p sched: %i\n" , + i, ac, ac->sched); +if (list_empty (&ac->tid_q) || (len >= size)) + goto done_for; + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, + list); + len +=snprintf (buf + len, size - len, +" first-tid: %p sched: %i paused: %i\n" , + tid, tid->sched, tid->paused); + } + done_for: +spin_unlock_bh (&txq->axq_lock); + } + done:if (len > size) len = size;
Signature · 1 line
1.7.2.3
PATCH RESEND 9/11 ath9k: Try all queues when looking for next packet to send.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
There can be multiple struct ath_atx_ac entries for each txq, so if the first one doesn't have any packets to send now, try the rest of them. This should help keep xmit going when using multiple stations, especially with AMPDU enabled.
---
:100644 100644 3aae523... 46481fb... M drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/ath9k/xmit.c | 97 ++++++++++++++++++++------------- 1 files changed, 59 insertions(+), 38 deletions(-)
drivers/net/wireless/ath/ath9k/xmit.c +59 -38
@@ -54,8 +54,8 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,static void ath_tx_complete_buf (struct ath_softc *sc,struct ath_buf *bf,struct ath_txq *txq,struct list_head *bf_q,struct ath_tx_status *ts,int txok,int sendbar); -static void ath_tx_txqaddbuf (struct ath_softc *sc,struct ath_txq *txq, -struct list_head *head); +static int ath_tx_txqaddbuf (struct ath_softc *sc,struct ath_txq *txq, +struct list_head *head);static void ath_buf_set_rate (struct ath_softc *sc,struct ath_buf *bf,int len);static void ath_tx_rc_status (struct ath_buf *bf,struct ath_tx_status *ts,int nframes,int nbad,int txok,bool update_rc);
@@ -789,18 +789,21 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,#undef PADBYTES } -static void ath_tx_sched_aggr (struct ath_softc *sc,struct ath_txq *txq, -struct ath_atx_tid *tid) +/* Return number of buffers set up for transmit. */ +static int ath_tx_sched_aggr (struct ath_softc *sc,struct ath_txq *txq, +struct ath_atx_tid *tid) {struct ath_buf *bf;enum ATH_AGGR_STATUS status;struct ath_frame_info *fi;struct list_head bf_q;int aggr_len; +int cnt =0 ; +int rv; do { if (list_empty(&tid->buf_q)) - return; + return cnt; INIT_LIST_HEAD(&bf_q);
@@ -811,7 +814,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,* block-ack window is not open. */ if (list_empty (&bf_q)) -break ; +return cnt; bf = list_first_entry(&bf_q, struct ath_buf, list); bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
@@ -823,7 +826,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, bf->bf_state.bf_type &= ~BUF_AGGR ;ath9k_hw_clr11n_aggr (sc->sc_ah, bf->bf_desc);ath_buf_set_rate (sc, bf, fi->framelen); -ath_tx_txqaddbuf (sc, txq, &bf_q); + rv =ath_tx_txqaddbuf (sc, txq, &bf_q); +if (rv >0 ) { +TX_STAT_INC (txq->axq_qnum, a_aggr); + cnt += rv; + }continue ; }
@@ -835,11 +842,15 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,/* anchor last desc of aggregate */ ath9k_hw_set11n_aggr_last (sc->sc_ah, bf->bf_lastbf->bf_desc); -ath_tx_txqaddbuf (sc, txq, &bf_q); -TX_STAT_INC (txq->axq_qnum, a_aggr); + rv =ath_tx_txqaddbuf (sc, txq, &bf_q); +if (rv >0 ) { +TX_STAT_INC (txq->axq_qnum, a_aggr); + cnt += rv; + } }while (txq->axq_ampdu_depth <ATH_AGGR_MIN_QDEPTH && status !=ATH_AGGR_BAW_CLOSED ); +return rv; } int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -1218,46 +1229,54 @@ void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) sc->tx.txqsetup &= ~(1 <<txq->axq_qnum); } +/** For each axq_acq entry, for each tid, if we can transmit +* one, do so and break out. +*/ void ath_txq_schedule (struct ath_softc *sc,struct ath_txq *txq) { -struct ath_atx_ac *ac; +struct ath_atx_ac *ac, *ac_tmp, *last;struct ath_atx_tid *tid; +bool did_one = false;if (list_empty (&txq->axq_acq))return ; - ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list); -list_del (&ac->list); - ac->sched = false; + last = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list); +list_for_each_entry_safe (ac, ac_tmp, &txq->axq_acq, list) { +list_del (&ac->list); + ac->sched = false; -do { -if (list_empty (&ac->tid_q)) -return ; +while (!list_empty (&ac->tid_q)) { - tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); -list_del (&tid->list); - tid->sched = false; + tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list); +list_del (&tid->list); + tid->sched = false; -if (tid->paused) -continue ; +if (tid->paused) +continue ; -ath_tx_sched_aggr (sc, txq, tid); +if (ath_tx_sched_aggr (sc, txq, tid) >0 ) + did_one = true; -/* -* add tid to round-robin queue if more frames -* are pending for the tid -*/ -if (!list_empty (&tid->buf_q)) -ath_tx_queue_tid (txq, tid); +/* +* add tid to round-robin queue if more frames +* are pending for the tid +*/ +if (!list_empty (&tid->buf_q)) +ath_tx_queue_tid (txq, tid); -break ; - }while (!list_empty (&ac->tid_q)); +break ; + } -if (!list_empty (&ac->tid_q)) { -if (!ac->sched) { - ac->sched = true; -list_add_tail (&ac->list, &txq->axq_acq); +if (!list_empty (&ac->tid_q)) { +if (!ac->sched) { + ac->sched = true; +list_add_tail (&ac->list, &txq->axq_acq); + } } + +if (did_one || (ac == last)) +return ; } }
@@ -1268,9 +1287,10 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)/* * Insert a chain of ath_buf (descriptors) on a txq and * assume the descriptors are already chained together by caller. +* Return number of buffers sent to DMA. */ -static void ath_tx_txqaddbuf (struct ath_softc *sc,struct ath_txq *txq, -struct list_head *head) +static int ath_tx_txqaddbuf (struct ath_softc *sc,struct ath_txq *txq, +struct list_head *head) {struct ath_hw *ah = sc->sc_ah;struct ath_common *common =ath9k_hw_common (ah);
@@ -1282,7 +1302,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,*/ if (list_empty (head)) -return ; +return 0 ; bf = list_first_entry(head, struct ath_buf, list);
@@ -1292,7 +1312,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,if (sc->sc_ah->caps.hw_caps &ATH9K_HW_CAP_EDMA ) {if (txq->axq_depth >=ATH_TXFIFO_DEPTH ) {list_splice_tail_init (head, &txq->txq_fifo_pending); -return ; +return 0 ; }if (!list_empty (&txq->txq_fifo[txq->txq_headidx])) ath_dbg(common, ATH_DBG_XMIT,
@@ -1326,6 +1346,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, txq->axq_depth++;if (bf_is_ampdu_not_probing (bf)) txq->axq_ampdu_depth++; +return 1 ; } static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
Signature · 1 line
1.7.2.3
PATCH RESEND 9/11 ath9k: Try all queues when looking for next packet to send.
Quoted 9 lines · greearb at candelatech.com
From: Ben Greear <[email protected]>
There can be multiple struct
ath_atx_acentries for each txq, so if the first one doesn't have any packets to send now, try the rest of them. This should help keep xmit going when using multiple stations, especially with AMPDU enabled.Signed-off-by Ben Greear <[email protected]>
This one doesn't seem to apply any more. Can I persuade you to rebase and resubmit it?
Thanks,
John
Signature · 2 lines
John W. Linville Someday the world will need a hero, and you linville at tuxdriver.com might be all we have. Be ready.
PATCH RESEND 9/11 ath9k: Try all queues when looking for next packet to send.
Quoted 9 lines · John W. Linville
Quoted 8 lines · greearb at candelatech.com
From: Ben Greear<[email protected]>
There can be multiple struct
ath_atx_acentries for each txq, so if the first one doesn't have any packets to send now, try the rest of them. This should help keep xmit going when using multiple stations, especially with AMPDU enabled.
Quoted 4 lines
Quoted 1 line
Signed-off-by Ben Greear<[email protected]>This one doesn't seem to apply any more. Can I persuade you to rebase and resubmit it?
I think this is already taken care of, or at least the important parts.
Felix did some initial work in this area, and then I followed on with this one:
ath9k: Try more than one queue when scheduling new aggregate.
The only ath9k patches I have in my queue that are not upstream are:
(From Louis Rodriguez)
ath9k: warn when we get a ATH9K_INT_TIM_TIMER and are idle
and my:
ath9k: Implement rx copy-break.
Which appears DOA as folks seem to like paged-skbs instead.
Thanks,
Ben
Signature · 2 lines
Ben Greear <[email protected]> Candela Technologies Inc http://www.candelatech.com
PATCH RESEND 10/11 ath9k: Restart xmit logic in xmit watchdog.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
The system can get into a state where the xmit queue is stopped, but there are no packets pending, so the queue will not be restarted.
Add logic to the xmit watchdog to attempt to restart the xmit logic if this situation is detected.
Example 'dmesg' output:
ath: txq: f4e723e0 axq_qnum: 2, mac80211_qnum: 2 axq_link: f4e996c8 pending frames: 1 axq_acq empty: 1 stopped: 0 axq_depth: 0 Attempting to restart tx logic.
---
:100644 100644 3f5c513... 3108699... M drivers/net/wireless/ath/ath9k/ath9k.h
:100644 100644 9e009cc... b0cb792... M drivers/net/wireless/ath/ath9k/debug.c
:100644 100644 59c01ca... 5279653... M drivers/net/wireless/ath/ath9k/init.c
:100644 100644 46481fb... 8631afb... M drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/ath9k/ath9k.h | 9 +++- drivers/net/wireless/ath/ath9k/debug.c | 4 +- drivers/net/wireless/ath/ath9k/init.c | 5 +- drivers/net/wireless/ath/ath9k/xmit.c | 79 ++++++++++++++++++++++---------- 4 files changed, 68 insertions(+), 29 deletions(-)
drivers/net/wireless/ath/ath9k/ath9k.h +8 -1
@@ -184,7 +184,8 @@ enum ATH_AGGR_STATUS {#define ATH_TXFIFO_DEPTH 8struct ath_txq { -u32 axq_qnum; +int mac80211_qnum;/* mac80211 queue number, -1 means not mac80211 Q */ +u32 axq_qnum;/* ath9k hardware queue number */ u32 *axq_link;struct list_head axq_q;spinlock_t axq_lock;
@@ -280,6 +281,11 @@ struct ath_tx_control {#define ATH_TX_XRETRY 0x02#define ATH_TX_BAR 0x04 +/** +* @txq_map: Index is mac80211 queue number. This is +* not necessarily the same as the hardware queue number +* (axq_qnum). +*/ struct ath_tx {u16 seq_no;u32 txqsetup;
@@ -629,6 +635,7 @@ struct ath_softc {struct ath9k_debug debug;spinlock_t nodes_lock;struct list_head nodes;/* basically, stations */ +unsigned int tx_complete_poll_work_seen;#endif struct ath_beacon_config cur_beacon_conf;struct delayed_work tx_complete_work;
drivers/net/wireless/ath/ath9k/debug.c +3 -1
@@ -629,9 +629,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,if (buf ==NULL )return -ENOMEM ; - len +=sprintf (buf,"Num-Tx-Queues: %i tx-queues-setup: 0x%x\n" + len +=sprintf (buf,"Num-Tx-Queues: %i tx-queues-setup: 0x%x" +" poll-work-seen: %u\n" "%30s %10s%10s%10s\n\n" ,ATH9K_NUM_TX_QUEUES , sc->tx.txqsetup, + sc->tx_complete_poll_work_seen,"BE" ,"BK" ,"VI" ,"VO" );PR ("MPDUs Queued: " , queued);
drivers/net/wireless/ath/ath9k/init.c +3 -2
@@ -442,9 +442,10 @@ static int ath9k_init_queues(struct ath_softc *sc) sc->config.cabqReadytime =ATH_CABQ_READY_TIME ;ath_cabq_update (sc); -for (i =0 ; i <WME_NUM_AC ; i++) +for (i =0 ; i <WME_NUM_AC ; i++) { sc->tx.txq_map[i] =ath_txq_setup (sc,ATH9K_TX_QUEUE_DATA , i); - + sc->tx.txq_map[i]->mac80211_qnum = i; + }return 0 ; }
drivers/net/wireless/ath/ath9k/xmit.c +54 -25
148 lines not on this page · raw message
Signature · 1 line
1.7.2.3
PATCH RESEND 11/11 ath9k: Implement rx copy-break.
In reply to greearb at candelatech.comFrom: Ben Greear <[email protected]>
This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.
---
:100644 100644 b2497b8... ea2f67c... M drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/recv.c | 92 ++++++++++++++++++++++----------- 1 files changed, 61 insertions(+), 31 deletions(-)
drivers/net/wireless/ath/ath9k/recv.c +61 -31
@@ -16,6 +16,7 @@#include "ath9k.h" #include "ar9003_mac.h" +#include <linux/pci.h> #define SKB_CB_ATHBUF (__skb) (*((struct ath_buf **)__skb->cb))
@@ -1623,7 +1624,7 @@ div_comb_done:int ath_rx_tasklet (struct ath_softc *sc,int flush,bool hp) {struct ath_buf *bf; -struct sk_buff *skb =NULL , *requeue_skb; +struct sk_buff *skb =NULL , *requeue_skb =NULL ;struct ieee80211_rx_status *rxs;struct ath_hw *ah = sc->sc_ah;struct ath_common *common =ath9k_hw_common (ah);
@@ -1634,7 +1635,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)*/ struct ieee80211_hw *hw =NULL ;struct ieee80211_hdr *hdr; -int retval; +int retval, len; +bool use_copybreak = true;bool decrypt_error = false;struct ath_rx_status rs;enum ath9k_rx_qtype qtype;
@@ -1702,42 +1704,70 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) unlikely(tsf_lower - rs.rs_tstamp > 0x10000000)) rxs->mactime += 0x100000000ULL; -/* Ensure we always have an skb to requeue once we are done -* processing the current buffer's skb */ - requeue_skb =ath_rxbuf_alloc (common, common->rx_bufsize,GFP_ATOMIC ); - -/* If there is no memory we ignore the current RX'd frame, -* tell hardware it can give us a new frame using the old -* skb and put it at the tail of the sc->rx.rxbuf list for -* processing. */ -if (!requeue_skb) - goto requeue; - -/* Unmap the frame */ -dma_unmap_single (sc->dev, bf->bf_buf_addr, - common->rx_bufsize, - dma_type); + len = rs.rs_datalen + ah->caps.rx_status_len; +if (use_copybreak) { + skb =netdev_alloc_skb (NULL , len); +if (!skb) { + skb = bf->bf_mpdu; + use_copybreak = false; + goto non_copybreak; + } + }else { +non_copybreak: +/* Ensure we always have an skb to requeue once we are +* done processing the current buffer's skb */ + requeue_skb =ath_rxbuf_alloc (common, + common->rx_bufsize, +GFP_ATOMIC ); + +/* If there is no memory we ignore the current RX'd +* frame, tell hardware it can give us a new frame +* using the old skb and put it at the tail of the +* sc->rx.rxbuf list for processing. */ +if (!requeue_skb) + goto requeue; + +/* Unmap the frame */ +dma_unmap_single (sc->dev, bf->bf_buf_addr, + common->rx_bufsize, + dma_type); + } -skb_put (skb, rs.rs_datalen + ah->caps.rx_status_len); +skb_put (skb, len);if (ah->caps.rx_status_len)skb_pull (skb, ah->caps.rx_status_len); +if (use_copybreak) { +struct pci_dev *pdev =to_pci_dev (sc->dev); +pci_dma_sync_single_for_cpu (pdev, bf->bf_buf_addr, + len,PCI_DMA_FROMDEVICE ); +skb_copy_from_linear_data (bf->bf_mpdu, skb->data, len); +pci_dma_sync_single_for_device (pdev, bf->bf_buf_addr, + len,PCI_DMA_FROMDEVICE ); +memcpy (skb->cb, bf->bf_mpdu->cb,sizeof (skb->cb)); + rxs =IEEE80211_SKB_RXCB (skb); + } +ath9k_rx_skb_postprocess (common, skb, &rs, rxs, decrypt_error); -/* We will now give hardware our shiny new allocated skb */ - bf->bf_mpdu = requeue_skb; - bf->bf_buf_addr =dma_map_single (sc->dev, requeue_skb->data, - common->rx_bufsize, - dma_type); -if (unlikely (dma_mapping_error (sc->dev, - bf->bf_buf_addr))) { -dev_kfree_skb_any (requeue_skb); - bf->bf_mpdu =NULL ; - bf->bf_buf_addr =0 ; -ath_err (common,"dma_mapping_error() on RX\n" ); -ath_rx_send_to_mac80211 (hw, sc, skb); -break ; +if (!use_copybreak) { +/* We will now give hardware our shiny new allocated +* skb */ + bf->bf_mpdu = requeue_skb; + bf->bf_buf_addr =dma_map_single (sc->dev, + requeue_skb->data, + common->rx_bufsize, + dma_type); +if (unlikely (dma_mapping_error (sc->dev, + bf->bf_buf_addr))) { +dev_kfree_skb_any (requeue_skb); + bf->bf_mpdu =NULL ; + bf->bf_buf_addr =0 ; +ath_err (common,"dma_mapping_error() on RX\n" ); +ath_rx_send_to_mac80211 (hw, sc, skb); +break ; + } }/*
Signature · 1 line
1.7.2.3
PATCH RESEND 11/11 ath9k: Implement rx copy-break.
Quoted 8 lines · greearb at candelatech.com
From: Ben Greear<[email protected]>
This saves us constantly allocating large, multi-page skbs. It should fix the order-1 allocation errors reported, and in a 60-vif scenario, this significantly decreases CPU utilization, and latency, and increases bandwidth.
Signed-off-by Ben Greear<[email protected]>
I think we should use Jouni's approach instead of this patch, as it also fixes order-1 allocations, but with less data copying involved.
- Felix