Commit 030d6294 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

ath9k: keep track of what's triggering hardware resets



Export how many times each of the reset triggers has fired through debugfs.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 34d25810
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -523,9 +523,22 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
	if (tmp & ATH9K_RX_FILTER_PHYRADAR)
		len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
	if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
		len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n");
	else
		len += snprintf(buf + len, sizeof(buf) - len, "\n");
		len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");

	len += snprintf(buf + len, sizeof(buf) - len,
		       "\n\nReset causes:\n"
		       "  baseband hang: %d\n"
		       "  baseband watchdog: %d\n"
		       "  fatal hardware error interrupt: %d\n"
		       "  tx hardware error: %d\n"
		       "  tx path hang: %d\n"
		       "  pll rx hang: %d\n",
		       sc->debug.stats.reset[RESET_TYPE_BB_HANG],
		       sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG],
		       sc->debug.stats.reset[RESET_TYPE_FATAL_INT],
		       sc->debug.stats.reset[RESET_TYPE_TX_ERROR],
		       sc->debug.stats.reset[RESET_TYPE_TX_HANG],
		       sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);

	if (len > sizeof(buf))
		len = sizeof(buf);
+13 −0
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ struct ath_buf;

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

#ifdef CONFIG_ATH9K_DEBUGFS
@@ -171,10 +173,21 @@ struct ath_rx_stats {
	u8 rs_antenna;
};

enum ath_reset_type {
	RESET_TYPE_BB_HANG,
	RESET_TYPE_BB_WATCHDOG,
	RESET_TYPE_FATAL_INT,
	RESET_TYPE_TX_ERROR,
	RESET_TYPE_TX_HANG,
	RESET_TYPE_PLL_HANG,
	__RESET_TYPE_MAX
};

struct ath_stats {
	struct ath_interrupt_stats istats;
	struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
	struct ath_rx_stats rxstats;
	u32 reset[__RESET_TYPE_MAX];
};

#define ATH_DBG_MAX_SAMPLES	10
+14 −1
Original line number Diff line number Diff line
@@ -679,6 +679,16 @@ void ath9k_tasklet(unsigned long data)

	if ((status & ATH9K_INT_FATAL) ||
	    (status & ATH9K_INT_BB_WATCHDOG)) {
#ifdef CONFIG_ATH9K_DEBUGFS
		enum ath_reset_type type;

		if (status & ATH9K_INT_FATAL)
			type = RESET_TYPE_FATAL_INT;
		else
			type = RESET_TYPE_BB_WATCHDOG;

		RESET_STAT_INC(sc, type);
#endif
		ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
		goto out;
	}
@@ -995,8 +1005,10 @@ void ath_hw_check(struct work_struct *work)
	ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, "
		"busy=%d (try %d)\n", busy, sc->hw_busy_count + 1);
	if (busy >= 99) {
		if (++sc->hw_busy_count >= 3)
		if (++sc->hw_busy_count >= 3) {
			RESET_STAT_INC(sc, RESET_TYPE_BB_HANG);
			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
		}

	} else if (busy >= 0)
		sc->hw_busy_count = 0;
@@ -1016,6 +1028,7 @@ static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
			/* Rx is hung for more than 500ms. Reset it */
			ath_dbg(common, ATH_DBG_RESET,
				"Possible RX hang, resetting");
			RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG);
			ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
			count = 0;
		}
+4 −1
Original line number Diff line number Diff line
@@ -564,9 +564,11 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,

	rcu_read_unlock();

	if (needreset)
	if (needreset) {
		RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR);
		ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
	}
}

static bool ath_lookup_legacy(struct ath_buf *bf)
{
@@ -2206,6 +2208,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
	if (needreset) {
		ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
			"tx hung, resetting the chip\n");
		RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
		ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
	}