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

Commit 7f010c93 authored by Ben Greear's avatar Ben Greear Committed by John W. Linville
Browse files

ath9k: Keep track of stations for debugfs.



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.

Signed-off-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent bda8adda
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -254,7 +254,10 @@ struct ath_atx_tid {
};
};


struct ath_node {
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_tid tid[WME_NUM_TID];
	struct ath_atx_ac ac[WME_NUM_AC];
	struct ath_atx_ac ac[WME_NUM_AC];
	u16 maxampdu;
	u16 maxampdu;
@@ -638,6 +641,8 @@ struct ath_softc {


#ifdef CONFIG_ATH9K_DEBUGFS
#ifdef CONFIG_ATH9K_DEBUGFS
	struct ath9k_debug debug;
	struct ath9k_debug debug;
	spinlock_t nodes_lock;
	struct list_head nodes; /* basically, stations */
#endif
#endif
	struct ath_beacon_config cur_beacon_conf;
	struct ath_beacon_config cur_beacon_conf;
	struct delayed_work tx_complete_work;
	struct delayed_work tx_complete_work;
+92 −2
Original line number Original line Diff line number Diff line
@@ -587,6 +587,8 @@ static const struct file_operations fops_wiphy = {
		sc->debug.stats.txstats[WME_AC_BK].elem, \
		sc->debug.stats.txstats[WME_AC_BK].elem, \
		sc->debug.stats.txstats[WME_AC_VI].elem, \
		sc->debug.stats.txstats[WME_AC_VI].elem, \
		sc->debug.stats.txstats[WME_AC_VO].elem); \
		sc->debug.stats.txstats[WME_AC_VO].elem); \
		if (len >= size)			  \
			goto done;			  \
} while(0)
} while(0)


#define PRX(str, elem)							\
#define PRX(str, elem)							\
@@ -597,6 +599,8 @@ do { \
			(unsigned int)(sc->tx.txq[WME_AC_BK].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_VI].elem),	\
			(unsigned int)(sc->tx.txq[WME_AC_VO].elem));	\
			(unsigned int)(sc->tx.txq[WME_AC_VO].elem));	\
	if (len >= size)						\
		goto done;						\
} while(0)
} while(0)


#define PRQLE(str, elem)						\
#define PRQLE(str, elem)						\
@@ -607,6 +611,8 @@ do { \
			list_empty(&sc->tx.txq[WME_AC_BK].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_VI].elem),	\
			list_empty(&sc->tx.txq[WME_AC_VO].elem));	\
			list_empty(&sc->tx.txq[WME_AC_VO].elem));	\
	if (len >= size)						\
		goto done;						\
} while (0)
} while (0)


static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
@@ -614,7 +620,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
{
{
	struct ath_softc *sc = file->private_data;
	struct ath_softc *sc = file->private_data;
	char *buf;
	char *buf;
	unsigned int len = 0, size = 4000;
	unsigned int len = 0, size = 8000;
	int i;
	int i;
	ssize_t retval = 0;
	ssize_t retval = 0;
	char tmp[32];
	char tmp[32];
@@ -623,7 +629,10 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
	if (buf == NULL)
	if (buf == NULL)
		return -ENOMEM;
		return -ENOMEM;


	len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
	len += sprintf(buf, "Num-Tx-Queues: %i  tx-queues-setup: 0x%x\n"
		       "%30s %10s%10s%10s\n\n",
		       ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup,
		       "BE", "BK", "VI", "VO");


	PR("MPDUs Queued:    ", queued);
	PR("MPDUs Queued:    ", queued);
	PR("MPDUs Completed: ", completed);
	PR("MPDUs Completed: ", completed);
@@ -644,6 +653,14 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
	PR("hw-put-tx-buf:   ", puttxbuf);
	PR("hw-put-tx-buf:   ", puttxbuf);
	PR("hw-tx-start:     ", txstart);
	PR("hw-tx-start:     ", txstart);
	PR("hw-tx-proc-desc: ", txprocdesc);
	PR("hw-tx-proc-desc: ", txprocdesc);
	len += snprintf(buf + len, size - len,
			"%s%11p%11p%10p%10p\n", "txq-memory-address:",
			&(sc->tx.txq[WME_AC_BE]),
			&(sc->tx.txq[WME_AC_BK]),
			&(sc->tx.txq[WME_AC_VI]),
			&(sc->tx.txq[WME_AC_VO]));
	if (len >= size)
		goto done;


	PRX("axq-qnum:        ", axq_qnum);
	PRX("axq-qnum:        ", axq_qnum);
	PRX("axq-depth:       ", axq_depth);
	PRX("axq-depth:       ", axq_depth);
@@ -661,6 +678,68 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
		snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
		snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
		PRQLE(tmp, txq_fifo[i]);
		PRQLE(tmp, txq_fifo[i]);
	}
	}

