ath9k: keep track of what's triggering hardware resets
authorFelix Fietkau <nbd@openwrt.org>
Fri, 7 Oct 2011 00:28:13 +0000 (02:28 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 11 Oct 2011 20:41:13 +0000 (16:41 -0400)
Export how many times each of the reset triggers has fired through debugfs.

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/xmit.c

index a5329c98f9ea53858772503669ba4c50e9e4cd6a..327aa28f60307a6609d6a8d8030ba9d3203c3322 100644 (file)
@@ -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);
index b93e88bd8c5890aa3fbd111b4025cd121201332b..356352ac2d6eeba7ea4834f90f44e5aa4d7aaf56 100644 (file)
@@ -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
index 98831866575832d3e84f34bbce53a90c17248274..366912f16ffaea9ce4b8190a82a652930d778da4 100644 (file)
@@ -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;
                }
index 49f1543ba13110a6bc025ecdfda8e2c6010f4aaf..7c4dae27931120c501c872396538755b70bd74cd 100644 (file)
@@ -564,8 +564,10 @@ 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);
        }