Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fec247c0 authored by Sujith's avatar Sujith Committed by John W. Linville
Browse files

ath9k: Add debug counters for TX



Location: ath9k/phy#/xmit

Signed-off-by: default avatarSujith <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0ee9c13c
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -237,7 +237,6 @@ struct ath_txq {
	spinlock_t axq_lock;
	u32 axq_depth;
	u8 axq_aggr_depth;
	u32 axq_totalqueued;
	bool stopped;
	bool axq_tx_inprogress;
	struct ath_buf *axq_linkbuf;
+85 −0
Original line number Diff line number Diff line
@@ -486,6 +486,83 @@ static const struct file_operations fops_wiphy = {
	.owner = THIS_MODULE
};

#define PR(str, elem)							\
	do {								\
		len += snprintf(buf + len, size - len,			\
				"%s%13u%11u%10u%10u\n", str,		\
		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BE]].elem, \
		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_BK]].elem, \
		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_WME_AC_VI]].elem, \
		sc->debug.stats.txstats[sc->tx.hwq_map[ATH9K_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;
	ssize_t retval = 0;

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

	len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");

	PR("MPDUs Queued:    ", queued);
	PR("MPDUs Completed: ", completed);
	PR("Aggregates:      ", a_aggr);
	PR("AMPDUs Queued:   ", a_queued);
	PR("AMPDUs Completed:", a_completed);
	PR("AMPDUs Retried:  ", a_retries);
	PR("AMPDUs XRetried: ", a_xretries);
	PR("FIFO Underrun:   ", fifo_underrun);
	PR("TXOP Exceeded:   ", xtxop);
	PR("TXTIMER Expiry:  ", timer_exp);
	PR("DESC CFG Error:  ", desc_cfg_err);
	PR("DATA Underrun:   ", data_underrun);
	PR("DELIM Underrun:  ", delim_underrun);

	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
	kfree(buf);

	return retval;
}

void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
		       struct ath_buf *bf)
{
	struct ath_desc *ds = bf->bf_desc;

	if (bf_isampdu(bf)) {
		if (bf_isxretried(bf))
			TX_STAT_INC(txq->axq_qnum, a_xretries);
		else
			TX_STAT_INC(txq->axq_qnum, a_completed);
	} else {
		TX_STAT_INC(txq->axq_qnum, completed);
	}

	if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)
		TX_STAT_INC(txq->axq_qnum, fifo_underrun);
	if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP)
		TX_STAT_INC(txq->axq_qnum, xtxop);
	if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED)
		TX_STAT_INC(txq->axq_qnum, timer_exp);
	if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR)
		TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
	if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN)
		TX_STAT_INC(txq->axq_qnum, data_underrun);
	if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN)
		TX_STAT_INC(txq->axq_qnum, delim_underrun);
}

static const struct file_operations fops_xmit = {
	.read = read_file_xmit,
	.open = ath9k_debugfs_open,
	.owner = THIS_MODULE
};

