Skip to content

Commit

Permalink
ath9k: Fix the 'xmit' debugfs file
Browse files Browse the repository at this point in the history
The 'xmit' debugfs file has become big and unwieldy, fix
multiple issues with its usage:

* Store TX counters/statistics only for the 4 Access Categories.
  Use IEEE80211_NUM_ACS instead of ATH9K_NUM_TX_QUEUES.

* Move various utility macros to debug.h, they can be reused
  elsewhere.

* Remove tx_complete_poll_work_seen.

* Remove code that accesses various internal queue-specific
  variables without any locking whatsoever. HW/SW queue details
  will be handled in a subsequent patch.

* Do not print internal values like txq_headidx and txq_headidx.
  They were mostly unused anyway, considering code like:
  PRX("txq_tailidx:     ", txq_headidx);

* Handle 'txprocdesc' for EDMA too.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Sujith Manoharan authored and John W. Linville committed Nov 21, 2012
1 parent bea843c commit 78ef731
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 105 deletions.
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath9k/ath9k.h
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,6 @@ 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;
Expand Down
104 changes: 5 additions & 99 deletions drivers/net/wireless/ath/ath9k/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,62 +512,19 @@ static const struct file_operations fops_interrupt = {
.llseek = default_llseek,
};

#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
#define PR(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem, \
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem, \
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem, \
sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem); \
if (len >= size) \
goto done; \
} 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_map[IEEE80211_AC_BE]->elem), \
(unsigned int)(sc->tx.txq_map[IEEE80211_AC_BK]->elem), \
(unsigned int)(sc->tx.txq_map[IEEE80211_AC_VI]->elem), \
(unsigned int)(sc->tx.txq_map[IEEE80211_AC_VO]->elem)); \
if (len >= size) \
goto done; \
} 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_map[IEEE80211_AC_BE]->elem), \
list_empty(&sc->tx.txq_map[IEEE80211_AC_BK]->elem), \
list_empty(&sc->tx.txq_map[IEEE80211_AC_VI]->elem), \
list_empty(&sc->tx.txq_map[IEEE80211_AC_VO]->elem)); \
if (len >= size) \
goto done; \
} 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 = 8000;
int i;
unsigned int len = 0, size = 2048;
ssize_t retval = 0;
char tmp[32];

buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;

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,
len += sprintf(buf, "%30s %10s%10s%10s\n\n",
"BE", "BK", "VI", "VO");

PR("MPDUs Queued: ", queued);
Expand All @@ -587,62 +544,11 @@ 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);
PR("HW-put-tx-buf: ", puttxbuf);
PR("HW-tx-start: ", txstart);
PR("HW-tx-proc-desc: ", txprocdesc);
PR("TX-Failed: ", txfailed);
len += snprintf(buf + len, size - len,
"%s%11p%11p%10p%10p\n", "txq-memory-address:",
sc->tx.txq_map[IEEE80211_AC_BE],
sc->tx.txq_map[IEEE80211_AC_BK],
sc->tx.txq_map[IEEE80211_AC_VI],
sc->tx.txq_map[IEEE80211_AC_VO]);
if (len >= size)
goto done;

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);
for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
PRQLE(tmp, txq_fifo[i]);
}

/* Print out more detailed queue-info */
for (i = 0; i <= IEEE80211_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;

Expand Down
17 changes: 16 additions & 1 deletion drivers/net/wireless/ath/ath9k/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,21 @@ struct ath_tx_stats {
u32 txfailed;
};

/*
* Various utility macros to print TX/Queue counters.
*/
#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
#define TXSTATS sc->debug.stats.txstats
#define PR(str, elem) \
do { \
len += snprintf(buf + len, size - len, \
"%s%13u%11u%10u%10u\n", str, \
TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \
TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \
TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \
TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \
} while(0)

#define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)

/**
Expand Down Expand Up @@ -227,7 +242,7 @@ struct ath_rx_stats {

struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
struct ath_tx_stats txstats[IEEE80211_NUM_ACS];
struct ath_rx_stats rxstats;
struct ath_dfs_stats dfs_stats;
u32 reset[__RESET_TYPE_MAX];
Expand Down
3 changes: 0 additions & 3 deletions drivers/net/wireless/ath/ath9k/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ void ath_tx_complete_poll_work(struct work_struct *work)
struct ath_txq *txq;
int i;
bool needreset = false;
#ifdef CONFIG_ATH9K_DEBUGFS
sc->tx_complete_poll_work_seen++;
#endif

for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
if (ATH_TXQ_SETUP(sc, i)) {
Expand Down
1 change: 0 additions & 1 deletion drivers/net/wireless/ath/ath9k/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1953,7 +1953,6 @@ static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
return 0;
}

#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
#define AWDATA(elem) \
do { \
data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/ath/ath9k/xmit.c
Original file line number Diff line number Diff line change
Expand Up @@ -2319,6 +2319,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)

ath_txq_lock(sc, txq);

TX_STAT_INC(txq->axq_qnum, txprocdesc);

if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
ath_txq_unlock(sc, txq);
return;
Expand Down

0 comments on commit 78ef731

Please sign in to comment.