done:
	if (len > size)
		len = size;

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

	return retval;
}

static ssize_t read_file_stations(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 = 64000;
	struct ath_node *an = NULL;
	ssize_t retval = 0;
	int q;

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

	len += snprintf(buf + len, size - len,
			"Stations:\n"
			" tid: addr sched paused buf_q-empty an ac\n"
			" ac: addr sched tid_q-empty txq\n");

	spin_lock(&sc->nodes_lock);
	list_for_each_entry(an, &sc->nodes, list) {
		len += snprintf(buf + len, size - len,
				"%pM\n", an->sta->addr);
		if (len >= size)
			goto done;

		for (q = 0; q < WME_NUM_TID; q++) {
			struct ath_atx_tid *tid = &(an->tid[q]);
			len += snprintf(buf + len, size - len,
					" tid: %p %s %s %i %p %p\n",
					tid, tid->sched ? "sched" : "idle",
					tid->paused ? "paused" : "running",
					list_empty(&tid->buf_q),
					tid->an, tid->ac);
			if (len >= size)
				goto done;
		}

		for (q = 0; q < WME_NUM_AC; q++) {
			struct ath_atx_ac *ac = &(an->ac[q]);
			len += snprintf(buf + len, size - len,
					" ac: %p %s %i %p\n",
					ac, ac->sched ? "sched" : "idle",
					list_empty(&ac->tid_q), ac->txq);
			if (len >= size)
				goto done;
		}
	}

done:
	spin_unlock(&sc->nodes_lock);
	if (len > size)
	if (len > size)
		len = size;
		len = size;


@@ -708,6 +787,13 @@ static const struct file_operations fops_xmit = {
	.llseek = default_llseek,
	.llseek = default_llseek,
};
};


static const struct file_operations fops_stations = {
	.read = read_file_stations,
	.open = ath9k_debugfs_open,
	.owner = THIS_MODULE,
	.llseek = default_llseek,
};

static ssize_t read_file_recv(struct file *file, char __user *user_buf,
static ssize_t read_file_recv(struct file *file, char __user *user_buf,
			      size_t count, loff_t *ppos)
			      size_t count, loff_t *ppos)
{
{
@@ -945,6 +1031,10 @@ int ath9k_init_debug(struct ath_hw *ah)
			sc, &fops_xmit))
			sc, &fops_xmit))
		goto err;
		goto err;


	if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_stations))
		goto err;

	if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
	if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
			sc, &fops_recv))
			sc, &fops_recv))
		goto err;
		goto err;
+4 −0
Original line number Original line Diff line number Diff line
@@ -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_serial_rw);
	spin_lock_init(&sc->sc_pm_lock);
	spin_lock_init(&sc->sc_pm_lock);
	mutex_init(&sc->mutex);
	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->intr_tq, ath9k_tasklet, (unsigned long)sc);
	tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
	tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
		     (unsigned long)sc);
		     (unsigned long)sc);
+13 −0
Original line number Original line Diff line number Diff line
@@ -548,6 +548,12 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
	struct ath_hw *ah = sc->sc_ah;
	struct ath_hw *ah = sc->sc_ah;
	an = (struct ath_node *)sta->drv_priv;
	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)
	if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
		sc->sc_flags |= SC_OP_ENABLE_APM;
		sc->sc_flags |= SC_OP_ENABLE_APM;


@@ -563,6 +569,13 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
{
{
	struct ath_node *an = (struct ath_node *)sta->drv_priv;
	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)
	if (sc->sc_flags & SC_OP_TXAGGR)
		ath_tx_node_cleanup(sc, an);
		ath_tx_node_cleanup(sc, an);
}
}