int ath9k_init_debug(struct ath_softc *sc)
{
@@ -529,6 +606,13 @@ int ath9k_init_debug(struct ath_softc *sc)
	if (!sc->debug.debugfs_wiphy)
		goto err;

	sc->debug.debugfs_xmit = debugfs_create_file("xmit",
						     S_IRUSR,
						     sc->debug.debugfs_phy,
						     sc, &fops_xmit);
	if (!sc->debug.debugfs_xmit)
		goto err;

	return 0;
err:
	ath9k_exit_debug(sc);
@@ -537,6 +621,7 @@ int ath9k_init_debug(struct ath_softc *sc)

void ath9k_exit_debug(struct ath_softc *sc)
{
	debugfs_remove(sc->debug.debugfs_xmit);
	debugfs_remove(sc->debug.debugfs_wiphy);
	debugfs_remove(sc->debug.debugfs_rcstat);
	debugfs_remove(sc->debug.debugfs_interrupt);
+54 −0
Original line number Diff line number Diff line
@@ -35,6 +35,15 @@ enum ATH_DEBUG {

#define DBG_DEFAULT (ATH_DBG_FATAL)

struct ath_txq;
struct ath_buf;

#ifdef CONFIG_ATH9K_DEBUG
#define TX_STAT_INC(q, c) sc->debug.stats.txstats[q].c++
#else
#define TX_STAT_INC(q, c) do { } while (0)
#endif

#ifdef CONFIG_ATH9K_DEBUG

/**
@@ -87,9 +96,45 @@ struct ath_rc_stats {
	u8 per;
};

/**
 * struct ath_tx_stats - Statistics about TX
 * @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_completed: Total AMPDUs completed
 * @a_retries: No. of AMPDUs retried (SW)
 * @a_xretries: No. of AMPDUs dropped due to xretries
 * @fifo_underrun: FIFO underrun occurrences
	Valid only for:
		- non-aggregate condition.
		- first packet of aggregate.
 * @xtxop: No. of frames filtered because of TXOP limit
 * @timer_exp: Transmit timer expiry
 * @desc_cfg_err: Descriptor configuration errors
 * @data_urn: TX data underrun errors
 * @delim_urn: TX delimiter underrun errors
 */
struct ath_tx_stats {
	u32 queued;
	u32 completed;
	u32 a_aggr;
	u32 a_queued;
	u32 a_completed;
	u32 a_retries;
	u32 a_xretries;
	u32 fifo_underrun;
	u32 xtxop;
	u32 timer_exp;
	u32 desc_cfg_err;
	u32 data_underrun;
	u32 delim_underrun;
};

struct ath_stats {
	struct ath_interrupt_stats istats;
	struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
	struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
};

struct ath9k_debug {
@@ -100,6 +145,7 @@ struct ath9k_debug {
	struct dentry *debugfs_interrupt;
	struct dentry *debugfs_rcstat;
	struct dentry *debugfs_wiphy;
	struct dentry *debugfs_xmit;
	struct ath_stats stats;
};

@@ -110,6 +156,8 @@ int ath9k_debug_create_root(void);
void ath9k_debug_remove_root(void);
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
		       struct ath_buf *bf);
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
			    int xretries, int retries, u8 per);

@@ -148,6 +196,12 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
{
}

static inline void ath_debug_stat_tx(struct ath_softc *sc,
				     struct ath_txq *txq,
				     struct ath_buf *bf)
{
}

static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
					  int xretries, int retries, u8 per)
{
+21 −13
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
				  struct ath_atx_tid *tid,
				  struct list_head *bf_head);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
				struct ath_txq *txq,
				struct list_head *bf_q,
				int txok, int sendbar);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
@@ -212,7 +213,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
			ath_tx_update_baw(sc, tid, bf->bf_seqno);

		spin_unlock(&txq->axq_lock);
		ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
		ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
		spin_lock(&txq->axq_lock);
	}

@@ -220,13 +221,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
	tid->baw_tail = tid->baw_head;
}

static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
			     struct ath_buf *bf)
{
	struct sk_buff *skb;
	struct ieee80211_hdr *hdr;

	bf->bf_state.bf_type |= BUF_RETRY;
	bf->bf_retries++;
	TX_STAT_INC(txq->axq_qnum, a_retries);

