From 9467e3f3fc8214fbf9e7ab7f3c957857b0b29c41 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Tue, 10 Apr 2012 07:23:37 +0000 Subject: [PATCH] Squirrel away SYNC interrupt debugging if it's enabled in the HAL. Bus errors will show up as various SYNC interrupts which will be passed back up to ath_intr(). --- sys/dev/ath/if_ath.c | 14 +++++++++++++- sys/dev/ath/if_ath_sysctl.c | 24 ++++++++++++++++++++++++ sys/dev/ath/if_athioctl.h | 4 ++++ sys/dev/ath/if_athvar.h | 1 + 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index f2552a6a00df..588880059164 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -1495,6 +1495,15 @@ ath_intr(void *arg) ah->ah_intrstate[3], ah->ah_intrstate[6]); #endif + + /* Squirrel away SYNC interrupt debugging */ + if (ah->ah_syncstate != 0) { + int i; + for (i = 0; i < 32; i++) + if (ah->ah_syncstate & (i << i)) + sc->sc_intr_stats.sync_intr[i]++; + } + status &= sc->sc_imask; /* discard unasked for bits */ /* Short-circuit un-handled interrupts */ @@ -6476,8 +6485,11 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) ifr->ifr_data, sizeof (sc->sc_stats)); case SIOCZATHSTATS: error = priv_check(curthread, PRIV_DRIVER); - if (error == 0) + if (error == 0) { memset(&sc->sc_stats, 0, sizeof(sc->sc_stats)); + memset(&sc->sc_intr_stats, 0, + sizeof(sc->sc_intr_stats)); + } break; #ifdef ATH_DIAGAPI case SIOCGATHDIAG: diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index 95c0615f3869..6e7c2c8024c4 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -655,6 +655,7 @@ ath_sysctl_clearstats(SYSCTL_HANDLER_ARGS) return 0; /* Not clearing the stats is still valid */ memset(&sc->sc_stats, 0, sizeof(sc->sc_stats)); memset(&sc->sc_aggr_stats, 0, sizeof(sc->sc_aggr_stats)); + memset(&sc->sc_intr_stats, 0, sizeof(sc->sc_intr_stats)); val = 0; return 0; @@ -677,6 +678,26 @@ ath_sysctl_stats_attach_rxphyerr(struct ath_softc *sc, struct sysctl_oid_list *p } } +static void +ath_sysctl_stats_attach_intr(struct ath_softc *sc, + struct sysctl_oid_list *parent) +{ + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + int i; + char sn[8]; + + tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "sync_intr", + CTLFLAG_RD, NULL, "Sync interrupt statistics"); + child = SYSCTL_CHILDREN(tree); + for (i = 0; i < 32; i++) { + snprintf(sn, sizeof(sn), "%d", i); + SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD, + &sc->sc_intr_stats.sync_intr[i], 0, ""); + } +} + void ath_sysctl_stats_attach(struct ath_softc *sc) { @@ -904,6 +925,9 @@ ath_sysctl_stats_attach(struct ath_softc *sc) /* Attach the RX phy error array */ ath_sysctl_stats_attach_rxphyerr(sc, child); + + /* Attach the interrupt statistics array */ + ath_sysctl_stats_attach_intr(sc, child); } /* diff --git a/sys/dev/ath/if_athioctl.h b/sys/dev/ath/if_athioctl.h index 23ce3b1a5a97..8627a6bf88a0 100644 --- a/sys/dev/ath/if_athioctl.h +++ b/sys/dev/ath/if_athioctl.h @@ -46,6 +46,10 @@ struct ath_tx_aggr_stats { u_int32_t aggr_rts_aggr_limited; }; +struct ath_intr_stats { + u_int32_t sync_intr[32]; +}; + struct ath_stats { u_int32_t ast_watchdog; /* device reset by watchdog */ u_int32_t ast_hardware; /* fatal hardware error interrupts */ diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 77e70662356e..1b2b9ab6ad2b 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -349,6 +349,7 @@ struct ath_softc { struct ifnet *sc_ifp; /* interface common */ struct ath_stats sc_stats; /* interface statistics */ struct ath_tx_aggr_stats sc_aggr_stats; + struct ath_intr_stats sc_intr_stats; int sc_debug; int sc_nvaps; /* # vaps */ int sc_nstavaps; /* # station vaps */