	skb = bf->bf_mpdu;
	hdr = (struct ieee80211_hdr *)skb->data;
@@ -328,7 +331,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
			if (!(tid->state & AGGR_CLEANUP) &&
			    ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
				if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
					ath_tx_set_retry(sc, bf);
					ath_tx_set_retry(sc, txq, bf);
					txpending = 1;
				} else {
					bf->bf_state.bf_type |= BUF_XRETRY;
@@ -375,7 +378,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
				ath_tx_rc_status(bf, ds, nbad, txok, false);
			}

			ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
			ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
		} else {
			/* retry the un-acked ones */
			if (bf->bf_next == NULL && bf_last->bf_stale) {
@@ -395,8 +398,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
					bf->bf_state.bf_type |= BUF_XRETRY;
					ath_tx_rc_status(bf, ds, nbad,
							 0, false);
					ath_tx_complete_buf(sc, bf, &bf_head,
							    0, 0);
					ath_tx_complete_buf(sc, bf, txq,
							    &bf_head, 0, 0);
					break;
				}

@@ -569,6 +572,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
}

static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
					     struct ath_txq *txq,
					     struct ath_atx_tid *tid,
					     struct list_head *bf_q)
{
@@ -633,6 +637,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
			bf_prev->bf_desc->ds_link = bf->bf_daddr;
		}
		bf_prev = bf;

	} while (!list_empty(&tid->buf_q));

	bf_first->bf_al = al;
@@ -655,7 +660,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,

		INIT_LIST_HEAD(&bf_q);

		status = ath_tx_form_aggr(sc, tid, &bf_q);
		status = ath_tx_form_aggr(sc, txq, tid, &bf_q);

		/*
		 * no frames picked up to be aggregated;
@@ -686,6 +691,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,

		txq->axq_aggr_depth++;
		ath_tx_txqaddbuf(sc, txq, &bf_q);
		TX_STAT_INC(txq->axq_qnum, a_aggr);

	} while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
		 status != ATH_AGGR_BAW_CLOSED);
@@ -737,7 +743,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
		}
		list_move_tail(&bf->list, &bf_head);
		ath_tx_update_baw(sc, txtid, bf->bf_seqno);
		ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
		ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
	}
	spin_unlock_bh(&txq->axq_lock);

@@ -859,7 +865,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
		spin_lock_init(&txq->axq_lock);
		txq->axq_depth = 0;
		txq->axq_aggr_depth = 0;
		txq->axq_totalqueued = 0;
		txq->axq_linkbuf = NULL;
		txq->axq_tx_inprogress = false;
		sc->tx.txqsetup |= 1<<qnum;
@@ -1025,7 +1030,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
		if (bf_isampdu(bf))
			ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
		else
			ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
			ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
	}

	spin_lock_bh(&txq->axq_lock);
@@ -1176,7 +1181,6 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,

	list_splice_tail_init(head, &txq->axq_q);
	txq->axq_depth++;
	txq->axq_totalqueued++;
	txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);

	DPRINTF(sc, ATH_DBG_QUEUE,
@@ -1224,6 +1228,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,

	bf = list_first_entry(bf_head, struct ath_buf, list);
	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:
@@ -1270,6 +1275,7 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
	bf->bf_lastbf = bf;
	ath_buf_set_rate(sc, bf);
	ath_tx_txqaddbuf(sc, txq, bf_head);
	TX_STAT_INC(txq->axq_qnum, queued);
}

static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@@ -1283,6 +1289,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
	bf->bf_nframes = 1;
	ath_buf_set_rate(sc, bf);
	ath_tx_txqaddbuf(sc, txq, bf_head);
	TX_STAT_INC(txq->axq_qnum, queued);
}

static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
@@ -1808,6 +1815,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
}

static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
				struct ath_txq *txq,
				struct list_head *bf_q,
				int txok, int sendbar)
{
@@ -1815,7 +1823,6 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
	unsigned long flags;
	int tx_flags = 0;


	if (sendbar)
		tx_flags = ATH_TX_BAR;

@@ -1828,6 +1835,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,

	dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
	ath_tx_complete(sc, skb, tx_flags);
	ath_debug_stat_tx(sc, txq, bf);

	/*
	 * Return the list of ath_buf of this mpdu to free queue
@@ -2015,7 +2023,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
		if (bf_isampdu(bf))
			ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
		else
			ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);
			ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0);

		ath_wake_mac80211_queue(sc, txq);